From cd93f204b5dea1eb96a7fca2e1d07b43d487542b Mon Sep 17 00:00:00 2001 From: Bob Owen Date: Thu, 20 Aug 2015 12:45:09 +0100 Subject: [PATCH 001/208] Bug 1185532: Turn on the NPAPI process sandbox for Windows 64-bit flash by default. r=bsmedberg --- browser/app/profile/firefox.js | 5 +++++ dom/plugins/ipc/PluginModuleParent.cpp | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index c691514ad32e..c4332e464477 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1184,7 +1184,12 @@ pref("security.sandbox.windows.log", false); // 3 - the strongest settings we seem to be able to use without breaking // everything, but will probably cause some functionality restrictions pref("dom.ipc.plugins.sandbox-level.default", 0); +#if defined(_AMD64_) +// The lines in PluginModuleParent.cpp should be changed in line with this. +pref("dom.ipc.plugins.sandbox-level.flash", 2); +#else pref("dom.ipc.plugins.sandbox-level.flash", 0); +#endif #if defined(MOZ_CONTENT_SANDBOX) // This controls the strength of the Windows content process sandbox for testing diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index fa682f000799..fe7fb480674f 100755 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -491,6 +491,16 @@ PluginModuleChromeParent::LoadModule(const char* aFilePath, uint32_t aPluginId, if (NS_FAILED(Preferences::GetInt(sandboxPref.get(), &sandboxLevel))) { sandboxLevel = Preferences::GetInt("dom.ipc.plugins.sandbox-level.default"); } + +#if defined(_AMD64_) + // As level 2 is now the default NPAPI sandbox level for 64-bit flash, we + // don't want to allow a lower setting unless this environment variable is + // set. This should be changed if the firefox.js pref file is changed. + if (aPluginTag->mIsFlashPlugin && + !PR_GetEnv("MOZ_ALLOW_WEAKER_SANDBOX") && sandboxLevel < 2) { + sandboxLevel = 2; + } +#endif #endif nsAutoPtr parent(new PluginModuleChromeParent(aFilePath, aPluginId, From ce4ccfdc897fcbab635dcda12f30ffe7600e963d Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Thu, 20 Aug 2015 08:03:31 -0400 Subject: [PATCH 002/208] Bug 1196253 - update in-tree psutil to 3.1.1. r=gps --- python/psutil/CREDITS | 49 +- python/psutil/HISTORY.rst | 137 +- python/psutil/INSTALL.rst | 72 +- python/psutil/MANIFEST.in | 9 +- python/psutil/Makefile | 76 +- python/psutil/PKG-INFO | 91 +- python/psutil/README.rst | 85 +- python/psutil/TODO | 61 +- python/psutil/docs/conf.py | 26 +- python/psutil/docs/index.rst | 231 ++- python/psutil/docs/xxx | 11 + python/psutil/examples/disk_usage.py | 7 +- python/psutil/examples/free.py | 7 +- python/psutil/examples/ifconfig.py | 78 + python/psutil/examples/iotop.py | 17 +- python/psutil/examples/meminfo.py | 7 +- python/psutil/examples/netstat.py | 5 +- python/psutil/examples/nettop.py | 10 +- python/psutil/examples/pidof.py | 53 + python/psutil/examples/pmap.py | 11 +- python/psutil/examples/process_detail.py | 25 +- python/psutil/examples/ps.py | 26 +- python/psutil/examples/pstree.py | 71 + python/psutil/examples/top.py | 13 +- python/psutil/examples/who.py | 3 +- python/psutil/make.bat | 185 +-- python/psutil/psutil.egg-info/PKG-INFO | 434 +++++ python/psutil/psutil.egg-info/SOURCES.txt | 96 ++ .../psutil.egg-info/dependency_links.txt | 1 + python/psutil/psutil.egg-info/top_level.txt | 1 + python/psutil/psutil/__init__.py | 731 ++++----- python/psutil/psutil/_common.py | 118 +- python/psutil/psutil/_compat.py | 260 +-- python/psutil/psutil/_psbsd.py | 122 +- python/psutil/psutil/_pslinux.py | 736 +++++---- python/psutil/psutil/_psosx.py | 52 +- python/psutil/psutil/_psposix.py | 23 +- python/psutil/psutil/_pssunos.py | 78 +- python/psutil/psutil/_psutil_bsd.c | 490 +++--- python/psutil/psutil/_psutil_bsd.h | 4 +- python/psutil/psutil/_psutil_linux.c | 191 ++- python/psutil/psutil/_psutil_linux.h | 1 + python/psutil/psutil/_psutil_osx.c | 279 ++-- python/psutil/psutil/_psutil_posix.c | 425 ++++- python/psutil/psutil/_psutil_posix.h | 5 + python/psutil/psutil/_psutil_sunos.c | 229 ++- python/psutil/psutil/_psutil_sunos.h | 1 + python/psutil/psutil/_psutil_windows.c | 1174 ++++++++------ python/psutil/psutil/_psutil_windows.h | 10 +- python/psutil/psutil/_pswindows.py | 136 +- python/psutil/psutil/arch/bsd/process_info.c | 32 +- python/psutil/psutil/arch/osx/process_info.c | 40 +- python/psutil/psutil/arch/windows/inet_ntop.c | 41 + python/psutil/psutil/arch/windows/inet_ntop.h | 10 + python/psutil/psutil/arch/windows/ntextapi.h | 93 +- .../psutil/arch/windows/process_handles.c | 766 +++++---- .../psutil/arch/windows/process_handles.h | 103 ++ .../psutil/psutil/arch/windows/process_info.c | 36 +- .../psutil/psutil/arch/windows/process_info.h | 9 + python/psutil/psutil/arch/windows/security.c | 24 +- python/psutil/setup.py | 56 +- python/psutil/test/README | 15 - python/psutil/test/README.rst | 21 + python/psutil/test/__init__.py | 0 python/psutil/test/_bsd.py | 39 +- python/psutil/test/_linux.py | 295 +++- python/psutil/test/_osx.py | 9 +- python/psutil/test/_posix.py | 36 +- python/psutil/test/_sunos.py | 10 +- python/psutil/test/_windows.py | 192 ++- python/psutil/test/test_memory_leaks.py | 102 +- python/psutil/test/test_psutil.py | 1425 ++++++++++------- python/psutil/tox.ini | 22 +- 73 files changed, 6510 insertions(+), 3829 deletions(-) create mode 100644 python/psutil/docs/xxx create mode 100644 python/psutil/examples/ifconfig.py create mode 100755 python/psutil/examples/pidof.py create mode 100644 python/psutil/examples/pstree.py create mode 100644 python/psutil/psutil.egg-info/PKG-INFO create mode 100644 python/psutil/psutil.egg-info/SOURCES.txt create mode 100644 python/psutil/psutil.egg-info/dependency_links.txt create mode 100644 python/psutil/psutil.egg-info/top_level.txt create mode 100644 python/psutil/psutil/arch/windows/inet_ntop.c create mode 100644 python/psutil/psutil/arch/windows/inet_ntop.h delete mode 100644 python/psutil/test/README create mode 100644 python/psutil/test/README.rst delete mode 100644 python/psutil/test/__init__.py diff --git a/python/psutil/CREDITS b/python/psutil/CREDITS index 29027150b126..170751b0a3b0 100644 --- a/python/psutil/CREDITS +++ b/python/psutil/CREDITS @@ -255,9 +255,56 @@ I: 492 N: Jeff Tang W: https://github.com/mrjefftang -I: 340, 529 +I: 340, 529, 616, 653, 654 N: Yaolong Huang E: airekans@gmail.com W: http://airekans.github.io/ I: 530 + +N: Anders Chrigström +W: https://github.com/anders-chrigstrom +I: 496 + +N: spacewander +E: spacewanderlzx@gmail.com +I: 561 + +N: Sylvain Mouquet +E: sylvain.mouquet@gmail.com +I: 565 + +N: karthikrev +I: 568 + +N: Bruno Binet +E: bruno.binet@gmail.com +I: 572 + +N: Gabi Davar +C: Israel +W: https://github.com/mindw +I: 578, 581, 587 + +N: spacewanderlzx +C: Guangzhou,China +E: spacewanderlzx@gmail.com +I: 555 + +N: Fabian Groffen +I: 611, 618 + +N: desbma +W: https://github.com/desbma +C: France +I: 628 + +N: John Burnett +W: http://www.johnburnett.com/ +C: Irvine, CA, US +I: 614 + +N: Árni Már Jónsson +E: Reykjavik, Iceland +E: https://github.com/arnimarj +I: 634 diff --git a/python/psutil/HISTORY.rst b/python/psutil/HISTORY.rst index 65309c1ba197..12b985d1e93f 100644 --- a/python/psutil/HISTORY.rst +++ b/python/psutil/HISTORY.rst @@ -1,10 +1,143 @@ Bug tracker at https://github.com/giampaolo/psutil/issues -2.1.3 2014-09-26 -================ +3.1.1 - 2015-07-15 +================== + +**Bug fixes** + +- #645: [Linux] psutil.cpu_times_percent() may produce negative results. +- #656: 'from psutil import *' does not work. + + +3.1.0 - 2015-07-15 +================== + +**Enhancements** + +- #534: [Linux] disk_partitions() added support for ZFS filesystems. +- #646: continuous tests integration for Windows with + https://ci.appveyor.com/project/giampaolo/psutil. +- #647: new dev guide: + https://github.com/giampaolo/psutil/blob/master/DEVGUIDE.rst +- #651: continuous code quality test integration with + https://scrutinizer-ci.com/g/giampaolo/psutil/ + +**Bug fixes** + +- #340: [Windows] Process.open_files() no longer hangs. Instead it uses a + thred which times out and skips the file handle in case it's taking too long + to be retrieved. (patch by Jeff Tang, PR #597) +- #627: [Windows] Process.name() no longer raises AccessDenied for pids owned + by another user. +- #636: [Windows] Process.memory_info() raise AccessDenied. +- #637: [UNIX] raise exception if trying to send signal to Process PID 0 as it + will affect os.getpid()'s process group instead of PID 0. +- #639: [Linux] Process.cmdline() can be truncated. +- #640: [Linux] *connections functions may swallow errors and return an + incomplete list of connnections. +- #642: repr() of exceptions is incorrect. +- #653: [Windows] Add inet_ntop function for Windows XP to support IPv6. +- #641: [Windows] Replace deprecated string functions with safe equivalents. + + +3.0.1 - 2015-06-18 +================== + +**Bug fixes** + +- #632: [Linux] better error message if cannot parse process UNIX connections. +- #634: [Linux] Proces.cmdline() does not include empty string arguments. +- #635: [UNIX] crash on module import if 'enum' package is installed on python + < 3.4. + + +3.0.0 - 2015-06-13 +================== + +**Enhancements** + +- #250: new psutil.net_if_stats() returning NIC statistics (isup, duplex, + speed, MTU). +- #376: new psutil.net_if_addrs() returning all NIC addresses a-la ifconfig. +- #469: on Python >= 3.4 ``IOPRIO_CLASS_*`` and ``*_PRIORITY_CLASS`` constants + returned by psutil.Process' ionice() and nice() methods are enums instead of + plain integers. +- #581: add .gitignore. (patch by Gabi Davar) +- #582: connection constants returned by psutil.net_connections() and + psutil.Process.connections() were turned from int to enums on Python > 3.4. +- #587: Move native extension into the package. +- #589: Process.cpu_affinity() accepts any kind of iterable (set, tuple, ...), + not only lists. +- #594: all deprecated APIs were removed. +- #599: [Windows] process name() can now be determined for all processes even + when running as a limited user. +- #602: pre-commit GIT hook. +- #629: enhanced support for py.test and nose test discovery and tests run. +- #616: [Windows] Add inet_ntop function for Windows XP. + +**Bug fixes** + +- #428: [all UNIXes except Linux] correct handling of zombie processes; + introduced new ZombieProcess exception class. +- #512: [BSD] fix segfault in net_connections(). +- #555: [Linux] psutil.users() correctly handles ":0" as an alias for + "localhost" +- #579: [Windows] Fixed open_files() for PID>64K. +- #579: [Windows] fixed many compiler warnings. +- #585: [FreeBSD] net_connections() may raise KeyError. +- #586: [FreeBSD] cpu_affinity() segfaults on set in case an invalid CPU + number is provided. +- #593: [FreeBSD] Process().memory_maps() segfaults. +- #606: Process.parent() may swallow NoSuchProcess exceptions. +- #611: [SunOS] net_io_counters has send and received swapped +- #614: [Linux]: cpu_count(logical=False) return the number of physical CPUs + instead of physical cores. +- #618: [SunOS] swap tests fail on Solaris when run as normal user +- #628: [Linux] Process.name() truncates process name in case it contains + spaces or parentheses. + + +2.2.1 - 2015-02-02 +================== **Bug fixes** +- #496: [Linux] fix "ValueError: ambiguos inode with multiple PIDs references" + (patch by Bruno Binet) + + +2.2.0 - 2015-01-06 +================== + +**Enhancements** + +- #521: drop support for Python 2.4 and 2.5. +- #553: new examples/pstree.py script. +- #564: C extension version mismatch in case the user messed up with psutil + installation or with sys.path is now detected at import time. +- #568: New examples/pidof.py script. +- #569: [FreeBSD] add support for process CPU affinity. + +**Bug fixes** + +- #496: [Solaris] can't import psutil. +- #547: [UNIX] Process.username() may raise KeyError if UID can't be resolved. +- #551: [Windows] get rid of the unicode hack for net_io_counters() NIC names. +- #556: [Linux] lots of file handles were left open. +- #561: [Linux] net_connections() might skip some legitimate UNIX sockets. + (patch by spacewander) +- #565: [Windows] use proper encoding for psutil.Process.username() and + psutil.users(). (patch by Sylvain Mouquet) +- #567: [Linux] in the alternative implementation of CPU affinity PyList_Append + and Py_BuildValue return values are not checked. +- #569: [FreeBSD] fix memory leak in psutil.cpu_count(logical=False). +- #571: [Linux] Process.open_files() might swallow AccessDenied exceptions and + return an incomplete list of open files. + + +2.1.3 - 2014-09-26 +================== + - #536: [Linux]: fix "undefined symbol: CPU_ALLOC" compilation error. diff --git a/python/psutil/INSTALL.rst b/python/psutil/INSTALL.rst index 93ce46919746..e518c430ee4d 100644 --- a/python/psutil/INSTALL.rst +++ b/python/psutil/INSTALL.rst @@ -4,12 +4,12 @@ Installing using pip on UNIX The easiest way to install psutil on UNIX is by using pip (but first you might need to install python header files; see later). -First install pip: +First install pip:: - $ wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py - python ez_setup.py + $ wget https://bootstrap.pypa.io/get-pip.py + $ python get-pip.py -...then run: +...then run:: $ pip install psutil @@ -22,51 +22,27 @@ Installing on Windows Just get the right installer for your Python version and architecture from: https://pypi.python.org/pypi/psutil/#downloads - - -================================== -Compiling on Windows using mingw32 -================================== - -First install mingw (http://www.mingw.org/) then add mingw "bin" folder to -environment PATH (NOTE: this assumes MinGW is installed in C:\MinGW): - - SET PATH=C:\MinGW\bin;%PATH% - -You can then compile psutil by running: - - setup.py build -c mingw32 - -To compile and install: - - setup.py build -c mingw32 install - -You can also use make.bat which automatically sets the env variable for you: - - make.bat build - -FWIW I managed to compile psutil against all 32-bit Python versions but not -64 bit. +Since wheels installers are also available you may also use pip. ======================================== Compiling on Windows using Visual Studio ======================================== -To use Visual Studio to compile psutil you must have the same version of -Visual Studio used to compile your installation of Python which is:: +In order to compile psutil on Windows you'll need Visual Studio (Mingw32 is +no longer supported). You must have the same version of Visual Studio used to compile +your installation of Python, that is:: - Python 2.4: VS 2003 - Python 2.5: VS 2003 - Python 2.6: VS 2008 - Python 2.7: VS 2008 - Python 3.3+: VS 2010 +* Python 2.6: VS 2008 +* Python 2.7: VS 2008 +* Python 3.3, 3.4: VS 2010 (you can download it from `MS website `_) +* Python 3.5: `VS 2015 UP `_ -...then run: +...then run:: setup.py build -...or: +...or:: make.bat build @@ -75,24 +51,20 @@ Windows SDK and .NET Framework 3.5 SP1 to be installed first. Once you have those run vcvars64.bat, then compile: http://stackoverflow.com/questions/11072521/ -If you do not have the right version of Visual Studio available then try using -MinGW instead. - - =================== Installing on Linux =================== gcc is required and so the python headers. They can easily be installed by -using the distro package manager. For example, on Debian amd Ubuntu: +using the distro package manager. For example, on Debian and Ubuntu:: $ sudo apt-get install gcc python-dev -...on Redhat and CentOS: +...on Redhat and CentOS:: $ sudo yum install gcc python-devel -Once done, you can build/install psutil with: +Once done, you can build/install psutil with:: $ python setup.py install @@ -104,11 +76,11 @@ Installing on OS X OS X installation from source will require gcc which you can obtain as part of the 'XcodeTools' installer from Apple. Then you can run the standard distutils commands. -To build only: +To build only:: $ python setup.py build -To install and build: +To install and build:: $ python setup.py install @@ -121,11 +93,11 @@ The same compiler used to install Python must be present on the system in order to build modules using distutils. Assuming it is installed, you can build using the standard distutils commands. -Build only: +Build only:: $ python setup.py build -Install and build: +Install and build:: $ python setup.py install @@ -138,7 +110,7 @@ A makefile is available for both UNIX and Windows (make.bat). It provides some automations for the tasks described above and might be preferred over using setup.py. With it you can:: - $ make install # just install + $ make install # just install (in --user mode) $ make uninstall # uninstall (needs pip) $ make test # run tests $ make clean # remove installation files diff --git a/python/psutil/MANIFEST.in b/python/psutil/MANIFEST.in index b275f613b381..d807be289d54 100644 --- a/python/psutil/MANIFEST.in +++ b/python/psutil/MANIFEST.in @@ -1,3 +1,7 @@ +include .coveragerc +include .git-pre-commit +include .git-pre-commit +include .gitignore include .travis.yml include CREDITS include HISTORY.rst @@ -10,8 +14,9 @@ include README.rst include setup.py include TODO include tox.ini -recursive-include docs * recursive-exclude docs/_build * +recursive-include .appveyor/* +recursive-include docs * recursive-include examples *.py recursive-include psutil *.py *.c *.h -recursive-include test *.py README \ No newline at end of file +recursive-include test *.py README* diff --git a/python/psutil/Makefile b/python/psutil/Makefile index 9b7949535054..1e4eb4b01ac5 100644 --- a/python/psutil/Makefile +++ b/python/psutil/Makefile @@ -16,31 +16,49 @@ clean: rm -f `find . -type f -name \*.bak` rm -f `find . -type f -name \*.rej` rm -rf `find . -type d -name __pycache__` + rm -rf *.core rm -rf *.egg-info rm -rf *\$testfile* + rm -rf .coverage rm -rf .tox rm -rf build rm -rf dist rm -rf docs/_build + rm -rf htmlcov build: clean $(PYTHON) setup.py build + @# copies *.so files in ./psutil directory in order to allow + @# "import psutil" when using the interactive interpreter from within + @# this directory. + $(PYTHON) setup.py build_ext -i + +# useful deps which are nice to have while developing / testing +setup-dev-env: + python -c "import urllib2; \ + r = urllib2.urlopen('https://bootstrap.pypa.io/get-pip.py'); \ + open('/tmp/get-pip.py', 'w').write(r.read());" + $(PYTHON) /tmp/get-pip.py --user + rm /tmp/get-pip.py + $(PYTHON) -m pip install --user --upgrade pip + $(PYTHON) -m pip install --user --upgrade \ + coverage \ + flake8 \ + ipaddress \ + ipdb \ + mock==1.0.1 \ + nose \ + pep8 \ + pyflakes \ + sphinx \ + sphinx-pypi-upload \ + unittest2 \ install: build - if test $(PYTHON) = python2.4; then \ - $(PYTHON) setup.py install; \ - elif test $(PYTHON) = python2.5; then \ - $(PYTHON) setup.py install; \ - else \ - $(PYTHON) setup.py install --user; \ - fi + $(PYTHON) setup.py install --user uninstall: - if test $(PYTHON) = python2.4; then \ - pip-2.4 uninstall -y -v psutil; \ - else \ - cd ..; $(PYTHON) -m pip uninstall -y -v psutil; \ - fi + cd ..; $(PYTHON) -m pip uninstall -y -v psutil test: install $(PYTHON) $(TSCRIPT) @@ -52,27 +70,36 @@ test-system: install $(PYTHON) -m unittest -v test.test_psutil.TestSystemAPIs test-memleaks: install - $(PYTHON) -m unittest -v test.test_memory_leaks + $(PYTHON) test/test_memory_leaks.py # Run a specific test by name; e.g. "make test-by-name disk_" will run # all test methods containing "disk_" in their name. # Requires "pip install nose". -test-by-name: - @$(PYTHON) -m nose test/test_psutil.py --nocapture -v -m $(filter-out $@,$(MAKECMDGOALS)) +test-by-name: install + @$(PYTHON) -m nose test/test_psutil.py test/_* --nocapture -v -m $(filter-out $@,$(MAKECMDGOALS)) + +# Same as above but for test_memory_leaks.py script. +test-memleaks-by-name: install + @$(PYTHON) -m nose test/test_memory_leaks.py --nocapture -v -m $(filter-out $@,$(MAKECMDGOALS)) + +coverage: install + # Note: coverage options are controlled by .coveragerc file + rm -rf .coverage htmlcov + $(PYTHON) -m coverage run $(TSCRIPT) + $(PYTHON) -m coverage report + @echo "writing results to htmlcov/index.html" + $(PYTHON) -m coverage html + $(PYTHON) -m webbrowser -t htmlcov/index.html -# requires "pip install pep8" pep8: - @git ls-files | grep \\.py$ | xargs pep8 + @git ls-files | grep \\.py$ | xargs $(PYTHON) -m pep8 -# requires "pip install pyflakes" pyflakes: @export PYFLAKES_NODOCTEST=1 && \ - git ls-files | grep \\.py$ | xargs pyflakes + git ls-files | grep \\.py$ | xargs $(PYTHON) -m pyflakes -# requires "pip install flake8" flake8: - @git ls-files | grep \\.py$ | xargs flake8 - + @git ls-files | grep \\.py$ | xargs $(PYTHON) -m flake8 # Upload source tarball on https://pypi.python.org/pypi/psutil. upload-src: clean @@ -88,3 +115,8 @@ upload-doc: git-tag-release: git tag -a release-`python -c "import setup; print(setup.get_version())"` -m `git rev-list HEAD --count`:`git rev-parse --short HEAD` echo "done; now run 'git push --follow-tags' to push the new tag on the remote repo" + +# install GIT pre-commit hook +install-git-hooks: + ln -sf ../../.git-pre-commit .git/hooks/pre-commit + chmod +x .git/hooks/pre-commit diff --git a/python/psutil/PKG-INFO b/python/psutil/PKG-INFO index f505977ea812..e74d33f6587d 100644 --- a/python/psutil/PKG-INFO +++ b/python/psutil/PKG-INFO @@ -1,36 +1,54 @@ Metadata-Version: 1.1 Name: psutil -Version: 2.1.3 +Version: 3.1.1 Summary: psutil is a cross-platform library for retrieving information onrunning processes and system utilization (CPU, memory, disks, network)in Python. Home-page: https://github.com/giampaolo/psutil Author: Giampaolo Rodola Author-email: g.rodola gmail com License: BSD -Description: .. image:: https://pypip.in/d/psutil/badge.png - :target: https://crate.io/packages/psutil/ - :alt: Download this month +Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg + :target: https://pypi.python.org/pypi/psutil#downloads + :alt: Downloads this month - .. image:: https://pypip.in/v/psutil/badge.png + .. image:: https://api.travis-ci.org/giampaolo/psutil.png?branch=master + :target: https://travis-ci.org/giampaolo/psutil + :alt: Linux tests (Travis) + + .. image:: https://ci.appveyor.com/api/projects/status/qdwvw7v1t915ywr5/branch/master?svg=true + :target: https://ci.appveyor.com/project/giampaolo/psutil + :alt: Windows tests (Appveyor) + + .. image:: https://coveralls.io/repos/giampaolo/psutil/badge.svg?branch=master&service=github + :target: https://coveralls.io/github/giampaolo/psutil?branch=master + :alt: Test coverage (coverall.io) + + .. image:: https://img.shields.io/pypi/v/psutil.svg :target: https://pypi.python.org/pypi/psutil/ :alt: Latest version - .. image:: https://pypip.in/license/psutil/badge.png + .. image:: https://img.shields.io/github/stars/giampaolo/psutil.svg + :target: https://github.com/giampaolo/psutil/ + :alt: Github stars + + .. image:: https://img.shields.io/scrutinizer/g/giampaolo/psutil.svg + :target: https://scrutinizer-ci.com/g/giampaolo/psutil/ + :alt: Code quality (scrutinizer-ci.com) + + .. image:: https://img.shields.io/pypi/l/psutil.svg :target: https://pypi.python.org/pypi/psutil/ :alt: License - .. image:: https://api.travis-ci.org/giampaolo/psutil.png?branch=master - :target: https://travis-ci.org/giampaolo/psutil - :alt: Travis - =========== Quick links =========== - `Home page `_ - `Documentation `_ + - `Installation `_ - `Download `_ - `Forum `_ - `Blog `_ + - `Development guide `_ - `What's new `_ ======= @@ -45,8 +63,9 @@ Description: .. image:: https://pypip.in/d/psutil/badge.png tools such as: ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice, ionice, iostat, iotop, uptime, pidof, tty, taskset, pmap. It currently supports **Linux, Windows, OSX, FreeBSD** and **Sun Solaris**, both **32-bit** and - **64-bit** architectures, with Python versions from **2.4 to 3.4**. PyPy is - also known to work. + **64-bit** architectures, with Python versions from **2.6 to 3.5** (users of + Python 2.4 and 2.5 may use `2.1.3 `__ version). + `PyPy `__ is also known to work. ==================== Example applications @@ -67,8 +86,8 @@ Description: .. image:: https://pypip.in/d/psutil/badge.png See also: * https://github.com/nicolargo/glances + * https://github.com/google/grr * https://github.com/Jahaja/psdash - * https://code.google.com/p/grr/ ============== Example usages @@ -117,9 +136,9 @@ Description: .. image:: https://pypip.in/d/psutil/badge.png .. code-block:: python >>> psutil.virtual_memory() - svmem(total=8374149120L, available=2081050624L, percent=75.1, used=8074080256L, free=300068864L, active=3294920704, inactive=1361616896, buffers=529895424L, cached=1251086336) + svmem(total=8374149120, available=2081050624, percent=75.1, used=8074080256, free=300068864, active=3294920704, inactive=1361616896, buffers=529895424, cached=1251086336) >>> psutil.swap_memory() - sswap(total=2097147904L, used=296128512L, free=1801019392L, percent=14.1, sin=304193536, sout=677842944) + sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944) >>> Disks @@ -148,11 +167,23 @@ Description: .. image:: https://pypip.in/d/psutil/badge.png 'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)} >>> >>> psutil.net_connections() - [pconn(fd=115, family=2, type=1, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254), - pconn(fd=117, family=2, type=1, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987), - pconn(fd=-1, family=2, type=1, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None), - pconn(fd=-1, family=2, type=1, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None) + [pconn(fd=115, family=, type=, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254), + pconn(fd=117, family=, type=, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987), + pconn(fd=-1, family=, type=, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None), + pconn(fd=-1, family=, type=, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None) ...] + >>> + >>> psutil.net_if_addrs() + {'lo': [snic(family=, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1'), + snic(family=, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None), + snic(family=, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00')], + 'wlan0': [snic(family=, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255'), + snic(family=, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None), + snic(family=, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff')]} + >>> + >>> psutil.net_if_stats() + {'eth0': snicstats(isup=True, duplex=, speed=100, mtu=1500), + 'lo': snicstats(isup=True, duplex=, speed=0, mtu=65536)} Other system info ================= @@ -218,7 +249,7 @@ Description: .. image:: https://pypip.in/d/psutil/badge.png >>> >>> p.memory_info() pmem(rss=7471104, vms=68513792) - >>> p.ext_memory_info() + >>> p.memory_info_ex() extmem(rss=9662464, vms=49192960, shared=3612672, text=2564096, lib=0, data=5754880, dirty=0) >>> p.memory_maps() [pmmap_grouped(path='/lib/x86_64-linux-gnu/libutil-2.15.so', rss=16384, anonymous=8192, swap=0), @@ -235,10 +266,10 @@ Description: .. image:: https://pypip.in/d/psutil/badge.png [popenfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)] >>> >>> p.connections() - [pconn(fd=115, family=2, type=1, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'), - pconn(fd=117, family=2, type=1, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'), - pconn(fd=119, family=2, type=1, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'), - pconn(fd=123, family=2, type=1, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')] + [pconn(fd=115, family=, type=, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'), + pconn(fd=117, family=, type=, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'), + pconn(fd=119, family=, type=, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'), + pconn(fd=123, family=, type=, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')] >>> >>> p.num_threads() 4 @@ -259,7 +290,7 @@ Description: .. image:: https://pypip.in/d/psutil/badge.png >>> >>> p.ionice(psutil.IOPRIO_CLASS_IDLE) # IO priority (Win and Linux only) >>> p.ionice() - pionice(ioclass=3, value=0) + pionice(ioclass=, value=0) >>> >>> p.rlimit(psutil.RLIMIT_NOFILE, (5, 5)) # set resource limits (Linux only) >>> p.rlimit(psutil.RLIMIT_NOFILE) @@ -327,6 +358,12 @@ Description: .. image:: https://pypip.in/d/psutil/badge.png Timeline ======== + - 2015-07-15: `psutil-3.1.1.tar.gz `_ + - 2015-07-15: `psutil-3.1.0.tar.gz `_ + - 2015-06-18: `psutil-3.0.1.tar.gz `_ + - 2015-06-13: `psutil-3.0.0.tar.gz `_ + - 2015-02-02: `psutil-2.2.1.tar.gz `_ + - 2015-01-06: `psutil-2.2.0.tar.gz `_ - 2014-09-26: `psutil-2.1.3.tar.gz `_ - 2014-09-21: `psutil-2.1.2.tar.gz `_ - 2014-04-30: `psutil-2.1.1.tar.gz `_ @@ -356,7 +393,7 @@ Description: .. image:: https://pypip.in/d/psutil/badge.png - 2009-03-06: `psutil-0.1.1.tar.gz `_ - 2009-01-27: `psutil-0.1.0.tar.gz `_ -Keywords: ps,top,kill,free,lsof,netstat,nice,tty,ionice,uptime,taskmgr,process,df,iotop,iostat,ifconfig,taskset,who,pidof,pmap,smem,monitoring,ulimit,prlimit +Keywords: ps,top,kill,free,lsof,netstat,nice,tty,ionice,uptime,taskmgr,process,df,iotop,iostat,ifconfig,taskset,who,pidof,pmap,smem,pstree,monitoring,ulimit,prlimit Platform: Platform Independent Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Console @@ -375,8 +412,6 @@ Classifier: Operating System :: POSIX :: SunOS/Solaris Classifier: Operating System :: POSIX Classifier: Programming Language :: C Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.4 -Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 diff --git a/python/psutil/README.rst b/python/psutil/README.rst index f0926851197d..564656146c42 100644 --- a/python/psutil/README.rst +++ b/python/psutil/README.rst @@ -1,28 +1,46 @@ -.. image:: https://pypip.in/d/psutil/badge.png - :target: https://crate.io/packages/psutil/ - :alt: Download this month +.. image:: https://img.shields.io/pypi/dm/psutil.svg + :target: https://pypi.python.org/pypi/psutil#downloads + :alt: Downloads this month -.. image:: https://pypip.in/v/psutil/badge.png +.. image:: https://api.travis-ci.org/giampaolo/psutil.png?branch=master + :target: https://travis-ci.org/giampaolo/psutil + :alt: Linux tests (Travis) + +.. image:: https://ci.appveyor.com/api/projects/status/qdwvw7v1t915ywr5/branch/master?svg=true + :target: https://ci.appveyor.com/project/giampaolo/psutil + :alt: Windows tests (Appveyor) + +.. image:: https://coveralls.io/repos/giampaolo/psutil/badge.svg?branch=master&service=github + :target: https://coveralls.io/github/giampaolo/psutil?branch=master + :alt: Test coverage (coverall.io) + +.. image:: https://img.shields.io/pypi/v/psutil.svg :target: https://pypi.python.org/pypi/psutil/ :alt: Latest version -.. image:: https://pypip.in/license/psutil/badge.png +.. image:: https://img.shields.io/github/stars/giampaolo/psutil.svg + :target: https://github.com/giampaolo/psutil/ + :alt: Github stars + +.. image:: https://img.shields.io/scrutinizer/g/giampaolo/psutil.svg + :target: https://scrutinizer-ci.com/g/giampaolo/psutil/ + :alt: Code quality (scrutinizer-ci.com) + +.. image:: https://img.shields.io/pypi/l/psutil.svg :target: https://pypi.python.org/pypi/psutil/ :alt: License -.. image:: https://api.travis-ci.org/giampaolo/psutil.png?branch=master - :target: https://travis-ci.org/giampaolo/psutil - :alt: Travis - =========== Quick links =========== - `Home page `_ - `Documentation `_ +- `Installation `_ - `Download `_ - `Forum `_ - `Blog `_ +- `Development guide `_ - `What's new `_ ======= @@ -37,8 +55,9 @@ running processes**. It implements many functionalities offered by command line tools such as: ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice, ionice, iostat, iotop, uptime, pidof, tty, taskset, pmap. It currently supports **Linux, Windows, OSX, FreeBSD** and **Sun Solaris**, both **32-bit** and -**64-bit** architectures, with Python versions from **2.4 to 3.4**. PyPy is -also known to work. +**64-bit** architectures, with Python versions from **2.6 to 3.5** (users of +Python 2.4 and 2.5 may use `2.1.3 `__ version). +`PyPy `__ is also known to work. ==================== Example applications @@ -59,8 +78,8 @@ Example applications See also: * https://github.com/nicolargo/glances + * https://github.com/google/grr * https://github.com/Jahaja/psdash - * https://code.google.com/p/grr/ ============== Example usages @@ -109,9 +128,9 @@ Memory .. code-block:: python >>> psutil.virtual_memory() - svmem(total=8374149120L, available=2081050624L, percent=75.1, used=8074080256L, free=300068864L, active=3294920704, inactive=1361616896, buffers=529895424L, cached=1251086336) + svmem(total=8374149120, available=2081050624, percent=75.1, used=8074080256, free=300068864, active=3294920704, inactive=1361616896, buffers=529895424, cached=1251086336) >>> psutil.swap_memory() - sswap(total=2097147904L, used=296128512L, free=1801019392L, percent=14.1, sin=304193536, sout=677842944) + sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944) >>> Disks @@ -140,11 +159,23 @@ Network 'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)} >>> >>> psutil.net_connections() - [pconn(fd=115, family=2, type=1, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254), - pconn(fd=117, family=2, type=1, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987), - pconn(fd=-1, family=2, type=1, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None), - pconn(fd=-1, family=2, type=1, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None) + [pconn(fd=115, family=, type=, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254), + pconn(fd=117, family=, type=, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987), + pconn(fd=-1, family=, type=, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None), + pconn(fd=-1, family=, type=, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None) ...] + >>> + >>> psutil.net_if_addrs() + {'lo': [snic(family=, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1'), + snic(family=, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None), + snic(family=, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00')], + 'wlan0': [snic(family=, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255'), + snic(family=, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None), + snic(family=, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff')]} + >>> + >>> psutil.net_if_stats() + {'eth0': snicstats(isup=True, duplex=, speed=100, mtu=1500), + 'lo': snicstats(isup=True, duplex=, speed=0, mtu=65536)} Other system info ================= @@ -210,7 +241,7 @@ Process management >>> >>> p.memory_info() pmem(rss=7471104, vms=68513792) - >>> p.ext_memory_info() + >>> p.memory_info_ex() extmem(rss=9662464, vms=49192960, shared=3612672, text=2564096, lib=0, data=5754880, dirty=0) >>> p.memory_maps() [pmmap_grouped(path='/lib/x86_64-linux-gnu/libutil-2.15.so', rss=16384, anonymous=8192, swap=0), @@ -227,10 +258,10 @@ Process management [popenfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)] >>> >>> p.connections() - [pconn(fd=115, family=2, type=1, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'), - pconn(fd=117, family=2, type=1, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'), - pconn(fd=119, family=2, type=1, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'), - pconn(fd=123, family=2, type=1, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')] + [pconn(fd=115, family=, type=, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'), + pconn(fd=117, family=, type=, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'), + pconn(fd=119, family=, type=, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'), + pconn(fd=123, family=, type=, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')] >>> >>> p.num_threads() 4 @@ -251,7 +282,7 @@ Process management >>> >>> p.ionice(psutil.IOPRIO_CLASS_IDLE) # IO priority (Win and Linux only) >>> p.ionice() - pionice(ioclass=3, value=0) + pionice(ioclass=, value=0) >>> >>> p.rlimit(psutil.RLIMIT_NOFILE, (5, 5)) # set resource limits (Linux only) >>> p.rlimit(psutil.RLIMIT_NOFILE) @@ -319,6 +350,12 @@ http://groups.google.com/group/psutil/ Timeline ======== +- 2015-07-15: `psutil-3.1.1.tar.gz `_ +- 2015-07-15: `psutil-3.1.0.tar.gz `_ +- 2015-06-18: `psutil-3.0.1.tar.gz `_ +- 2015-06-13: `psutil-3.0.0.tar.gz `_ +- 2015-02-02: `psutil-2.2.1.tar.gz `_ +- 2015-01-06: `psutil-2.2.0.tar.gz `_ - 2014-09-26: `psutil-2.1.3.tar.gz `_ - 2014-09-21: `psutil-2.1.2.tar.gz `_ - 2014-04-30: `psutil-2.1.1.tar.gz `_ diff --git a/python/psutil/TODO b/python/psutil/TODO index a2bd9f53ab7e..a5df809d023a 100644 --- a/python/psutil/TODO +++ b/python/psutil/TODO @@ -9,22 +9,29 @@ https://github.com/giampaolo/psutil/issues HIGHER PRIORITY =============== - * #250: net ifaces speed. - - * #376: ifconfig functionalities aka psutil.net_ifaces (could be merged - with #250) - * OpenBSD support. * #371: CPU temperature (apparently OSX and Linux only; on Linux it requires lm-sensors lib). - * #269: expose network ifaces RX/TW queues. + * #269: expose network ifaces RX/TW queues. This should probably go into + net_if_stats(). Figure out on what platforms this is supported: + Linux: yes + Others: ? - * Process.threads(): thread names + * Process.threads(): thread names; patch for OSX available at: + https://code.google.com/p/plcrashreporter/issues/detail?id=65 * Asynchronous psutil.Popen (see http://bugs.python.org/issue1191964) + * (Windows) fall back on using WMIC for Process methods returning AccessDenied + + * #613: thread names. + + * #604: emulate os.getloadavg() on Windows + + * #269: NIC rx/tx queue. + LOWER PRIORITY ============== @@ -39,11 +46,6 @@ LOWER PRIORITY * AIX support? - * examples/pidof.py (same as 'pidof' cli tool) - - * examples/pstree.py (same as 'pstree' cli tool) - * threads() should also return thread names in order to implement it - * examples/taskmgr-gui.py (using tk). * system-wide number of open file descriptors: @@ -55,10 +57,7 @@ LOWER PRIORITY * #357: what CPU a process is on. - * thread names: - * https://code.google.com/p/plcrashreporter/issues/detail?id=65 - - * Doc / wiki which compares similarities between UNIX cli tools and psutil. + * Doc / wiki which compares similarities between UNIX cli tools and psutil. Example: df -a -> psutil.disk_partitions lsof -> psutil.Process.open_files() and psutil.Process.open_connections() @@ -70,7 +69,13 @@ LOWER PRIORITY DEBATABLE ========= - * support wheels? http://pythonwheels.com/ + * psutil.proc_tree() something which obtains a {pid:ppid, ...} dict for + all running processes in one shot. This can be factored out from + Process.children() and exposed as a first class function. + PROS: on Windows we can take advantage of _psutil_windows.ppid_map() + which is faster than iterating over all pids and calling ppid(). + CONS: examples/pstree.py shows this can be easily done in the user code + so maybe it's not worth the addition. * advanced cmdline interface exposing the whole API and providing different kind of outputs (e.g. pprinted, colorized, json). @@ -91,10 +96,18 @@ DEBATABLE Also, we can probably reimplement wait_pid() on POSIX which is currently implemented as a busy-loop. - * Certain systems (XXX figure out which ones exactly) provide CPU times about - process children. On those systems Process.cpu_times() might return - a (user, system, user_children, system_children) ntuple. - Also, os.times() provides 'elapsed' times as well. + * Certain systems provide CPU times about process children. On those systems + Process.cpu_times() might return a (user, system, user_children, + system_children) ntuple. + * Linux: /proc/{PID}/stat + * Solaris: pr_cutime and pr_cstime + * FreeBSD: none + * OSX: none + * Windows: none + + * ...also, os.times() provides 'elapsed' times as well. + + * ...also Linux provides guest_time and cguest_time. * Enrich exception classes hierarchy on Python >= 3.3 / post PEP-3151 so that: - NoSuchProcess inherits from ProcessLookupError @@ -130,6 +143,10 @@ DEBATABLE * round Process.memory_percent() result? + * #550: number of threads per core. + + * Have psutil.Process().cpu_affinity([]) be an alias for "all CPUs"? + COMPATIBILITY BREAKAGE ====================== @@ -147,4 +164,4 @@ Removals (will likely happen in 2.2): REJECTED IDEAS ============== -STUB \ No newline at end of file +STUB diff --git a/python/psutil/docs/conf.py b/python/psutil/docs/conf.py index 9ec91df70dda..9fa163b65eac 100644 --- a/python/psutil/docs/conf.py +++ b/python/psutil/docs/conf.py @@ -14,29 +14,17 @@ import datetime import os -import sys -if sys.version_info >= (3, ): - def u(s): - return s -else: - def u(s): - if not isinstance(s, unicode): # NOQA - s = unicode(s, "unicode_escape") # NOQA - return s - - -PROJECT_NAME = u("psutil") -AUTHOR = u("Giampaolo Rodola'") +PROJECT_NAME = "psutil" +AUTHOR = "Giampaolo Rodola'" THIS_YEAR = str(datetime.datetime.now().year) HERE = os.path.abspath(os.path.dirname(__file__)) def get_version(): INIT = os.path.abspath(os.path.join(HERE, '../psutil/__init__.py')) - f = open(INIT, 'r') - try: + with open(INIT, 'r') as f: for line in f: if line.startswith('__version__'): ret = eval(line.strip().split(' = ')[1]) @@ -46,8 +34,6 @@ def get_version(): return ret else: raise ValueError("couldn't find version string") - finally: - f.close() VERSION = get_version() @@ -77,7 +63,7 @@ def get_version(): # General information about the project. project = PROJECT_NAME -copyright = u('2009-%s, %s' % (THIS_YEAR, AUTHOR)) +copyright = '2009-%s, %s' % (THIS_YEAR, AUTHOR) # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -223,7 +209,7 @@ def get_version(): # [howto/manual]). latex_documents = [ ('index', '%s.tex' % PROJECT_NAME, - u('%s documentation') % PROJECT_NAME, AUTHOR), + '%s documentation' % PROJECT_NAME, AUTHOR), ] # The name of an image file (relative to this directory) to place at @@ -255,7 +241,7 @@ def get_version(): # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', PROJECT_NAME, u('%s documentation') % PROJECT_NAME, [AUTHOR], 1) + ('index', PROJECT_NAME, '%s documentation' % PROJECT_NAME, [AUTHOR], 1) ] # If true, show URL addresses after external links. diff --git a/python/psutil/docs/index.rst b/python/psutil/docs/index.rst index e053b9357534..44301922678d 100644 --- a/python/psutil/docs/index.rst +++ b/python/psutil/docs/index.rst @@ -18,8 +18,10 @@ Quick links * `Home page `__ * `Blog `__ -* `Download `__ * `Forum `__ +* `Download `__ +* `Installation `_ +* `Development guide `_ * `What's new `__ About @@ -38,8 +40,8 @@ From project's home page: ionice, iostat, iotop, uptime, pidof, tty, taskset, pmap*. It currently supports **Linux, Windows, OSX, FreeBSD** and **Sun Solaris**, both **32-bit** and **64-bit** architectures, with Python versions from - **2.4** to **3.4**. - `Pypy `__ is also known to work. + **2.6 to 3.4** (users of Python 2.4 and 2.5 may use `2.1.3 `__ version). + `PyPy `__ is also known to work. The psutil documentation you're reading is distributed as a single HTML page. @@ -66,7 +68,7 @@ CPU - **guest** *(Linux 2.6.24+)* - **guest_nice** *(Linux 3.2.0+)* - When *percpu* is ``True`` return a list of nameduples for each logical CPU + When *percpu* is ``True`` return a list of namedtuples for each logical CPU on the system. First element of the list refers to first CPU, second element to second CPU and so on. @@ -199,7 +201,7 @@ Memory * **total**: total swap memory in bytes * **used**: used swap memory in bytes * **free**: free swap memory in bytes - * **percent**: the percentage usage + * **percent**: the percentage usage calculated as ``(total - available) / total * 100`` * **sin**: the number of bytes the system has swapped in from disk (cumulative) * **sout**: the number of bytes the system has swapped out from disk @@ -274,7 +276,7 @@ Disks If *perdisk* is ``True`` return the same information for every physical disk installed on the system as a dictionary with partition names as the keys and - the namedutuple described above as the values. + the namedtuple described above as the values. See `examples/iotop.py `__ for an example application. @@ -321,7 +323,7 @@ Network .. function:: net_connections(kind='inet') - Return system-wide socket connections as a list of namedutples. + Return system-wide socket connections as a list of namedtuples. Every namedtuple provides 7 attributes: - **fd**: the socket file descriptor, if retrievable, else ``-1``. @@ -383,6 +385,7 @@ Network | "all" | the sum of all the possible families and protocols | +----------------+-----------------------------------------------------+ + On OSX this function requires root privileges. To get per-process connections use :meth:`Process.connections`. Also, see `netstat.py sample script `__. @@ -390,17 +393,85 @@ Network >>> import psutil >>> psutil.net_connections() - [pconn(fd=115, family=2, type=1, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254), - pconn(fd=117, family=2, type=1, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987), - pconn(fd=-1, family=2, type=1, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None), - pconn(fd=-1, family=2, type=1, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None) + [pconn(fd=115, family=, type=, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254), + pconn(fd=117, family=, type=, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987), + pconn(fd=-1, family=, type=, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None), + pconn(fd=-1, family=, type=, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None) ...] .. note:: (OSX) :class:`psutil.AccessDenied` is always raised unless running as root (lsof does the same). .. note:: (Solaris) UNIX sockets are not supported. - *New in 2.1.0* + .. versionadded:: 2.1.0 + +.. function:: net_if_addrs() + + Return the addresses associated to each NIC (network interface card) + installed on the system as a dictionary whose keys are the NIC names and + value is a list of namedtuples for each address assigned to the NIC. + Each namedtuple includes 4 fields: + + - **family** + - **address** + - **netmask** + - **broadcast** + + *family* can be either + `AF_INET `__, + `AF_INET6 `__ + or :const:`psutil.AF_LINK`, which refers to a MAC address. + *address* is the primary address, *netmask* and *broadcast* may be ``None``. + Example:: + + >>> import psutil + >>> psutil.net_if_addrs() + {'lo': [snic(family=, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1'), + snic(family=, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None), + snic(family=, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00')], + 'wlan0': [snic(family=, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255'), + snic(family=, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None), + snic(family=, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff')]} + >>> + + See also `examples/ifconfig.py `__ + for an example application. + + .. note:: if you're interested in others families (e.g. AF_BLUETOOTH) you can + use the more powerful `netifaces `__ + extension. + + .. note:: you can have more than one address of the same family associated + with each interface (that's why dict values are lists). + + *New in 3.0.0* + +.. function:: net_if_stats() + + Return information about each NIC (network interface card) installed on the + system as a dictionary whose keys are the NIC names and value is a namedtuple + with the following fields: + + - **isup** + - **duplex** + - **speed** + - **mtu** + + *isup* is a boolean indicating whether the NIC is up and running, *duplex* + can be either :const:`NIC_DUPLEX_FULL`, :const:`NIC_DUPLEX_HALF` or + :const:`NIC_DUPLEX_UNKNOWN`, *speed* is the NIC speed expressed in mega bits + (MB), if it can't be determined (e.g. 'localhost') it will be set to ``0``, + *mtu* is the maximum transmission unit expressed in bytes. + See also `examples/ifconfig.py `__ + for an example application. + Example: + + >>> import psutil + >>> psutil.net_if_stats() + {'eth0': snicstats(isup=True, duplex=, speed=100, mtu=1500), + 'lo': snicstats(isup=True, duplex=, speed=0, mtu=65536)} + + *New in 3.0.0* Other system info @@ -498,7 +569,7 @@ Functions import psutil def on_terminate(proc): - print("process {} terminated".format(proc)) + print("process {} terminated with exit code {}".format(proc, proc.returncode)) procs = [...] # a list of Process instances for p in procs: @@ -521,6 +592,18 @@ Exceptions exists. "name" is the name the process had before disappearing and gets set only if :meth:`Process.name()` was previosly called. +.. class:: ZombieProcess(pid, name=None, ppid=None, msg=None) + + This may be raised by :class:`Process` class methods when querying a zombie + process on UNIX (Windows doesn't have zombie processes). Depending on the + method called the OS may be able to succeed in retrieving the process + information or not. + Note: this is a subclass of :class:`NoSuchProcess` so if you're not + interested in retrieving zombies (e.g. when using :func:`process_iter()`) + you can ignore this exception and just catch :class:`NoSuchProcess`. + + *New in 3.0.0* + .. class:: AccessDenied(pid=None, name=None, msg=None) Raised by :class:`Process` class methods when permission to perform an @@ -609,20 +692,24 @@ Process class >>> datetime.datetime.fromtimestamp(p.create_time()).strftime("%Y-%m-%d %H:%M:%S") '2011-03-05 18:03:52' - .. method:: as_dict(attrs=[], ad_value=None) + .. method:: as_dict(attrs=None, ad_value=None) Utility method returning process information as a hashable dictionary. If *attrs* is specified it must be a list of strings reflecting available :class:`Process` class's attribute names (e.g. ``['cpu_times', 'name']``) else all public (read only) attributes are assumed. *ad_value* is the value which gets assigned to a dict key in case :class:`AccessDenied` - exception is raised when retrieving that particular process information. + or :class:`ZombieProcess` exception is raised when retrieving that + particular process information. >>> import psutil >>> p = psutil.Process() >>> p.as_dict(attrs=['pid', 'name', 'username']) {'username': 'giampaolo', 'pid': 12366, 'name': 'python'} + .. versionchanged:: 3.0.0 *ad_value* is used also when incurring into + :class:`ZombieProcess` exception, not only :class:`AccessDenied` + .. method:: parent() Utility method which returns the parent process as a :class:`Process` @@ -646,7 +733,7 @@ Process class .. method:: uids() The **real**, **effective** and **saved** user ids of this process as a - nameduple. This is the same as + namedtuple. This is the same as `os.getresuid() `__ but can be used for every process PID. @@ -655,7 +742,7 @@ Process class .. method:: gids() The **real**, **effective** and **saved** group ids of this process as a - nameduple. This is the same as + namedtuple. This is the same as `os.getresgid() `__ but can be used for every process PID. @@ -682,6 +769,13 @@ Process class 10 >>> + Starting from `Python 3.3 `__ this + functionality is also available as + `os.getpriority() `__ + and + `os.setpriority() `__ + (UNIX only). + On Windows this is available as well by using `GetPriorityClass `__ and `SetPriorityClass `__ @@ -692,12 +786,6 @@ Process class >>> p.nice(psutil.HIGH_PRIORITY_CLASS) - Starting from `Python 3.3 `__ this - same functionality is available as - `os.getpriority() `__ - and - `os.setpriority() `__. - .. method:: ionice(ioclass=None, value=None) Get or set @@ -714,7 +802,7 @@ Process class >>> p = psutil.Process() >>> p.ionice(psutil.IOPRIO_CLASS_IDLE) # set >>> p.ionice() # get - pionice(ioclass=3, value=0) + pionice(ioclass=, value=0) >>> On Windows only *ioclass* is used and it can be set to ``2`` (normal), @@ -722,6 +810,10 @@ Process class Availability: Linux and Windows > Vista + .. versionchanged:: 3.0.0 on >= Python 3.4 the returned ``ioclass`` + constant is an `enum `__ + instead of a plain integer. + .. method:: rlimit(resource, limits=None) Get or set process resource limits (see @@ -761,7 +853,7 @@ Process class >>> p.io_counters() pio(read_count=454556, write_count=3456, read_bytes=110592, write_bytes=0) - Availability: all platforms except OSX + Availability: all platforms except OSX and Solaris .. method:: num_ctx_switches() @@ -836,7 +928,8 @@ Process class `CPU affinity `__. CPU affinity consists in telling the OS to run a certain process on a limited set of CPUs only. The number of eligible CPUs can be obtained with - ``list(range(psutil.cpu_count()))``. + ``list(range(psutil.cpu_count()))``. On set raises ``ValueError`` in case + an invalid CPU number is specified. >>> import psutil >>> psutil.cpu_count() @@ -845,9 +938,17 @@ Process class >>> p.cpu_affinity() # get [0, 1, 2, 3] >>> p.cpu_affinity([0]) # set; from now on, process will run on CPU #0 only + >>> p.cpu_affinity() + [0] >>> + >>> # reset affinity against all CPUs + >>> all_cpus = list(range(psutil.cpu_count())) + >>> p.cpu_affinity(all_cpus) + >>> + + Availability: Linux, Windows, BSD - Availability: Linux, Windows + .. versionchanged:: 2.2.0 added support for FreeBSD .. method:: memory_info() @@ -903,7 +1004,7 @@ Process class .. method:: memory_maps(grouped=True) - Return process's mapped memory regions as a list of nameduples whose + Return process's mapped memory regions as a list of namedtuples whose fields are variable depending on the platform. As such, portable applications should rely on namedtuple's `path` and `rss` fields only. This method is useful to obtain a detailed representation of process @@ -958,15 +1059,31 @@ Process class the absolute file name and the file descriptor number (on Windows this is always ``-1``). Example: - >>> import psutil - >>> f = open('file.ext', 'w') - >>> p = psutil.Process() - >>> p.open_files() - [popenfile(path='/home/giampaolo/svn/psutil/file.ext', fd=3)] + >>> import psutil + >>> f = open('file.ext', 'w') + >>> p = psutil.Process() + >>> p.open_files() + [popenfile(path='/home/giampaolo/svn/psutil/file.ext', fd=3)] + + .. warning:: + on Windows this is not fully reliable as due to some limitations of the + Windows API the underlying implementation may hang when retrieving + certain file handles. + In order to work around that psutil on Windows Vista (and higher) spawns + a thread and kills it if it's not responding after 100ms. + That implies that on Windows this method is not guaranteed to enumerate + all regular file handles (see full discusion + `here `_). + + .. warning:: + on FreeBSD this method can return files with a 'null' path (see + `issue 595 `_). + + .. versionchanged:: 3.1.0 no longer hangs on Windows. .. method:: connections(kind="inet") - Return socket connections opened by process as a list of namedutples. + Return socket connections opened by process as a list of namedtuples. To get system-wide connections use :func:`psutil.net_connections()`. Every namedtuple provides 6 attributes: @@ -1032,10 +1149,10 @@ Process class >>> p.name() 'firefox' >>> p.connections() - [pconn(fd=115, family=2, type=1, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'), - pconn(fd=117, family=2, type=1, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'), - pconn(fd=119, family=2, type=1, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'), - pconn(fd=123, family=2, type=1, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')] + [pconn(fd=115, family=, type=, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'), + pconn(fd=117, family=, type=, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'), + pconn(fd=119, family=, type=, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'), + pconn(fd=123, family=, type=, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')] .. method:: is_running() @@ -1125,7 +1242,7 @@ Popen class :meth:`send_signal() `, :meth:`terminate() ` and :meth:`kill() ` - so that you don't accidentally terminate another process, fixing + so that you can't accidentally terminate another process, fixing http://bugs.python.org/issue6973. >>> import psutil @@ -1197,6 +1314,10 @@ Constants Availability: Windows + .. versionchanged:: 3.0.0 on Python >= 3.4 these constants are + `enums `__ + instead of a plain integer. + .. _const-ioprio: .. data:: IOPRIO_CLASS_NONE IOPRIO_CLASS_RT @@ -1220,6 +1341,10 @@ Constants Availability: Linux + .. versionchanged:: 3.0.0 on Python >= 3.4 thse constants are + `enums `__ + instead of a plain integer. + .. _const-rlimit: .. data:: RLIMIT_INFINITY RLIMIT_AS @@ -1245,3 +1370,31 @@ Constants `man prlimit `__ for futher information. Availability: Linux + +.. _const-aflink: +.. data:: AF_LINK + + Constant which identifies a MAC address associated with a network interface. + To be used in conjunction with :func:`psutil.net_if_addrs()`. + + *New in 3.0.0* + +.. _const-duplex: +.. data:: NIC_DUPLEX_FULL + NIC_DUPLEX_HALF + NIC_DUPLEX_UNKNOWN + + Constants which identifies whether a NIC (network interface card) has full or + half mode speed. NIC_DUPLEX_FULL means the NIC is able to send and receive + data (files) simultaneously, NIC_DUPLEX_FULL means the NIC can either send or + receive data at a time. + To be used in conjunction with :func:`psutil.net_if_stats()`. + + *New in 3.0.0* + +Development guide +================= + +If you plan on hacking on psutil (e.g. want to add a new feature or fix a bug) +take a look at the +`development guide `_. diff --git a/python/psutil/docs/xxx b/python/psutil/docs/xxx new file mode 100644 index 000000000000..b78d53f2d6bb --- /dev/null +++ b/python/psutil/docs/xxx @@ -0,0 +1,11 @@ +cpu 1974613 1749 485728 6305758 80280 15 5924 0 0 0 + +cpu0 519156 374 132999 5977865 72925 10 1458 0 0 0 + +cpu1 524667 401 125931 108960 2110 4 2214 0 0 0 + +cpu2 462286 520 117046 109514 2666 0 828 0 0 0 + +cpu3 468502 453 109750 109418 2578 0 1424 0 0 0 + + diff --git a/python/psutil/examples/disk_usage.py b/python/psutil/examples/disk_usage.py index 787cb0f5ac9a..d8600a8c4764 100755 --- a/python/psutil/examples/disk_usage.py +++ b/python/psutil/examples/disk_usage.py @@ -18,7 +18,6 @@ import sys import os import psutil -from psutil._compat import print_ def bytes2human(n): @@ -40,8 +39,8 @@ def bytes2human(n): def main(): templ = "%-17s %8s %8s %8s %5s%% %9s %s" - print_(templ % ("Device", "Total", "Used", "Free", "Use ", "Type", - "Mount")) + print(templ % ("Device", "Total", "Used", "Free", "Use ", "Type", + "Mount")) for part in psutil.disk_partitions(all=False): if os.name == 'nt': if 'cdrom' in part.opts or part.fstype == '': @@ -50,7 +49,7 @@ def main(): # partition or just hang. continue usage = psutil.disk_usage(part.mountpoint) - print_(templ % ( + print(templ % ( part.device, bytes2human(usage.total), bytes2human(usage.used), diff --git a/python/psutil/examples/free.py b/python/psutil/examples/free.py index 95e11fb6847d..913ca58a4cfa 100755 --- a/python/psutil/examples/free.py +++ b/python/psutil/examples/free.py @@ -14,15 +14,14 @@ """ import psutil -from psutil._compat import print_ def main(): virt = psutil.virtual_memory() swap = psutil.swap_memory() templ = "%-7s %10s %10s %10s %10s %10s %10s" - print_(templ % ('', 'total', 'used', 'free', 'shared', 'buffers', 'cache')) - print_(templ % ( + print(templ % ('', 'total', 'used', 'free', 'shared', 'buffers', 'cache')) + print(templ % ( 'Mem:', int(virt.total / 1024), int(virt.used / 1024), @@ -30,7 +29,7 @@ def main(): int(getattr(virt, 'shared', 0) / 1024), int(getattr(virt, 'buffers', 0) / 1024), int(getattr(virt, 'cached', 0) / 1024))) - print_(templ % ( + print(templ % ( 'Swap:', int(swap.total / 1024), int(swap.used / 1024), int(swap.free / 1024), diff --git a/python/psutil/examples/ifconfig.py b/python/psutil/examples/ifconfig.py new file mode 100644 index 000000000000..e7a436cc0a0a --- /dev/null +++ b/python/psutil/examples/ifconfig.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python + +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +A clone of 'ifconfig' on UNIX. + +$ python examples/ifconfig.py +lo (speed=0MB, duplex=?, mtu=65536, up=yes): + IPv4 address : 127.0.0.1 + broadcast : 127.0.0.1 + netmask : 255.0.0.0 + IPv6 address : ::1 + netmask : ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff + MAC address : 00:00:00:00:00:00 + broadcast : 00:00:00:00:00:00 + +wlan0 (speed=0MB, duplex=?, mtu=1500, up=yes): + IPv4 address : 10.0.3.1 + broadcast : 10.0.3.255 + netmask : 255.255.255.0 + IPv6 address : fe80::3005:adff:fe31:8698 + netmask : ffff:ffff:ffff:ffff:: + MAC address : 32:05:ad:31:86:98 + broadcast : ff:ff:ff:ff:ff:ff + +eth0 (speed=100MB, duplex=full, mtu=1500, up=yes): + IPv4 address : 192.168.1.2 + broadcast : 192.168.1.255 + netmask : 255.255.255.0 + IPv6 address : fe80::c685:8ff:fe45:641 + netmask : ffff:ffff:ffff:ffff:: + MAC address : c4:85:08:45:06:41 + broadcast : ff:ff:ff:ff:ff:ff +""" + +from __future__ import print_function +import socket + +import psutil + + +af_map = { + socket.AF_INET: 'IPv4', + socket.AF_INET6: 'IPv6', + psutil.AF_LINK: 'MAC', +} + +duplex_map = { + psutil.NIC_DUPLEX_FULL: "full", + psutil.NIC_DUPLEX_HALF: "half", + psutil.NIC_DUPLEX_UNKNOWN: "?", +} + + +def main(): + stats = psutil.net_if_stats() + for nic, addrs in psutil.net_if_addrs().items(): + if nic in stats: + print("%s (speed=%sMB, duplex=%s, mtu=%s, up=%s):" % ( + nic, stats[nic].speed, duplex_map[stats[nic].duplex], + stats[nic].mtu, "yes" if stats[nic].isup else "no")) + else: + print("%s:" % (nic)) + for addr in addrs: + print(" %-8s" % af_map.get(addr.family, addr.family), end="") + print(" address : %s" % addr.address) + if addr.broadcast: + print(" broadcast : %s" % addr.broadcast) + if addr.netmask: + print(" netmask : %s" % addr.netmask) + print("") + + +if __name__ == '__main__': + main() diff --git a/python/psutil/examples/iotop.py b/python/psutil/examples/iotop.py index 47f1ca552634..16ac7fbf61b7 100755 --- a/python/psutil/examples/iotop.py +++ b/python/psutil/examples/iotop.py @@ -30,14 +30,15 @@ Author: Giampaolo Rodola' """ -import os +import atexit +import time import sys -import psutil -if not hasattr(psutil.Process, 'io_counters') or os.name != 'posix': +try: + import curses +except ImportError: sys.exit('platform not supported') -import time -import curses -import atexit + +import psutil # --- curses stuff @@ -116,7 +117,7 @@ def poll(interval): if not p._cmdline: p._cmdline = p.name() p._username = p.username() - except psutil.NoSuchProcess: + except (psutil.NoSuchProcess, psutil.ZombieProcess): procs.remove(p) disks_after = psutil.disk_io_counters() @@ -167,7 +168,7 @@ def refresh_window(procs, disks_read, disks_write): def main(): try: interval = 0 - while 1: + while True: args = poll(interval) refresh_window(*args) interval = 1 diff --git a/python/psutil/examples/meminfo.py b/python/psutil/examples/meminfo.py index 671f907caf55..c463a3de4b63 100755 --- a/python/psutil/examples/meminfo.py +++ b/python/psutil/examples/meminfo.py @@ -31,7 +31,6 @@ """ import psutil -from psutil._compat import print_ def bytes2human(n): @@ -56,13 +55,13 @@ def pprint_ntuple(nt): value = getattr(nt, name) if name != 'percent': value = bytes2human(value) - print_('%-10s : %7s' % (name.capitalize(), value)) + print('%-10s : %7s' % (name.capitalize(), value)) def main(): - print_('MEMORY\n------') + print('MEMORY\n------') pprint_ntuple(psutil.virtual_memory()) - print_('\nSWAP\n----') + print('\nSWAP\n----') pprint_ntuple(psutil.swap_memory()) if __name__ == '__main__': diff --git a/python/psutil/examples/netstat.py b/python/psutil/examples/netstat.py index 70bc23175493..884622e9e3a6 100755 --- a/python/psutil/examples/netstat.py +++ b/python/psutil/examples/netstat.py @@ -23,7 +23,6 @@ from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM import psutil -from psutil._compat import print_ AD = "-" @@ -38,7 +37,7 @@ def main(): templ = "%-5s %-30s %-30s %-13s %-6s %s" - print_(templ % ( + print(templ % ( "Proto", "Local address", "Remote address", "Status", "PID", "Program name")) proc_names = {} @@ -52,7 +51,7 @@ def main(): raddr = "" if c.raddr: raddr = "%s:%s" % (c.raddr) - print_(templ % ( + print(templ % ( proto_map[(c.family, c.type)], laddr, raddr or AD, diff --git a/python/psutil/examples/nettop.py b/python/psutil/examples/nettop.py index 857285cf885b..7a8343ee4cd9 100755 --- a/python/psutil/examples/nettop.py +++ b/python/psutil/examples/nettop.py @@ -31,13 +31,13 @@ pkts-recv 1214470 0 """ -import sys -import os -if os.name != 'posix': - sys.exit('platform not supported') import atexit -import curses import time +import sys +try: + import curses +except ImportError: + sys.exit('platform not supported') import psutil diff --git a/python/psutil/examples/pidof.py b/python/psutil/examples/pidof.py new file mode 100755 index 000000000000..8692a3152bc3 --- /dev/null +++ b/python/psutil/examples/pidof.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +# Copyright (c) 2009, Giampaolo Rodola', karthikrev. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + + +""" +A clone of 'pidof' cmdline utility. +$ pidof python +1140 1138 1136 1134 1133 1129 1127 1125 1121 1120 1119 +""" + +from __future__ import print_function +import psutil +import sys + + +def pidof(pgname): + pids = [] + for proc in psutil.process_iter(): + # search for matches in the process name and cmdline + try: + name = proc.name() + except psutil.Error: + pass + else: + if name == pgname: + pids.append(str(proc.pid)) + continue + + try: + cmdline = proc.cmdline() + except psutil.Error: + pass + else: + if cmdline and cmdline[0] == pgname: + pids.append(str(proc.pid)) + + return pids + + +def main(): + if len(sys.argv) != 2: + sys.exit('usage: %s pgname' % __file__) + else: + pgname = sys.argv[1] + pids = pidof(pgname) + if pids: + print(" ".join(pids)) + +if __name__ == '__main__': + main() diff --git a/python/psutil/examples/pmap.py b/python/psutil/examples/pmap.py index 1936c0b276f9..7593777aef22 100755 --- a/python/psutil/examples/pmap.py +++ b/python/psutil/examples/pmap.py @@ -33,26 +33,25 @@ import sys import psutil -from psutil._compat import print_ def main(): if len(sys.argv) != 2: sys.exit('usage: pmap ') p = psutil.Process(int(sys.argv[1])) - print_("pid=%s, name=%s" % (p.pid, p.name())) + print("pid=%s, name=%s" % (p.pid, p.name())) templ = "%-16s %10s %-7s %s" - print_(templ % ("Address", "RSS", "Mode", "Mapping")) + print(templ % ("Address", "RSS", "Mode", "Mapping")) total_rss = 0 for m in p.memory_maps(grouped=False): total_rss += m.rss - print_(templ % ( + print(templ % ( m.addr.split('-')[0].zfill(16), str(m.rss / 1024) + 'K', m.perms, m.path)) - print_("-" * 33) - print_(templ % ("Total", str(total_rss / 1024) + 'K', '', '')) + print("-" * 33) + print(templ % ("Total", str(total_rss / 1024) + 'K', '', '')) if __name__ == '__main__': main() diff --git a/python/psutil/examples/process_detail.py b/python/psutil/examples/process_detail.py index a07872865838..e20371aefe97 100755 --- a/python/psutil/examples/process_detail.py +++ b/python/psutil/examples/process_detail.py @@ -68,8 +68,8 @@ def run(pid): try: p = psutil.Process(pid) pinfo = p.as_dict(ad_value=ACCESS_DENIED) - except psutil.NoSuchProcess: - sys.exit(str(sys.exc_info()[1])) + except psutil.NoSuchProcess as err: + sys.exit(str(err)) try: parent = p.parent() @@ -79,13 +79,19 @@ def run(pid): parent = '' except psutil.Error: parent = '' - started = datetime.datetime.fromtimestamp( - pinfo['create_time']).strftime('%Y-%m-%d %H:%M') + if pinfo['create_time'] != ACCESS_DENIED: + started = datetime.datetime.fromtimestamp( + pinfo['create_time']).strftime('%Y-%m-%d %H:%M') + else: + started = ACCESS_DENIED io = pinfo.get('io_counters', ACCESS_DENIED) - mem = '%s%% (resident=%s, virtual=%s) ' % ( - round(pinfo['memory_percent'], 1), - convert_bytes(pinfo['memory_info'].rss), - convert_bytes(pinfo['memory_info'].vms)) + if pinfo['memory_info'] != ACCESS_DENIED: + mem = '%s%% (resident=%s, virtual=%s) ' % ( + round(pinfo['memory_percent'], 1), + convert_bytes(pinfo['memory_info'].rss), + convert_bytes(pinfo['memory_info'].vms)) + else: + mem = ACCESS_DENIED children = p.children() print_('pid', pinfo['pid']) @@ -101,8 +107,7 @@ def run(pid): print_('gids', 'real=%s, effective=%s, saved=%s' % pinfo['gids']) if POSIX: print_('terminal', pinfo['terminal'] or '') - if hasattr(p, 'getcwd'): - print_('cwd', pinfo['cwd']) + print_('cwd', pinfo['cwd']) print_('memory', mem) print_('cpu', '%s%% (user=%s, system=%s)' % ( pinfo['cpu_percent'], diff --git a/python/psutil/examples/ps.py b/python/psutil/examples/ps.py index 2ead74700735..2b67bd18fffb 100644 --- a/python/psutil/examples/ps.py +++ b/python/psutil/examples/ps.py @@ -16,7 +16,6 @@ import time import psutil -from psutil._compat import print_ def main(): @@ -27,8 +26,8 @@ def main(): if os.name == 'posix': attrs.append('uids') attrs.append('terminal') - print_(templ % ("USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "TTY", - "START", "TIME", "COMMAND")) + print(templ % ("USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "TTY", + "START", "TIME", "COMMAND")) for p in psutil.process_iter(): try: pinfo = p.as_dict(attrs, ad_value='') @@ -65,16 +64,17 @@ def main(): int(pinfo['memory_info'].rss / 1024) or '?' memp = pinfo['memory_percent'] and \ round(pinfo['memory_percent'], 1) or '?' - print_(templ % (user[:10], - pinfo['pid'], - pinfo['cpu_percent'], - memp, - vms, - rss, - pinfo.get('terminal', '') or '?', - ctime, - cputime, - pinfo['name'].strip() or '?')) + print(templ % ( + user[:10], + pinfo['pid'], + pinfo['cpu_percent'], + memp, + vms, + rss, + pinfo.get('terminal', '') or '?', + ctime, + cputime, + pinfo['name'].strip() or '?')) if __name__ == '__main__': diff --git a/python/psutil/examples/pstree.py b/python/psutil/examples/pstree.py new file mode 100644 index 000000000000..1bf8c9c0493d --- /dev/null +++ b/python/psutil/examples/pstree.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python + +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +Similar to 'ps aux --forest' on Linux, prints the process list +as a tree structure. + +$ python examples/pstree.py +0 ? +|- 1 init +| |- 289 cgmanager +| |- 616 upstart-socket-bridge +| |- 628 rpcbind +| |- 892 upstart-file-bridge +| |- 907 dbus-daemon +| |- 978 avahi-daemon +| | `_ 979 avahi-daemon +| |- 987 NetworkManager +| | |- 2242 dnsmasq +| | `_ 10699 dhclient +| |- 993 polkitd +| |- 1061 getty +| |- 1066 su +| | `_ 1190 salt-minion... +... +""" + +from __future__ import print_function +import collections +import sys + +import psutil + + +def print_tree(parent, tree, indent=''): + try: + name = psutil.Process(parent).name() + except psutil.Error: + name = "?" + print(parent, name) + if parent not in tree: + return + children = tree[parent][:-1] + for child in children: + sys.stdout.write(indent + "|- ") + print_tree(child, tree, indent + "| ") + child = tree[parent][-1] + sys.stdout.write(indent + "`_ ") + print_tree(child, tree, indent + " ") + + +def main(): + # construct a dict where 'values' are all the processes + # having 'key' as their parent + tree = collections.defaultdict(list) + for p in psutil.process_iter(): + try: + tree[p.ppid()].append(p.pid) + except (psutil.NoSuchProcess, psutil.ZombieProcess): + pass + # on systems supporting PID 0, PID 0's parent is usually 0 + if 0 in tree and 0 in tree[0]: + tree[0].remove(0) + print_tree(min(tree), tree) + + +if __name__ == '__main__': + main() diff --git a/python/psutil/examples/top.py b/python/psutil/examples/top.py index 479c797e22a5..7aebef1d42ab 100755 --- a/python/psutil/examples/top.py +++ b/python/psutil/examples/top.py @@ -34,14 +34,15 @@ ... """ +from datetime import datetime, timedelta +import atexit import os +import time import sys -if os.name != 'posix': +try: + import curses +except ImportError: sys.exit('platform not supported') -import atexit -import curses -import time -from datetime import datetime, timedelta import psutil @@ -221,7 +222,7 @@ def refresh_window(procs, procs_status): def main(): try: interval = 0 - while 1: + while True: args = poll(interval) refresh_window(*args) interval = 1 diff --git a/python/psutil/examples/who.py b/python/psutil/examples/who.py index 8ffbc81872da..b382bebfa338 100755 --- a/python/psutil/examples/who.py +++ b/python/psutil/examples/who.py @@ -18,13 +18,12 @@ from datetime import datetime import psutil -from psutil._compat import print_ def main(): users = psutil.users() for user in users: - print_("%-15s %-15s %s (%s)" % ( + print("%-15s %-15s %s (%s)" % ( user.name, user.terminal or '-', datetime.fromtimestamp(user.started).strftime("%Y-%m-%d %H:%M"), diff --git a/python/psutil/make.bat b/python/psutil/make.bat index 72ace94c2f8d..9c430101dd5e 100644 --- a/python/psutil/make.bat +++ b/python/psutil/make.bat @@ -7,18 +7,16 @@ rem psutil ("make.bat build", "make.bat install") and running tests rem ("make.bat test"). rem rem This script is modeled after my Windows installation which uses: -rem - mingw32 for Python 2.4 and 2.5 rem - Visual studio 2008 for Python 2.6, 2.7, 3.2 rem - Visual studio 2010 for Python 3.3+ rem ...therefore it might not work on your Windows installation. rem rem By default C:\Python27\python.exe is used. rem To compile for a specific Python version run: +rem set PYTHON=C:\Python34\python.exe & make.bat build rem -rem set PYTHON=C:\Python24\python.exe & make.bat build -rem -rem If you compile by using mingw on Python 2.4 and 2.5 you need to patch -rem distutils first: http://stackoverflow.com/questions/13592192 +rem To use a different test script: +rem set PYTHON=C:\Python34\python.exe & set TSCRIPT=foo.py & make.bat test rem ========================================================================== if "%PYTHON%" == "" ( @@ -28,8 +26,16 @@ if "%TSCRIPT%" == "" ( set TSCRIPT=test\test_psutil.py ) -rem Needed to compile using Mingw. -set PATH=C:\MinGW\bin;%PATH% +set PYTHON26=C:\Python26\python.exe +set PYTHON27=C:\Python27\python.exe +set PYTHON33=C:\Python33\python.exe +set PYTHON34=C:\Python34\python.exe +set PYTHON26-64=C:\Python26-64\python.exe +set PYTHON27-64=C:\Python27-64\python.exe +set PYTHON33-64=C:\Python33-64\python.exe +set PYTHON34-64=C:\Python34-64\python.exe + +set ALL_PYTHONS=%PYTHON26% %PYTHON27% %PYTHON33% %PYTHON34% %PYTHON26-64% %PYTHON27-64% %PYTHON33-64% %PYTHON34-64% rem Needed to locate the .pypirc file and upload exes on PYPI. set HOME=%USERPROFILE% @@ -40,23 +46,21 @@ if "%1" == "help" ( :help echo Run `make ^` where ^ is one of: echo build compile without installing - echo build-exes create exe installers in dist directory - echo build-wheels create wheel installers in dist directory + echo build-all build exes + wheels echo clean clean build files + echo flake8 run flake8 echo install compile and install - echo memtest run memory leak tests - echo setup-env install pip, unittest2, wheels for all python versions + echo setup-dev-env install pip, pywin32, wheels, etc. for all python versions echo test run tests + echo test-memleaks run memory leak tests echo test-process run process related tests echo test-system run system APIs related tests echo uninstall uninstall - echo upload-exes upload exe installers on pypi - echo upload-wheels upload wheel installers on pypi + echo upload-all upload exes + wheels goto :eof ) if "%1" == "clean" ( - :clean for /r %%R in (__pycache__) do if exist %%R (rmdir /S /Q %%R) for /r %%R in (*.pyc) do if exist %%R (del /s %%R) for /r %%R in (*.pyd) do if exist %%R (del /s %%R) @@ -71,31 +75,25 @@ if "%1" == "clean" ( if "%1" == "build" ( :build - if %PYTHON%==C:\Python24\python.exe ( - %PYTHON% setup.py build -c mingw32 - ) else if %PYTHON%==C:\Python25\python.exe ( - %PYTHON% setup.py build -c mingw32 - ) else ( - %PYTHON% setup.py build - ) + "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat" + %PYTHON% setup.py build + if %errorlevel% neq 0 goto :error + rem copies *.pyd files in ./psutil directory in order to allow + rem "import psutil" when using the interactive interpreter from + rem within this directory. + %PYTHON% setup.py build_ext -i if %errorlevel% neq 0 goto :error goto :eof ) if "%1" == "install" ( :install - if %PYTHON%==C:\Python24\python.exe ( - %PYTHON% setup.py build -c mingw32 install - ) else if %PYTHON%==C:\Python25\python.exe ( - %PYTHON% setup.py build -c mingw32 install - ) else ( - %PYTHON% setup.py build install - ) + call :build + %PYTHON% setup.py install goto :eof ) if "%1" == "uninstall" ( - :uninstall for %%A in ("%PYTHON%") do ( set folder=%%~dpA ) @@ -106,125 +104,98 @@ if "%1" == "uninstall" ( ) if "%1" == "test" ( - :test call :install %PYTHON% %TSCRIPT% goto :eof ) if "%1" == "test-process" ( - :test call :install %PYTHON% -m unittest -v test.test_psutil.TestProcess goto :eof ) if "%1" == "test-system" ( - :test call :install %PYTHON% -m unittest -v test.test_psutil.TestSystem goto :eof ) if "%1" == "test-memleaks" ( - :memtest call :install %PYTHON% test\test_memory_leaks.py goto :eof ) -if "%1" == "build-exes" ( - :build-exes - rem mingw 32 versions - C:\Python24\python.exe setup.py build -c mingw32 bdist_wininst || goto :error - C:\Python25\python.exe setup.py build -c mingw32 bdist_wininst || goto :error - rem "standard" 32 bit versions, using VS 2008 (2.6, 2.7) or VS 2010 (3.3+) - C:\Python26\python.exe setup.py build bdist_wininst || goto :error - C:\Python27\python.exe setup.py build bdist_wininst || goto :error - C:\Python33\python.exe setup.py build bdist_wininst || goto :error - C:\Python34\python.exe setup.py build bdist_wininst || goto :error - rem 64 bit versions - rem Python 2.7 + VS 2008 requires vcvars64.bat to be run first: - rem http://stackoverflow.com/questions/11072521/ - rem Windows SDK and .NET Framework 3.5 SP1 also need to be installed (sigh) +if "%1" == "build-all" ( + :build-all "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat" - C:\Python27-64\python.exe setup.py build bdist_wininst || goto :error - C:\Python33-64\python.exe setup.py build bdist_wininst || goto :error - C:\Python34-64\python.exe setup.py build bdist_wininst || goto :error + for %%P in (%ALL_PYTHONS%) do ( + @echo ------------------------------------------------ + @echo building exe for %%P + @echo ------------------------------------------------ + %%P setup.py build bdist_wininst || goto :error + @echo ------------------------------------------------ + @echo building wheel for %%P + @echo ------------------------------------------------ + %%P setup.py build bdist_wheel || goto :error + ) echo OK goto :eof ) -if "%1" == "upload-exes" ( +if "%1" == "upload-all" ( :upload-exes - rem mingw 32 versions - C:\Python25\python.exe setup.py build -c mingw32 bdist_wininst upload || goto :error - rem "standard" 32 bit versions, using VS 2008 (2.6, 2.7) or VS 2010 (3.3+) - C:\Python26\python.exe setup.py bdist_wininst upload || goto :error - C:\Python27\python.exe setup.py bdist_wininst upload || goto :error - C:\Python33\python.exe setup.py bdist_wininst upload || goto :error - C:\Python34\python.exe setup.py bdist_wininst upload || goto :error - rem 64 bit versions - C:\Python27-64\python.exe setup.py build bdist_wininst upload || goto :error - C:\Python33-64\python.exe setup.py build bdist_wininst upload || goto :error - C:\Python34-64\python.exe setup.py build bdist_wininst upload || goto :error + "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat" + for %%P in (%ALL_PYTHONS%) do ( + @echo ------------------------------------------------ + @echo uploading exe for %%P + @echo ------------------------------------------------ + %%P setup.py build bdist_wininst upload || goto :error + @echo ------------------------------------------------ + @echo uploading wheel for %%P + @echo ------------------------------------------------ + %%P setup.py build bdist_wheel upload || goto :error + ) echo OK goto :eof ) -if "%1" == "setup-env" ( +if "%1" == "setup-dev-env" ( :setup-env - C:\python27\python.exe -c "import urllib2; url = urllib2.urlopen('https://raw.github.com/pypa/pip/master/contrib/get-pip.py'); data = url.read(); f = open('get-pip.py', 'w'); f.write(data)" - C:\python26\python.exe get-pip.py & C:\python26\scripts\pip install unittest2 wheel --upgrade - C:\python27\python.exe get-pip.py & C:\python27\scripts\pip install wheel --upgrade - C:\python33\python.exe get-pip.py & C:\python33\scripts\pip install wheel --upgrade - C:\python34\scripts\easy_install.exe wheel - rem 64-bit versions - C:\python27-64\python.exe get-pip.py & C:\python27-64\scripts\pip install wheel --upgrade - C:\python33-64\python.exe get-pip.py & C:\python33-64\scripts\pip install wheel --upgrade - C:\python34-64\scripts\easy_install.exe wheel - goto :eof -) - -if "%1" == "build-wheels" ( - :build-wheels - C:\Python26\python.exe setup.py build bdist_wheel || goto :error - C:\Python27\python.exe setup.py build bdist_wheel || goto :error - C:\Python33\python.exe setup.py build bdist_wheel || goto :error - C:\Python34\python.exe setup.py build bdist_wheel || goto :error - rem 64 bit versions - rem Python 2.7 + VS 2008 requires vcvars64.bat to be run first: - rem http://stackoverflow.com/questions/11072521/ - rem Windows SDK and .NET Framework 3.5 SP1 also need to be installed (sigh) - "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat" - C:\Python27-64\python.exe setup.py build bdist_wheel || goto :error - C:\Python33-64\python.exe setup.py build bdist_wheel || goto :error - C:\Python34-64\python.exe setup.py build bdist_wheel || goto :error - echo OK + @echo ------------------------------------------------ + @echo downloading pip installer + @echo ------------------------------------------------ + C:\python27\python.exe -c "import urllib2; r = urllib2.urlopen('https://raw.github.com/pypa/pip/master/contrib/get-pip.py'); open('get-pip.py', 'wb').write(r.read())" + for %%P in (%ALL_PYTHONS%) do ( + @echo ------------------------------------------------ + @echo installing pip for %%P + @echo ------------------------------------------------ + %%P get-pip.py + ) + for %%P in (%ALL_PYTHONS%) do ( + @echo ------------------------------------------------ + @echo installing deps for %%P + @echo ------------------------------------------------ + rem mandatory / for unittests + %%P -m pip install unittest2 ipaddress mock wmi wheel pypiwin32 --upgrade + rem nice to have + %%P -m pip install ipdb pep8 pyflakes flake8 --upgrade + ) goto :eof ) -if "%1" == "upload-wheels" ( - :build-wheels - C:\Python26\python.exe setup.py build bdist_wheel upload || goto :error - C:\Python27\python.exe setup.py build bdist_wheel upload || goto :error - C:\Python33\python.exe setup.py build bdist_wheel upload || goto :error - C:\Python34\python.exe setup.py build bdist_wheel upload || goto :error - rem 64 bit versions - rem Python 2.7 + VS 2008 requires vcvars64.bat to be run first: - rem http://stackoverflow.com/questions/11072521/ - rem Windows SDK and .NET Framework 3.5 SP1 also need to be installed (sigh) - "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat" - C:\Python27-64\python.exe setup.py build bdist_wheel upload || goto :error - C:\Python33-64\python.exe setup.py build bdist_wheel upload || goto :error - C:\Python34-64\python.exe setup.py build bdist_wheel upload || goto :error - echo OK +if "%1" == "flake8" ( + :flake8 + %PYTHON% -c "from flake8.main import main; main()" goto :eof ) goto :help :error - echo last command exited with error code %errorlevel% - exit /b %errorlevel% + @echo ------------------------------------------------ + @echo last command exited with error code %errorlevel% + @echo ------------------------------------------------ + @exit /b %errorlevel% goto :eof diff --git a/python/psutil/psutil.egg-info/PKG-INFO b/python/psutil/psutil.egg-info/PKG-INFO new file mode 100644 index 000000000000..e74d33f6587d --- /dev/null +++ b/python/psutil/psutil.egg-info/PKG-INFO @@ -0,0 +1,434 @@ +Metadata-Version: 1.1 +Name: psutil +Version: 3.1.1 +Summary: psutil is a cross-platform library for retrieving information onrunning processes and system utilization (CPU, memory, disks, network)in Python. +Home-page: https://github.com/giampaolo/psutil +Author: Giampaolo Rodola +Author-email: g.rodola gmail com +License: BSD +Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg + :target: https://pypi.python.org/pypi/psutil#downloads + :alt: Downloads this month + + .. image:: https://api.travis-ci.org/giampaolo/psutil.png?branch=master + :target: https://travis-ci.org/giampaolo/psutil + :alt: Linux tests (Travis) + + .. image:: https://ci.appveyor.com/api/projects/status/qdwvw7v1t915ywr5/branch/master?svg=true + :target: https://ci.appveyor.com/project/giampaolo/psutil + :alt: Windows tests (Appveyor) + + .. image:: https://coveralls.io/repos/giampaolo/psutil/badge.svg?branch=master&service=github + :target: https://coveralls.io/github/giampaolo/psutil?branch=master + :alt: Test coverage (coverall.io) + + .. image:: https://img.shields.io/pypi/v/psutil.svg + :target: https://pypi.python.org/pypi/psutil/ + :alt: Latest version + + .. image:: https://img.shields.io/github/stars/giampaolo/psutil.svg + :target: https://github.com/giampaolo/psutil/ + :alt: Github stars + + .. image:: https://img.shields.io/scrutinizer/g/giampaolo/psutil.svg + :target: https://scrutinizer-ci.com/g/giampaolo/psutil/ + :alt: Code quality (scrutinizer-ci.com) + + .. image:: https://img.shields.io/pypi/l/psutil.svg + :target: https://pypi.python.org/pypi/psutil/ + :alt: License + + =========== + Quick links + =========== + + - `Home page `_ + - `Documentation `_ + - `Installation `_ + - `Download `_ + - `Forum `_ + - `Blog `_ + - `Development guide `_ + - `What's new `_ + + ======= + Summary + ======= + + psutil (python system and process utilities) is a cross-platform library for + retrieving information on **running processes** and **system utilization** + (CPU, memory, disks, network) in Python. It is useful mainly for **system + monitoring**, **profiling and limiting process resources** and **management of + running processes**. It implements many functionalities offered by command line + tools such as: ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice, + ionice, iostat, iotop, uptime, pidof, tty, taskset, pmap. It currently supports + **Linux, Windows, OSX, FreeBSD** and **Sun Solaris**, both **32-bit** and + **64-bit** architectures, with Python versions from **2.6 to 3.5** (users of + Python 2.4 and 2.5 may use `2.1.3 `__ version). + `PyPy `__ is also known to work. + + ==================== + Example applications + ==================== + + .. image:: http://psutil.googlecode.com/svn/wiki/images/top-thumb.png + :target: http://psutil.googlecode.com/svn/wiki/images/top.png + :alt: top + + .. image:: http://psutil.googlecode.com/svn/wiki/images/nettop-thumb.png + :target: http://psutil.googlecode.com/svn/wiki/images/nettop.png + :alt: nettop + + .. image:: http://psutil.googlecode.com/svn/wiki/images/iotop-thumb.png + :target: http://psutil.googlecode.com/svn/wiki/images/iotop.png + :alt: iotop + + See also: + + * https://github.com/nicolargo/glances + * https://github.com/google/grr + * https://github.com/Jahaja/psdash + + ============== + Example usages + ============== + + CPU + === + + .. code-block:: python + + >>> import psutil + >>> psutil.cpu_times() + scputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540, iowait=629.59, irq=0.0, softirq=19.42, steal=0.0, guest=0, nice=0.0) + >>> + >>> for x in range(3): + ... psutil.cpu_percent(interval=1) + ... + 4.0 + 5.9 + 3.8 + >>> + >>> for x in range(3): + ... psutil.cpu_percent(interval=1, percpu=True) + ... + [4.0, 6.9, 3.7, 9.2] + [7.0, 8.5, 2.4, 2.1] + [1.2, 9.0, 9.9, 7.2] + >>> + >>> + >>> for x in range(3): + ... psutil.cpu_times_percent(interval=1, percpu=False) + ... + scputimes(user=1.5, nice=0.0, system=0.5, idle=96.5, iowait=1.5, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0) + scputimes(user=1.0, nice=0.0, system=0.0, idle=99.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0) + scputimes(user=2.0, nice=0.0, system=0.0, idle=98.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0) + >>> + >>> psutil.cpu_count() + 4 + >>> psutil.cpu_count(logical=False) + 2 + >>> + + Memory + ====== + + .. code-block:: python + + >>> psutil.virtual_memory() + svmem(total=8374149120, available=2081050624, percent=75.1, used=8074080256, free=300068864, active=3294920704, inactive=1361616896, buffers=529895424, cached=1251086336) + >>> psutil.swap_memory() + sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944) + >>> + + Disks + ===== + + .. code-block:: python + + >>> psutil.disk_partitions() + [sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'), + sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')] + >>> + >>> psutil.disk_usage('/') + sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5) + >>> + >>> psutil.disk_io_counters(perdisk=False) + sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568) + >>> + + Network + ======= + + .. code-block:: python + + >>> psutil.net_io_counters(pernic=True) + {'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0), + 'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)} + >>> + >>> psutil.net_connections() + [pconn(fd=115, family=, type=, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254), + pconn(fd=117, family=, type=, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987), + pconn(fd=-1, family=, type=, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None), + pconn(fd=-1, family=, type=, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None) + ...] + >>> + >>> psutil.net_if_addrs() + {'lo': [snic(family=, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1'), + snic(family=, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None), + snic(family=, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00')], + 'wlan0': [snic(family=, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255'), + snic(family=, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None), + snic(family=, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff')]} + >>> + >>> psutil.net_if_stats() + {'eth0': snicstats(isup=True, duplex=, speed=100, mtu=1500), + 'lo': snicstats(isup=True, duplex=, speed=0, mtu=65536)} + + Other system info + ================= + + .. code-block:: python + + >>> psutil.users() + [user(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0), + user(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0)] + >>> + >>> psutil.boot_time() + 1365519115.0 + >>> + + Process management + ================== + + .. code-block:: python + + >>> import psutil + >>> psutil.pids() + [1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224, + 268, 1215, 1216, 1220, 1221, 1243, 1244, 1301, 1601, 2237, 2355, + 2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245, + 4263, 4282, 4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358, + 4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446, 5167, 5234, 5235, + 5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071] + >>> + >>> p = psutil.Process(7055) + >>> p.name() + 'python' + >>> p.exe() + '/usr/bin/python' + >>> p.cwd() + '/home/giampaolo' + >>> p.cmdline() + ['/usr/bin/python', 'main.py'] + >>> + >>> p.status() + 'running' + >>> p.username() + 'giampaolo' + >>> p.create_time() + 1267551141.5019531 + >>> p.terminal() + '/dev/pts/0' + >>> + >>> p.uids() + puids(real=1000, effective=1000, saved=1000) + >>> p.gids() + pgids(real=1000, effective=1000, saved=1000) + >>> + >>> p.cpu_times() + pcputimes(user=1.02, system=0.31) + >>> p.cpu_percent(interval=1.0) + 12.1 + >>> p.cpu_affinity() + [0, 1, 2, 3] + >>> p.cpu_affinity([0]) # set + >>> + >>> p.memory_percent() + 0.63423 + >>> + >>> p.memory_info() + pmem(rss=7471104, vms=68513792) + >>> p.memory_info_ex() + extmem(rss=9662464, vms=49192960, shared=3612672, text=2564096, lib=0, data=5754880, dirty=0) + >>> p.memory_maps() + [pmmap_grouped(path='/lib/x86_64-linux-gnu/libutil-2.15.so', rss=16384, anonymous=8192, swap=0), + pmmap_grouped(path='/lib/x86_64-linux-gnu/libc-2.15.so', rss=6384, anonymous=15, swap=0), + pmmap_grouped(path='/lib/x86_64-linux-gnu/libcrypto.so.1.0.0', rss=34124, anonymous=1245, swap=0), + pmmap_grouped(path='[heap]', rss=54653, anonymous=8192, swap=0), + pmmap_grouped(path='[stack]', rss=1542, anonymous=166, swap=0), + ...] + >>> + >>> p.io_counters() + pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632) + >>> + >>> p.open_files() + [popenfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)] + >>> + >>> p.connections() + [pconn(fd=115, family=, type=, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'), + pconn(fd=117, family=, type=, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'), + pconn(fd=119, family=, type=, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'), + pconn(fd=123, family=, type=, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')] + >>> + >>> p.num_threads() + 4 + >>> p.num_fds() + 8 + >>> p.threads() + [pthread(id=5234, user_time=22.5, system_time=9.2891), + pthread(id=5235, user_time=0.0, system_time=0.0), + pthread(id=5236, user_time=0.0, system_time=0.0), + pthread(id=5237, user_time=0.0707, system_time=1.1)] + >>> + >>> p.num_ctx_switches() + pctxsw(voluntary=78, involuntary=19) + >>> + >>> p.nice() + 0 + >>> p.nice(10) # set + >>> + >>> p.ionice(psutil.IOPRIO_CLASS_IDLE) # IO priority (Win and Linux only) + >>> p.ionice() + pionice(ioclass=, value=0) + >>> + >>> p.rlimit(psutil.RLIMIT_NOFILE, (5, 5)) # set resource limits (Linux only) + >>> p.rlimit(psutil.RLIMIT_NOFILE) + (5, 5) + >>> + >>> p.suspend() + >>> p.resume() + >>> + >>> p.terminate() + >>> p.wait(timeout=3) + 0 + >>> + >>> psutil.test() + USER PID %CPU %MEM VSZ RSS TTY START TIME COMMAND + root 1 0.0 0.0 24584 2240 Jun17 00:00 init + root 2 0.0 0.0 0 0 Jun17 00:00 kthreadd + root 3 0.0 0.0 0 0 Jun17 00:05 ksoftirqd/0 + ... + giampaolo 31475 0.0 0.0 20760 3024 /dev/pts/0 Jun19 00:00 python2.4 + giampaolo 31721 0.0 2.2 773060 181896 00:04 10:30 chrome + root 31763 0.0 0.0 0 0 00:05 00:00 kworker/0:1 + >>> + + Further process APIs + ==================== + + .. code-block:: python + + >>> for p in psutil.process_iter(): + ... print(p) + ... + psutil.Process(pid=1, name='init') + psutil.Process(pid=2, name='kthreadd') + psutil.Process(pid=3, name='ksoftirqd/0') + ... + >>> + >>> def on_terminate(proc): + ... print("process {} terminated".format(proc)) + ... + >>> # waits for multiple processes to terminate + >>> gone, alive = psutil.wait_procs(procs_list, 3, callback=on_terminate) + >>> + + ====== + Donate + ====== + + A lot of time and effort went into making psutil as it is right now. + If you feel psutil is useful to you or your business and want to support its future development please consider donating me (`Giampaolo Rodola' `_) some money. + I only ask for a small donation, but of course I appreciate any amount. + + .. image:: http://www.paypal.com/en_US/i/btn/x-click-but04.gif + :target: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8 + :alt: Donate via PayPal + + Don't want to donate money? Then maybe you could `write me a recommendation on Linkedin `_. + + ============ + Mailing list + ============ + + http://groups.google.com/group/psutil/ + + ======== + Timeline + ======== + + - 2015-07-15: `psutil-3.1.1.tar.gz `_ + - 2015-07-15: `psutil-3.1.0.tar.gz `_ + - 2015-06-18: `psutil-3.0.1.tar.gz `_ + - 2015-06-13: `psutil-3.0.0.tar.gz `_ + - 2015-02-02: `psutil-2.2.1.tar.gz `_ + - 2015-01-06: `psutil-2.2.0.tar.gz `_ + - 2014-09-26: `psutil-2.1.3.tar.gz `_ + - 2014-09-21: `psutil-2.1.2.tar.gz `_ + - 2014-04-30: `psutil-2.1.1.tar.gz `_ + - 2014-04-08: `psutil-2.1.0.tar.gz `_ + - 2014-03-10: `psutil-2.0.0.tar.gz `_ + - 2013-11-25: `psutil-1.2.1.tar.gz `_ + - 2013-11-20: `psutil-1.2.0.tar.gz `_ + - 2013-11-07: `psutil-1.1.3.tar.gz `_ + - 2013-10-22: `psutil-1.1.2.tar.gz `_ + - 2013-10-08: `psutil-1.1.1.tar.gz `_ + - 2013-09-28: `psutil-1.1.0.tar.gz `_ + - 2013-07-12: `psutil-1.0.1.tar.gz `_ + - 2013-07-10: `psutil-1.0.0.tar.gz `_ + - 2013-05-03: `psutil-0.7.1.tar.gz `_ + - 2013-04-12: `psutil-0.7.0.tar.gz `_ + - 2012-08-16: `psutil-0.6.1.tar.gz `_ + - 2012-08-13: `psutil-0.6.0.tar.gz `_ + - 2012-06-29: `psutil-0.5.1.tar.gz `_ + - 2012-06-27: `psutil-0.5.0.tar.gz `_ + - 2011-12-14: `psutil-0.4.1.tar.gz `_ + - 2011-10-29: `psutil-0.4.0.tar.gz `_ + - 2011-07-08: `psutil-0.3.0.tar.gz `_ + - 2011-03-20: `psutil-0.2.1.tar.gz `_ + - 2010-11-13: `psutil-0.2.0.tar.gz `_ + - 2010-03-02: `psutil-0.1.3.tar.gz `_ + - 2009-05-06: `psutil-0.1.2.tar.gz `_ + - 2009-03-06: `psutil-0.1.1.tar.gz `_ + - 2009-01-27: `psutil-0.1.0.tar.gz `_ + +Keywords: ps,top,kill,free,lsof,netstat,nice,tty,ionice,uptime,taskmgr,process,df,iotop,iostat,ifconfig,taskset,who,pidof,pmap,smem,pstree,monitoring,ulimit,prlimit +Platform: Platform Independent +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Console +Classifier: Environment :: Win32 (MS Windows) +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: Information Technology +Classifier: Intended Audience :: System Administrators +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Operating System :: Microsoft :: Windows :: Windows NT/2000 +Classifier: Operating System :: Microsoft +Classifier: Operating System :: OS Independent +Classifier: Operating System :: POSIX :: BSD :: FreeBSD +Classifier: Operating System :: POSIX :: Linux +Classifier: Operating System :: POSIX :: SunOS/Solaris +Classifier: Operating System :: POSIX +Classifier: Programming Language :: C +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.0 +Classifier: Programming Language :: Python :: 3.1 +Classifier: Programming Language :: Python :: 3.2 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Programming Language :: Python +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: System :: Benchmark +Classifier: Topic :: System :: Hardware +Classifier: Topic :: System :: Monitoring +Classifier: Topic :: System :: Networking :: Monitoring +Classifier: Topic :: System :: Networking +Classifier: Topic :: System :: Systems Administration +Classifier: Topic :: Utilities diff --git a/python/psutil/psutil.egg-info/SOURCES.txt b/python/psutil/psutil.egg-info/SOURCES.txt new file mode 100644 index 000000000000..990b53e75f1c --- /dev/null +++ b/python/psutil/psutil.egg-info/SOURCES.txt @@ -0,0 +1,96 @@ +.coveragerc +.git-pre-commit +.gitignore +.travis.yml +CREDITS +HISTORY.rst +INSTALL.rst +LICENSE +MANIFEST.in +Makefile +README.rst +TODO +make.bat +setup.py +tox.ini +docs/Makefile +docs/README +docs/conf.py +docs/index.rst +docs/make.bat +docs/xxx +docs/_static/copybutton.js +docs/_static/favicon.ico +docs/_static/logo.png +docs/_static/sidebar.js +docs/_template/globaltoc.html +docs/_template/indexcontent.html +docs/_template/indexsidebar.html +docs/_template/page.html +docs/_themes/pydoctheme/theme.conf +docs/_themes/pydoctheme/static/pydoctheme.css +examples/disk_usage.py +examples/free.py +examples/ifconfig.py +examples/iotop.py +examples/killall.py +examples/meminfo.py +examples/netstat.py +examples/nettop.py +examples/pidof.py +examples/pmap.py +examples/process_detail.py +examples/ps.py +examples/pstree.py +examples/top.py +examples/who.py +psutil/__init__.py +psutil/_common.py +psutil/_compat.py +psutil/_psbsd.py +psutil/_pslinux.py +psutil/_psosx.py +psutil/_psposix.py +psutil/_pssunos.py +psutil/_psutil_bsd.c +psutil/_psutil_bsd.h +psutil/_psutil_common.c +psutil/_psutil_common.h +psutil/_psutil_linux.c +psutil/_psutil_linux.h +psutil/_psutil_osx.c +psutil/_psutil_osx.h +psutil/_psutil_posix.c +psutil/_psutil_posix.h +psutil/_psutil_sunos.c +psutil/_psutil_sunos.h +psutil/_psutil_windows.c +psutil/_psutil_windows.h +psutil/_pswindows.py +psutil.egg-info/PKG-INFO +psutil.egg-info/SOURCES.txt +psutil.egg-info/dependency_links.txt +psutil.egg-info/top_level.txt +psutil/arch/bsd/process_info.c +psutil/arch/bsd/process_info.h +psutil/arch/osx/process_info.c +psutil/arch/osx/process_info.h +psutil/arch/windows/glpi.h +psutil/arch/windows/inet_ntop.c +psutil/arch/windows/inet_ntop.h +psutil/arch/windows/ntextapi.h +psutil/arch/windows/process_handles.c +psutil/arch/windows/process_handles.h +psutil/arch/windows/process_info.c +psutil/arch/windows/process_info.h +psutil/arch/windows/security.c +psutil/arch/windows/security.h +test/README.rst +test/_bsd.py +test/_linux.py +test/_osx.py +test/_posix.py +test/_sunos.py +test/_windows.py +test/test_memory_leaks.py +test/test_psutil.py \ No newline at end of file diff --git a/python/psutil/psutil.egg-info/dependency_links.txt b/python/psutil/psutil.egg-info/dependency_links.txt new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/python/psutil/psutil.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/python/psutil/psutil.egg-info/top_level.txt b/python/psutil/psutil.egg-info/top_level.txt new file mode 100644 index 000000000000..a4d92cc08db6 --- /dev/null +++ b/python/psutil/psutil.egg-info/top_level.txt @@ -0,0 +1 @@ +psutil diff --git a/python/psutil/psutil/__init__.py b/python/psutil/psutil/__init__.py index 8cb551874d31..1444425b8d2d 100644 --- a/python/psutil/psutil/__init__.py +++ b/python/psutil/psutil/__init__.py @@ -12,106 +12,78 @@ from __future__ import division -__author__ = "Giampaolo Rodola'" -__version__ = "2.1.3" -version_info = tuple([int(num) for num in __version__.split('.')]) - -__all__ = [ - # exceptions - "Error", "NoSuchProcess", "AccessDenied", "TimeoutExpired", - # constants - "version_info", "__version__", - "STATUS_RUNNING", "STATUS_IDLE", "STATUS_SLEEPING", "STATUS_DISK_SLEEP", - "STATUS_STOPPED", "STATUS_TRACING_STOP", "STATUS_ZOMBIE", "STATUS_DEAD", - "STATUS_WAKING", "STATUS_LOCKED", "STATUS_WAITING", "STATUS_LOCKED", - "CONN_ESTABLISHED", "CONN_SYN_SENT", "CONN_SYN_RECV", "CONN_FIN_WAIT1", - "CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT", - "CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", "CONN_NONE", - # classes - "Process", "Popen", - # functions - "pid_exists", "pids", "process_iter", "wait_procs", # proc - "virtual_memory", "swap_memory", # memory - "cpu_times", "cpu_percent", "cpu_times_percent", "cpu_count", # cpu - "net_io_counters", "net_connections", # network - "disk_io_counters", "disk_partitions", "disk_usage", # disk - "users", "boot_time", # others -] - -import sys +import collections +import errno +import functools import os -import time import signal -import warnings -import errno import subprocess +import sys +import time try: import pwd except ImportError: pwd = None -from psutil._common import memoize -from psutil._compat import property, callable, long, defaultdict -from psutil._compat import (wraps as _wraps, - PY3 as _PY3) -from psutil._common import (deprecated_method as _deprecated_method, - deprecated as _deprecated, - sdiskio as _nt_sys_diskio, - snetio as _nt_sys_netio) - -from psutil._common import (STATUS_RUNNING, # NOQA - STATUS_SLEEPING, - STATUS_DISK_SLEEP, - STATUS_STOPPED, - STATUS_TRACING_STOP, - STATUS_ZOMBIE, - STATUS_DEAD, - STATUS_WAKING, - STATUS_LOCKED, - STATUS_IDLE, # bsd - STATUS_WAITING, # bsd - STATUS_LOCKED) # bsd - -from psutil._common import (CONN_ESTABLISHED, - CONN_SYN_SENT, - CONN_SYN_RECV, - CONN_FIN_WAIT1, - CONN_FIN_WAIT2, - CONN_TIME_WAIT, - CONN_CLOSE, - CONN_CLOSE_WAIT, - CONN_LAST_ACK, - CONN_LISTEN, - CONN_CLOSING, - CONN_NONE) +from . import _common +from ._common import memoize +from ._compat import callable, long +from ._compat import PY3 as _PY3 + +from ._common import (STATUS_RUNNING, # NOQA + STATUS_SLEEPING, + STATUS_DISK_SLEEP, + STATUS_STOPPED, + STATUS_TRACING_STOP, + STATUS_ZOMBIE, + STATUS_DEAD, + STATUS_WAKING, + STATUS_LOCKED, + STATUS_IDLE, # bsd + STATUS_WAITING) # bsd + +from ._common import (CONN_ESTABLISHED, + CONN_SYN_SENT, + CONN_SYN_RECV, + CONN_FIN_WAIT1, + CONN_FIN_WAIT2, + CONN_TIME_WAIT, + CONN_CLOSE, + CONN_CLOSE_WAIT, + CONN_LAST_ACK, + CONN_LISTEN, + CONN_CLOSING, + CONN_NONE) + +from ._common import (NIC_DUPLEX_FULL, # NOQA + NIC_DUPLEX_HALF, + NIC_DUPLEX_UNKNOWN) if sys.platform.startswith("linux"): - import psutil._pslinux as _psplatform - from psutil._pslinux import (phymem_buffers, # NOQA - cached_phymem) - - from psutil._pslinux import (IOPRIO_CLASS_NONE, # NOQA - IOPRIO_CLASS_RT, - IOPRIO_CLASS_BE, - IOPRIO_CLASS_IDLE) + from . import _pslinux as _psplatform + + from ._pslinux import (IOPRIO_CLASS_NONE, # NOQA + IOPRIO_CLASS_RT, + IOPRIO_CLASS_BE, + IOPRIO_CLASS_IDLE) # Linux >= 2.6.36 if _psplatform.HAS_PRLIMIT: - from _psutil_linux import (RLIM_INFINITY, # NOQA - RLIMIT_AS, - RLIMIT_CORE, - RLIMIT_CPU, - RLIMIT_DATA, - RLIMIT_FSIZE, - RLIMIT_LOCKS, - RLIMIT_MEMLOCK, - RLIMIT_NOFILE, - RLIMIT_NPROC, - RLIMIT_RSS, - RLIMIT_STACK) + from ._psutil_linux import (RLIM_INFINITY, # NOQA + RLIMIT_AS, + RLIMIT_CORE, + RLIMIT_CPU, + RLIMIT_DATA, + RLIMIT_FSIZE, + RLIMIT_LOCKS, + RLIMIT_MEMLOCK, + RLIMIT_NOFILE, + RLIMIT_NPROC, + RLIMIT_RSS, + RLIMIT_STACK) # Kinda ugly but considerably faster than using hasattr() and # setattr() against the module object (we are at import time: # speed matters). - import _psutil_linux + from . import _psutil_linux try: RLIMIT_MSGQUEUE = _psutil_linux.RLIMIT_MSGQUEUE except AttributeError: @@ -135,38 +107,80 @@ del _psutil_linux elif sys.platform.startswith("win32"): - import psutil._pswindows as _psplatform - from _psutil_windows import (ABOVE_NORMAL_PRIORITY_CLASS, # NOQA - BELOW_NORMAL_PRIORITY_CLASS, - HIGH_PRIORITY_CLASS, - IDLE_PRIORITY_CLASS, - NORMAL_PRIORITY_CLASS, - REALTIME_PRIORITY_CLASS) - from psutil._pswindows import CONN_DELETE_TCB # NOQA + from . import _pswindows as _psplatform + from ._psutil_windows import (ABOVE_NORMAL_PRIORITY_CLASS, # NOQA + BELOW_NORMAL_PRIORITY_CLASS, + HIGH_PRIORITY_CLASS, + IDLE_PRIORITY_CLASS, + NORMAL_PRIORITY_CLASS, + REALTIME_PRIORITY_CLASS) + from ._pswindows import CONN_DELETE_TCB # NOQA elif sys.platform.startswith("darwin"): - import psutil._psosx as _psplatform + from . import _psosx as _psplatform elif sys.platform.startswith("freebsd"): - import psutil._psbsd as _psplatform + from . import _psbsd as _psplatform elif sys.platform.startswith("sunos"): - import psutil._pssunos as _psplatform - from psutil._pssunos import (CONN_IDLE, # NOQA - CONN_BOUND) + from . import _pssunos as _psplatform + from ._pssunos import (CONN_IDLE, # NOQA + CONN_BOUND) -else: +else: # pragma: no cover raise NotImplementedError('platform %s is not supported' % sys.platform) -__all__.extend(_psplatform.__extra__all__) - +__all__ = [ + # exceptions + "Error", "NoSuchProcess", "ZombieProcess", "AccessDenied", + "TimeoutExpired", + # constants + "version_info", "__version__", + "STATUS_RUNNING", "STATUS_IDLE", "STATUS_SLEEPING", "STATUS_DISK_SLEEP", + "STATUS_STOPPED", "STATUS_TRACING_STOP", "STATUS_ZOMBIE", "STATUS_DEAD", + "STATUS_WAKING", "STATUS_LOCKED", "STATUS_WAITING", "STATUS_LOCKED", + "CONN_ESTABLISHED", "CONN_SYN_SENT", "CONN_SYN_RECV", "CONN_FIN_WAIT1", + "CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT", + "CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", "CONN_NONE", + "AF_LINK", + "NIC_DUPLEX_FULL", "NIC_DUPLEX_HALF", "NIC_DUPLEX_UNKNOWN", + # classes + "Process", "Popen", + # functions + "pid_exists", "pids", "process_iter", "wait_procs", # proc + "virtual_memory", "swap_memory", # memory + "cpu_times", "cpu_percent", "cpu_times_percent", "cpu_count", # cpu + "net_io_counters", "net_connections", "net_if_addrs", # network + "net_if_stats", + "disk_io_counters", "disk_partitions", "disk_usage", # disk + "users", "boot_time", # others +] +__all__.extend(_psplatform.__extra__all__) +__author__ = "Giampaolo Rodola'" +__version__ = "3.1.1" +version_info = tuple([int(num) for num in __version__.split('.')]) +AF_LINK = _psplatform.AF_LINK _TOTAL_PHYMEM = None _POSIX = os.name == 'posix' _WINDOWS = os.name == 'nt' _timer = getattr(time, 'monotonic', time.time) +# Sanity check in case the user messed up with psutil installation +# or did something weird with sys.path. In this case we might end +# up importing a python module using a C extension module which +# was compiled for a different version of psutil. +# We want to prevent that by failing sooner rather than later. +# See: https://github.com/giampaolo/psutil/issues/564 +if (int(__version__.replace('.', '')) != + getattr(_psplatform.cext, 'version', None)): + msg = "version conflict: %r C extension module was built for another " \ + "version of psutil (different than %s)" % (_psplatform.cext.__file__, + __version__) + raise ImportError(msg) + + # ===================================================================== # --- exceptions # ===================================================================== @@ -176,14 +190,24 @@ class Error(Exception): from this one. """ + def __init__(self, msg=""): + self.msg = msg + + def __repr__(self): + ret = "%s.%s %s" % (self.__class__.__module__, + self.__class__.__name__, self.msg) + return ret.strip() + + __str__ = __repr__ + class NoSuchProcess(Error): """Exception raised when a process with a certain PID doesn't - or no longer exists (zombie). + or no longer exists. """ def __init__(self, pid, name=None, msg=None): - Error.__init__(self) + Error.__init__(self, msg) self.pid = pid self.name = name self.msg = msg @@ -194,15 +218,37 @@ def __init__(self, pid, name=None, msg=None): details = "(pid=%s)" % self.pid self.msg = "process no longer exists " + details - def __str__(self): - return self.msg + +class ZombieProcess(NoSuchProcess): + """Exception raised when querying a zombie process. This is + raised on OSX, BSD and Solaris only, and not always: depending + on the query the OS may be able to succeed anyway. + On Linux all zombie processes are querable (hence this is never + raised). Windows doesn't have zombie processes. + """ + + def __init__(self, pid, name=None, ppid=None, msg=None): + Error.__init__(self, msg) + self.pid = pid + self.ppid = ppid + self.name = name + self.msg = msg + if msg is None: + if name and ppid: + details = "(pid=%s, name=%s, ppid=%s)" % ( + self.pid, repr(self.name), self.ppid) + elif name: + details = "(pid=%s, name=%s)" % (self.pid, repr(self.name)) + else: + details = "(pid=%s)" % self.pid + self.msg = "process still exists but it's a zombie " + details class AccessDenied(Error): """Exception raised when permission to perform an action is denied.""" def __init__(self, pid=None, name=None, msg=None): - Error.__init__(self) + Error.__init__(self, msg) self.pid = pid self.name = name self.msg = msg @@ -214,9 +260,6 @@ def __init__(self, pid=None, name=None, msg=None): else: self.msg = "" - def __str__(self): - return self.msg - class TimeoutExpired(Error): """Raised on Process.wait(timeout) if timeout expires and process @@ -224,21 +267,19 @@ class TimeoutExpired(Error): """ def __init__(self, seconds, pid=None, name=None): - Error.__init__(self) + Error.__init__(self, "timeout after %s seconds" % seconds) self.seconds = seconds self.pid = pid self.name = name - self.msg = "timeout after %s seconds" % seconds if (pid is not None) and (name is not None): self.msg += " (pid=%s, name=%s)" % (pid, repr(name)) elif (pid is not None): self.msg += " (pid=%s)" % self.pid - def __str__(self): - return self.msg # push exception classes into platform specific module namespace _psplatform.NoSuchProcess = NoSuchProcess +_psplatform.ZombieProcess = ZombieProcess _psplatform.AccessDenied = AccessDenied _psplatform.TimeoutExpired = TimeoutExpired @@ -247,11 +288,12 @@ def __str__(self): # --- Process class # ===================================================================== + def _assert_pid_not_reused(fun): """Decorator which raises NoSuchProcess in case a process is no longer running or its PID has been reused. """ - @_wraps(fun) + @functools.wraps(fun) def wrapper(self, *args, **kwargs): if not self.is_running(): raise NoSuchProcess(self.pid, self._name) @@ -325,6 +367,11 @@ def _init(self, pid, _ignore_nsp=False): # process creation time on all platforms even as a # limited user pass + except ZombieProcess: + # Let's consider a zombie process as legitimate as + # tehcnically it's still alive (it can be queried, + # although not always, and it's returned by pids()). + pass except NoSuchProcess: if not _ignore_nsp: msg = 'no process found with pid %s' % pid @@ -341,6 +388,8 @@ def __str__(self): try: pid = self.pid name = repr(self.name()) + except ZombieProcess: + details = "(pid=%s (zombie))" % self.pid except NoSuchProcess: details = "(pid=%s (terminated))" % self.pid except AccessDenied: @@ -370,7 +419,7 @@ def __hash__(self): # --- utility methods - def as_dict(self, attrs=[], ad_value=None): + def as_dict(self, attrs=None, ad_value=None): """Utility method returning process information as a hashable dictionary. @@ -380,32 +429,17 @@ def as_dict(self, attrs=[], ad_value=None): only) attributes are assumed. 'ad_value' is the value which gets assigned in case - AccessDenied exception is raised when retrieving that - particular process information. + AccessDenied or ZombieProcess exception is raised when + retrieving that particular process information. """ excluded_names = set( ['send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait', 'is_running', 'as_dict', 'parent', 'children', 'rlimit']) retdict = dict() - ls = set(attrs or [x for x in dir(self) if not x.startswith('get')]) + ls = set(attrs or [x for x in dir(self)]) for name in ls: if name.startswith('_'): continue - if name.startswith('set_'): - continue - if name.startswith('get_'): - msg = "%s() is deprecated; use %s() instead" % (name, name[4:]) - warnings.warn(msg, category=DeprecationWarning, stacklevel=2) - name = name[4:] - if name in ls: - continue - if name == 'getcwd': - msg = "getcwd() is deprecated; use cwd() instead" - warnings.warn(msg, category=DeprecationWarning, stacklevel=2) - name = 'cwd' - if name in ls: - continue - if name in excluded_names: continue try: @@ -414,7 +448,7 @@ def as_dict(self, attrs=[], ad_value=None): ret = attr() else: ret = attr - except AccessDenied: + except (AccessDenied, ZombieProcess): ret = ad_value except NotImplementedError: # in case of not implemented functionality (may happen @@ -433,9 +467,10 @@ def parent(self): """ ppid = self.ppid() if ppid is not None: + ctime = self.create_time() try: parent = Process(ppid) - if parent.create_time() <= self.create_time(): + if parent.create_time() <= ctime: return parent # ...else ppid has been reused by another process except NoSuchProcess: @@ -480,8 +515,7 @@ def ppid(self): if _POSIX: return self._proc.ppid() else: - if self._ppid is None: - self._ppid = self._proc.ppid() + self._ppid = self._ppid or self._proc.ppid() return self._ppid def name(self): @@ -520,9 +554,9 @@ def guess_it(fallback): # Attempt to guess only in case of an absolute path. # It is not safe otherwise as the process might have # changed cwd. - if (os.path.isabs(exe) - and os.path.isfile(exe) - and os.access(exe, os.X_OK)): + if (os.path.isabs(exe) and + os.path.isfile(exe) and + os.access(exe, os.X_OK)): return exe if isinstance(fallback, AccessDenied): raise fallback @@ -531,8 +565,7 @@ def guess_it(fallback): if self._exe is None: try: exe = self._proc.exe() - except AccessDenied: - err = sys.exc_info()[1] + except AccessDenied as err: return guess_it(fallback=err) else: if not exe: @@ -552,7 +585,10 @@ def cmdline(self): def status(self): """The process current status as a STATUS_* constant.""" - return self._proc.status() + try: + return self._proc.status() + except ZombieProcess: + return STATUS_ZOMBIE def username(self): """The name of the user that owns the process. @@ -563,7 +599,12 @@ def username(self): # might happen if python was installed from sources raise ImportError( "requires pwd module shipped with standard python") - return pwd.getpwuid(self.uids().real).pw_name + real_uid = self.uids().real + try: + return pwd.getpwuid(real_uid).pw_name + except KeyError: + # the uid can't be resolved by the system + return str(real_uid) else: return self._proc.username() @@ -644,7 +685,7 @@ def ionice(self, ioclass=None, value=None): """ if ioclass is None: if value is not None: - raise ValueError("'ioclass' must be specified") + raise ValueError("'ioclass' argument must be specified") return self._proc.ionice_get() else: return self._proc.ionice_set(ioclass, value) @@ -667,18 +708,22 @@ def rlimit(self, resource, limits=None): else: return self._proc.rlimit(resource, limits) - # Windows and Linux only + # Windows, Linux and BSD only if hasattr(_psplatform.Process, "cpu_affinity_get"): def cpu_affinity(self, cpus=None): """Get or set process CPU affinity. If specified 'cpus' must be a list of CPUs for which you want to set the affinity (e.g. [0, 1]). + (Windows, Linux and BSD only). """ + # Automatically remove duplicates both on get and + # set (for get it's not really necessary, it's + # just for extra safety). if cpus is None: - return self._proc.cpu_affinity_get() + return list(set(self._proc.cpu_affinity_get())) else: - self._proc.cpu_affinity_set(cpus) + self._proc.cpu_affinity_set(list(set(cpus))) if _WINDOWS: @@ -750,7 +795,7 @@ def children(self, recursive=False): # (self) it means child's PID has been reused if self.create_time() <= p.create_time(): ret.append(p) - except NoSuchProcess: + except (NoSuchProcess, ZombieProcess): pass else: # Windows only (faster) @@ -762,24 +807,24 @@ def children(self, recursive=False): # (self) it means child's PID has been reused if self.create_time() <= child.create_time(): ret.append(child) - except NoSuchProcess: + except (NoSuchProcess, ZombieProcess): pass else: # construct a dict where 'values' are all the processes # having 'key' as their parent - table = defaultdict(list) + table = collections.defaultdict(list) if ppid_map is None: for p in process_iter(): try: table[p.ppid()].append(p) - except NoSuchProcess: + except (NoSuchProcess, ZombieProcess): pass else: for pid, ppid in ppid_map.items(): try: p = Process(pid) table[ppid].append(p) - except NoSuchProcess: + except (NoSuchProcess, ZombieProcess): pass # At this point we have a mapping table where table[self.pid] # are the current process' children. @@ -792,7 +837,7 @@ def children(self, recursive=False): # if child happens to be older than its parent # (self) it means child's PID has been reused intime = self.create_time() <= child.create_time() - except NoSuchProcess: + except (NoSuchProcess, ZombieProcess): pass else: if intime: @@ -831,9 +876,11 @@ def cpu_percent(self, interval=None): blocking = interval is not None and interval > 0.0 num_cpus = cpu_count() if _POSIX: - timer = lambda: _timer() * num_cpus + def timer(): + return _timer() * num_cpus else: - timer = lambda: sum(cpu_times()) + def timer(): + return sum(cpu_times()) if blocking: st1 = timer() pt1 = self._proc.cpu_times() @@ -908,7 +955,7 @@ def memory_percent(self): return 0.0 def memory_maps(self, grouped=True): - """Return process' mapped memory regions as a list of nameduples + """Return process' mapped memory regions as a list of namedtuples whose fields are variable depending on the platform. If 'grouped' is True the mapped regions with the same 'path' @@ -964,10 +1011,15 @@ def connections(self, kind='inet'): if _POSIX: def _send_signal(self, sig): + if self.pid == 0: + # see "man 2 kill" + raise ValueError( + "preventing sending signal to process with PID 0 as it " + "would affect every process in the process group of the " + "calling process (os.getpid()) instead of PID 0") try: os.kill(self.pid, sig) - except OSError: - err = sys.exc_info()[1] + except OSError as err: if err.errno == errno.ESRCH: self._gone = True raise NoSuchProcess(self.pid, self._name) @@ -1049,119 +1101,12 @@ def wait(self, timeout=None): raise ValueError("timeout must be a positive integer") return self._proc.wait(timeout) - # --- deprecated APIs - - _locals = set(locals()) - - @_deprecated_method(replacement='children') - def get_children(self): - pass - - @_deprecated_method(replacement='connections') - def get_connections(self): - pass - - if "cpu_affinity" in _locals: - @_deprecated_method(replacement='cpu_affinity') - def get_cpu_affinity(self): - pass - - @_deprecated_method(replacement='cpu_affinity') - def set_cpu_affinity(self, cpus): - pass - - @_deprecated_method(replacement='cpu_percent') - def get_cpu_percent(self): - pass - - @_deprecated_method(replacement='cpu_times') - def get_cpu_times(self): - pass - - @_deprecated_method(replacement='cwd') - def getcwd(self): - pass - - @_deprecated_method(replacement='memory_info_ex') - def get_ext_memory_info(self): - pass - - if "io_counters" in _locals: - @_deprecated_method(replacement='io_counters') - def get_io_counters(self): - pass - - if "ionice" in _locals: - @_deprecated_method(replacement='ionice') - def get_ionice(self): - pass - - @_deprecated_method(replacement='ionice') - def set_ionice(self, ioclass, value=None): - pass - - @_deprecated_method(replacement='memory_info') - def get_memory_info(self): - pass - - @_deprecated_method(replacement='memory_maps') - def get_memory_maps(self): - pass - - @_deprecated_method(replacement='memory_percent') - def get_memory_percent(self): - pass - - @_deprecated_method(replacement='nice') - def get_nice(self): - pass - - @_deprecated_method(replacement='num_ctx_switches') - def get_num_ctx_switches(self): - pass - - if 'num_fds' in _locals: - @_deprecated_method(replacement='num_fds') - def get_num_fds(self): - pass - - if 'num_handles' in _locals: - @_deprecated_method(replacement='num_handles') - def get_num_handles(self): - pass - - @_deprecated_method(replacement='num_threads') - def get_num_threads(self): - pass - - @_deprecated_method(replacement='open_files') - def get_open_files(self): - pass - - if "rlimit" in _locals: - @_deprecated_method(replacement='rlimit') - def get_rlimit(self): - pass - - @_deprecated_method(replacement='rlimit') - def set_rlimit(self, resource, limits): - pass - - @_deprecated_method(replacement='threads') - def get_threads(self): - pass - - @_deprecated_method(replacement='nice') - def set_nice(self, value): - pass - - del _locals - # ===================================================================== # --- Popen class # ===================================================================== + class Popen(Process): """A more convenient interface to stdlib subprocess module. It starts a sub process and deals with it exactly as when using @@ -1229,6 +1174,7 @@ def wait(self, timeout=None): # --- system processes related functions # ===================================================================== + def pids(): """Return a list of current running PIDs.""" return _psplatform.pids() @@ -1395,13 +1341,14 @@ def check_gone(proc, timeout): # --- CPU related functions # ===================================================================== + @memoize def cpu_count(logical=True): """Return the number of logical CPUs in the system (same as os.cpu_count() in Python 3.4). If logical is False return the number of physical cores only - (hyper thread CPUs are excluded). + (e.g. hyper thread CPUs are excluded). Return None if undetermined. @@ -1431,7 +1378,7 @@ def cpu_times(percpu=False): - guest (Linux >= 2.6.24) - guest_nice (Linux >= 3.2.0) - When percpu is True return a list of nameduples for each CPU. + When percpu is True return a list of namedtuples for each CPU. First element of the list refers to first CPU, second element to second CPU and so on. The order of the list is consistent across calls. @@ -1558,23 +1505,20 @@ def calculate(t1, t2): except ZeroDivisionError: field_perc = 0.0 field_perc = round(field_perc, 1) - if _WINDOWS: - # XXX - # Work around: - # https://github.com/giampaolo/psutil/issues/392 - # CPU times are always supposed to increase over time - # or at least remain the same and that's because time - # cannot go backwards. - # Surprisingly sometimes this might not be the case on - # Windows where 'system' CPU time can be smaller - # compared to the previous call, resulting in corrupted - # percentages (< 0 or > 100). - # I really don't know what to do about that except - # forcing the value to 0 or 100. - if field_perc > 100.0: - field_perc = 100.0 - elif field_perc < 0.0: - field_perc = 0.0 + # CPU times are always supposed to increase over time + # or at least remain the same and that's because time + # cannot go backwards. + # Surprisingly sometimes this might not be the case (at + # least on Windows and Linux), see: + # https://github.com/giampaolo/psutil/issues/392 + # https://github.com/giampaolo/psutil/issues/645 + # I really don't know what to do about that except + # forcing the value to 0 or 100. + if field_perc > 100.0: + field_perc = 100.0 + # `<=` because `-0.0 == 0.0` evaluates to True + elif field_perc <= 0.0: + field_perc = 0.0 nums.append(field_perc) return _psplatform.scputimes(*nums) @@ -1605,6 +1549,7 @@ def calculate(t1, t2): # --- system memory related functions # ===================================================================== + def virtual_memory(): """Return statistics about system memory usage as a namedtuple including the following fields, expressed in bytes: @@ -1685,6 +1630,7 @@ def swap_memory(): # --- disks/paritions related functions # ===================================================================== + def disk_usage(path): """Return disk usage statistics about the given path as a namedtuple including total, used and free space expressed in bytes plus the @@ -1718,7 +1664,7 @@ def disk_io_counters(perdisk=False): If perdisk is True return the same information for every physical disk installed on the system as a dictionary - with partition names as the keys and the namedutuple + with partition names as the keys and the namedtuple described above as the values. On recent Windows versions 'diskperf -y' command may need to be @@ -1729,16 +1675,17 @@ def disk_io_counters(perdisk=False): raise RuntimeError("couldn't find any physical disk") if perdisk: for disk, fields in rawdict.items(): - rawdict[disk] = _nt_sys_diskio(*fields) + rawdict[disk] = _common.sdiskio(*fields) return rawdict else: - return _nt_sys_diskio(*[sum(x) for x in zip(*rawdict.values())]) + return _common.sdiskio(*[sum(x) for x in zip(*rawdict.values())]) # ===================================================================== # --- network related functions # ===================================================================== + def net_io_counters(pernic=False): """Return network I/O statistics as a namedtuple including the following fields: @@ -1763,10 +1710,10 @@ def net_io_counters(pernic=False): raise RuntimeError("couldn't find any network interface") if pernic: for nic, fields in rawdict.items(): - rawdict[nic] = _nt_sys_netio(*fields) + rawdict[nic] = _common.snetio(*fields) return rawdict else: - return _nt_sys_netio(*[sum(x) for x in zip(*rawdict.values())]) + return _common.snetio(*[sum(x) for x in zip(*rawdict.values())]) def net_connections(kind='inet'): @@ -1789,19 +1736,75 @@ def net_connections(kind='inet'): udp6 UDP over IPv6 unix UNIX socket (both UDP and TCP protocols) all the sum of all the possible families and protocols + + On OSX this function requires root privileges. """ return _psplatform.net_connections(kind) +def net_if_addrs(): + """Return the addresses associated to each NIC (network interface + card) installed on the system as a dictionary whose keys are the + NIC names and value is a list of namedtuples for each address + assigned to the NIC. Each namedtuple includes 4 fields: + + - family + - address + - netmask + - broadcast + + 'family' can be either socket.AF_INET, socket.AF_INET6 or + psutil.AF_LINK, which refers to a MAC address. + 'address' is the primary address, 'netmask' and 'broadcast' + may be None. + Note: you can have more than one address of the same family + associated with each interface. + """ + has_enums = sys.version_info >= (3, 4) + if has_enums: + import socket + rawlist = _psplatform.net_if_addrs() + rawlist.sort(key=lambda x: x[1]) # sort by family + ret = collections.defaultdict(list) + for name, fam, addr, mask, broadcast in rawlist: + if has_enums: + try: + fam = socket.AddressFamily(fam) + except ValueError: + if os.name == 'nt' and fam == -1: + fam = _psplatform.AF_LINK + elif (hasattr(_psplatform, "AF_LINK") and + _psplatform.AF_LINK == fam): + # Linux defines AF_LINK as an alias for AF_PACKET. + # We re-set the family here so that repr(family) + # will show AF_LINK rather than AF_PACKET + fam = _psplatform.AF_LINK + ret[name].append(_common.snic(fam, addr, mask, broadcast)) + return dict(ret) + + +def net_if_stats(): + """Return information about each NIC (network interface card) + installed on the system as a dictionary whose keys are the + NIC names and value is a namedtuple with the following fields: + + - isup: whether the interface is up (bool) + - duplex: can be either NIC_DUPLEX_FULL, NIC_DUPLEX_HALF or + NIC_DUPLEX_UNKNOWN + - speed: the NIC speed expressed in mega bits (MB); if it can't + be determined (e.g. 'localhost') it will be set to 0. + - mtu: the maximum transmission unit expressed in bytes. + """ + return _psplatform.net_if_stats() + + # ===================================================================== # --- other system related functions # ===================================================================== def boot_time(): - """Return the system boot time expressed in seconds since the epoch. - This is also available as psutil.BOOT_TIME. - """ + """Return the system boot time expressed in seconds since the epoch.""" # Note: we are not caching this because it is subject to # system clock updates. return _psplatform.boot_time() @@ -1820,75 +1823,11 @@ def users(): return _psplatform.users() -# ===================================================================== -# --- deprecated functions -# ===================================================================== - -@_deprecated(replacement="psutil.pids()") -def get_pid_list(): - return pids() - - -@_deprecated(replacement="list(process_iter())") -def get_process_list(): - return list(process_iter()) - - -@_deprecated(replacement="psutil.users()") -def get_users(): - return users() - - -@_deprecated(replacement="psutil.virtual_memory()") -def phymem_usage(): - """Return the amount of total, used and free physical memory - on the system in bytes plus the percentage usage. - Deprecated; use psutil.virtual_memory() instead. - """ - return virtual_memory() - - -@_deprecated(replacement="psutil.swap_memory()") -def virtmem_usage(): - return swap_memory() - - -@_deprecated(replacement="psutil.phymem_usage().free") -def avail_phymem(): - return phymem_usage().free - - -@_deprecated(replacement="psutil.phymem_usage().used") -def used_phymem(): - return phymem_usage().used - - -@_deprecated(replacement="psutil.virtmem_usage().total") -def total_virtmem(): - return virtmem_usage().total - - -@_deprecated(replacement="psutil.virtmem_usage().used") -def used_virtmem(): - return virtmem_usage().used - - -@_deprecated(replacement="psutil.virtmem_usage().free") -def avail_virtmem(): - return virtmem_usage().free - - -@_deprecated(replacement="psutil.net_io_counters()") -def network_io_counters(pernic=False): - return net_io_counters(pernic) - - def test(): """List info of all currently running processes emulating ps aux output. """ import datetime - from psutil._compat import print_ today_day = datetime.date.today() templ = "%-10s %5s %4s %4s %7s %7s %-13s %5s %7s %s" @@ -1897,8 +1836,8 @@ def test(): if _POSIX: attrs.append('uids') attrs.append('terminal') - print_(templ % ("USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "TTY", - "START", "TIME", "COMMAND")) + print(templ % ("USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "TTY", + "START", "TIME", "COMMAND")) for p in process_iter(): try: pinfo = p.as_dict(attrs, ad_value='') @@ -1917,14 +1856,6 @@ def test(): time.localtime(sum(pinfo['cpu_times']))) try: user = p.username() - except KeyError: - if _POSIX: - if pinfo['uids']: - user = str(pinfo['uids'].real) - else: - user = '' - else: - raise except Error: user = '' if _WINDOWS and '\\' in user: @@ -1935,56 +1866,20 @@ def test(): int(pinfo['memory_info'].rss / 1024) or '?' memp = pinfo['memory_percent'] and \ round(pinfo['memory_percent'], 1) or '?' - print_(templ % (user[:10], - pinfo['pid'], - pinfo['cpu_percent'], - memp, - vms, - rss, - pinfo.get('terminal', '') or '?', - ctime, - cputime, - pinfo['name'].strip() or '?')) - - -def _replace_module(): - """Dirty hack to replace the module object in order to access - deprecated module constants, see: - http://www.dr-josiah.com/2013/12/properties-on-python-modules.html - """ - class ModuleWrapper(object): - - def __repr__(self): - return repr(self._module) - __str__ = __repr__ - - @property - def NUM_CPUS(self): - msg = "NUM_CPUS constant is deprecated; use cpu_count() instead" - warnings.warn(msg, category=DeprecationWarning, stacklevel=2) - return cpu_count() - - @property - def BOOT_TIME(self): - msg = "BOOT_TIME constant is deprecated; use boot_time() instead" - warnings.warn(msg, category=DeprecationWarning, stacklevel=2) - return boot_time() - - @property - def TOTAL_PHYMEM(self): - msg = "TOTAL_PHYMEM constant is deprecated; " \ - "use virtual_memory().total instead" - warnings.warn(msg, category=DeprecationWarning, stacklevel=2) - return virtual_memory().total - - mod = ModuleWrapper() - mod.__dict__ = globals() - mod._module = sys.modules[__name__] - sys.modules[__name__] = mod - - -_replace_module() -del property, memoize, division, _replace_module + print(templ % ( + user[:10], + pinfo['pid'], + pinfo['cpu_percent'], + memp, + vms, + rss, + pinfo.get('terminal', '') or '?', + ctime, + cputime, + pinfo['name'].strip() or '?')) + + +del memoize, division if sys.version_info < (3, 0): del num diff --git a/python/psutil/psutil/_common.py b/python/psutil/psutil/_common.py index 9db5ad37f306..e9acf595d764 100644 --- a/python/psutil/psutil/_common.py +++ b/python/psutil/psutil/_common.py @@ -8,19 +8,23 @@ from __future__ import division import errno +import functools import os import socket import stat import sys -import warnings +from collections import namedtuple +from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM try: import threading except ImportError: import dummy_threading as threading -from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM +if sys.version_info >= (3, 4): + import enum +else: + enum = None -from psutil._compat import namedtuple, wraps # --- constants @@ -53,6 +57,18 @@ CONN_CLOSING = "CLOSING" CONN_NONE = "NONE" +if enum is None: + NIC_DUPLEX_FULL = 2 + NIC_DUPLEX_HALF = 1 + NIC_DUPLEX_UNKNOWN = 0 +else: + class NicDuplex(enum.IntEnum): + NIC_DUPLEX_FULL = 2 + NIC_DUPLEX_HALF = 1 + NIC_DUPLEX_UNKNOWN = 0 + + globals().update(NicDuplex.__members__) + # --- functions @@ -82,7 +98,7 @@ def memoize(fun): >>> foo.cache_clear() >>> """ - @wraps(fun) + @functools.wraps(fun) def wrapper(*args, **kwargs): key = (args, frozenset(sorted(kwargs.items()))) lock.acquire() @@ -109,43 +125,6 @@ def cache_clear(): return wrapper -# http://code.activestate.com/recipes/577819-deprecated-decorator/ -def deprecated(replacement=None): - """A decorator which can be used to mark functions as deprecated.""" - def outer(fun): - msg = "psutil.%s is deprecated" % fun.__name__ - if replacement is not None: - msg += "; use %s instead" % replacement - if fun.__doc__ is None: - fun.__doc__ = msg - - @wraps(fun) - def inner(*args, **kwargs): - warnings.warn(msg, category=DeprecationWarning, stacklevel=2) - return fun(*args, **kwargs) - - return inner - return outer - - -def deprecated_method(replacement): - """A decorator which can be used to mark a method as deprecated - 'replcement' is the method name which will be called instead. - """ - def outer(fun): - msg = "%s() is deprecated; use %s() instead" % ( - fun.__name__, replacement) - if fun.__doc__ is None: - fun.__doc__ = msg - - @wraps(fun) - def inner(self, *args, **kwargs): - warnings.warn(msg, category=DeprecationWarning, stacklevel=2) - return getattr(self, replacement)(*args, **kwargs) - return inner - return outer - - def isfile_strict(path): """Same as os.path.isfile() but does not swallow EACCES / EPERM exceptions, see: @@ -153,8 +132,7 @@ def isfile_strict(path): """ try: st = os.stat(path) - except OSError: - err = sys.exc_info()[1] + except OSError as err: if err.errno in (errno.EPERM, errno.EACCES): raise return False @@ -162,6 +140,30 @@ def isfile_strict(path): return stat.S_ISREG(st.st_mode) +def sockfam_to_enum(num): + """Convert a numeric socket family value to an IntEnum member. + If it's not a known member, return the numeric value itself. + """ + if enum is None: + return num + try: + return socket.AddressFamily(num) + except (ValueError, AttributeError): + return num + + +def socktype_to_enum(num): + """Convert a numeric socket type value to an IntEnum member. + If it's not a known member, return the numeric value itself. + """ + if enum is None: + return num + try: + return socket.AddressType(num) + except (ValueError, AttributeError): + return num + + # --- Process.connections() 'kind' parameter mapping conn_tmap = { @@ -186,7 +188,7 @@ def isfile_strict(path): "unix": ([AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]), }) -del AF_INET, AF_INET6, AF_UNIX, SOCK_STREAM, SOCK_DGRAM, socket +del AF_INET, AF_INET6, AF_UNIX, SOCK_STREAM, SOCK_DGRAM # --- namedtuples for psutil.* system-related functions @@ -212,6 +214,10 @@ def isfile_strict(path): # psutil.net_connections() sconn = namedtuple('sconn', ['fd', 'family', 'type', 'laddr', 'raddr', 'status', 'pid']) +# psutil.net_if_addrs() +snic = namedtuple('snic', ['family', 'address', 'netmask', 'broadcast']) +# psutil.net_if_stats() +snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu']) # --- namedtuples for psutil.Process methods @@ -235,24 +241,6 @@ def isfile_strict(path): pionice = namedtuple('pionice', ['ioclass', 'value']) # psutil.Process.ctx_switches() pctxsw = namedtuple('pctxsw', ['voluntary', 'involuntary']) - - -# --- misc - -# backward compatibility layer for Process.connections() ntuple -class pconn( - namedtuple('pconn', - ['fd', 'family', 'type', 'laddr', 'raddr', 'status'])): - __slots__ = () - - @property - def local_address(self): - warnings.warn("'local_address' field is deprecated; use 'laddr'" - "instead", category=DeprecationWarning, stacklevel=2) - return self.laddr - - @property - def remote_address(self): - warnings.warn("'remote_address' field is deprecated; use 'raddr'" - "instead", category=DeprecationWarning, stacklevel=2) - return self.raddr +# psutil.Process.connections() +pconn = namedtuple('pconn', ['fd', 'family', 'type', 'laddr', 'raddr', + 'status']) diff --git a/python/psutil/psutil/_compat.py b/python/psutil/psutil/_compat.py index ad3bccee0b03..38744a84aea1 100644 --- a/python/psutil/psutil/_compat.py +++ b/python/psutil/psutil/_compat.py @@ -6,59 +6,29 @@ """Module which provides compatibility with older Python versions.""" -__all__ = ["PY3", "int", "long", "xrange", "exec_", "callable", "namedtuple", - "property", "wraps", "defaultdict", "update_wrapper", "lru_cache"] - +import collections +import functools import sys -try: - import __builtin__ -except ImportError: - import builtins as __builtin__ # py3 + +__all__ = ["PY3", "long", "xrange", "unicode", "callable", "lru_cache"] PY3 = sys.version_info[0] == 3 if PY3: - int = int long = int xrange = range unicode = str - basestring = str - exec_ = getattr(__builtin__, "exec") - print_ = getattr(__builtin__, "print") def u(s): return s - - def b(s): - return s.encode("latin-1") else: - int = int long = long xrange = xrange unicode = unicode - basestring = basestring def u(s): return unicode(s, "unicode_escape") - def b(s): - return s - - def exec_(code, globs=None, locs=None): - if globs is None: - frame = _sys._getframe(1) - globs = frame.f_globals - if locs is None: - locs = frame.f_locals - del frame - elif locs is None: - locs = globs - exec("""exec code in globs, locs""") - - def print_(s): - sys.stdout.write(s + '\n') - sys.stdout.flush() - # removed in 3.0, reintroduced in 3.2 try: @@ -70,222 +40,6 @@ def callable(obj): # --- stdlib additions -# py 2.6 collections.namedtuple -# Taken from: http://code.activestate.com/recipes/500261/ -# Credits: Raymond Hettinger -try: - from collections import namedtuple -except ImportError: - from operator import itemgetter as _itemgetter - from keyword import iskeyword as _iskeyword - import sys as _sys - - def namedtuple(typename, field_names, verbose=False, rename=False): - """A collections.namedtuple implementation, see: - http://docs.python.org/library/collections.html#namedtuple - """ - if isinstance(field_names, basestring): - field_names = field_names.replace(',', ' ').split() - field_names = tuple(map(str, field_names)) - if rename: - names = list(field_names) - seen = set() - for i, name in enumerate(names): - if ((not min(c.isalnum() or c == '_' for c in name) - or _iskeyword(name) - or not name or name[0].isdigit() - or name.startswith('_') - or name in seen)): - names[i] = '_%d' % i - seen.add(name) - field_names = tuple(names) - for name in (typename,) + field_names: - if not min(c.isalnum() or c == '_' for c in name): - raise ValueError('Type names and field names can only contain ' - 'alphanumeric characters and underscores: %r' - % name) - if _iskeyword(name): - raise ValueError('Type names and field names cannot be a ' - 'keyword: %r' % name) - if name[0].isdigit(): - raise ValueError('Type names and field names cannot start ' - 'with a number: %r' % name) - seen_names = set() - for name in field_names: - if name.startswith('_') and not rename: - raise ValueError( - 'Field names cannot start with an underscore: %r' % name) - if name in seen_names: - raise ValueError('Encountered duplicate field name: %r' % name) - seen_names.add(name) - - numfields = len(field_names) - argtxt = repr(field_names).replace("'", "")[1:-1] - reprtxt = ', '.join('%s=%%r' % name for name in field_names) - template = '''class %(typename)s(tuple): - '%(typename)s(%(argtxt)s)' \n - __slots__ = () \n - _fields = %(field_names)r \n - def __new__(_cls, %(argtxt)s): - return _tuple.__new__(_cls, (%(argtxt)s)) \n - @classmethod - def _make(cls, iterable, new=tuple.__new__, len=len): - 'Make a new %(typename)s object from a sequence or iterable' - result = new(cls, iterable) - if len(result) != %(numfields)d: - raise TypeError( - 'Expected %(numfields)d arguments, got %%d' %% len(result)) - return result \n - def __repr__(self): - return '%(typename)s(%(reprtxt)s)' %% self \n - def _asdict(self): - 'Return a new dict which maps field names to their values' - return dict(zip(self._fields, self)) \n - def _replace(_self, **kwds): - result = _self._make(map(kwds.pop, %(field_names)r, _self)) - if kwds: - raise ValueError( - 'Got unexpected field names: %%r' %% kwds.keys()) - return result \n - def __getnewargs__(self): - return tuple(self) \n\n''' % locals() - for i, name in enumerate(field_names): - template += ' %s = _property(_itemgetter(%d))\n' % (name, i) - if verbose: - sys.stdout.write(template + '\n') - sys.stdout.flush() - - namespace = dict( - _itemgetter=_itemgetter, __name__='namedtuple_%s' % typename, - _property=property, _tuple=tuple) - try: - exec_(template, namespace) - except SyntaxError: - e = sys.exc_info()[1] - raise SyntaxError(e.message + ':\n' + template) - result = namespace[typename] - try: - result.__module__ = _sys._getframe( - 1).f_globals.get('__name__', '__main__') - except (AttributeError, ValueError): - pass - - return result - - -# hack to support property getter/setter/deleter on python < 2.6 -# http://docs.python.org/library/functions.html?highlight=property#property -if hasattr(property, 'setter'): - property = property -else: - class property(__builtin__.property): - __metaclass__ = type - - def __init__(self, fget, *args, **kwargs): - super(property, self).__init__(fget, *args, **kwargs) - self.__doc__ = fget.__doc__ - - def getter(self, method): - return property(method, self.fset, self.fdel) - - def setter(self, method): - return property(self.fget, method, self.fdel) - - def deleter(self, method): - return property(self.fget, self.fset, method) - - -# py 2.5 collections.defauldict -# Taken from: -# http://code.activestate.com/recipes/523034-emulate-collectionsdefaultdict/ -# Credits: Jason Kirtland -try: - from collections import defaultdict -except ImportError: - class defaultdict(dict): - """Dict subclass that calls a factory function to supply - missing values: - http://docs.python.org/library/collections.html#collections.defaultdict - """ - - def __init__(self, default_factory=None, *a, **kw): - if ((default_factory is not None and - not hasattr(default_factory, '__call__'))): - raise TypeError('first argument must be callable') - dict.__init__(self, *a, **kw) - self.default_factory = default_factory - - def __getitem__(self, key): - try: - return dict.__getitem__(self, key) - except KeyError: - return self.__missing__(key) - - def __missing__(self, key): - if self.default_factory is None: - raise KeyError(key) - self[key] = value = self.default_factory() - return value - - def __reduce__(self): - if self.default_factory is None: - args = tuple() - else: - args = self.default_factory, - return type(self), args, None, None, self.items() - - def copy(self): - return self.__copy__() - - def __copy__(self): - return type(self)(self.default_factory, self) - - def __deepcopy__(self, memo): - import copy - return type(self)(self.default_factory, - copy.deepcopy(self.items())) - - def __repr__(self): - return 'defaultdict(%s, %s)' % (self.default_factory, - dict.__repr__(self)) - - -# py 2.5 functools.wraps -try: - from functools import wraps -except ImportError: - def wraps(original): - def inner(fn): - for attribute in ['__module__', '__name__', '__doc__']: - setattr(fn, attribute, getattr(original, attribute)) - for attribute in ['__dict__']: - if hasattr(fn, attribute): - getattr(fn, attribute).update(getattr(original, attribute)) - else: - setattr(fn, attribute, - getattr(original, attribute).copy()) - return fn - return inner - - -# py 2.5 functools.update_wrapper -try: - from functools import update_wrapper -except ImportError: - WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__') - WRAPPER_UPDATES = ('__dict__',) - - def update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, - updated=WRAPPER_UPDATES): - """Update a wrapper function to look like the wrapped function, see: - http://docs.python.org/library/functools.html#functools.update_wrapper - """ - for attr in assigned: - setattr(wrapper, attr, getattr(wrapped, attr)) - for attr in updated: - getattr(wrapper, attr).update(getattr(wrapped, attr, {})) - return wrapper - # py 3.2 functools.lru_cache # Taken from: http://code.activestate.com/recipes/578078 @@ -298,8 +52,8 @@ def update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, except ImportError: from dummy_threading import RLock - _CacheInfo = namedtuple("CacheInfo", - ["hits", "misses", "maxsize", "currsize"]) + _CacheInfo = collections.namedtuple( + "CacheInfo", ["hits", "misses", "maxsize", "currsize"]) class _HashedSeq(list): __slots__ = 'hashvalue' @@ -430,6 +184,6 @@ def cache_clear(): wrapper.__wrapped__ = user_function wrapper.cache_info = cache_info wrapper.cache_clear = cache_clear - return update_wrapper(wrapper, user_function) + return functools.update_wrapper(wrapper, user_function) return decorating_function diff --git a/python/psutil/psutil/_psbsd.py b/python/psutil/psutil/_psbsd.py index 9dcdfc21c944..db54a02e1360 100644 --- a/python/psutil/psutil/_psbsd.py +++ b/python/psutil/psutil/_psbsd.py @@ -7,15 +7,17 @@ """FreeBSD platform implementation.""" import errno +import functools import os -import sys +import xml.etree.ElementTree as ET +from collections import namedtuple -from psutil import _common -from psutil import _psposix -from psutil._common import conn_tmap, usage_percent -from psutil._compat import namedtuple, wraps -import _psutil_bsd as cext -import _psutil_posix +from . import _common +from . import _psposix +from . import _psutil_bsd as cext +from . import _psutil_posix as cext_posix +from ._common import conn_tmap, usage_percent, sockfam_to_enum +from ._common import socktype_to_enum __extra__all__ = [] @@ -48,6 +50,7 @@ } PAGESIZE = os.sysconf("SC_PAGE_SIZE") +AF_LINK = cext_posix.AF_LINK # extend base mem ntuple with BSD-specific memory metrics svmem = namedtuple( @@ -63,12 +66,13 @@ # set later from __init__.py NoSuchProcess = None +ZombieProcess = None AccessDenied = None TimeoutExpired = None def virtual_memory(): - """System virtual memory as a namedutple.""" + """System virtual memory as a namedtuple.""" mem = cext.virtual_mem() total, free, active, inactive, wired, cached, buffers, shared = mem avail = inactive + cached + free @@ -86,14 +90,14 @@ def swap_memory(): def cpu_times(): - """Return system per-CPU times as a named tuple""" + """Return system per-CPU times as a namedtuple""" user, nice, system, idle, irq = cext.cpu_times() return scputimes(user, nice, system, idle, irq) if hasattr(cext, "per_cpu_times"): def per_cpu_times(): - """Return system CPU times as a named tuple""" + """Return system CPU times as a namedtuple""" ret = [] for cpu_t in cext.per_cpu_times(): user, nice, system, idle, irq = cpu_t @@ -131,19 +135,25 @@ def cpu_count_physical(): # We may get None in case "sysctl kern.sched.topology_spec" # is not supported on this BSD version, in which case we'll mimic # os.cpu_count() and return None. + ret = None s = cext.cpu_count_phys() if s is not None: # get rid of padding chars appended at the end of the string index = s.rfind("") if index != -1: s = s[:index + 9] - if sys.version_info >= (2, 5): - import xml.etree.ElementTree as ET - root = ET.fromstring(s) - return len(root.findall('group/children/group/cpu')) or None - else: - s = s[s.find(''):] - return s.count("> + if err.errno in (errno.EINVAL, errno.EDEADLK): + for cpu in cpus: + if cpu not in allcpus: + raise ValueError("invalid CPU #%i (choose between %s)" + % (cpu, allcpus)) + raise diff --git a/python/psutil/psutil/_pslinux.py b/python/psutil/psutil/_pslinux.py index 2abd59c3ce9e..7eb25f519c29 100644 --- a/python/psutil/psutil/_pslinux.py +++ b/python/psutil/psutil/_pslinux.py @@ -10,19 +10,27 @@ import base64 import errno +import functools import os import re import socket import struct import sys import warnings +from collections import namedtuple, defaultdict -from psutil import _common -from psutil import _psposix -from psutil._common import (isfile_strict, usage_percent, deprecated) -from psutil._compat import PY3, namedtuple, wraps, b, defaultdict -import _psutil_linux as cext -import _psutil_posix +from . import _common +from . import _psposix +from . import _psutil_linux as cext +from . import _psutil_posix as cext_posix +from ._common import isfile_strict, usage_percent +from ._common import NIC_DUPLEX_FULL, NIC_DUPLEX_HALF, NIC_DUPLEX_UNKNOWN +from ._compat import PY3, long + +if sys.version_info >= (3, 4): + import enum +else: + enum = None __extra__all__ = [ @@ -32,10 +40,7 @@ # connection status constants "CONN_ESTABLISHED", "CONN_SYN_SENT", "CONN_SYN_RECV", "CONN_FIN_WAIT1", "CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT", - "CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", - # other - "phymem_buffers", "cached_phymem"] - + "CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", ] # --- constants @@ -52,12 +57,27 @@ PAGESIZE = os.sysconf("SC_PAGE_SIZE") BOOT_TIME = None # set later DEFAULT_ENCODING = sys.getdefaultencoding() +if enum is None: + AF_LINK = socket.AF_PACKET +else: + AddressFamily = enum.IntEnum('AddressFamily', + {'AF_LINK': socket.AF_PACKET}) + AF_LINK = AddressFamily.AF_LINK # ioprio_* constants http://linux.die.net/man/2/ioprio_get -IOPRIO_CLASS_NONE = 0 -IOPRIO_CLASS_RT = 1 -IOPRIO_CLASS_BE = 2 -IOPRIO_CLASS_IDLE = 3 +if enum is None: + IOPRIO_CLASS_NONE = 0 + IOPRIO_CLASS_RT = 1 + IOPRIO_CLASS_BE = 2 + IOPRIO_CLASS_IDLE = 3 +else: + class IOPriority(enum.IntEnum): + IOPRIO_CLASS_NONE = 0 + IOPRIO_CLASS_RT = 1 + IOPRIO_CLASS_BE = 2 + IOPRIO_CLASS_IDLE = 3 + + globals().update(IOPriority.__members__) # taken from /fs/proc/array.c PROC_STATUSES = { @@ -90,6 +110,7 @@ # set later from __init__.py NoSuchProcess = None +ZombieProcess = None AccessDenied = None TimeoutExpired = None @@ -102,11 +123,8 @@ def _get_cputimes_fields(): (user, nice, system, idle, iowait, irq, softirq, [steal, [guest, [guest_nice]]]) """ - f = open('/proc/stat', 'rb') - try: + with open('/proc/stat', 'rb') as f: values = f.readline().split()[1:] - finally: - f.close() fields = ['user', 'nice', 'system', 'idle', 'iowait', 'irq', 'softirq'] vlen = len(values) if vlen >= 8: @@ -143,19 +161,17 @@ def _get_cputimes_fields(): def virtual_memory(): total, free, buffers, shared, _, _ = cext.linux_sysinfo() cached = active = inactive = None - f = open('/proc/meminfo', 'rb') - CACHED, ACTIVE, INACTIVE = b("Cached:"), b("Active:"), b("Inactive:") - try: + with open('/proc/meminfo', 'rb') as f: for line in f: - if line.startswith(CACHED): + if line.startswith(b"Cached:"): cached = int(line.split()[1]) * 1024 - elif line.startswith(ACTIVE): + elif line.startswith(b"Active:"): active = int(line.split()[1]) * 1024 - elif line.startswith(INACTIVE): + elif line.startswith(b"Inactive:"): inactive = int(line.split()[1]) * 1024 - if (cached is not None - and active is not None - and inactive is not None): + if (cached is not None and + active is not None and + inactive is not None): break else: # we might get here when dealing with exotic Linux flavors, see: @@ -164,8 +180,6 @@ def virtual_memory(): "be determined and were set to 0" warnings.warn(msg, RuntimeWarning) cached = active = inactive = 0 - finally: - f.close() avail = free + buffers + cached used = total - free percent = usage_percent((total - avail), total, _round=1) @@ -178,16 +192,14 @@ def swap_memory(): used = total - free percent = usage_percent(used, total, _round=1) # get pgin/pgouts - f = open("/proc/vmstat", "rb") - SIN, SOUT = b('pswpin'), b('pswpout') - sin = sout = None - try: + with open("/proc/vmstat", "rb") as f: + sin = sout = None for line in f: # values are expressed in 4 kilo bytes, we want bytes instead - if line.startswith(SIN): - sin = int(line.split(b(' '))[1]) * 4 * 1024 - elif line.startswith(SOUT): - sout = int(line.split(b(' '))[1]) * 4 * 1024 + if line.startswith(b'pswpin'): + sin = int(line.split(b' ')[1]) * 4 * 1024 + elif line.startswith(b'pswpout'): + sout = int(line.split(b' ')[1]) * 4 * 1024 if sin is not None and sout is not None: break else: @@ -197,21 +209,9 @@ def swap_memory(): "be determined and were set to 0" warnings.warn(msg, RuntimeWarning) sin = sout = 0 - finally: - f.close() return _common.sswap(total, used, free, percent, sin, sout) -@deprecated(replacement='psutil.virtual_memory().cached') -def cached_phymem(): - return virtual_memory().cached - - -@deprecated(replacement='psutil.virtual_memory().buffers') -def phymem_buffers(): - return virtual_memory().buffers - - # --- CPUs def cpu_times(): @@ -221,11 +221,8 @@ def cpu_times(): [guest_nice]]]) Last 3 fields may not be available on all Linux kernel versions. """ - f = open('/proc/stat', 'rb') - try: + with open('/proc/stat', 'rb') as f: values = f.readline().split() - finally: - f.close() fields = values[1:len(scputimes._fields) + 1] fields = [float(x) / CLOCK_TICKS for x in fields] return scputimes(*fields) @@ -236,21 +233,17 @@ def per_cpu_times(): for every CPU available on the system. """ cpus = [] - f = open('/proc/stat', 'rb') - try: + with open('/proc/stat', 'rb') as f: # get rid of the first line which refers to system wide CPU stats f.readline() - CPU = b('cpu') for line in f: - if line.startswith(CPU): + if line.startswith(b'cpu'): values = line.split() fields = values[1:len(scputimes._fields) + 1] fields = [float(x) / CLOCK_TICKS for x in fields] entry = scputimes(*fields) cpus.append(entry) return cpus - finally: - f.close() def cpu_count_logical(): @@ -260,53 +253,51 @@ def cpu_count_logical(): except ValueError: # as a second fallback we try to parse /proc/cpuinfo num = 0 - f = open('/proc/cpuinfo', 'rb') - try: - lines = f.readlines() - finally: - f.close() - PROCESSOR = b('processor') - for line in lines: - if line.lower().startswith(PROCESSOR): - num += 1 - - # unknown format (e.g. amrel/sparc architectures), see: - # https://github.com/giampaolo/psutil/issues/200 - # try to parse /proc/stat as a last resort - if num == 0: - f = open('/proc/stat', 'rt') - try: - lines = f.readlines() - finally: - f.close() - search = re.compile('cpu\d') - for line in lines: - line = line.split(' ')[0] - if search.match(line): - num += 1 + with open('/proc/cpuinfo', 'rb') as f: + for line in f: + if line.lower().startswith(b'processor'): + num += 1 + + # unknown format (e.g. amrel/sparc architectures), see: + # https://github.com/giampaolo/psutil/issues/200 + # try to parse /proc/stat as a last resort + if num == 0: + search = re.compile('cpu\d') + with open('/proc/stat', 'rt') as f: + for line in f: + line = line.split(' ')[0] + if search.match(line): + num += 1 - if num == 0: - # mimic os.cpu_count() - return None - return num + if num == 0: + # mimic os.cpu_count() + return None + return num def cpu_count_physical(): - """Return the number of physical CPUs in the system.""" - f = open('/proc/cpuinfo', 'rb') - try: - lines = f.readlines() - finally: - f.close() - found = set() - PHYSICAL_ID = b('physical id') - for line in lines: - if line.lower().startswith(PHYSICAL_ID): - found.add(line.strip()) - if found: - return len(found) - else: - return None # mimic os.cpu_count() + """Return the number of physical cores in the system.""" + mapping = {} + current_info = {} + with open('/proc/cpuinfo', 'rb') as f: + for line in f: + line = line.strip().lower() + if not line: + # new section + if (b'physical id' in current_info and + b'cpu cores' in current_info): + mapping[current_info[b'physical id']] = \ + current_info[b'cpu cores'] + current_info = {} + else: + # ongoing section + if (line.startswith(b'physical id') or + line.startswith(b'cpu cores')): + key, value = line.split(b'\t:', 1) + current_info[key] = int(value) + + # mimic os.cpu_count() + return sum(mapping.values()) or None # --- other system functions @@ -322,7 +313,7 @@ def users(): # to use them in the future. if not user_process: continue - if hostname == ':0.0': + if hostname == ':0.0' or hostname == ':0': hostname = 'localhost' nt = _common.suser(user, tty or None, hostname, tstamp) retlist.append(nt) @@ -332,24 +323,20 @@ def users(): def boot_time(): """Return the system boot time expressed in seconds since the epoch.""" global BOOT_TIME - f = open('/proc/stat', 'rb') - try: - BTIME = b('btime') + with open('/proc/stat', 'rb') as f: for line in f: - if line.startswith(BTIME): + if line.startswith(b'btime'): ret = float(line.strip().split()[1]) BOOT_TIME = ret return ret - raise RuntimeError("line 'btime' not found") - finally: - f.close() + raise RuntimeError("line 'btime' not found in /proc/stat") # --- processes def pids(): """Returns a list of PIDs currently running on the system.""" - return [int(x) for x in os.listdir(b('/proc')) if x.isdigit()] + return [int(x) for x in os.listdir(b'/proc') if x.isdigit()] def pid_exists(pid): @@ -396,9 +383,17 @@ def get_proc_inodes(self, pid): for fd in os.listdir("/proc/%s/fd" % pid): try: inode = os.readlink("/proc/%s/fd/%s" % (pid, fd)) - except OSError: - # TODO: need comment here - continue + except OSError as err: + # ENOENT == file which is gone in the meantime; + # os.stat('/proc/%s' % self.pid) will be done later + # to force NSP (if it's the case) + if err.errno in (errno.ENOENT, errno.ESRCH): + continue + elif err.errno == errno.EINVAL: + # not a link + continue + else: + raise else: if inode.startswith('socket:['): # the process is using a socket @@ -411,7 +406,7 @@ def get_all_inodes(self): for pid in pids(): try: inodes.update(self.get_proc_inodes(pid)) - except OSError: + except OSError as err: # os.listdir() is gonna raise a lot of access denied # exceptions in case of unprivileged user; that's fine # as we'll just end up returning a connection with PID @@ -419,7 +414,6 @@ def get_all_inodes(self): # Both netstat -an and lsof does the same so it's # unlikely we can do any better. # ENOENT just means a PID disappeared on us. - err = sys.exc_info()[1] if err.errno not in ( errno.ENOENT, errno.ESRCH, errno.EPERM, errno.EACCES): raise @@ -477,59 +471,67 @@ def process_inet(self, file, family, type_, inodes, filter_pid=None): if file.endswith('6') and not os.path.exists(file): # IPv6 not supported return - f = open(file, 'rt') - f.readline() # skip the first line - for line in f: - _, laddr, raddr, status, _, _, _, _, _, inode = \ - line.split()[:10] - if inode in inodes: - # We assume inet sockets are unique, so we error - # out if there are multiple references to the - # same inode. We won't do this for UNIX sockets. - if len(inodes[inode]) > 1 and type_ != socket.AF_UNIX: - raise ValueError("ambiguos inode with multiple " - "PIDs references") - pid, fd = inodes[inode][0] - else: - pid, fd = None, -1 - if filter_pid is not None and filter_pid != pid: - continue - else: - if type_ == socket.SOCK_STREAM: - status = TCP_STATUSES[status] + with open(file, 'rt') as f: + f.readline() # skip the first line + for line in f: + try: + _, laddr, raddr, status, _, _, _, _, _, inode = \ + line.split()[:10] + except ValueError: + raise RuntimeError( + "error while parsing %s; malformed line %r" % ( + file, line)) + if inode in inodes: + # # We assume inet sockets are unique, so we error + # # out if there are multiple references to the + # # same inode. We won't do this for UNIX sockets. + # if len(inodes[inode]) > 1 and family != socket.AF_UNIX: + # raise ValueError("ambiguos inode with multiple " + # "PIDs references") + pid, fd = inodes[inode][0] else: - status = _common.CONN_NONE - laddr = self.decode_address(laddr, family) - raddr = self.decode_address(raddr, family) - yield (fd, family, type_, laddr, raddr, status, pid) - f.close() + pid, fd = None, -1 + if filter_pid is not None and filter_pid != pid: + continue + else: + if type_ == socket.SOCK_STREAM: + status = TCP_STATUSES[status] + else: + status = _common.CONN_NONE + laddr = self.decode_address(laddr, family) + raddr = self.decode_address(raddr, family) + yield (fd, family, type_, laddr, raddr, status, pid) def process_unix(self, file, family, inodes, filter_pid=None): """Parse /proc/net/unix files.""" - f = open(file, 'rt') - f.readline() # skip the first line - for line in f: - tokens = line.split() - _, _, _, _, type_, _, inode = tokens[0:7] - if inode in inodes: - # With UNIX sockets we can have a single inode - # referencing many file descriptors. - pairs = inodes[inode] - else: - pairs = [(None, -1)] - for pid, fd in pairs: - if filter_pid is not None and filter_pid != pid: - continue + with open(file, 'rt') as f: + f.readline() # skip the first line + for line in f: + tokens = line.split() + try: + _, _, _, _, type_, _, inode = tokens[0:7] + except ValueError: + raise RuntimeError( + "error while parsing %s; malformed line %r" % ( + file, line)) + if inode in inodes: + # With UNIX sockets we can have a single inode + # referencing many file descriptors. + pairs = inodes[inode] else: - if len(tokens) == 8: - path = tokens[-1] + pairs = [(None, -1)] + for pid, fd in pairs: + if filter_pid is not None and filter_pid != pid: + continue else: - path = "" - type_ = int(type_) - raddr = None - status = _common.CONN_NONE - yield (fd, family, type_, path, raddr, status, pid) - f.close() + if len(tokens) == 8: + path = tokens[-1] + else: + path = "" + type_ = int(type_) + raddr = None + status = _common.CONN_NONE + yield (fd, family, type_, path, raddr, status, pid) def retrieve(self, kind, pid=None): if kind not in self.tmap: @@ -542,7 +544,7 @@ def retrieve(self, kind, pid=None): return [] else: inodes = self.get_all_inodes() - ret = [] + ret = set() for f, family, type_ in self.tmap[kind]: if family in (socket.AF_INET, socket.AF_INET6): ls = self.process_inet( @@ -557,8 +559,8 @@ def retrieve(self, kind, pid=None): else: conn = _common.sconn(fd, family, type_, laddr, raddr, status, bound_pid) - ret.append(conn) - return ret + ret.add(conn) + return list(ret) _connections = Connections() @@ -573,12 +575,8 @@ def net_io_counters(): """Return network I/O statistics for every network interface installed on the system as a dict of raw tuples. """ - f = open("/proc/net/dev", "rt") - try: + with open("/proc/net/dev", "rt") as f: lines = f.readlines() - finally: - f.close() - retdict = {} for line in lines[2:]: colon = line.rfind(':') @@ -598,6 +596,23 @@ def net_io_counters(): return retdict +def net_if_stats(): + """Get NIC stats (isup, duplex, speed, mtu).""" + duplex_map = {cext.DUPLEX_FULL: NIC_DUPLEX_FULL, + cext.DUPLEX_HALF: NIC_DUPLEX_HALF, + cext.DUPLEX_UNKNOWN: NIC_DUPLEX_UNKNOWN} + names = net_io_counters().keys() + ret = {} + for name in names: + isup, duplex, speed, mtu = cext.net_if_stats(name) + duplex = duplex_map[duplex] + ret[name] = _common.snicstats(isup, duplex, speed, mtu) + return ret + + +net_if_addrs = cext_posix.net_if_addrs + + # --- disks def disk_io_counters(): @@ -611,11 +626,8 @@ def disk_io_counters(): # determine partitions we want to look for partitions = [] - f = open("/proc/partitions", "rt") - try: + with open("/proc/partitions", "rt") as f: lines = f.readlines()[2:] - finally: - f.close() for line in reversed(lines): _, _, _, name = line.split() if name[-1].isdigit(): @@ -631,11 +643,8 @@ def disk_io_counters(): partitions.append(name) # retdict = {} - f = open("/proc/diskstats", "rt") - try: + with open("/proc/diskstats", "rt") as f: lines = f.readlines() - finally: - f.close() for line in lines: # http://www.mjmwired.net/kernel/Documentation/iostats.txt fields = line.split() @@ -658,15 +667,18 @@ def disk_io_counters(): def disk_partitions(all=False): - """Return mounted disk partitions as a list of nameduples""" - phydevs = [] - f = open("/proc/filesystems", "r") - try: + """Return mounted disk partitions as a list of namedtuples""" + fstypes = set() + with open("/proc/filesystems", "r") as f: for line in f: + line = line.strip() if not line.startswith("nodev"): - phydevs.append(line.strip()) - finally: - f.close() + fstypes.add(line.strip()) + else: + # ignore all lines starting with "nodev" except "nodev zfs" + fstype = line.split("\t")[1] + if fstype == "zfs": + fstypes.add("zfs") retlist = [] partitions = cext.disk_partitions() @@ -675,7 +687,7 @@ def disk_partitions(all=False): if device == 'none': device = '' if not all: - if device == '' or fstype not in phydevs: + if device == '' or fstype not in fstypes: continue ntuple = _common.sdiskpart(device, mountpoint, fstype, opts) retlist.append(ntuple) @@ -691,18 +703,17 @@ def wrap_exceptions(fun): """Decorator which translates bare OSError and IOError exceptions into NoSuchProcess and AccessDenied. """ - @wraps(fun) + @functools.wraps(fun) def wrapper(self, *args, **kwargs): try: return fun(self, *args, **kwargs) - except EnvironmentError: + except EnvironmentError as err: # support for private module import if NoSuchProcess is None or AccessDenied is None: raise # ENOENT (no such file or directory) gets raised on open(). # ESRCH (no such process) can get raised on read() if # process is gone in meantime. - err = sys.exc_info()[1] if err.errno in (errno.ENOENT, errno.ESRCH): raise NoSuchProcess(self.pid, self._name) if err.errno in (errno.EPERM, errno.EACCES): @@ -711,34 +722,43 @@ def wrapper(self, *args, **kwargs): return wrapper +def wrap_exceptions_w_zombie(fun): + """Same as above but also handles zombies.""" + @functools.wraps(fun) + def wrapper(self, *args, **kwargs): + try: + return wrap_exceptions(fun)(self) + except NoSuchProcess: + if not pid_exists(self.pid): + raise + else: + raise ZombieProcess(self.pid, self._name, self._ppid) + return wrapper + + class Process(object): """Linux process implementation.""" - __slots__ = ["pid", "_name"] + __slots__ = ["pid", "_name", "_ppid"] def __init__(self, pid): self.pid = pid self._name = None + self._ppid = None @wrap_exceptions def name(self): fname = "/proc/%s/stat" % self.pid - if PY3: - f = open(fname, "rt", encoding=DEFAULT_ENCODING) - else: - f = open(fname, "rt") - try: - name = f.read().split(' ')[1].replace('(', '').replace(')', '') - finally: - f.close() + kw = dict(encoding=DEFAULT_ENCODING) if PY3 else dict() + with open(fname, "rt", **kw) as f: + data = f.read() # XXX - gets changed later and probably needs refactoring - return name + return data[data.find('(') + 1:data.rfind(')')] def exe(self): try: exe = os.readlink("/proc/%s/exe" % self.pid) - except (OSError, IOError): - err = sys.exc_info()[1] + except OSError as err: if err.errno in (errno.ENOENT, errno.ESRCH): # no such file error; might be raised also if the # path actually exists for system processes with @@ -746,8 +766,10 @@ def exe(self): if os.path.lexists("/proc/%s" % self.pid): return "" else: - # ok, it is a process which has gone away - raise NoSuchProcess(self.pid, self._name) + if not pid_exists(self.pid): + raise NoSuchProcess(self.pid, self._name) + else: + raise ZombieProcess(self.pid, self._name, self._ppid) if err.errno in (errno.EPERM, errno.EACCES): raise AccessDenied(self.pid, self._name) raise @@ -765,24 +787,18 @@ def exe(self): @wrap_exceptions def cmdline(self): fname = "/proc/%s/cmdline" % self.pid - if PY3: - f = open(fname, "rt", encoding=DEFAULT_ENCODING) - else: - f = open(fname, "rt") - try: - # return the args as a list - return [x for x in f.read().split('\x00') if x] - finally: - f.close() + kw = dict(encoding=DEFAULT_ENCODING) if PY3 else dict() + with open(fname, "rt", **kw) as f: + data = f.read() + if data.endswith('\x00'): + data = data[:-1] + return [x for x in data.split('\x00')] @wrap_exceptions def terminal(self): tmap = _psposix._get_terminal_map() - f = open("/proc/%s/stat" % self.pid, 'rb') - try: - tty_nr = int(f.read().split(b(' '))[6]) - finally: - f.close() + with open("/proc/%s/stat" % self.pid, 'rb') as f: + tty_nr = int(f.read().split(b' ')[6]) try: return tmap[tty_nr] except KeyError: @@ -792,27 +808,22 @@ def terminal(self): @wrap_exceptions def io_counters(self): fname = "/proc/%s/io" % self.pid - f = open(fname, 'rb') - SYSCR, SYSCW = b("syscr"), b("syscw") - READ_BYTES, WRITE_BYTES = b("read_bytes"), b("write_bytes") - try: + with open(fname, 'rb') as f: rcount = wcount = rbytes = wbytes = None for line in f: - if rcount is None and line.startswith(SYSCR): + if rcount is None and line.startswith(b"syscr"): rcount = int(line.split()[1]) - elif wcount is None and line.startswith(SYSCW): + elif wcount is None and line.startswith(b"syscw"): wcount = int(line.split()[1]) - elif rbytes is None and line.startswith(READ_BYTES): + elif rbytes is None and line.startswith(b"read_bytes"): rbytes = int(line.split()[1]) - elif wbytes is None and line.startswith(WRITE_BYTES): + elif wbytes is None and line.startswith(b"write_bytes"): wbytes = int(line.split()[1]) for x in (rcount, wcount, rbytes, wbytes): if x is None: raise NotImplementedError( "couldn't read all necessary info from %r" % fname) return _common.pio(rcount, wcount, rbytes, wbytes) - finally: - f.close() else: def io_counters(self): raise NotImplementedError("couldn't find /proc/%s/io (kernel " @@ -820,14 +831,11 @@ def io_counters(self): @wrap_exceptions def cpu_times(self): - f = open("/proc/%s/stat" % self.pid, 'rb') - try: + with open("/proc/%s/stat" % self.pid, 'rb') as f: st = f.read().strip() - finally: - f.close() # ignore the first two values ("pid (exe)") - st = st[st.find(b(')')) + 2:] - values = st.split(b(' ')) + st = st[st.find(b')') + 2:] + values = st.split(b' ') utime = float(values[11]) / CLOCK_TICKS stime = float(values[12]) / CLOCK_TICKS return _common.pcputimes(utime, stime) @@ -844,14 +852,11 @@ def wait(self, timeout=None): @wrap_exceptions def create_time(self): - f = open("/proc/%s/stat" % self.pid, 'rb') - try: + with open("/proc/%s/stat" % self.pid, 'rb') as f: st = f.read().strip() - finally: - f.close() # ignore the first two values ("pid (exe)") - st = st[st.rfind(b(')')) + 2:] - values = st.split(b(' ')) + st = st[st.rfind(b')') + 2:] + values = st.split(b' ') # According to documentation, starttime is in field 21 and the # unit is jiffies (clock ticks). # We first divide it for clock ticks and then add uptime returning @@ -862,13 +867,10 @@ def create_time(self): @wrap_exceptions def memory_info(self): - f = open("/proc/%s/statm" % self.pid, 'rb') - try: + with open("/proc/%s/statm" % self.pid, 'rb') as f: vms, rss = f.readline().split()[:2] return _common.pmem(int(rss) * PAGESIZE, int(vms) * PAGESIZE) - finally: - f.close() @wrap_exceptions def memory_info_ex(self): @@ -883,23 +885,20 @@ def memory_info_ex(self): # | data | data + stack | drs | DATA | # | dirty | dirty pages (unused in Linux 2.6) | dt | | # ============================================================ - f = open("/proc/%s/statm" % self.pid, "rb") - try: + with open("/proc/%s/statm" % self.pid, "rb") as f: vms, rss, shared, text, lib, data, dirty = \ [int(x) * PAGESIZE for x in f.readline().split()[:7]] - finally: - f.close() return pextmem(rss, vms, shared, text, lib, data, dirty) if os.path.exists('/proc/%s/smaps' % os.getpid()): + + @wrap_exceptions def memory_maps(self): - """Return process's mapped memory regions as a list of nameduples. + """Return process's mapped memory regions as a list of named tuples. Fields are explained in 'man proc'; here is an updated (Apr 2012) version: http://goo.gl/fmebo """ - f = None - try: - f = open("/proc/%s/smaps" % self.pid, "rt") + with open("/proc/%s/smaps" % self.pid, "rt") as f: first_line = f.readline() current_block = [first_line] @@ -923,6 +922,7 @@ def get_blocks(): "rpret line %r" % line) yield (current_block.pop(), data) + ls = [] if first_line: # smaps file can be empty for header, data in get_blocks(): hfields = header.split(None, 5) @@ -935,35 +935,20 @@ def get_blocks(): path = '[anon]' else: path = path.strip() - yield (addr, perms, path, - data['Rss:'], - data.get('Size:', 0), - data.get('Pss:', 0), - data.get('Shared_Clean:', 0), - data.get('Shared_Dirty:', 0), - data.get('Private_Clean:', 0), - data.get('Private_Dirty:', 0), - data.get('Referenced:', 0), - data.get('Anonymous:', 0), - data.get('Swap:', 0)) - f.close() - except EnvironmentError: - # XXX - Can't use wrap_exceptions decorator as we're - # returning a generator; this probably needs some - # refactoring in order to avoid this code duplication. - if f is not None: - f.close() - err = sys.exc_info()[1] - if err.errno in (errno.ENOENT, errno.ESRCH): - raise NoSuchProcess(self.pid, self._name) - if err.errno in (errno.EPERM, errno.EACCES): - raise AccessDenied(self.pid, self._name) - raise - except: - if f is not None: - f.close() - raise - f.close() + ls.append(( + addr, perms, path, + data['Rss:'], + data.get('Size:', 0), + data.get('Pss:', 0), + data.get('Shared_Clean:', 0), + data.get('Shared_Dirty:', 0), + data.get('Private_Clean:', 0), + data.get('Private_Dirty:', 0), + data.get('Referenced:', 0), + data.get('Anonymous:', 0), + data.get('Swap:', 0) + )) + return ls else: def memory_maps(self): @@ -972,7 +957,7 @@ def memory_maps(self): % self.pid raise NotImplementedError(msg) - @wrap_exceptions + @wrap_exceptions_w_zombie def cwd(self): # readlink() might return paths containing null bytes causing # problems when used with other fs-related functions (os.*, @@ -983,14 +968,11 @@ def cwd(self): @wrap_exceptions def num_ctx_switches(self): vol = unvol = None - f = open("/proc/%s/status" % self.pid, "rb") - VOLUNTARY = b("voluntary_ctxt_switches") - NON_VOLUNTARY = b("nonvoluntary_ctxt_switches") - try: + with open("/proc/%s/status" % self.pid, "rb") as f: for line in f: - if line.startswith(VOLUNTARY): + if line.startswith(b"voluntary_ctxt_switches"): vol = int(line.split()[1]) - elif line.startswith(NON_VOLUNTARY): + elif line.startswith(b"nonvoluntary_ctxt_switches"): unvol = int(line.split()[1]) if vol is not None and unvol is not None: return _common.pctxsw(vol, unvol) @@ -998,20 +980,14 @@ def num_ctx_switches(self): "'voluntary_ctxt_switches' and 'nonvoluntary_ctxt_switches'" "fields were not found in /proc/%s/status; the kernel is " "probably older than 2.6.23" % self.pid) - finally: - f.close() @wrap_exceptions def num_threads(self): - f = open("/proc/%s/status" % self.pid, "rb") - try: - THREADS = b("Threads:") + with open("/proc/%s/status" % self.pid, "rb") as f: for line in f: - if line.startswith(THREADS): + if line.startswith(b"Threads:"): return int(line.split()[1]) raise NotImplementedError("line not found") - finally: - f.close() @wrap_exceptions def threads(self): @@ -1020,23 +996,20 @@ def threads(self): retlist = [] hit_enoent = False for thread_id in thread_ids: + fname = "/proc/%s/task/%s/stat" % (self.pid, thread_id) try: - f = open("/proc/%s/task/%s/stat" % (self.pid, thread_id), 'rb') - except EnvironmentError: - err = sys.exc_info()[1] + with open(fname, 'rb') as f: + st = f.read().strip() + except IOError as err: if err.errno == errno.ENOENT: # no such file or directory; it means thread # disappeared on us hit_enoent = True continue raise - try: - st = f.read().strip() - finally: - f.close() # ignore the first two values ("pid (exe)") - st = st[st.find(b(')')) + 2:] - values = st.split(b(' ')) + st = st[st.find(b')') + 2:] + values = st.split(b' ') utime = float(values[11]) / CLOCK_TICKS stime = float(values[12]) / CLOCK_TICKS ntuple = _common.pthread(int(thread_id), utime, stime) @@ -1048,19 +1021,16 @@ def threads(self): @wrap_exceptions def nice_get(self): - # f = open('/proc/%s/stat' % self.pid, 'r') - # try: + # with open('/proc/%s/stat' % self.pid, 'r') as f: # data = f.read() # return int(data.split()[18]) - # finally: - # f.close() # Use C implementation - return _psutil_posix.getpriority(self.pid) + return cext_posix.getpriority(self.pid) @wrap_exceptions def nice_set(self, value): - return _psutil_posix.setpriority(self.pid, value) + return cext_posix.setpriority(self.pid, value) @wrap_exceptions def cpu_affinity_get(self): @@ -1070,8 +1040,7 @@ def cpu_affinity_get(self): def cpu_affinity_set(self, cpus): try: cext.proc_cpu_affinity_set(self.pid, cpus) - except OSError: - err = sys.exc_info()[1] + except OSError as err: if err.errno == errno.EINVAL: allcpus = tuple(range(len(per_cpu_times()))) for cpu in cpus: @@ -1086,64 +1055,82 @@ def cpu_affinity_set(self, cpus): @wrap_exceptions def ionice_get(self): ioclass, value = cext.proc_ioprio_get(self.pid) + if enum is not None: + ioclass = IOPriority(ioclass) return _common.pionice(ioclass, value) @wrap_exceptions def ionice_set(self, ioclass, value): + if value is not None: + if not PY3 and not isinstance(value, (int, long)): + msg = "value argument is not an integer (gor %r)" % value + raise TypeError(msg) + if not 0 <= value <= 8: + raise ValueError( + "value argument range expected is between 0 and 8") + if ioclass in (IOPRIO_CLASS_NONE, None): if value: - msg = "can't specify value with IOPRIO_CLASS_NONE" + msg = "can't specify value with IOPRIO_CLASS_NONE " \ + "(got %r)" % value raise ValueError(msg) ioclass = IOPRIO_CLASS_NONE value = 0 - if ioclass in (IOPRIO_CLASS_RT, IOPRIO_CLASS_BE): - if value is None: - value = 4 elif ioclass == IOPRIO_CLASS_IDLE: if value: - msg = "can't specify value with IOPRIO_CLASS_IDLE" + msg = "can't specify value with IOPRIO_CLASS_IDLE " \ + "(got %r)" % value raise ValueError(msg) value = 0 + elif ioclass in (IOPRIO_CLASS_RT, IOPRIO_CLASS_BE): + if value is None: + # TODO: add comment explaining why this is 4 (?) + value = 4 else: - value = 0 - if not 0 <= value <= 8: - raise ValueError( - "value argument range expected is between 0 and 8") + # otherwise we would get OSError(EVINAL) + raise ValueError("invalid ioclass argument %r" % ioclass) + return cext.proc_ioprio_set(self.pid, ioclass, value) if HAS_PRLIMIT: @wrap_exceptions def rlimit(self, resource, limits=None): - # if pid is 0 prlimit() applies to the calling process and - # we don't want that + # If pid is 0 prlimit() applies to the calling process and + # we don't want that. We should never get here though as + # PID 0 is not supported on Linux. if self.pid == 0: raise ValueError("can't use prlimit() against PID 0 process") - if limits is None: - # get - return cext.linux_prlimit(self.pid, resource) - else: - # set - if len(limits) != 2: - raise ValueError( - "second argument must be a (soft, hard) tuple") - soft, hard = limits - cext.linux_prlimit(self.pid, resource, soft, hard) + try: + if limits is None: + # get + return cext.linux_prlimit(self.pid, resource) + else: + # set + if len(limits) != 2: + raise ValueError( + "second argument must be a (soft, hard) tuple, " + "got %s" % repr(limits)) + soft, hard = limits + cext.linux_prlimit(self.pid, resource, soft, hard) + except OSError as err: + if err.errno == errno.ENOSYS and pid_exists(self.pid): + # I saw this happening on Travis: + # https://travis-ci.org/giampaolo/psutil/jobs/51368273 + raise ZombieProcess(self.pid, self._name, self._ppid) + else: + raise @wrap_exceptions def status(self): - f = open("/proc/%s/status" % self.pid, 'rb') - try: - STATE = b("State:") + with open("/proc/%s/status" % self.pid, 'rb') as f: for line in f: - if line.startswith(STATE): + if line.startswith(b"State:"): letter = line.split()[1] if PY3: letter = letter.decode() # XXX is '?' legit? (we're not supposed to return # it anyway) return PROC_STATUSES.get(letter, '?') - finally: - f.close() @wrap_exceptions def open_files(self): @@ -1152,24 +1139,26 @@ def open_files(self): hit_enoent = False for fd in files: file = "/proc/%s/fd/%s" % (self.pid, fd) - if os.path.islink(file): - try: - file = os.readlink(file) - except OSError: - # ENOENT == file which is gone in the meantime - err = sys.exc_info()[1] - if err.errno in (errno.ENOENT, errno.ESRCH): - hit_enoent = True - continue - raise + try: + file = os.readlink(file) + except OSError as err: + # ENOENT == file which is gone in the meantime + if err.errno in (errno.ENOENT, errno.ESRCH): + hit_enoent = True + continue + elif err.errno == errno.EINVAL: + # not a link + continue else: - # If file is not an absolute path there's no way - # to tell whether it's a regular file or not, - # so we skip it. A regular file is always supposed - # to be absolutized though. - if file.startswith('/') and isfile_strict(file): - ntuple = _common.popenfile(file, int(fd)) - retlist.append(ntuple) + raise + else: + # If file is not an absolute path there's no way + # to tell whether it's a regular file or not, + # so we skip it. A regular file is always supposed + # to be absolutized though. + if file.startswith('/') and isfile_strict(file): + ntuple = _common.popenfile(file, int(fd)) + retlist.append(ntuple) if hit_enoent: # raise NSP if the process disappeared on us os.stat('/proc/%s' % self.pid) @@ -1188,39 +1177,30 @@ def num_fds(self): @wrap_exceptions def ppid(self): - f = open("/proc/%s/status" % self.pid, 'rb') - try: - PPID = b("PPid:") + fpath = "/proc/%s/status" % self.pid + with open(fpath, 'rb') as f: for line in f: - if line.startswith(PPID): + if line.startswith(b"PPid:"): # PPid: nnnn return int(line.split()[1]) - raise NotImplementedError("line not found") - finally: - f.close() + raise NotImplementedError("line 'PPid' not found in %s" % fpath) @wrap_exceptions def uids(self): - f = open("/proc/%s/status" % self.pid, 'rb') - try: - UID = b('Uid:') + fpath = "/proc/%s/status" % self.pid + with open(fpath, 'rb') as f: for line in f: - if line.startswith(UID): + if line.startswith(b'Uid:'): _, real, effective, saved, fs = line.split() return _common.puids(int(real), int(effective), int(saved)) - raise NotImplementedError("line not found") - finally: - f.close() + raise NotImplementedError("line 'Uid' not found in %s" % fpath) @wrap_exceptions def gids(self): - f = open("/proc/%s/status" % self.pid, 'rb') - try: - GID = b('Gid:') + fpath = "/proc/%s/status" % self.pid + with open(fpath, 'rb') as f: for line in f: - if line.startswith(GID): + if line.startswith(b'Gid:'): _, real, effective, saved, fs = line.split() return _common.pgids(int(real), int(effective), int(saved)) - raise NotImplementedError("line not found") - finally: - f.close() + raise NotImplementedError("line 'Gid' not found in %s" % fpath) diff --git a/python/psutil/psutil/_psosx.py b/python/psutil/psutil/_psosx.py index 8953867da7a0..41875fe4045e 100644 --- a/python/psutil/psutil/_psosx.py +++ b/python/psutil/psutil/_psosx.py @@ -7,15 +7,16 @@ """OSX platform implementation.""" import errno +import functools import os -import sys +from collections import namedtuple -from psutil import _common -from psutil import _psposix -from psutil._common import conn_tmap, usage_percent, isfile_strict -from psutil._compat import namedtuple, wraps -import _psutil_osx as cext -import _psutil_posix +from . import _common +from . import _psposix +from . import _psutil_osx as cext +from . import _psutil_posix as cext_posix +from ._common import conn_tmap, usage_percent, isfile_strict +from ._common import sockfam_to_enum, socktype_to_enum __extra__all__ = [] @@ -23,6 +24,7 @@ # --- constants PAGESIZE = os.sysconf("SC_PAGE_SIZE") +AF_LINK = cext_posix.AF_LINK # http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h TCP_STATUSES = { @@ -65,6 +67,7 @@ # set later from __init__.py NoSuchProcess = None +ZombieProcess = None AccessDenied = None TimeoutExpired = None @@ -165,28 +168,44 @@ def net_connections(kind='inet'): return ret +def net_if_stats(): + """Get NIC stats (isup, duplex, speed, mtu).""" + names = net_io_counters().keys() + ret = {} + for name in names: + isup, duplex, speed, mtu = cext_posix.net_if_stats(name) + if hasattr(_common, 'NicDuplex'): + duplex = _common.NicDuplex(duplex) + ret[name] = _common.snicstats(isup, duplex, speed, mtu) + return ret + + pids = cext.pids pid_exists = _psposix.pid_exists disk_usage = _psposix.disk_usage net_io_counters = cext.net_io_counters disk_io_counters = cext.disk_io_counters +net_if_addrs = cext_posix.net_if_addrs def wrap_exceptions(fun): """Decorator which translates bare OSError exceptions into NoSuchProcess and AccessDenied. """ - @wraps(fun) + @functools.wraps(fun) def wrapper(self, *args, **kwargs): try: return fun(self, *args, **kwargs) - except OSError: + except OSError as err: # support for private module import - if NoSuchProcess is None or AccessDenied is None: + if (NoSuchProcess is None or AccessDenied is None or + ZombieProcess is None): raise - err = sys.exc_info()[1] if err.errno == errno.ESRCH: - raise NoSuchProcess(self.pid, self._name) + if not pid_exists(self.pid): + raise NoSuchProcess(self.pid, self._name) + else: + raise ZombieProcess(self.pid, self._name, self._ppid) if err.errno in (errno.EPERM, errno.EACCES): raise AccessDenied(self.pid, self._name) raise @@ -196,11 +215,12 @@ def wrapper(self, *args, **kwargs): class Process(object): """Wrapper class around underlying C implementation.""" - __slots__ = ["pid", "_name"] + __slots__ = ["pid", "_name", "_ppid"] def __init__(self, pid): self.pid = pid self._name = None + self._ppid = None @wrap_exceptions def name(self): @@ -293,6 +313,8 @@ def connections(self, kind='inet'): for item in rawlist: fd, fam, type, laddr, raddr, status = item status = TCP_STATUSES[status] + fam = sockfam_to_enum(fam) + type = socktype_to_enum(type) nt = _common.pconn(fd, fam, type, laddr, raddr, status) ret.append(nt) return ret @@ -315,11 +337,11 @@ def wait(self, timeout=None): @wrap_exceptions def nice_get(self): - return _psutil_posix.getpriority(self.pid) + return cext_posix.getpriority(self.pid) @wrap_exceptions def nice_set(self, value): - return _psutil_posix.setpriority(self.pid, value) + return cext_posix.setpriority(self.pid, value) @wrap_exceptions def status(self): diff --git a/python/psutil/psutil/_psposix.py b/python/psutil/psutil/_psposix.py index 810760439c1c..5bb16a386d14 100644 --- a/python/psutil/psutil/_psposix.py +++ b/python/psutil/psutil/_psposix.py @@ -12,8 +12,8 @@ import sys import time -from psutil._common import sdiskusage, usage_percent, memoize -from psutil._compat import PY3, unicode +from ._common import sdiskusage, usage_percent, memoize +from ._compat import PY3, unicode class TimeoutExpired(Exception): @@ -31,8 +31,7 @@ def pid_exists(pid): return True try: os.kill(pid, 0) - except OSError: - err = sys.exc_info()[1] + except OSError as err: if err.errno == errno.ESRCH: # ESRCH == No such process return False @@ -69,17 +68,18 @@ def check_timeout(delay): timer = getattr(time, 'monotonic', time.time) if timeout is not None: - waitcall = lambda: os.waitpid(pid, os.WNOHANG) + def waitcall(): + return os.waitpid(pid, os.WNOHANG) stop_at = timer() + timeout else: - waitcall = lambda: os.waitpid(pid, 0) + def waitcall(): + return os.waitpid(pid, 0) delay = 0.0001 - while 1: + while True: try: retpid, status = waitcall() - except OSError: - err = sys.exc_info()[1] + except OSError as err: if err.errno == errno.EINTR: delay = check_timeout(delay) continue @@ -90,7 +90,7 @@ def check_timeout(delay): # - pid never existed in the first place # In both cases we'll eventually return None as we # can't determine its exit status code. - while 1: + while True: if pid_exists(pid): delay = check_timeout(delay) else: @@ -150,8 +150,7 @@ def _get_terminal_map(): assert name not in ret try: ret[os.stat(name).st_rdev] = name - except OSError: - err = sys.exc_info()[1] + except OSError as err: if err.errno != errno.ENOENT: raise return ret diff --git a/python/psutil/psutil/_pssunos.py b/python/psutil/psutil/_pssunos.py index 2fc1ec4522b9..bc35a718c36e 100644 --- a/python/psutil/psutil/_pssunos.py +++ b/python/psutil/psutil/_pssunos.py @@ -11,18 +11,21 @@ import socket import subprocess import sys +from collections import namedtuple -from psutil import _common -from psutil import _psposix -from psutil._common import usage_percent, isfile_strict -from psutil._compat import namedtuple, PY3 -import _psutil_posix -import _psutil_sunos as cext +from . import _common +from . import _psposix +from . import _psutil_posix as cext_posix +from . import _psutil_sunos as cext +from ._common import isfile_strict, socktype_to_enum, sockfam_to_enum +from ._common import usage_percent +from ._compat import PY3 __extra__all__ = ["CONN_IDLE", "CONN_BOUND"] PAGE_SIZE = os.sysconf('SC_PAGE_SIZE') +AF_LINK = cext_posix.AF_LINK CONN_IDLE = "IDLE" CONN_BOUND = "BOUND" @@ -63,6 +66,7 @@ # set later from __init__.py NoSuchProcess = None +ZombieProcess = None AccessDenied = None TimeoutExpired = None @@ -71,6 +75,7 @@ disk_io_counters = cext.disk_io_counters net_io_counters = cext.net_io_counters disk_usage = _psposix.disk_usage +net_if_addrs = cext_posix.net_if_addrs def virtual_memory(): @@ -91,7 +96,9 @@ def swap_memory(): # usr/src/cmd/swap/swap.c # ...nevertheless I can't manage to obtain the same numbers as 'swap' # cmdline utility, so let's parse its output (sigh!) - p = subprocess.Popen(['swap', '-l', '-k'], stdout=subprocess.PIPE) + p = subprocess.Popen(['/usr/bin/env', 'PATH=/usr/sbin:/sbin:%s' % + os.environ['PATH'], 'swap', '-l', '-k'], + stdout=subprocess.PIPE) stdout, stderr = p.communicate() if PY3: stdout = stdout.decode(sys.stdout.encoding) @@ -209,7 +216,7 @@ def net_connections(kind, _pid=-1): % (kind, ', '.join([repr(x) for x in cmap]))) families, types = _common.conn_tmap[kind] rawlist = cext.net_connections(_pid, families, types) - ret = [] + ret = set() for item in rawlist: fd, fam, type_, laddr, raddr, status, pid = item if fam not in families: @@ -217,11 +224,24 @@ def net_connections(kind, _pid=-1): if type_ not in types: continue status = TCP_STATUSES[status] + fam = sockfam_to_enum(fam) + type_ = socktype_to_enum(type_) if _pid == -1: nt = _common.sconn(fd, fam, type_, laddr, raddr, status, pid) else: nt = _common.pconn(fd, fam, type_, laddr, raddr, status) - ret.append(nt) + ret.add(nt) + return list(ret) + + +def net_if_stats(): + """Get NIC stats (isup, duplex, speed, mtu).""" + ret = cext.net_if_stats() + for name, items in ret.items(): + isup, duplex, speed, mtu = items + if hasattr(_common, 'NicDuplex'): + duplex = _common.NicDuplex(duplex) + ret[name] = _common.snicstats(isup, duplex, speed, mtu) return ret @@ -232,16 +252,19 @@ def wrap_exceptions(fun): def wrapper(self, *args, **kwargs): try: return fun(self, *args, **kwargs) - except EnvironmentError: + except EnvironmentError as err: # support for private module import - if NoSuchProcess is None or AccessDenied is None: + if (NoSuchProcess is None or AccessDenied is None or + ZombieProcess is None): raise # ENOENT (no such file or directory) gets raised on open(). # ESRCH (no such process) can get raised on read() if # process is gone in meantime. - err = sys.exc_info()[1] if err.errno in (errno.ENOENT, errno.ESRCH): - raise NoSuchProcess(self.pid, self._name) + if not pid_exists(self.pid): + raise NoSuchProcess(self.pid, self._name) + else: + raise ZombieProcess(self.pid, self._name, self._ppid) if err.errno in (errno.EPERM, errno.EACCES): raise AccessDenied(self.pid, self._name) raise @@ -251,11 +274,12 @@ def wrapper(self, *args, **kwargs): class Process(object): """Wrapper class around underlying C implementation.""" - __slots__ = ["pid", "_name"] + __slots__ = ["pid", "_name", "_ppid"] def __init__(self, pid): self.pid = pid self._name = None + self._ppid = None @wrap_exceptions def name(self): @@ -292,10 +316,11 @@ def nice_get(self): # Note: tested on Solaris 11; on Open Solaris 5 everything is # fine. try: - return _psutil_posix.getpriority(self.pid) - except EnvironmentError: - err = sys.exc_info()[1] - if err.errno in (errno.ENOENT, errno.ESRCH): + return cext_posix.getpriority(self.pid) + except EnvironmentError as err: + # 48 is 'operation not supported' but errno does not expose + # it. It occurs for low system pids. + if err.errno in (errno.ENOENT, errno.ESRCH, 48): if pid_exists(self.pid): raise AccessDenied(self.pid, self._name) raise @@ -308,7 +333,7 @@ def nice_set(self, value): # The process actually exists though, as it has a name, # creation time, etc. raise AccessDenied(self.pid, self._name) - return _psutil_posix.setpriority(self.pid, value) + return cext_posix.setpriority(self.pid, value) @wrap_exceptions def ppid(self): @@ -338,8 +363,7 @@ def terminal(self): for x in (0, 1, 2, 255): try: return os.readlink('/proc/%d/path/%d' % (self.pid, x)) - except OSError: - err = sys.exc_info()[1] + except OSError as err: if err.errno == errno.ENOENT: hit_enoent = True continue @@ -356,8 +380,7 @@ def cwd(self): # Reference: http://goo.gl/55XgO try: return os.readlink("/proc/%s/path/cwd" % self.pid) - except OSError: - err = sys.exc_info()[1] + except OSError as err: if err.errno == errno.ENOENT: os.stat("/proc/%s" % self.pid) return None @@ -388,9 +411,8 @@ def threads(self): try: utime, stime = cext.query_process_thread( self.pid, tid) - except EnvironmentError: + except EnvironmentError as err: # ENOENT == thread gone in meantime - err = sys.exc_info()[1] if err.errno == errno.ENOENT: hit_enoent = True continue @@ -413,9 +435,8 @@ def open_files(self): if os.path.islink(path): try: file = os.readlink(path) - except OSError: + except OSError as err: # ENOENT == file which is gone in the meantime - err = sys.exc_info()[1] if err.errno == errno.ENOENT: hit_enoent = True continue @@ -495,8 +516,7 @@ def toaddr(start, end): if not name.startswith('['): try: name = os.readlink('/proc/%s/path/%s' % (self.pid, name)) - except OSError: - err = sys.exc_info()[1] + except OSError as err: if err.errno == errno.ENOENT: # sometimes the link may not be resolved by # readlink() even if it exists (ls shows it). diff --git a/python/psutil/psutil/_psutil_bsd.c b/python/psutil/psutil/_psutil_bsd.c index 5a9f9c08b70c..7b6e56173d2d 100644 --- a/python/psutil/psutil/_psutil_bsd.c +++ b/python/psutil/psutil/_psutil_bsd.c @@ -21,12 +21,14 @@ #include #include #include +#include #include #include #include // for struct xsocket #include #include +#include // for xinpcb struct #include #include @@ -49,6 +51,7 @@ #include // net io counters #include #include +#include #include // process open files/connections #include @@ -91,6 +94,18 @@ psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) } +/* + * Set exception to AccessDenied if pid exists else NoSuchProcess. + */ +void +psutil_raise_ad_or_nsp(long pid) { + if (psutil_pid_exists(pid) == 0) + NoSuchProcess(); + else + AccessDenied(); +} + + /* * Return a Python list of all the PIDs running on the system. */ @@ -104,9 +119,8 @@ psutil_pids(PyObject *self, PyObject *args) PyObject *retlist = PyList_New(0); PyObject *pid = NULL; - if (retlist == NULL) { + if (retlist == NULL) return NULL; - } if (psutil_get_proc_list(&proclist, &num_processes) != 0) { PyErr_SetString(PyExc_RuntimeError, "failed to retrieve process list."); @@ -132,9 +146,8 @@ psutil_pids(PyObject *self, PyObject *args) error: Py_XDECREF(pid); Py_DECREF(retlist); - if (orig_address != NULL) { + if (orig_address != NULL) free(orig_address); - } return NULL; } @@ -167,12 +180,10 @@ psutil_proc_name(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("s", kp.ki_comm); } @@ -191,9 +202,8 @@ psutil_proc_exe(PyObject *self, PyObject *args) int mib[4]; size_t size; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } mib[0] = CTL_KERN; mib[1] = KERN_PROC; @@ -207,12 +217,10 @@ psutil_proc_exe(PyObject *self, PyObject *args) return NULL; } if (size == 0 || strlen(pathname) == 0) { - if (psutil_pid_exists(pid) == 0) { + if (psutil_pid_exists(pid) == 0) return NoSuchProcess(); - } - else { + else strcpy(pathname, ""); - } } return Py_BuildValue("s", pathname); } @@ -227,18 +235,16 @@ psutil_proc_cmdline(PyObject *self, PyObject *args) long pid; PyObject *arglist = NULL; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } // get the commandline, defined in arch/bsd/process_info.c arglist = psutil_get_arg_list(pid); // psutil_get_arg_list() returns NULL only if psutil_cmd_args // failed with ESRCH (no process with that PID) - if (NULL == arglist) { + if (NULL == arglist) return PyErr_SetFromErrno(PyExc_OSError); - } return Py_BuildValue("N", arglist); } @@ -251,12 +257,10 @@ psutil_proc_ppid(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("l", (long)kp.ki_ppid); } @@ -269,12 +273,10 @@ psutil_proc_status(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("i", (int)kp.ki_stat); } @@ -288,12 +290,10 @@ psutil_proc_uids(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("lll", (long)kp.ki_ruid, (long)kp.ki_uid, @@ -310,12 +310,10 @@ psutil_proc_gids(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("lll", (long)kp.ki_rgid, (long)kp.ki_groups[0], @@ -332,12 +330,10 @@ psutil_proc_tty_nr(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("i", kp.ki_tdev); } @@ -350,12 +346,10 @@ psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("(ll)", kp.ki_rusage.ru_nvcsw, kp.ki_rusage.ru_nivcsw); @@ -370,12 +364,10 @@ psutil_proc_num_threads(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("l", (long)kp.ki_numthreads); } @@ -456,9 +448,8 @@ psutil_proc_threads(PyObject *self, PyObject *args) error: Py_XDECREF(pyTuple); Py_DECREF(retList); - if (kip != NULL) { + if (kip != NULL) free(kip); - } return NULL; } @@ -472,12 +463,10 @@ psutil_proc_cpu_times(PyObject *self, PyObject *args) long pid; double user_t, sys_t; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } // convert from microseconds to seconds user_t = TV2DOUBLE(kp.ki_rusage.ru_utime); sys_t = TV2DOUBLE(kp.ki_rusage.ru_stime); @@ -500,14 +489,10 @@ psutil_cpu_count_logical(PyObject *self, PyObject *args) mib[1] = HW_NCPU; len = sizeof(ncpu); - if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) { - // mimic os.cpu_count() - Py_INCREF(Py_None); - return Py_None; - } - else { + if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) + Py_RETURN_NONE; // mimic os.cpu_count() + else return Py_BuildValue("i", ncpu); - } } @@ -520,6 +505,7 @@ psutil_cpu_count_phys(PyObject *self, PyObject *args) { void *topology = NULL; size_t size = 0; + PyObject *py_str; if (sysctlbyname("kern.sched.topology_spec", NULL, &size, NULL, 0)) goto error; @@ -533,11 +519,14 @@ psutil_cpu_count_phys(PyObject *self, PyObject *args) if (sysctlbyname("kern.sched.topology_spec", topology, &size, NULL, 0)) goto error; - return Py_BuildValue("s", topology); + py_str = Py_BuildValue("s", topology); + free(topology); + return py_str; error: - Py_INCREF(Py_None); - return Py_None; + if (topology != NULL) + free(topology); + Py_RETURN_NONE; } @@ -550,12 +539,10 @@ psutil_proc_create_time(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("d", TV2DOUBLE(kp.ki_start)); } @@ -569,12 +556,10 @@ psutil_proc_io_counters(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } // there's apparently no way to determine bytes count, hence return -1. return Py_BuildValue("(llll)", kp.ki_rusage.ru_inblock, @@ -592,12 +577,10 @@ psutil_proc_memory_info(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("(lllll)", ptoa(kp.ki_rssize), // rss (long)kp.ki_size, // vms @@ -749,7 +732,10 @@ psutil_cpu_times(PyObject *self, PyObject *args) #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 /* - * Return files opened by process as a list of (path, fd) tuples + * Return files opened by process as a list of (path, fd) tuples. + * TODO: this is broken as it may report empty paths. 'procstat' + * utility has the same problem see: + * https://github.com/giampaolo/psutil/issues/595 */ static PyObject * psutil_proc_open_files(PyObject *self, PyObject *args) @@ -867,9 +853,8 @@ psutil_proc_cwd(PyObject *self, PyObject *args) * (lsof can't do that it either). Since this happens even * as root we return an empty string instead of AccessDenied. */ - if (path == NULL) { + if (path == NULL) path = Py_BuildValue("s", ""); - } free(freep); return path; @@ -887,7 +872,6 @@ psutil_fetch_tcplist(void) { char *buf; size_t len; - int error; for (;;) { if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) < 0) { @@ -917,7 +901,8 @@ psutil_sockaddr_port(int family, struct sockaddr_storage *ss) if (family == AF_INET) { sin = (struct sockaddr_in *)ss; return (sin->sin_port); - } else { + } + else { sin6 = (struct sockaddr_in6 *)ss; return (sin6->sin6_port); } @@ -932,7 +917,8 @@ psutil_sockaddr_addr(int family, struct sockaddr_storage *ss) if (family == AF_INET) { sin = (struct sockaddr_in *)ss; return (&sin->sin_addr); - } else { + } + else { sin6 = (struct sockaddr_in6 *)ss; return (&sin6->sin6_addr); } @@ -1030,12 +1016,10 @@ psutil_proc_connections(PyObject *self, PyObject *args) PyObject *_family = NULL; PyObject *_type = NULL; - if (retList == NULL) { + if (retList == NULL) return NULL; - } - if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) { + if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) goto error; - } if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) { PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); goto error; @@ -1063,22 +1047,18 @@ psutil_proc_connections(PyObject *self, PyObject *args) raddr = NULL; kif = &freep[i]; - if (kif->kf_type == KF_TYPE_SOCKET) - { + if (kif->kf_type == KF_TYPE_SOCKET) { // apply filters _family = PyLong_FromLong((long)kif->kf_sock_domain); inseq = PySequence_Contains(af_filter, _family); Py_DECREF(_family); - if (inseq == 0) { + if (inseq == 0) continue; - } _type = PyLong_FromLong((long)kif->kf_sock_type); inseq = PySequence_Contains(type_filter, _type); Py_DECREF(_type); - if (inseq == 0) { + if (inseq == 0) continue; - } - // IPv4 / IPv6 socket if ((kif->kf_sock_domain == AF_INET) || (kif->kf_sock_domain == AF_INET6)) { @@ -1112,12 +1092,10 @@ psutil_proc_connections(PyObject *self, PyObject *args) laddr = Py_BuildValue("(si)", lip, lport); if (!laddr) goto error; - if (rport != 0) { + if (rport != 0) raddr = Py_BuildValue("(si)", rip, rport); - } - else { + else raddr = Py_BuildValue("()"); - } if (!raddr) goto error; tuple = Py_BuildValue("(iiiNNi)", @@ -1140,7 +1118,7 @@ psutil_proc_connections(PyObject *self, PyObject *args) sun = (struct sockaddr_un *)&kif->kf_sa_local; snprintf( path, sizeof(path), "%.*s", - (sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), + (int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), sun->sun_path); tuple = Py_BuildValue("(iiisOi)", @@ -1250,7 +1228,7 @@ void remove_spaces(char *str) { do while (*p2 == ' ') p2++; - while (*p1++ = *p2++); + while ((*p1++ = *p2++)); } @@ -1264,7 +1242,7 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) long pid; int ptrwidth; int i, cnt; - char addr[30]; + char addr[1000]; char perms[4]; const char *path; struct kinfo_proc kp; @@ -1274,15 +1252,12 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) PyObject *pytuple = NULL; PyObject *retlist = PyList_New(0); - if (retlist == NULL) { + if (retlist == NULL) return NULL; - } - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) goto error; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) goto error; - } freep = kinfo_getvmmap(pid, &cnt); if (freep == NULL) { @@ -1306,36 +1281,36 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) if (strlen(kve->kve_path) == 0) { switch (kve->kve_type) { - case KVME_TYPE_NONE: - path = "[none]"; - break; - case KVME_TYPE_DEFAULT: - path = "[default]"; - break; - case KVME_TYPE_VNODE: - path = "[vnode]"; - break; - case KVME_TYPE_SWAP: - path = "[swap]"; - break; - case KVME_TYPE_DEVICE: - path = "[device]"; - break; - case KVME_TYPE_PHYS: - path = "[phys]"; - break; - case KVME_TYPE_DEAD: - path = "[dead]"; - break; - case KVME_TYPE_SG: - path = "[sg]"; - break; - case KVME_TYPE_UNKNOWN: - path = "[unknown]"; - break; - default: - path = "[?]"; - break; + case KVME_TYPE_NONE: + path = "[none]"; + break; + case KVME_TYPE_DEFAULT: + path = "[default]"; + break; + case KVME_TYPE_VNODE: + path = "[vnode]"; + break; + case KVME_TYPE_SWAP: + path = "[swap]"; + break; + case KVME_TYPE_DEVICE: + path = "[device]"; + break; + case KVME_TYPE_PHYS: + path = "[phys]"; + break; + case KVME_TYPE_DEAD: + path = "[dead]"; + break; + case KVME_TYPE_SG: + path = "[sg]"; + break; + case KVME_TYPE_UNKNOWN: + path = "[unknown]"; + break; + default: + path = "[?]"; + break; } } else { @@ -1489,9 +1464,9 @@ psutil_net_io_counters(PyObject *self, PyObject *args) size_t len; PyObject *py_retdict = PyDict_New(); PyObject *py_ifc_info = NULL; + if (py_retdict == NULL) return NULL; - mib[0] = CTL_NET; // networking subsystem mib[1] = PF_ROUTE; // type of information mib[2] = 0; // protocol (IPPROTO_xxx) @@ -1533,9 +1508,8 @@ psutil_net_io_counters(PyObject *self, PyObject *args) // http://lists.freebsd.org/pipermail/freebsd-current/ // 2011-October/028752.html // 'ifconfig -a' doesn't show them, nor do we. - if (strncmp(ifc_name, "usbus", 5) == 0) { + if (strncmp(ifc_name, "usbus", 5) == 0) continue; - } py_ifc_info = Py_BuildValue("(kkkkkkki)", if2m->ifm_data.ifi_obytes, @@ -1580,9 +1554,9 @@ psutil_disk_io_counters(PyObject *self, PyObject *args) PyObject *py_retdict = PyDict_New(); PyObject *py_disk_info = NULL; + if (py_retdict == NULL) return NULL; - if (devstat_checkversion(NULL) < 0) { PyErr_Format(PyExc_RuntimeError, "devstat_checkversion() failed"); goto error; @@ -1626,9 +1600,8 @@ psutil_disk_io_counters(PyObject *self, PyObject *args) Py_DECREF(py_disk_info); } - if (stats.dinfo->mem_ptr) { + if (stats.dinfo->mem_ptr) free(stats.dinfo->mem_ptr); - } free(stats.dinfo); return py_retdict; @@ -1766,14 +1739,16 @@ psutil_get_pid_from_sock(int sock_hash) if (xf->xf_data == NULL) continue; hash = (int)((uintptr_t)xf->xf_data % HASHSIZE); - if (sock_hash == hash) { + if (sock_hash == hash) return xf->xf_pid; - } } return -1; } +// Reference: +// https://gitorious.org/freebsd/freebsd/source/ +// f1d6f4778d2044502209708bc167c05f9aa48615:usr.bin/sockstat/sockstat.c int psutil_gather_inet(int proto, PyObject *py_retlist) { struct xinpgen *xig, *exig; @@ -1781,25 +1756,26 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) struct xtcpcb *xtp; struct inpcb *inp; struct xsocket *so; - struct sock *sock; - const char *varname; + const char *varname = NULL; size_t len, bufsize; void *buf; - int hash, retry, vflag, type; + int hash; + int retry; + int type; PyObject *tuple = NULL; PyObject *laddr = NULL; PyObject *raddr = NULL; switch (proto) { - case IPPROTO_TCP: - varname = "net.inet.tcp.pcblist"; - type = SOCK_STREAM; - break; - case IPPROTO_UDP: - varname = "net.inet.udp.pcblist"; - type = SOCK_DGRAM; - break; + case IPPROTO_TCP: + varname = "net.inet.tcp.pcblist"; + type = SOCK_STREAM; + break; + case IPPROTO_UDP: + varname = "net.inet.udp.pcblist"; + type = SOCK_DGRAM; + break; } buf = NULL; @@ -1808,10 +1784,8 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) do { for (;;) { buf = realloc(buf, bufsize); - if (buf == NULL) { - // XXX - continue; - } + if (buf == NULL) + continue; // XXX len = bufsize; if (sysctlbyname(varname, buf, &len, NULL, 0) == 0) break; @@ -1831,33 +1805,41 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) for (;;) { + int lport, rport, pid, status, family; + xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len); if (xig >= exig) break; switch (proto) { - case IPPROTO_TCP: - xtp = (struct xtcpcb *)xig; - if (xtp->xt_len != sizeof *xtp) { - PyErr_Format(PyExc_RuntimeError, "struct xtcpcb size mismatch"); - goto error; - } - break; - case IPPROTO_UDP: - xip = (struct xinpcb *)xig; - if (xip->xi_len != sizeof *xip) { - PyErr_Format(PyExc_RuntimeError, "struct xinpcb size mismatch"); + case IPPROTO_TCP: + xtp = (struct xtcpcb *)xig; + if (xtp->xt_len != sizeof *xtp) { + PyErr_Format(PyExc_RuntimeError, + "struct xtcpcb size mismatch"); + goto error; + } + inp = &xtp->xt_inp; + so = &xtp->xt_socket; + status = xtp->xt_tp.t_state; + break; + case IPPROTO_UDP: + xip = (struct xinpcb *)xig; + if (xip->xi_len != sizeof *xip) { + PyErr_Format(PyExc_RuntimeError, + "struct xinpcb size mismatch"); + goto error; + } + inp = &xip->xi_inp; + so = &xip->xi_socket; + status = PSUTIL_CONN_NONE; + break; + default: + PyErr_Format(PyExc_RuntimeError, "invalid proto"); goto error; - } - inp = &xip->xi_inp; - so = &xip->xi_socket; - break; } - inp = &xtp->xt_inp; - so = &xtp->xt_socket; char lip[200], rip[200]; - int family, lport, rport, pid, status; hash = (int)((uintptr_t)so->xso_so % HASHSIZE); pid = psutil_get_pid_from_sock(hash); @@ -1865,7 +1847,6 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) continue; lport = ntohs(inp->inp_lport); rport = ntohs(inp->inp_fport); - status = xtp->xt_tp.t_state; if (inp->inp_vflag & INP_IPV4) { family = AF_INET; @@ -1882,12 +1863,10 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) laddr = Py_BuildValue("(si)", lip, lport); if (!laddr) goto error; - if (rport != 0) { + if (rport != 0) raddr = Py_BuildValue("(si)", rip, rport); - } - else { + else raddr = Py_BuildValue("()"); - } if (!raddr) goto error; tuple = Py_BuildValue("(iiiNNii)", -1, family, type, laddr, raddr, @@ -1897,7 +1876,7 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) if (PyList_Append(py_retlist, tuple)) goto error; Py_DECREF(tuple); - } + } free(buf); return 1; @@ -1915,12 +1894,14 @@ int psutil_gather_unix(int proto, PyObject *py_retlist) { struct xunpgen *xug, *exug; struct xunpcb *xup; - struct sock *sock; - const char *varname, *protoname; - size_t len, bufsize; + const char *varname = NULL; + const char *protoname = NULL; + size_t len; + size_t bufsize; void *buf; - int hash, retry; - int family, lport, rport, pid; + int hash; + int retry; + int pid; struct sockaddr_un *sun; char path[PATH_MAX]; @@ -1929,14 +1910,14 @@ int psutil_gather_unix(int proto, PyObject *py_retlist) PyObject *raddr = NULL; switch (proto) { - case SOCK_STREAM: - varname = "net.local.stream.pcblist"; - protoname = "stream"; - break; - case SOCK_DGRAM: - varname = "net.local.dgram.pcblist"; - protoname = "dgram"; - break; + case SOCK_STREAM: + varname = "net.local.stream.pcblist"; + protoname = "stream"; + break; + case SOCK_DGRAM: + varname = "net.local.dgram.pcblist"; + protoname = "dgram"; + break; } buf = NULL; @@ -1973,10 +1954,8 @@ int psutil_gather_unix(int proto, PyObject *py_retlist) if (xug >= exug) break; xup = (struct xunpcb *)xug; - if (xup->xu_len != sizeof *xup) { - warnx("struct xunpgen size mismatch"); + if (xup->xu_len != sizeof *xup) goto error; - } hash = (int)((uintptr_t) xup->xu_socket.xso_so % HASHSIZE); pid = psutil_get_pid_from_sock(hash); @@ -1985,7 +1964,7 @@ int psutil_gather_unix(int proto, PyObject *py_retlist) sun = (struct sockaddr_un *)&xup->xu_addr; snprintf(path, sizeof(path), "%.*s", - (sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), + (int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), sun->sun_path); tuple = Py_BuildValue("(iiisOii)", -1, AF_UNIX, proto, path, Py_None, @@ -2016,13 +1995,12 @@ int psutil_gather_unix(int proto, PyObject *py_retlist) static PyObject* psutil_net_connections(PyObject* self, PyObject* args) { - PyObject *af_filter = NULL; - PyObject *type_filter = NULL; PyObject *py_retlist = PyList_New(0); + if (py_retlist == NULL) + return NULL; if (psutil_populate_xfiles() != 1) goto error; - if (psutil_gather_inet(IPPROTO_TCP, py_retlist) == 0) goto error; if (psutil_gather_inet(IPPROTO_UDP, py_retlist) == 0) @@ -2042,6 +2020,107 @@ psutil_net_connections(PyObject* self, PyObject* args) } +/* + * Get process CPU affinity. + * Reference: http://sources.freebsd.org/RELENG_9/src/usr.bin/cpuset/cpuset.c + */ +static PyObject* +psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args) +{ + long pid; + int ret; + int i; + cpuset_t mask; + PyObject* py_retlist; + PyObject* py_cpu_num; + + if (!PyArg_ParseTuple(args, "i", &pid)) + return NULL; + ret = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, pid, + sizeof(mask), &mask); + if (ret != 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + py_retlist = PyList_New(0); + if (py_retlist == NULL) + return NULL; + + for (i = 0; i < CPU_SETSIZE; i++) { + if (CPU_ISSET(i, &mask)) { + py_cpu_num = Py_BuildValue("i", i); + if (py_cpu_num == NULL) + goto error; + if (PyList_Append(py_retlist, py_cpu_num)) + goto error; + } + } + + return py_retlist; + +error: + Py_XDECREF(py_cpu_num); + Py_DECREF(py_retlist); + return NULL; +} + + +/* + * Set process CPU affinity. + * Reference: http://sources.freebsd.org/RELENG_9/src/usr.bin/cpuset/cpuset.c + */ +static PyObject * +psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) +{ + long pid; + int i; + int seq_len; + int ret; + cpuset_t cpu_set; + PyObject *py_cpu_set; + PyObject *py_cpu_seq = NULL; + + if (!PyArg_ParseTuple(args, "lO", &pid, &py_cpu_set)) + return NULL; + + py_cpu_seq = PySequence_Fast(py_cpu_set, "expected a sequence or integer"); + if (!py_cpu_seq) + return NULL; + seq_len = PySequence_Fast_GET_SIZE(py_cpu_seq); + + // calculate the mask + CPU_ZERO(&cpu_set); + for (i = 0; i < seq_len; i++) { + PyObject *item = PySequence_Fast_GET_ITEM(py_cpu_seq, i); +#if PY_MAJOR_VERSION >= 3 + long value = PyLong_AsLong(item); +#else + long value = PyInt_AsLong(item); +#endif + if (value == -1 && PyErr_Occurred()) + goto error; + CPU_SET(value, &cpu_set); + } + + // set affinity + ret = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, pid, + sizeof(cpu_set), &cpu_set); + if (ret != 0) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + Py_DECREF(py_cpu_seq); + Py_RETURN_NONE; + +error: + if (py_cpu_seq != NULL) + Py_DECREF(py_cpu_seq); + return NULL; +} + + /* * define the psutil C module methods and initialize the module. */ @@ -2083,6 +2162,10 @@ PsutilMethods[] = "Return process IO counters"}, {"proc_tty_nr", psutil_proc_tty_nr, METH_VARARGS, "Return process tty (terminal) number"}, + {"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS, + "Return process CPU affinity."}, + {"proc_cpu_affinity_set", psutil_proc_cpu_affinity_set, METH_VARARGS, + "Set process CPU affinity."}, #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 {"proc_open_files", psutil_proc_open_files, METH_VARARGS, "Return files opened by process as a list of (path, fd) tuples"}, @@ -2181,6 +2264,8 @@ void init_psutil_bsd(void) #else PyObject *module = Py_InitModule("_psutil_bsd", PsutilMethods); #endif + PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); + // process status constants PyModule_AddIntConstant(module, "SSTOP", SSTOP); PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); @@ -2203,9 +2288,8 @@ void init_psutil_bsd(void) PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT); PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE); - if (module == NULL) { + if (module == NULL) INITERROR; - } #if PY_MAJOR_VERSION >= 3 return module; #endif diff --git a/python/psutil/psutil/_psutil_bsd.h b/python/psutil/psutil/_psutil_bsd.h index 2bc7c7018a84..803957dac78a 100644 --- a/python/psutil/psutil/_psutil_bsd.h +++ b/python/psutil/psutil/_psutil_bsd.h @@ -26,6 +26,8 @@ static PyObject* psutil_proc_status(PyObject* self, PyObject* args); static PyObject* psutil_proc_threads(PyObject* self, PyObject* args); static PyObject* psutil_proc_tty_nr(PyObject* self, PyObject* args); static PyObject* psutil_proc_uids(PyObject* self, PyObject* args); +static PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args); +static PyObject* psutil_proc_cpu_affinity_set(PyObject* self, PyObject* args); #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 static PyObject* psutil_proc_open_files(PyObject* self, PyObject* args); @@ -48,4 +50,4 @@ static PyObject* psutil_virtual_mem(PyObject* self, PyObject* args); #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 static PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args); -#endif \ No newline at end of file +#endif diff --git a/python/psutil/psutil/_psutil_linux.c b/python/psutil/psutil/_psutil_linux.c index 4602178e4e50..a3bf5643ccc0 100644 --- a/python/psutil/psutil/_psutil_linux.c +++ b/python/psutil/psutil/_psutil_linux.c @@ -19,6 +19,11 @@ #include #include #include +#include +#include +#include +#include +#include #include "_psutil_linux.h" @@ -46,6 +51,12 @@ enum { IOPRIO_WHO_PROCESS = 1, }; +// May happen on old RedHat versions, see: +// https://github.com/giampaolo/psutil/issues/607 +#ifndef DUPLEX_UNKNOWN + #define DUPLEX_UNKNOWN 0xff +#endif + static inline int ioprio_get(int which, int who) { @@ -74,13 +85,11 @@ psutil_proc_ioprio_get(PyObject *self, PyObject *args) { long pid; int ioprio, ioclass, iodata; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid); - if (ioprio == -1) { + if (ioprio == -1) return PyErr_SetFromErrno(PyExc_OSError); - } ioclass = IOPRIO_PRIO_CLASS(ioprio); iodata = IOPRIO_PRIO_DATA(ioprio); return Py_BuildValue("ii", ioclass, iodata); @@ -99,16 +108,13 @@ psutil_proc_ioprio_set(PyObject *self, PyObject *args) int ioprio, ioclass, iodata; int retval; - if (! PyArg_ParseTuple(args, "lii", &pid, &ioclass, &iodata)) { + if (! PyArg_ParseTuple(args, "lii", &pid, &ioclass, &iodata)) return NULL; - } ioprio = IOPRIO_PRIO_VALUE(ioclass, iodata); retval = ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio); - if (retval == -1) { + if (retval == -1) return PyErr_SetFromErrno(PyExc_OSError); - } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } #endif @@ -129,9 +135,8 @@ psutil_linux_prlimit(PyObject *self, PyObject *args) PyObject *soft = NULL; PyObject *hard = NULL; - if (! PyArg_ParseTuple(args, "li|OO", &pid, &resource, &soft, &hard)) { + if (! PyArg_ParseTuple(args, "li|OO", &pid, &resource, &soft, &hard)) return NULL; - } // get if (soft == NULL && hard == NULL) { @@ -169,8 +174,7 @@ psutil_linux_prlimit(PyObject *self, PyObject *args) ret = prlimit(pid, resource, newp, &old); if (ret == -1) return PyErr_SetFromErrno(PyExc_OSError); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } } #endif @@ -235,10 +239,9 @@ static PyObject * psutil_linux_sysinfo(PyObject *self, PyObject *args) { struct sysinfo info; - if (sysinfo(&info) != 0) { - return PyErr_SetFromErrno(PyExc_OSError); - } + if (sysinfo(&info) != 0) + return PyErr_SetFromErrno(PyExc_OSError); // note: boot time might also be determined from here return Py_BuildValue( "(KKKKKK)", @@ -268,10 +271,8 @@ psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) cpu_set_t *mask = NULL; PyObject *res = NULL; - if (!PyArg_ParseTuple(args, "i", &pid)) { + if (!PyArg_ParseTuple(args, "i", &pid)) return NULL; - } - ncpus = NCPUS_START; while (1) { setsize = CPU_ALLOC_SIZE(ncpus); @@ -303,7 +304,6 @@ psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) #else PyObject *cpu_num = PyInt_FromLong(cpu); #endif - --count; if (cpu_num == NULL) goto error; if (PyList_Append(res, cpu_num)) { @@ -311,6 +311,7 @@ psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) goto error; } Py_DECREF(cpu_num); + --count; } } CPU_FREE(mask); @@ -325,33 +326,45 @@ psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) #else +/* + * Alternative implementation in case CPU_ALLOC is not defined. + */ static PyObject * psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) { cpu_set_t cpuset; unsigned int len = sizeof(cpu_set_t); long pid; - int i; - PyObject* ret_list; + int i; + PyObject* py_retlist = NULL; + PyObject *py_cpu_num = NULL; - if (!PyArg_ParseTuple(args, "i", &pid)) { + if (!PyArg_ParseTuple(args, "i", &pid)) return NULL; - } - CPU_ZERO(&cpuset); - if (sched_getaffinity(pid, len, &cpuset) < 0) { + if (sched_getaffinity(pid, len, &cpuset) < 0) return PyErr_SetFromErrno(PyExc_OSError); - } - - ret_list = PyList_New(0); + py_retlist = PyList_New(0); + if (py_retlist == NULL) + goto error; for (i = 0; i < CPU_SETSIZE; ++i) { if (CPU_ISSET(i, &cpuset)) { - PyList_Append(ret_list, Py_BuildValue("i", i)); + py_cpu_num = Py_BuildValue("i", i); + if (py_cpu_num == NULL) + goto error; + if (PyList_Append(py_retlist, py_cpu_num)) + goto error; + Py_DECREF(py_cpu_num); } } - return ret_list; + return py_retlist; + +error: + Py_XDECREF(py_cpu_num); + Py_DECREF(py_retlist); + return NULL; } #endif @@ -368,22 +381,18 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) PyObject *py_cpu_set; PyObject *py_cpu_seq = NULL; - if (!PyArg_ParseTuple(args, "lO", &pid, &py_cpu_set)) { - goto error; - } + if (!PyArg_ParseTuple(args, "lO", &pid, &py_cpu_set)) + return NULL; if (!PySequence_Check(py_cpu_set)) { - // does not work on Python 2.4 - // PyErr_Format(PyExc_TypeError, "sequence argument expected, got %s", - // Py_TYPE(py_cpu_set)->tp_name); - PyErr_Format(PyExc_TypeError, "sequence argument expected"); + PyErr_Format(PyExc_TypeError, "sequence argument expected, got %s", + Py_TYPE(py_cpu_set)->tp_name); goto error; } py_cpu_seq = PySequence_Fast(py_cpu_set, "expected a sequence or integer"); - if (!py_cpu_seq) { + if (!py_cpu_seq) goto error; - } seq_len = PySequence_Fast_GET_SIZE(py_cpu_seq); CPU_ZERO(&cpu_set); for (i = 0; i < seq_len; i++) { @@ -393,9 +402,8 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) #else long value = PyInt_AsLong(item); #endif - if (value == -1 && PyErr_Occurred()) { + if (value == -1 && PyErr_Occurred()) goto error; - } CPU_SET(value, &cpu_set); } @@ -406,14 +414,11 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) } Py_DECREF(py_cpu_seq); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; error: - if (py_cpu_seq != NULL) { + if (py_cpu_seq != NULL) Py_DECREF(py_cpu_seq); - } - return NULL; } @@ -465,6 +470,87 @@ psutil_users(PyObject *self, PyObject *args) } +/* + * Return stats about a particular network + * interface. References: + * https://github.com/dpaleino/wicd/blob/master/wicd/backends/be-ioctl.py + * http://www.i-scream.org/libstatgrab/ + */ +static PyObject* +psutil_net_if_stats(PyObject* self, PyObject* args) +{ + char *nic_name; + int sock = 0; + int ret; + int duplex; + int speed; + int mtu; + struct ifreq ifr; + struct ethtool_cmd ethcmd; + PyObject *py_is_up = NULL; + PyObject *py_ret = NULL; + + if (! PyArg_ParseTuple(args, "s", &nic_name)) + return NULL; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) + goto error; + strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name)); + + // is up? + ret = ioctl(sock, SIOCGIFFLAGS, &ifr); + if (ret == -1) + goto error; + if ((ifr.ifr_flags & IFF_UP) != 0) + py_is_up = Py_True; + else + py_is_up = Py_False; + Py_INCREF(py_is_up); + + // MTU + ret = ioctl(sock, SIOCGIFMTU, &ifr); + if (ret == -1) + goto error; + mtu = ifr.ifr_mtu; + + // duplex and speed + memset(ðcmd, 0, sizeof ethcmd); + ethcmd.cmd = ETHTOOL_GSET; + ifr.ifr_data = (caddr_t)ðcmd; + ret = ioctl(sock, SIOCETHTOOL, &ifr); + + if (ret != -1) { + duplex = ethcmd.duplex; + speed = ethcmd.speed; + } + else { + if (errno == EOPNOTSUPP) { + // we typically get here in case of wi-fi cards + duplex = DUPLEX_UNKNOWN; + speed = 0; + } + else { + goto error; + } + } + + close(sock); + py_ret = Py_BuildValue("[Oiii]", py_is_up, duplex, speed, mtu); + if (!py_ret) + goto error; + Py_DECREF(py_is_up); + return py_ret; + +error: + Py_XDECREF(py_is_up); + if (sock != 0) + close(sock); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + + /* * Define the psutil C module methods and initialize the module. */ @@ -491,6 +577,8 @@ PsutilMethods[] = "device, mount point and filesystem type"}, {"users", psutil_users, METH_VARARGS, "Return currently connected users as a list of tuples"}, + {"net_if_stats", psutil_net_if_stats, METH_VARARGS, + "Return NIC stats (isup, duplex, speed, mtu)"}, // --- linux specific @@ -559,6 +647,7 @@ void init_psutil_linux(void) #endif + PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); #if PSUTIL_HAVE_PRLIMIT PyModule_AddIntConstant(module, "RLIM_INFINITY", RLIM_INFINITY); PyModule_AddIntConstant(module, "RLIMIT_AS", RLIMIT_AS); @@ -588,10 +677,12 @@ void init_psutil_linux(void) PyModule_AddIntConstant(module, "RLIMIT_SIGPENDING", RLIMIT_SIGPENDING); #endif #endif + PyModule_AddIntConstant(module, "DUPLEX_HALF", DUPLEX_HALF); + PyModule_AddIntConstant(module, "DUPLEX_FULL", DUPLEX_FULL); + PyModule_AddIntConstant(module, "DUPLEX_UNKNOWN", DUPLEX_UNKNOWN); - if (module == NULL) { + if (module == NULL) INITERROR; - } #if PY_MAJOR_VERSION >= 3 return module; #endif diff --git a/python/psutil/psutil/_psutil_linux.h b/python/psutil/psutil/_psutil_linux.h index 04ffec3da1f7..ec6a338719a2 100644 --- a/python/psutil/psutil/_psutil_linux.h +++ b/python/psutil/psutil/_psutil_linux.h @@ -18,3 +18,4 @@ static PyObject* psutil_proc_ioprio_get(PyObject* self, PyObject* args); static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args); static PyObject* psutil_linux_sysinfo(PyObject* self, PyObject* args); static PyObject* psutil_users(PyObject* self, PyObject* args); +static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args); diff --git a/python/psutil/psutil/_psutil_osx.c b/python/psutil/psutil/_psutil_osx.c index 0c8334577590..3ebf8ff27219 100644 --- a/python/psutil/psutil/_psutil_osx.c +++ b/python/psutil/psutil/_psutil_osx.c @@ -120,12 +120,10 @@ psutil_proc_name(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_get_kinfo_proc(pid, &kp) == -1) { + if (psutil_get_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("s", kp.kp_proc.p_comm); } @@ -139,9 +137,8 @@ psutil_proc_cwd(PyObject *self, PyObject *args) long pid; struct proc_vnodepathinfo pathinfo; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } if (! psutil_proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, &pathinfo, sizeof(pathinfo))) @@ -162,17 +159,14 @@ psutil_proc_exe(PyObject *self, PyObject *args) char buf[PATH_MAX]; int ret; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } ret = proc_pidpath(pid, &buf, sizeof(buf)); if (ret == 0) { - if (! psutil_pid_exists(pid)) { + if (! psutil_pid_exists(pid)) return NoSuchProcess(); - } - else { + else return AccessDenied(); - } } return Py_BuildValue("s", buf); } @@ -187,9 +181,8 @@ psutil_proc_cmdline(PyObject *self, PyObject *args) long pid; PyObject *arglist = NULL; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } // get the commandline, defined in arch/osx/process_info.c arglist = psutil_get_arg_list(pid); @@ -205,12 +198,10 @@ psutil_proc_ppid(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_get_kinfo_proc(pid, &kp) == -1) { + if (psutil_get_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("l", (long)kp.kp_eproc.e_ppid); } @@ -223,12 +214,10 @@ psutil_proc_uids(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_get_kinfo_proc(pid, &kp) == -1) { + if (psutil_get_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("lll", (long)kp.kp_eproc.e_pcred.p_ruid, (long)kp.kp_eproc.e_ucred.cr_uid, @@ -244,12 +233,10 @@ psutil_proc_gids(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_get_kinfo_proc(pid, &kp) == -1) { + if (psutil_get_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("lll", (long)kp.kp_eproc.e_pcred.p_rgid, (long)kp.kp_eproc.e_ucred.cr_groups[0], @@ -265,12 +252,10 @@ psutil_proc_tty_nr(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_get_kinfo_proc(pid, &kp) == -1) { + if (psutil_get_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("i", kp.kp_eproc.e_tdev); } @@ -299,9 +284,8 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) if (py_list == NULL) return NULL; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) goto error; - } err = task_for_pid(mach_task_self(), pid, &task); @@ -324,11 +308,8 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) err = vm_region_recurse_64(task, &address, &size, &depth, (vm_region_info_64_t)&info, &count); - - if (err == KERN_INVALID_ADDRESS) { + if (err == KERN_INVALID_ADDRESS) break; - } - if (info.is_submap) { depth++; } @@ -356,32 +337,30 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) if (strlen(buf) == 0) { switch (info.share_mode) { - /* - case SM_LARGE_PAGE: - // Treat SM_LARGE_PAGE the same as SM_PRIVATE - // since they are not shareable and are wired. - */ - case SM_COW: - strcpy(buf, "[cow]"); - break; - case SM_PRIVATE: - strcpy(buf, "[prv]"); - break; - case SM_EMPTY: - strcpy(buf, "[nul]"); - break; - case SM_SHARED: - case SM_TRUESHARED: - strcpy(buf, "[shm]"); - break; - case SM_PRIVATE_ALIASED: - strcpy(buf, "[ali]"); - break; - case SM_SHARED_ALIASED: - strcpy(buf, "[s/a]"); - break; - default: - strcpy(buf, "[???]"); + // case SM_LARGE_PAGE: + // Treat SM_LARGE_PAGE the same as SM_PRIVATE + // since they are not shareable and are wired. + case SM_COW: + strcpy(buf, "[cow]"); + break; + case SM_PRIVATE: + strcpy(buf, "[prv]"); + break; + case SM_EMPTY: + strcpy(buf, "[nul]"); + break; + case SM_SHARED: + case SM_TRUESHARED: + strcpy(buf, "[shm]"); + break; + case SM_PRIVATE_ALIASED: + strcpy(buf, "[ali]"); + break; + case SM_SHARED_ALIASED: + strcpy(buf, "[s/a]"); + break; + default: + strcpy(buf, "[???]"); } } @@ -432,19 +411,14 @@ psutil_cpu_count_logical(PyObject *self, PyObject *args) int mib[2]; int ncpu; size_t len; - mib[0] = CTL_HW; mib[1] = HW_NCPU; len = sizeof(ncpu); - if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) { - // mimic os.cpu_count() - Py_INCREF(Py_None); - return Py_None; - } - else { + if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) + Py_RETURN_NONE; // mimic os.cpu_count() + else return Py_BuildValue("i", ncpu); - } } @@ -456,12 +430,11 @@ psutil_cpu_count_phys(PyObject *self, PyObject *args) { int num; size_t size = sizeof(int); - if (sysctlbyname("hw.physicalcpu", &num, &size, NULL, 0)) { - // mimic os.cpu_count() - Py_INCREF(Py_None); - return Py_None; - } - return Py_BuildValue("i", num); + + if (sysctlbyname("hw.physicalcpu", &num, &size, NULL, 0)) + Py_RETURN_NONE; // mimic os.cpu_count() + else + return Py_BuildValue("i", num); } @@ -475,12 +448,11 @@ psutil_proc_cpu_times(PyObject *self, PyObject *args) { long pid; struct proc_taskinfo pti; - if (! PyArg_ParseTuple(args, "l", &pid)) { + + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) { + if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) return NULL; - } return Py_BuildValue("(dd)", (float)pti.pti_total_user / 1000000000.0, (float)pti.pti_total_system / 1000000000.0); @@ -496,12 +468,10 @@ psutil_proc_create_time(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_get_kinfo_proc(pid, &kp) == -1) { + if (psutil_get_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("d", TV2DOUBLE(kp.kp_proc.p_starttime)); } @@ -514,13 +484,11 @@ psutil_proc_memory_info(PyObject *self, PyObject *args) { long pid; struct proc_taskinfo pti; - if (! PyArg_ParseTuple(args, "l", &pid)) { + + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) { + if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) return NULL; - } - // Note: determining other memory stats on OSX is a mess: // http://www.opensource.apple.com/source/top/top-67/libtop.c?txt // I just give up... @@ -544,12 +512,11 @@ psutil_proc_num_threads(PyObject *self, PyObject *args) { long pid; struct proc_taskinfo pti; - if (! PyArg_ParseTuple(args, "l", &pid)) { + + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) { + if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) return NULL; - } return Py_BuildValue("k", pti.pti_threadnum); } @@ -562,12 +529,11 @@ psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) { long pid; struct proc_taskinfo pti; - if (! PyArg_ParseTuple(args, "l", &pid)) { + + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) { + if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) return NULL; - } // unvoluntary value seems not to be available; // pti.pti_csw probably refers to the sum of the two (getrusage() // numbers seems to confirm this theory). @@ -587,10 +553,10 @@ psutil_virtual_mem(PyObject *self, PyObject *args) size_t len = sizeof(total); vm_statistics_data_t vm; int pagesize = getpagesize(); - // physical mem mib[0] = CTL_HW; mib[1] = HW_MEMSIZE; + if (sysctl(mib, 2, &total, &len, NULL, 0)) { if (errno != 0) PyErr_SetFromErrno(PyExc_OSError); @@ -600,9 +566,8 @@ psutil_virtual_mem(PyObject *self, PyObject *args) } // vm - if (!psutil_sys_vminfo(&vm)) { + if (!psutil_sys_vminfo(&vm)) return NULL; - } return Py_BuildValue( "KKKKK", @@ -637,9 +602,8 @@ psutil_swap_mem(PyObject *self, PyObject *args) PyErr_Format(PyExc_RuntimeError, "sysctl(VM_SWAPUSAGE) failed"); return NULL; } - if (!psutil_sys_vminfo(&vmstat)) { + if (!psutil_sys_vminfo(&vmstat)) return NULL; - } return Py_BuildValue( "LLLKK", @@ -664,11 +628,10 @@ psutil_cpu_times(PyObject *self, PyObject *args) mach_port_t host_port = mach_host_self(); error = host_statistics(host_port, HOST_CPU_LOAD_INFO, (host_info_t)&r_load, &count); - if (error != KERN_SUCCESS) { + if (error != KERN_SUCCESS) return PyErr_Format(PyExc_RuntimeError, "Error in host_statistics(): %s", mach_error_string(error)); - } mach_port_deallocate(mach_task_self(), host_port); return Py_BuildValue( @@ -728,9 +691,8 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) ret = vm_deallocate(mach_task_self(), (vm_address_t)info_array, info_count * sizeof(int)); - if (ret != KERN_SUCCESS) { + if (ret != KERN_SUCCESS) PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2); - } return py_retlist; error: @@ -739,9 +701,8 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) if (cpu_load_info != NULL) { ret = vm_deallocate(mach_task_self(), (vm_address_t)info_array, info_count * sizeof(int)); - if (ret != KERN_SUCCESS) { + if (ret != KERN_SUCCESS) PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2); - } } return NULL; } @@ -900,12 +861,10 @@ psutil_proc_status(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_get_kinfo_proc(pid, &kp) == -1) { + if (psutil_get_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("i", (int)kp.kp_proc.p_stat); } @@ -934,19 +893,16 @@ psutil_proc_threads(PyObject *self, PyObject *args) return NULL; // the argument passed should be a process id - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) goto error; - } // task_for_pid() requires special privileges err = task_for_pid(mach_task_self(), pid, &task); if (err != KERN_SUCCESS) { - if (! psutil_pid_exists(pid)) { + if (! psutil_pid_exists(pid)) NoSuchProcess(); - } - else { + else AccessDenied(); - } goto error; } @@ -999,9 +955,8 @@ psutil_proc_threads(PyObject *self, PyObject *args) ret = vm_deallocate(task, (vm_address_t)thread_list, thread_count * sizeof(int)); - if (ret != KERN_SUCCESS) { + if (ret != KERN_SUCCESS) PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2); - } mach_port_deallocate(mach_task_self(), task); @@ -1015,9 +970,8 @@ psutil_proc_threads(PyObject *self, PyObject *args) if (thread_list != NULL) { ret = vm_deallocate(task, (vm_address_t)thread_list, thread_count * sizeof(int)); - if (ret != KERN_SUCCESS) { + if (ret != KERN_SUCCESS) PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2); - } } return NULL; } @@ -1048,9 +1002,8 @@ psutil_proc_open_files(PyObject *self, PyObject *args) if (retList == NULL) return NULL; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) goto error; - } pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); if (pidinfo_result <= 0) { @@ -1127,19 +1080,14 @@ psutil_proc_open_files(PyObject *self, PyObject *args) error: Py_XDECREF(tuple); Py_DECREF(retList); - if (fds_pointer != NULL) { + if (fds_pointer != NULL) free(fds_pointer); - } - if (errno != 0) { + if (errno != 0) return PyErr_SetFromErrno(PyExc_OSError); - } - else if (! psutil_pid_exists(pid)) { + else if (! psutil_pid_exists(pid)) return NoSuchProcess(); - } - else { - // exception has already been set earlier - return NULL; - } + else + return NULL; // exception has already been set earlier } @@ -1175,23 +1123,19 @@ psutil_proc_connections(PyObject *self, PyObject *args) if (retList == NULL) return NULL; - if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) { + if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) goto error; - } if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) { PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); goto error; } - if (pid == 0) { + if (pid == 0) return retList; - } - pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); - if (pidinfo_result <= 0) { + if (pidinfo_result <= 0) goto error; - } fds_pointer = malloc(pidinfo_result); if (fds_pointer == NULL) { @@ -1201,10 +1145,8 @@ psutil_proc_connections(PyObject *self, PyObject *args) pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer, pidinfo_result); - if (pidinfo_result <= 0) { + if (pidinfo_result <= 0) goto error; - } - iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE); for (i = 0; i < iterations; i++) { @@ -1225,14 +1167,12 @@ psutil_proc_connections(PyObject *self, PyObject *args) // let's assume socket has been closed continue; } - if (errno != 0) { + if (errno != 0) PyErr_SetFromErrno(PyExc_OSError); - } - else { + else PyErr_Format( PyExc_RuntimeError, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed"); - } goto error; } if (nb < sizeof(si)) { @@ -1258,15 +1198,13 @@ psutil_proc_connections(PyObject *self, PyObject *args) _family = PyLong_FromLong((long)family); inseq = PySequence_Contains(af_filter, _family); Py_DECREF(_family); - if (inseq == 0) { + if (inseq == 0) continue; - } _type = PyLong_FromLong((long)type); inseq = PySequence_Contains(type_filter, _type); Py_DECREF(_type); - if (inseq == 0) { + if (inseq == 0) continue; - } if (errno != 0) { PyErr_SetFromErrno(PyExc_OSError); @@ -1305,22 +1243,18 @@ psutil_proc_connections(PyObject *self, PyObject *args) lport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport); rport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_fport); - if (type == SOCK_STREAM) { + if (type == SOCK_STREAM) state = (int)si.psi.soi_proto.pri_tcp.tcpsi_state; - } - else { + else state = PSUTIL_CONN_NONE; - } laddr = Py_BuildValue("(si)", lip, lport); if (!laddr) goto error; - if (rport != 0) { + if (rport != 0) raddr = Py_BuildValue("(si)", rip, rport); - } - else { + else raddr = Py_BuildValue("()"); - } if (!raddr) goto error; @@ -1359,19 +1293,15 @@ psutil_proc_connections(PyObject *self, PyObject *args) Py_XDECREF(raddr); Py_DECREF(retList); - if (fds_pointer != NULL) { + if (fds_pointer != NULL) free(fds_pointer); - } - if (errno != 0) { + if (errno != 0) return PyErr_SetFromErrno(PyExc_OSError); - } - else if (! psutil_pid_exists(pid) ) { + else if (! psutil_pid_exists(pid)) return NoSuchProcess(); - } - else { + else return PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDLISTFDS) failed"); - } } @@ -1386,19 +1316,16 @@ psutil_proc_num_fds(PyObject *self, PyObject *args) int num; struct proc_fdinfo *fds_pointer; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); - if (pidinfo_result <= 0) { + if (pidinfo_result <= 0) return PyErr_SetFromErrno(PyExc_OSError); - } fds_pointer = malloc(pidinfo_result); - if (fds_pointer == NULL) { + if (fds_pointer == NULL) return PyErr_NoMemory(); - } pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer, pidinfo_result); if (pidinfo_result <= 0) { @@ -1851,6 +1778,7 @@ init_psutil_osx(void) #else PyObject *module = Py_InitModule("_psutil_osx", PsutilMethods); #endif + PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); // process status constants, defined in: // http://fxr.watson.org/fxr/source/bsd/sys/proc.h?v=xnu-792.6.70#L149 PyModule_AddIntConstant(module, "SIDL", SIDL); @@ -1872,9 +1800,8 @@ init_psutil_osx(void) PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT); PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE); - if (module == NULL) { + if (module == NULL) INITERROR; - } #if PY_MAJOR_VERSION >= 3 return module; #endif diff --git a/python/psutil/psutil/_psutil_posix.c b/python/psutil/psutil/_psutil_posix.c index ad2e59dbb880..183dab0e12ee 100644 --- a/python/psutil/psutil/_psutil_posix.c +++ b/python/psutil/psutil/_psutil_posix.c @@ -10,6 +10,24 @@ #include #include #include +#include +#include +#include + +#ifdef __linux +#include +#include +#endif // end linux + +#if defined(__FreeBSD__) || defined(__APPLE__) +#include +#include +#include +#endif + +#if defined(__sun) +#include +#endif #include "_psutil_posix.h" @@ -23,13 +41,12 @@ psutil_posix_getpriority(PyObject *self, PyObject *args) long pid; int priority; errno = 0; - if (! PyArg_ParseTuple(args, "l", &pid)) { + + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } priority = getpriority(PRIO_PROCESS, pid); - if (errno != 0) { + if (errno != 0) return PyErr_SetFromErrno(PyExc_OSError); - } return Py_BuildValue("i", priority); } @@ -43,18 +60,394 @@ psutil_posix_setpriority(PyObject *self, PyObject *args) long pid; int priority; int retval; - if (! PyArg_ParseTuple(args, "li", &pid, &priority)) { + + if (! PyArg_ParseTuple(args, "li", &pid, &priority)) return NULL; - } retval = setpriority(PRIO_PROCESS, pid, priority); - if (retval == -1) { + if (retval == -1) return PyErr_SetFromErrno(PyExc_OSError); + Py_RETURN_NONE; +} + + +/* + * Translate a sockaddr struct into a Python string. + * Return None if address family is not AF_INET* or AF_PACKET. + */ +static PyObject * +psutil_convert_ipaddr(struct sockaddr *addr, int family) +{ + char buf[NI_MAXHOST]; + int err; + int addrlen; + int n; + size_t len; + const char *data; + char *ptr; + + if (addr == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + else if (family == AF_INET || family == AF_INET6) { + if (family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + else + addrlen = sizeof(struct sockaddr_in6); + err = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, + NI_NUMERICHOST); + if (err != 0) { + // XXX we get here on FreeBSD when processing 'lo' / AF_INET6 + // broadcast. Not sure what to do other than returning None. + // ifconfig does not show anything BTW. + //PyErr_Format(PyExc_RuntimeError, gai_strerror(err)); + //return NULL; + Py_INCREF(Py_None); + return Py_None; + } + else { + return Py_BuildValue("s", buf); + } + } +#ifdef __linux + else if (family == AF_PACKET) { + struct sockaddr_ll *lladdr = (struct sockaddr_ll *)addr; + len = lladdr->sll_halen; + data = (const char *)lladdr->sll_addr; + } +#endif +#if defined(__FreeBSD__) || defined(__APPLE__) + else if (addr->sa_family == AF_LINK) { + // Note: prior to Python 3.4 socket module does not expose + // AF_LINK so we'll do. + struct sockaddr_dl *dladdr = (struct sockaddr_dl *)addr; + len = dladdr->sdl_alen; + data = LLADDR(dladdr); + } +#endif + else { + // unknown family + Py_INCREF(Py_None); + return Py_None; + } + + // AF_PACKET or AF_LINK + if (len > 0) { + ptr = buf; + for (n = 0; n < len; ++n) { + sprintf(ptr, "%02x:", data[n] & 0xff); + ptr += 3; + } + *--ptr = '\0'; + return Py_BuildValue("s", buf); + } + else { + Py_INCREF(Py_None); + return Py_None; + } +} + + +/* + * Return NICs information a-la ifconfig as a list of tuples. + * TODO: on Solaris we won't get any MAC address. + */ +static PyObject* +psutil_net_if_addrs(PyObject* self, PyObject* args) +{ + struct ifaddrs *ifaddr, *ifa; + int family; + + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_address = NULL; + PyObject *py_netmask = NULL; + PyObject *py_broadcast = NULL; + + if (py_retlist == NULL) + return NULL; + if (getifaddrs(&ifaddr) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (!ifa->ifa_addr) + continue; + family = ifa->ifa_addr->sa_family; + py_address = psutil_convert_ipaddr(ifa->ifa_addr, family); + // If the primary address can't be determined just skip it. + // I've never seen this happen on Linux but I did on FreeBSD. + if (py_address == Py_None) + continue; + if (py_address == NULL) + goto error; + py_netmask = psutil_convert_ipaddr(ifa->ifa_netmask, family); + if (py_netmask == NULL) + goto error; +#ifdef __linux + py_broadcast = psutil_convert_ipaddr(ifa->ifa_ifu.ifu_broadaddr, family); +#else + py_broadcast = psutil_convert_ipaddr(ifa->ifa_broadaddr, family); +#endif + if (py_broadcast == NULL) + goto error; + py_tuple = Py_BuildValue( + "(siOOO)", + ifa->ifa_name, + family, + py_address, + py_netmask, + py_broadcast + ); + + if (! py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + Py_DECREF(py_address); + Py_DECREF(py_netmask); + Py_DECREF(py_broadcast); + } + + freeifaddrs(ifaddr); + return py_retlist; + +error: + if (ifaddr != NULL) + freeifaddrs(ifaddr); + Py_DECREF(py_retlist); + Py_XDECREF(py_tuple); + Py_XDECREF(py_address); + Py_XDECREF(py_netmask); + Py_XDECREF(py_broadcast); + return NULL; +} + + +/* + * net_if_stats() implementation. This is here because it is common + * to both OSX and FreeBSD and I didn't know where else to put it. + */ +#if defined(__FreeBSD__) || defined(__APPLE__) + +#include +#include +#include + +int psutil_get_nic_speed(int ifm_active) { + // Determine NIC speed. Taken from: + // http://www.i-scream.org/libstatgrab/ + // Assuming only ETHER devices + switch(IFM_TYPE(ifm_active)) { + case IFM_ETHER: + switch(IFM_SUBTYPE(ifm_active)) { +#if defined(IFM_HPNA_1) && ((!defined(IFM_10G_LR)) \ + || (IFM_10G_LR != IFM_HPNA_1)) + // HomePNA 1.0 (1Mb/s) + case(IFM_HPNA_1): + return 1; +#endif + // 10 Mbit + case(IFM_10_T): // 10BaseT - RJ45 + case(IFM_10_2): // 10Base2 - Thinnet + case(IFM_10_5): // 10Base5 - AUI + case(IFM_10_STP): // 10BaseT over shielded TP + case(IFM_10_FL): // 10baseFL - Fiber + return 10; + // 100 Mbit + case(IFM_100_TX): // 100BaseTX - RJ45 + case(IFM_100_FX): // 100BaseFX - Fiber + case(IFM_100_T4): // 100BaseT4 - 4 pair cat 3 + case(IFM_100_VG): // 100VG-AnyLAN + case(IFM_100_T2): // 100BaseT2 + return 100; + // 1000 Mbit + case(IFM_1000_SX): // 1000BaseSX - multi-mode fiber + case(IFM_1000_LX): // 1000baseLX - single-mode fiber + case(IFM_1000_CX): // 1000baseCX - 150ohm STP +#if defined(IFM_1000_TX) && !defined(OPENBSD) + // FreeBSD 4 and others (but NOT OpenBSD)? + case(IFM_1000_TX): +#endif +#ifdef IFM_1000_FX + case(IFM_1000_FX): +#endif +#ifdef IFM_1000_T + case(IFM_1000_T): +#endif + return 1000; +#if defined(IFM_10G_SR) || defined(IFM_10G_LR) || defined(IFM_10G_CX4) \ + || defined(IFM_10G_T) +#ifdef IFM_10G_SR + case(IFM_10G_SR): +#endif +#ifdef IFM_10G_LR + case(IFM_10G_LR): +#endif +#ifdef IFM_10G_CX4 + case(IFM_10G_CX4): +#endif +#ifdef IFM_10G_TWINAX + case(IFM_10G_TWINAX): +#endif +#ifdef IFM_10G_TWINAX_LONG + case(IFM_10G_TWINAX_LONG): +#endif +#ifdef IFM_10G_T + case(IFM_10G_T): +#endif + return 10000; +#endif +#if defined(IFM_2500_SX) +#ifdef IFM_2500_SX + case(IFM_2500_SX): +#endif + return 2500; +#endif // any 2.5GBit stuff... + // We don't know what it is + default: + return 0; + } + break; + +#ifdef IFM_TOKEN + case IFM_TOKEN: + switch(IFM_SUBTYPE(ifm_active)) { + case IFM_TOK_STP4: // Shielded twisted pair 4m - DB9 + case IFM_TOK_UTP4: // Unshielded twisted pair 4m - RJ45 + return 4; + case IFM_TOK_STP16: // Shielded twisted pair 16m - DB9 + case IFM_TOK_UTP16: // Unshielded twisted pair 16m - RJ45 + return 16; +#if defined(IFM_TOK_STP100) || defined(IFM_TOK_UTP100) +#ifdef IFM_TOK_STP100 + case IFM_TOK_STP100: // Shielded twisted pair 100m - DB9 +#endif +#ifdef IFM_TOK_UTP100 + case IFM_TOK_UTP100: // Unshielded twisted pair 100m - RJ45 +#endif + return 100; +#endif + // We don't know what it is + default: + return 0; + } + break; +#endif + +#ifdef IFM_FDDI + case IFM_FDDI: + switch(IFM_SUBTYPE(ifm_active)) { + // We don't know what it is + default: + return 0; + } + break; +#endif + case IFM_IEEE80211: + switch(IFM_SUBTYPE(ifm_active)) { + case IFM_IEEE80211_FH1: // Frequency Hopping 1Mbps + case IFM_IEEE80211_DS1: // Direct Sequence 1Mbps + return 1; + case IFM_IEEE80211_FH2: // Frequency Hopping 2Mbps + case IFM_IEEE80211_DS2: // Direct Sequence 2Mbps + return 2; + case IFM_IEEE80211_DS5: // Direct Sequence 5Mbps + return 5; + case IFM_IEEE80211_DS11: // Direct Sequence 11Mbps + return 11; + case IFM_IEEE80211_DS22: // Direct Sequence 22Mbps + return 22; + // We don't know what it is + default: + return 0; + } + break; + + default: + return 0; } - Py_INCREF(Py_None); - return Py_None; } +/* + * Return stats about a particular network interface. + * References: + * http://www.i-scream.org/libstatgrab/ + */ +static PyObject * +psutil_net_if_stats(PyObject *self, PyObject *args) +{ + char *nic_name; + int sock = 0; + int ret; + int duplex; + int speed; + int mtu; + struct ifreq ifr; + struct ifmediareq ifmed; + + PyObject *py_is_up = NULL; + + if (! PyArg_ParseTuple(args, "s", &nic_name)) + return NULL; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) + goto error; + strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name)); + + // is up? + ret = ioctl(sock, SIOCGIFFLAGS, &ifr); + if (ret == -1) + goto error; + if ((ifr.ifr_flags & IFF_UP) != 0) + py_is_up = Py_True; + else + py_is_up = Py_False; + Py_INCREF(py_is_up); + + // MTU + ret = ioctl(sock, SIOCGIFMTU, &ifr); + if (ret == -1) + goto error; + mtu = ifr.ifr_mtu; + + // speed / duplex + memset(&ifmed, 0, sizeof(struct ifmediareq)); + strlcpy(ifmed.ifm_name, nic_name, sizeof(ifmed.ifm_name)); + ret = ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmed); + if (ret == -1) { + speed = 0; + duplex = 0; + } + else { + speed = psutil_get_nic_speed(ifmed.ifm_active); + if ((ifmed.ifm_active | IFM_FDX) == ifmed.ifm_active) + duplex = 2; + else if ((ifmed.ifm_active | IFM_HDX) == ifmed.ifm_active) + duplex = 1; + else + duplex = 0; + } + + close(sock); + Py_DECREF(py_is_up); + + return Py_BuildValue("[Oiii]", py_is_up, duplex, speed, mtu); + +error: + Py_XDECREF(py_is_up); + if (sock != 0) + close(sock); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} +#endif // net_if_stats() implementation + + /* * define the psutil C module methods and initialize the module. */ @@ -65,6 +458,12 @@ PsutilMethods[] = "Return process priority"}, {"setpriority", psutil_posix_setpriority, METH_VARARGS, "Set process priority"}, + {"net_if_addrs", psutil_net_if_addrs, METH_VARARGS, + "Retrieve NICs information"}, +#if defined(__FreeBSD__) || defined(__APPLE__) + {"net_if_stats", psutil_net_if_stats, METH_VARARGS, + "Return NIC stats."}, +#endif {NULL, NULL, 0, NULL} }; @@ -119,9 +518,13 @@ void init_psutil_posix(void) #else PyObject *module = Py_InitModule("_psutil_posix", PsutilMethods); #endif - if (module == NULL) { + +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__sun) + PyModule_AddIntConstant(module, "AF_LINK", AF_LINK); +#endif + + if (module == NULL) INITERROR; - } #if PY_MAJOR_VERSION >= 3 return module; #endif diff --git a/python/psutil/psutil/_psutil_posix.h b/python/psutil/psutil/_psutil_posix.h index 5a4681d18876..bbe6fc5ad2d3 100644 --- a/python/psutil/psutil/_psutil_posix.h +++ b/python/psutil/psutil/_psutil_posix.h @@ -6,5 +6,10 @@ #include +static PyObject* psutil_net_if_addrs(PyObject* self, PyObject* args); static PyObject* psutil_posix_getpriority(PyObject* self, PyObject* args); static PyObject* psutil_posix_setpriority(PyObject* self, PyObject* args); + +#if defined(__FreeBSD__) || defined(__APPLE__) +static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args); +#endif diff --git a/python/psutil/psutil/_psutil_sunos.c b/python/psutil/psutil/_psutil_sunos.c index 031aacb001f8..0cb6978f27f3 100644 --- a/python/psutil/psutil/_psutil_sunos.c +++ b/python/psutil/psutil/_psutil_sunos.c @@ -30,6 +30,8 @@ #include // for MNTTAB #include #include +#include +#include #include #include #include @@ -38,6 +40,7 @@ #include #include #include +#include #include "_psutil_sunos.h" @@ -201,13 +204,11 @@ proc_io_counters(PyObject* self, PyObject* args) char path[100]; prusage_t info; - if (! PyArg_ParseTuple(args, "i", &pid)) { + if (! PyArg_ParseTuple(args, "i", &pid)) return NULL; - } sprintf(path, "/proc/%i/usage", pid); - if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) { + if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) return NULL; - } // On Solaris we only have 'pr_ioch' which accounts for bytes read // *and* written. @@ -315,9 +316,8 @@ psutil_swap_mem(PyObject *self, PyObject *args) uint_t sout = 0; kc = kstat_open(); - if (kc == NULL) { + if (kc == NULL) return PyErr_SetFromErrno(PyExc_OSError);; - } k = kc->kc_chain; while (k != NULL) { @@ -442,8 +442,6 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) kstat_ctl_t *kc; kstat_t *ksp; cpu_stat_t cs; - int numcpus; - int i; PyObject *py_retlist = PyList_New(0); PyObject *py_cputime = NULL; @@ -456,29 +454,24 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) goto error; } - numcpus = sysconf(_SC_NPROCESSORS_ONLN) - 1; - for (i = 0; i <= numcpus; i++) { - ksp = kstat_lookup(kc, "cpu_stat", i, NULL); - if (ksp == NULL) { - PyErr_SetFromErrno(PyExc_OSError); - goto error; - } - if (kstat_read(kc, ksp, &cs) == -1) { - PyErr_SetFromErrno(PyExc_OSError); - goto error; + for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) { + if (strcmp(ksp->ks_module, "cpu_stat") == 0) { + if (kstat_read(kc, ksp, &cs) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + py_cputime = Py_BuildValue("ffff", + (float)cs.cpu_sysinfo.cpu[CPU_USER], + (float)cs.cpu_sysinfo.cpu[CPU_KERNEL], + (float)cs.cpu_sysinfo.cpu[CPU_IDLE], + (float)cs.cpu_sysinfo.cpu[CPU_WAIT]); + if (py_cputime == NULL) + goto error; + if (PyList_Append(py_retlist, py_cputime)) + goto error; + Py_DECREF(py_cputime); + py_cputime = NULL; } - - py_cputime = Py_BuildValue("ffff", - (float)cs.cpu_sysinfo.cpu[CPU_USER], - (float)cs.cpu_sysinfo.cpu[CPU_KERNEL], - (float)cs.cpu_sysinfo.cpu[CPU_IDLE], - (float)cs.cpu_sysinfo.cpu[CPU_WAIT]); - if (py_cputime == NULL) - goto error; - if (PyList_Append(py_retlist, py_cputime)) - goto error; - Py_DECREF(py_cputime); - } kstat_close(kc); @@ -576,17 +569,14 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) PyObject *pytuple = NULL; PyObject *py_retlist = PyList_New(0); - if (py_retlist == NULL) { + if (py_retlist == NULL) return NULL; - } - if (! PyArg_ParseTuple(args, "i", &pid)) { + if (! PyArg_ParseTuple(args, "i", &pid)) goto error; - } sprintf(path, "/proc/%i/status", pid); - if (! psutil_file_to_struct(path, (void *)&status, sizeof(status))) { + if (! psutil_file_to_struct(path, (void *)&status, sizeof(status))) goto error; - } sprintf(path, "/proc/%i/xmap", pid); if (stat(path, &st) == -1) { @@ -722,9 +712,8 @@ psutil_net_io_counters(PyObject *self, PyObject *args) (strcmp(ksp->ks_module, "lo") != 0)) { goto skip; */ - if ((strcmp(ksp->ks_module, "link") != 0)) { + if ((strcmp(ksp->ks_module, "link") != 0)) goto next; - } if (kstat_read(kc, ksp, NULL) == -1) { errno = 0; @@ -747,18 +736,18 @@ psutil_net_io_counters(PyObject *self, PyObject *args) #if defined(_INT64_TYPE) py_ifc_info = Py_BuildValue("(KKKKkkii)", - rbytes->value.ui64, wbytes->value.ui64, - rpkts->value.ui64, + rbytes->value.ui64, wpkts->value.ui64, + rpkts->value.ui64, ierrs->value.ui32, oerrs->value.ui32, #else py_ifc_info = Py_BuildValue("(kkkkkkii)", - rbytes->value.ui32, wbytes->value.ui32, - rpkts->value.ui32, + rbytes->value.ui32, wpkts->value.ui32, + rpkts->value.ui32, ierrs->value.ui32, oerrs->value.ui32, #endif @@ -810,7 +799,7 @@ static PyObject * psutil_net_connections(PyObject *self, PyObject *args) { long pid; - int sd = NULL; + int sd = 0; mib2_tcpConnEntry_t *tp = NULL; mib2_udpEntry_t *ude; #if defined(AF_INET6) @@ -822,6 +811,7 @@ psutil_net_connections(PyObject *self, PyObject *args) char lip[200], rip[200]; int lport, rport; int processed_pid; + int databuf_init = 0; struct strbuf ctlbuf, databuf; struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf; struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf; @@ -922,6 +912,7 @@ psutil_net_connections(PyObject *self, PyObject *args) PyErr_NoMemory(); goto error; } + databuf_init = 1; flags = 0; getcode = getmsg(sd, (struct strbuf *)0, &databuf, &flags); @@ -948,9 +939,8 @@ psutil_net_connections(PyObject *self, PyObject *args) py_laddr = Py_BuildValue("(si)", lip, lport); if (!py_laddr) goto error; - if (rport != 0) { + if (rport != 0) py_raddr = Py_BuildValue("(si)", rip, rport); - } else { py_raddr = Py_BuildValue("()"); } @@ -962,9 +952,8 @@ psutil_net_connections(PyObject *self, PyObject *args) py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET, SOCK_STREAM, py_laddr, py_raddr, state, processed_pid); - if (!py_tuple) { + if (!py_tuple) goto error; - } if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); @@ -991,12 +980,10 @@ psutil_net_connections(PyObject *self, PyObject *args) py_laddr = Py_BuildValue("(si)", lip, lport); if (!py_laddr) goto error; - if (rport != 0) { + if (rport != 0) py_raddr = Py_BuildValue("(si)", rip, rport); - } - else { + else py_raddr = Py_BuildValue("()"); - } if (!py_raddr) goto error; state = tp6->tcp6ConnEntryInfo.ce_state; @@ -1004,9 +991,8 @@ psutil_net_connections(PyObject *self, PyObject *args) // add item py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET6, SOCK_STREAM, py_laddr, py_raddr, state, processed_pid); - if (!py_tuple) { + if (!py_tuple) goto error; - } if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); @@ -1039,9 +1025,8 @@ psutil_net_connections(PyObject *self, PyObject *args) py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET, SOCK_DGRAM, py_laddr, py_raddr, PSUTIL_CONN_NONE, processed_pid); - if (!py_tuple) { + if (!py_tuple) goto error; - } if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); @@ -1049,7 +1034,9 @@ psutil_net_connections(PyObject *self, PyObject *args) } #if defined(AF_INET6) // UDPv6 - else if (mibhdr->level == MIB2_UDP6 || mibhdr->level == MIB2_UDP6_ENTRY) { + else if (mibhdr->level == MIB2_UDP6 || + mibhdr->level == MIB2_UDP6_ENTRY) + { ude6 = (mib2_udp6Entry_t *)databuf.buf; num_ent = mibhdr->len / sizeof(mib2_udp6Entry_t); for (i = 0; i < num_ent; i++, ude6++) { @@ -1067,9 +1054,8 @@ psutil_net_connections(PyObject *self, PyObject *args) py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET6, SOCK_DGRAM, py_laddr, py_raddr, PSUTIL_CONN_NONE, processed_pid); - if (!py_tuple) { + if (!py_tuple) goto error; - } if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); @@ -1087,8 +1073,9 @@ psutil_net_connections(PyObject *self, PyObject *args) Py_XDECREF(py_laddr); Py_XDECREF(py_raddr); Py_DECREF(py_retlist); - // TODO : free databuf - if (sd != NULL) + if (databuf_init == 1) + free(databuf.buf); + if (sd != 0) close(sd); return NULL; } @@ -1137,7 +1124,7 @@ psutil_cpu_count_phys(PyObject *self, PyObject *args) for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { if (strcmp(ksp->ks_module, "cpu_info") != 0) continue; - if (kstat_read(kc, ksp, NULL) == NULL) + if (kstat_read(kc, ksp, NULL) == -1) goto error; ncpus += 1; } @@ -1152,8 +1139,117 @@ psutil_cpu_count_phys(PyObject *self, PyObject *args) // mimic os.cpu_count() if (kc != NULL) kstat_close(kc); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; +} + + +/* + * Return stats about a particular network + * interface. References: + * https://github.com/dpaleino/wicd/blob/master/wicd/backends/be-ioctl.py + * http://www.i-scream.org/libstatgrab/ + */ +static PyObject* +psutil_net_if_stats(PyObject* self, PyObject* args) +{ + kstat_ctl_t *kc = NULL; + kstat_t *ksp; + kstat_named_t *knp; + int ret; + int sock = 0; + int duplex; + int speed; + + PyObject *py_retdict = PyDict_New(); + PyObject *py_ifc_info = NULL; + PyObject *py_is_up = NULL; + + if (py_retdict == NULL) + return NULL; + kc = kstat_open(); + if (kc == NULL) + goto error; + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) + goto error; + + for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { + if (strcmp(ksp->ks_class, "net") == 0) { + struct ifreq ifr; + + kstat_read(kc, ksp, NULL); + if (ksp->ks_type != KSTAT_TYPE_NAMED) + continue; + if (strcmp(ksp->ks_class, "net") != 0) + continue; + + strncpy(ifr.ifr_name, ksp->ks_name, sizeof(ifr.ifr_name)); + ret = ioctl(sock, SIOCGIFFLAGS, &ifr); + if (ret == -1) + continue; // not a network interface + + // is up? + if ((ifr.ifr_flags & IFF_UP) != 0) { + if ((knp = kstat_data_lookup(ksp, "link_up")) != NULL) { + if (knp->value.ui32 != 0u) + py_is_up = Py_True; + else + py_is_up = Py_False; + } + else { + py_is_up = Py_True; + } + } + else { + py_is_up = Py_False; + } + Py_INCREF(py_is_up); + + // duplex + duplex = 0; // unknown + if ((knp = kstat_data_lookup(ksp, "link_duplex")) != NULL) { + if (knp->value.ui32 == 1) + duplex = 1; // half + else if (knp->value.ui32 == 2) + duplex = 2; // full + } + + // speed + if ((knp = kstat_data_lookup(ksp, "ifspeed")) != NULL) + // expressed in bits per sec, we want mega bits per sec + speed = (int)knp->value.ui64 / 1000000; + else + speed = 0; + + // mtu + ret = ioctl(sock, SIOCGIFMTU, &ifr); + if (ret == -1) + goto error; + + py_ifc_info = Py_BuildValue("(Oiii)", py_is_up, duplex, speed, + ifr.ifr_mtu); + if (!py_ifc_info) + goto error; + if (PyDict_SetItemString(py_retdict, ksp->ks_name, py_ifc_info)) + goto error; + Py_DECREF(py_ifc_info); + } + } + + close(sock); + kstat_close(kc); + return py_retdict; + +error: + Py_XDECREF(py_is_up); + Py_XDECREF(py_ifc_info); + Py_DECREF(py_retdict); + if (sock != 0) + close(sock); + if (kc != NULL) + kstat_close(kc); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; } @@ -1198,6 +1294,8 @@ PsutilMethods[] = "Return the number of physical CPUs on the system."}, {"net_connections", psutil_net_connections, METH_VARARGS, "Return TCP and UDP syste-wide open connections."}, + {"net_if_stats", psutil_net_if_stats, METH_VARARGS, + "Return NIC stats (isup, duplex, speed, mtu)"}, {NULL, NULL, 0, NULL} }; @@ -1254,6 +1352,8 @@ void init_psutil_sunos(void) #else PyObject *module = Py_InitModule("_psutil_sunos", PsutilMethods); #endif + PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); + PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); PyModule_AddIntConstant(module, "SRUN", SRUN); PyModule_AddIntConstant(module, "SZOMB", SZOMB); @@ -1281,9 +1381,8 @@ void init_psutil_sunos(void) PyModule_AddIntConstant(module, "TCPS_BOUND", TCPS_BOUND); PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE); - if (module == NULL) { + if (module == NULL) INITERROR; - } #if PY_MAJOR_VERSION >= 3 return module; #endif diff --git a/python/psutil/psutil/_psutil_sunos.h b/python/psutil/psutil/_psutil_sunos.h index 414a7d80e624..f93dbfe0fd38 100644 --- a/python/psutil/psutil/_psutil_sunos.h +++ b/python/psutil/psutil/_psutil_sunos.h @@ -25,3 +25,4 @@ static PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args); static PyObject* psutil_swap_mem(PyObject* self, PyObject* args); static PyObject* psutil_users(PyObject* self, PyObject* args); static PyObject* psutil_net_connections(PyObject* self, PyObject* args); +static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args); diff --git a/python/psutil/psutil/_psutil_windows.c b/python/psutil/psutil/_psutil_windows.c index b536afec608e..3e0f7a7cdc8e 100644 --- a/python/psutil/psutil/_psutil_windows.c +++ b/python/psutil/psutil/_psutil_windows.c @@ -20,6 +20,7 @@ #include #include #include +#include // Link with Iphlpapi.lib #pragma comment(lib, "IPHLPAPI.lib") @@ -30,11 +31,158 @@ #include "arch/windows/process_info.h" #include "arch/windows/process_handles.h" #include "arch/windows/ntextapi.h" +#include "arch/windows/inet_ntop.h" #ifdef __MINGW32__ #include "arch/windows/glpi.h" #endif + +/* + * ============================================================================ + * Utilities + * ============================================================================ + */ + + // a flag for connections without an actual status +static int PSUTIL_CONN_NONE = 128; + +#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) +#define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) +#define LO_T ((float)1e-7) +#define HI_T (LO_T*4294967296.0) +#define BYTESWAP_USHORT(x) ((((USHORT)(x) << 8) | ((USHORT)(x) >> 8)) & 0xffff) +#ifndef AF_INET6 +#define AF_INET6 23 +#endif +#define _psutil_conn_decref_objs() \ + Py_DECREF(_AF_INET); \ + Py_DECREF(_AF_INET6);\ + Py_DECREF(_SOCK_STREAM);\ + Py_DECREF(_SOCK_DGRAM); + +typedef BOOL (WINAPI *LPFN_GLPI) + (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD); + +// fix for mingw32, see +// https://github.com/giampaolo/psutil/issues/351#c2 +typedef struct _DISK_PERFORMANCE_WIN_2008 { + LARGE_INTEGER BytesRead; + LARGE_INTEGER BytesWritten; + LARGE_INTEGER ReadTime; + LARGE_INTEGER WriteTime; + LARGE_INTEGER IdleTime; + DWORD ReadCount; + DWORD WriteCount; + DWORD QueueDepth; + DWORD SplitCount; + LARGE_INTEGER QueryTime; + DWORD StorageDeviceNumber; + WCHAR StorageManagerName[8]; +} DISK_PERFORMANCE_WIN_2008; + +// --- network connections mingw32 support +#ifndef _IPRTRMIB_H +typedef struct _MIB_TCP6ROW_OWNER_PID { + UCHAR ucLocalAddr[16]; + DWORD dwLocalScopeId; + DWORD dwLocalPort; + UCHAR ucRemoteAddr[16]; + DWORD dwRemoteScopeId; + DWORD dwRemotePort; + DWORD dwState; + DWORD dwOwningPid; +} MIB_TCP6ROW_OWNER_PID, *PMIB_TCP6ROW_OWNER_PID; + +typedef struct _MIB_TCP6TABLE_OWNER_PID { + DWORD dwNumEntries; + MIB_TCP6ROW_OWNER_PID table[ANY_SIZE]; +} MIB_TCP6TABLE_OWNER_PID, *PMIB_TCP6TABLE_OWNER_PID; +#endif + +#ifndef __IPHLPAPI_H__ +typedef struct in6_addr { + union { + UCHAR Byte[16]; + USHORT Word[8]; + } u; +} IN6_ADDR, *PIN6_ADDR, FAR *LPIN6_ADDR; + +typedef enum _UDP_TABLE_CLASS { + UDP_TABLE_BASIC, + UDP_TABLE_OWNER_PID, + UDP_TABLE_OWNER_MODULE +} UDP_TABLE_CLASS, *PUDP_TABLE_CLASS; + +typedef struct _MIB_UDPROW_OWNER_PID { + DWORD dwLocalAddr; + DWORD dwLocalPort; + DWORD dwOwningPid; +} MIB_UDPROW_OWNER_PID, *PMIB_UDPROW_OWNER_PID; + +typedef struct _MIB_UDPTABLE_OWNER_PID { + DWORD dwNumEntries; + MIB_UDPROW_OWNER_PID table[ANY_SIZE]; +} MIB_UDPTABLE_OWNER_PID, *PMIB_UDPTABLE_OWNER_PID; +#endif + +typedef struct _MIB_UDP6ROW_OWNER_PID { + UCHAR ucLocalAddr[16]; + DWORD dwLocalScopeId; + DWORD dwLocalPort; + DWORD dwOwningPid; +} MIB_UDP6ROW_OWNER_PID, *PMIB_UDP6ROW_OWNER_PID; + +typedef struct _MIB_UDP6TABLE_OWNER_PID { + DWORD dwNumEntries; + MIB_UDP6ROW_OWNER_PID table[ANY_SIZE]; +} MIB_UDP6TABLE_OWNER_PID, *PMIB_UDP6TABLE_OWNER_PID; + + +PIP_ADAPTER_ADDRESSES +psutil_get_nic_addresses() { + // allocate a 15 KB buffer to start with + int outBufLen = 15000; + DWORD dwRetVal = 0; + ULONG attempts = 0; + PIP_ADAPTER_ADDRESSES pAddresses = NULL; + + do { + pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen); + if (pAddresses == NULL) { + PyErr_NoMemory(); + return NULL; + } + + dwRetVal = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, + &outBufLen); + if (dwRetVal == ERROR_BUFFER_OVERFLOW) { + free(pAddresses); + pAddresses = NULL; + } + else { + break; + } + + attempts++; + } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (attempts < 3)); + + if (dwRetVal != NO_ERROR) { + PyErr_SetString(PyExc_RuntimeError, "GetAdaptersAddresses() failed."); + return NULL; + } + + return pAddresses; +} + + +/* + * ============================================================================ + * Public Python API + * ============================================================================ + */ + + /* * Return a Python float representing the system uptime expressed in seconds * since the epoch. @@ -82,14 +230,12 @@ psutil_pid_exists(PyObject *self, PyObject *args) long pid; int status; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } status = psutil_pid_is_running(pid); - if (-1 == status) { + if (-1 == status) return NULL; // exception raised in psutil_pid_is_running() - } return PyBool_FromLong(status); } @@ -106,13 +252,11 @@ psutil_pids(PyObject *self, PyObject *args) PyObject *pid = NULL; PyObject *retlist = PyList_New(0); - if (retlist == NULL) { + if (retlist == NULL) return NULL; - } proclist = psutil_get_pids(&numberOfReturnedPIDs); - if (NULL == proclist) { + if (proclist == NULL) goto error; - } for (i = 0; i < numberOfReturnedPIDs; i++) { pid = Py_BuildValue("I", proclist[i]); @@ -145,12 +289,10 @@ psutil_proc_kill(PyObject *self, PyObject *args) HANDLE hProcess; long pid; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (pid == 0) { + if (pid == 0) return AccessDenied(); - } hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); if (hProcess == NULL) { @@ -172,8 +314,7 @@ psutil_proc_kill(PyObject *self, PyObject *args) } CloseHandle(hProcess); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } @@ -189,12 +330,10 @@ psutil_proc_wait(PyObject *self, PyObject *args) long pid; long timeout; - if (! PyArg_ParseTuple(args, "ll", &pid, &timeout)) { + if (! PyArg_ParseTuple(args, "ll", &pid, &timeout)) return NULL; - } - if (pid == 0) { + if (pid == 0) return AccessDenied(); - } hProcess = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid); @@ -202,8 +341,7 @@ psutil_proc_wait(PyObject *self, PyObject *args) if (GetLastError() == ERROR_INVALID_PARAMETER) { // no such process; we do not want to raise NSP but // return None instead. - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } else { PyErr_SetFromWindowsErr(0); @@ -250,15 +388,12 @@ psutil_proc_cpu_times(PyObject *self, PyObject *args) HANDLE hProcess; FILETIME ftCreate, ftExit, ftKernel, ftUser; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } hProcess = psutil_handle_from_pid(pid); - if (hProcess == NULL) { + if (hProcess == NULL) return NULL; - } - if (! GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) { CloseHandle(hProcess); if (GetLastError() == ERROR_ACCESS_DENIED) { @@ -293,32 +428,6 @@ psutil_proc_cpu_times(PyObject *self, PyObject *args) } -/* - * Alternative implementation of the one above but bypasses ACCESS DENIED. - */ -static PyObject * -psutil_proc_cpu_times_2(PyObject *self, PyObject *args) -{ - DWORD pid; - PSYSTEM_PROCESS_INFORMATION process; - PVOID buffer; - double user, kernel; - - if (! PyArg_ParseTuple(args, "l", &pid)) { - return NULL; - } - if (! psutil_get_proc_info(pid, &process, &buffer)) { - return NULL; - } - user = (double)process->UserTime.HighPart * 429.4967296 + \ - (double)process->UserTime.LowPart * 1e-7; - kernel = (double)process->KernelTime.HighPart * 429.4967296 + \ - (double)process->KernelTime.LowPart * 1e-7; - free(buffer); - return Py_BuildValue("(dd)", user, kernel); -} - - /* * Return a Python float indicating the process create time expressed in * seconds since the epoch. @@ -333,20 +442,16 @@ psutil_proc_create_time(PyObject *self, PyObject *args) BOOL ret; FILETIME ftCreate, ftExit, ftKernel, ftUser; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } // special case for PIDs 0 and 4, return system boot time - if (0 == pid || 4 == pid) { + if (0 == pid || 4 == pid) return psutil_boot_time(NULL, NULL); - } hProcess = psutil_handle_from_pid(pid); - if (hProcess == NULL) { + if (hProcess == NULL) return NULL; - } - if (! GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) { CloseHandle(hProcess); if (GetLastError() == ERROR_ACCESS_DENIED) { @@ -368,9 +473,8 @@ psutil_proc_create_time(PyObject *self, PyObject *args) ret = GetExitCodeProcess(hProcess, &exitCode); CloseHandle(hProcess); if (ret != 0) { - if (exitCode != STILL_ACTIVE) { + if (exitCode != STILL_ACTIVE) return NoSuchProcess(); - } } else { // Ignore access denied as it means the process is still alive. @@ -393,39 +497,6 @@ psutil_proc_create_time(PyObject *self, PyObject *args) } -/* - * Alternative implementation of the one above but bypasses ACCESS DENIED. - */ -static PyObject * -psutil_proc_create_time_2(PyObject *self, PyObject *args) -{ - DWORD pid; - PSYSTEM_PROCESS_INFORMATION process; - PVOID buffer; - long long unix_time; - - if (! PyArg_ParseTuple(args, "l", &pid)) { - return NULL; - } - if (! psutil_get_proc_info(pid, &process, &buffer)) { - return NULL; - } - // special case for PIDs 0 and 4, return system boot time - if (0 == pid || 4 == pid) { - return psutil_boot_time(NULL, NULL); - } - /* - Convert the LARGE_INTEGER union to a Unix time. - It's the best I could find by googling and borrowing code here and there. - The time returned has a precision of 1 second. - */ - unix_time = ((LONGLONG)process->CreateTime.HighPart) << 32; - unix_time += process->CreateTime.LowPart - 116444736000000000LL; - unix_time /= 10000000; - free(buffer); - return Py_BuildValue("d", (double)unix_time); -} - /* * Return the number of logical CPUs. @@ -437,20 +508,13 @@ psutil_cpu_count_logical(PyObject *self, PyObject *args) system_info.dwNumberOfProcessors = 0; GetSystemInfo(&system_info); - if (system_info.dwNumberOfProcessors == 0) { - // mimic os.cpu_count() - Py_INCREF(Py_None); - return Py_None; - } - else { + if (system_info.dwNumberOfProcessors == 0) + Py_RETURN_NONE; // mimic os.cpu_count() + else return Py_BuildValue("I", system_info.dwNumberOfProcessors); - } } -typedef BOOL (WINAPI *LPFN_GLPI) (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, - PDWORD); - /* * Return the number of physical CPU cores. */ @@ -510,8 +574,7 @@ psutil_cpu_count_phys(PyObject *self, PyObject *args) // mimic os.cpu_count() if (buffer != NULL) free(buffer); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } @@ -524,20 +587,16 @@ psutil_proc_cmdline(PyObject *self, PyObject *args) { int pid_return; PyObject *arglist; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if ((pid == 0) || (pid == 4)) { + if ((pid == 0) || (pid == 4)) return Py_BuildValue("[]"); - } pid_return = psutil_pid_is_running(pid); - if (pid_return == 0) { + if (pid_return == 0) return NoSuchProcess(); - } - if (pid_return == -1) { + if (pid_return == -1) return NULL; - } // XXX the assumptio below probably needs to go away @@ -563,15 +622,13 @@ psutil_proc_exe(PyObject *self, PyObject *args) { long pid; HANDLE hProcess; wchar_t exe[MAX_PATH]; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } hProcess = psutil_handle_from_pid_waccess(pid, PROCESS_QUERY_INFORMATION); - if (NULL == hProcess) { + if (NULL == hProcess) return NULL; - } - if (GetProcessImageFileNameW(hProcess, &exe, MAX_PATH) == 0) { + if (GetProcessImageFileNameW(hProcess, exe, MAX_PATH) == 0) { CloseHandle(hProcess); PyErr_SetFromWindowsErr(0); return NULL; @@ -581,6 +638,47 @@ psutil_proc_exe(PyObject *self, PyObject *args) { } +/* + * Return process base name. + * Note: psutil_proc_exe() is attempted first because it's faster + * but it raise AccessDenied for processes owned by other users + * in which case we fall back on using this. + */ +static PyObject * +psutil_proc_name(PyObject *self, PyObject *args) { + long pid; + int ok; + PROCESSENTRY32 pentry; + HANDLE hSnapShot; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, pid); + if (hSnapShot == INVALID_HANDLE_VALUE) { + PyErr_SetFromWindowsErr(0); + return NULL; + } + pentry.dwSize = sizeof(PROCESSENTRY32); + ok = Process32First(hSnapShot, &pentry); + if (! ok) { + CloseHandle(hSnapShot); + PyErr_SetFromWindowsErr(0); + return NULL; + } + while (ok) { + if (pentry.th32ProcessID == pid) { + CloseHandle(hSnapShot); + return Py_BuildValue("s", pentry.szExeFile); + } + ok = Process32Next(hSnapShot, &pentry); + } + + CloseHandle(hSnapShot); + NoSuchProcess(); + return NULL; +} + + /* * Return process memory information as a Python tuple. */ @@ -596,16 +694,15 @@ psutil_proc_memory_info(PyObject *self, PyObject *args) #endif SIZE_T private = 0; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } hProcess = psutil_handle_from_pid(pid); - if (NULL == hProcess) { + if (NULL == hProcess) return NULL; - } - if (! GetProcessMemoryInfo(hProcess, &cnt, sizeof(cnt)) ) { + if (! GetProcessMemoryInfo(hProcess, (PPROCESS_MEMORY_COUNTERS)&cnt, + sizeof(cnt))) { CloseHandle(hProcess); return PyErr_SetFromWindowsErr(0); } @@ -668,12 +765,10 @@ psutil_proc_memory_info_2(PyObject *self, PyObject *args) unsigned int m1, m2, m3, m4, m5, m6, m7, m8; #endif - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (! psutil_get_proc_info(pid, &process, &buffer)) { + if (! psutil_get_proc_info(pid, &process, &buffer)) return NULL; - } #if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2 private = process->PrivatePageCount; @@ -716,10 +811,8 @@ psutil_virtual_mem(PyObject *self, PyObject *args) MEMORYSTATUSEX memInfo; memInfo.dwLength = sizeof(MEMORYSTATUSEX); - if (! GlobalMemoryStatusEx(&memInfo) ) { + if (! GlobalMemoryStatusEx(&memInfo)) return PyErr_SetFromWindowsErr(0); - } - return Py_BuildValue("(LLLLLL)", memInfo.ullTotalPhys, // total memInfo.ullAvailPhys, // avail @@ -730,10 +823,6 @@ psutil_virtual_mem(PyObject *self, PyObject *args) } -#define LO_T ((float)1e-7) -#define HI_T (LO_T*4294967296.0) - - /* * Retrieves system CPU timing information as a (user, system, idle) * tuple. On a multiprocessor system, the values returned are the @@ -745,9 +834,8 @@ psutil_cpu_times(PyObject *self, PyObject *args) float idle, kernel, user, system; FILETIME idle_time, kernel_time, user_time; - if (!GetSystemTimes(&idle_time, &kernel_time, &user_time)) { + if (!GetSystemTimes(&idle_time, &kernel_time, &user_time)) return PyErr_SetFromWindowsErr(0); - } idle = (float)((HI_T * idle_time.dwHighDateTime) + \ (LO_T * idle_time.dwLowDateTime)); @@ -848,12 +936,10 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) error: Py_XDECREF(arg); Py_DECREF(retlist); - if (sppi) { + if (sppi) free(sppi); - } - if (hNtDll) { + if (hNtDll) FreeLibrary(hNtDll); - } PyErr_SetFromWindowsErr(0); return NULL; } @@ -876,14 +962,12 @@ psutil_proc_cwd(PyObject *self, PyObject *args) PyObject *cwd_from_wchar = NULL; PyObject *cwd = NULL; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } processHandle = psutil_handle_from_pid(pid); - if (processHandle == NULL) { + if (processHandle == NULL) return NULL; - } pebAddress = psutil_get_peb_address(processHandle); @@ -1072,15 +1156,12 @@ psutil_proc_suspend(PyObject *self, PyObject *args) { long pid; int suspend = 1; - if (! PyArg_ParseTuple(args, "l", &pid)) { - return NULL; - } - if (! psutil_proc_suspend_or_resume(pid, suspend)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - Py_INCREF(Py_None); - return Py_None; + if (! psutil_proc_suspend_or_resume(pid, suspend)) + return NULL; + Py_RETURN_NONE; } @@ -1089,35 +1170,12 @@ psutil_proc_resume(PyObject *self, PyObject *args) { long pid; int suspend = 0; - if (! PyArg_ParseTuple(args, "l", &pid)) { - return NULL; - } - if (! psutil_proc_suspend_or_resume(pid, suspend)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - Py_INCREF(Py_None); - return Py_None; -} - - -static PyObject * -psutil_proc_num_threads(PyObject *self, PyObject *args) -{ - DWORD pid; - PSYSTEM_PROCESS_INFORMATION process; - PVOID buffer; - int num; - - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! psutil_proc_suspend_or_resume(pid, suspend)) return NULL; - } - if (! psutil_get_proc_info(pid, &process, &buffer)) { - return NULL; - } - num = (int)process->NumberOfThreads; - free(buffer); - return Py_BuildValue("i", num); + Py_RETURN_NONE; } @@ -1134,12 +1192,10 @@ psutil_proc_threads(PyObject *self, PyObject *args) PyObject *pyTuple = NULL; HANDLE hThreadSnap = NULL; - if (retList == NULL) { + if (retList == NULL) return NULL; - } - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) goto error; - } if (pid == 0) { // raise AD instead of returning 0 as procexp is able to // retrieve useful information somehow @@ -1152,9 +1208,8 @@ psutil_proc_threads(PyObject *self, PyObject *args) NoSuchProcess(); goto error; } - if (pid_return == -1) { + if (pid_return == -1) goto error; - } hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (hThreadSnap == INVALID_HANDLE_VALUE) { @@ -1172,10 +1227,8 @@ psutil_proc_threads(PyObject *self, PyObject *args) // Walk the thread snapshot to find all threads of the process. // If the thread belongs to the process, increase the counter. - do - { - if (te32.th32OwnerProcessID == pid) - { + do { + if (te32.th32OwnerProcessID == pid) { pyTuple = NULL; hThread = NULL; hThread = OpenThread(THREAD_QUERY_INFORMATION, @@ -1226,9 +1279,8 @@ psutil_proc_threads(PyObject *self, PyObject *args) Py_DECREF(retList); if (hThread != NULL) CloseHandle(hThread); - if (hThreadSnap != NULL) { + if (hThreadSnap != NULL) CloseHandle(hThreadSnap); - } return NULL; } @@ -1241,20 +1293,16 @@ psutil_proc_open_files(PyObject *self, PyObject *args) DWORD access = PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; PyObject *filesList; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } processHandle = psutil_handle_from_pid_waccess(pid, access); - if (processHandle == NULL) { + if (processHandle == NULL) return NULL; - } - filesList = psutil_get_open_files(pid, processHandle); CloseHandle(processHandle); - if (filesList == NULL) { + if (filesList == NULL) return PyErr_SetFromWindowsErr(0); - } return filesList; } @@ -1271,17 +1319,15 @@ psutil_win32_QueryDosDevice(PyObject *self, PyObject *args) TCHAR d = TEXT('A'); TCHAR szBuff[5]; - if (!PyArg_ParseTuple(args, "s", &lpDevicePath)) { + if (!PyArg_ParseTuple(args, "s", &lpDevicePath)) return NULL; - } - while (d <= TEXT('Z')) - { + while (d <= TEXT('Z')) { TCHAR szDeviceName[3] = {d, TEXT(':'), TEXT('\0')}; TCHAR szTarget[512] = {0}; if (QueryDosDevice(szDeviceName, szTarget, 511) != 0) { if (_tcscmp(lpDevicePath, szTarget) == 0) { - _stprintf(szBuff, TEXT("%c:"), d); + _stprintf_s(szBuff, _countof(szBuff), TEXT("%c:"), d); return Py_BuildValue("s", szBuff); } } @@ -1310,15 +1356,13 @@ psutil_proc_username(PyObject *self, PyObject *args) PTSTR fullName; PyObject *returnObject; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } processHandle = psutil_handle_from_pid_waccess( pid, PROCESS_QUERY_INFORMATION); - if (processHandle == NULL) { + if (processHandle == NULL) return NULL; - } if (!OpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle)) { CloseHandle(processHandle); @@ -1331,9 +1375,8 @@ psutil_proc_username(PyObject *self, PyObject *args) bufferSize = 0x100; user = malloc(bufferSize); - if (user == NULL) { + if (user == NULL) return PyErr_NoMemory(); - } if (!GetTokenInformation(tokenHandle, TokenUser, user, bufferSize, &bufferSize)) @@ -1404,90 +1447,16 @@ psutil_proc_username(PyObject *self, PyObject *args) memcpy(&fullName[domainNameSize + 1], name, nameSize); fullName[domainNameSize + 1 + nameSize] = '\0'; - returnObject = Py_BuildValue("s", fullName); - - free(fullName); - free(name); - free(domainName); - free(user); - - return returnObject; -} - - -// --- network connections mingw32 support - -#ifndef _IPRTRMIB_H -typedef struct _MIB_TCP6ROW_OWNER_PID { - UCHAR ucLocalAddr[16]; - DWORD dwLocalScopeId; - DWORD dwLocalPort; - UCHAR ucRemoteAddr[16]; - DWORD dwRemoteScopeId; - DWORD dwRemotePort; - DWORD dwState; - DWORD dwOwningPid; -} MIB_TCP6ROW_OWNER_PID, *PMIB_TCP6ROW_OWNER_PID; - -typedef struct _MIB_TCP6TABLE_OWNER_PID { - DWORD dwNumEntries; - MIB_TCP6ROW_OWNER_PID table[ANY_SIZE]; -} MIB_TCP6TABLE_OWNER_PID, *PMIB_TCP6TABLE_OWNER_PID; -#endif - -#ifndef __IPHLPAPI_H__ -typedef struct in6_addr { - union { - UCHAR Byte[16]; - USHORT Word[8]; - } u; -} IN6_ADDR, *PIN6_ADDR, FAR *LPIN6_ADDR; - -typedef enum _UDP_TABLE_CLASS { - UDP_TABLE_BASIC, - UDP_TABLE_OWNER_PID, - UDP_TABLE_OWNER_MODULE -} UDP_TABLE_CLASS, *PUDP_TABLE_CLASS; - -typedef struct _MIB_UDPROW_OWNER_PID { - DWORD dwLocalAddr; - DWORD dwLocalPort; - DWORD dwOwningPid; -} MIB_UDPROW_OWNER_PID, *PMIB_UDPROW_OWNER_PID; - -typedef struct _MIB_UDPTABLE_OWNER_PID { - DWORD dwNumEntries; - MIB_UDPROW_OWNER_PID table[ANY_SIZE]; -} MIB_UDPTABLE_OWNER_PID, *PMIB_UDPTABLE_OWNER_PID; -#endif - -typedef struct _MIB_UDP6ROW_OWNER_PID { - UCHAR ucLocalAddr[16]; - DWORD dwLocalScopeId; - DWORD dwLocalPort; - DWORD dwOwningPid; -} MIB_UDP6ROW_OWNER_PID, *PMIB_UDP6ROW_OWNER_PID; - -typedef struct _MIB_UDP6TABLE_OWNER_PID { - DWORD dwNumEntries; - MIB_UDP6ROW_OWNER_PID table[ANY_SIZE]; -} MIB_UDP6TABLE_OWNER_PID, *PMIB_UDP6TABLE_OWNER_PID; - - -#define BYTESWAP_USHORT(x) ((((USHORT)(x) << 8) | ((USHORT)(x) >> 8)) & 0xffff) - -#ifndef AF_INET6 -#define AF_INET6 23 -#endif + returnObject = PyUnicode_Decode( + fullName, _tcslen(fullName), Py_FileSystemDefaultEncoding, "replace"); -#define _psutil_conn_decref_objs() \ - Py_DECREF(_AF_INET); \ - Py_DECREF(_AF_INET6);\ - Py_DECREF(_SOCK_STREAM);\ - Py_DECREF(_SOCK_DGRAM); + free(fullName); + free(name); + free(domainName); + free(user); -// a signaler for connections without an actual status -static int PSUTIL_CONN_NONE = 128; + return returnObject; +} /* @@ -1939,9 +1908,8 @@ psutil_proc_priority_get(PyObject *self, PyObject *args) long pid; DWORD priority; HANDLE hProcess; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } hProcess = psutil_handle_from_pid(pid); if (hProcess == NULL) { @@ -1985,8 +1953,7 @@ psutil_proc_priority_set(PyObject *self, PyObject *args) PyErr_SetFromWindowsErr(0); return NULL; } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } @@ -2005,9 +1972,8 @@ psutil_proc_io_priority_get(PyObject *self, PyObject *args) (_NtQueryInformationProcess)GetProcAddress( GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess"); - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } hProcess = psutil_handle_from_pid(pid); if (hProcess == NULL) { return NULL; @@ -2061,8 +2027,7 @@ psutil_proc_io_priority_set(PyObject *self, PyObject *args) ); CloseHandle(hProcess); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } #endif @@ -2077,9 +2042,8 @@ psutil_proc_io_counters(PyObject *self, PyObject *args) HANDLE hProcess; IO_COUNTERS IoCounters; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } hProcess = psutil_handle_from_pid(pid); if (NULL == hProcess) { return NULL; @@ -2097,32 +2061,6 @@ psutil_proc_io_counters(PyObject *self, PyObject *args) } -/* - * Alternative implementation of the one above but bypasses ACCESS DENIED. - */ -static PyObject * -psutil_proc_io_counters_2(PyObject *self, PyObject *args) -{ - DWORD pid; - PSYSTEM_PROCESS_INFORMATION process; - PVOID buffer; - LONGLONG rcount, wcount, rbytes, wbytes; - - if (! PyArg_ParseTuple(args, "l", &pid)) { - return NULL; - } - if (! psutil_get_proc_info(pid, &process, &buffer)) { - return NULL; - } - rcount = process->ReadOperationCount.QuadPart; - wcount = process->WriteOperationCount.QuadPart; - rbytes = process->ReadTransferCount.QuadPart; - wbytes = process->WriteTransferCount.QuadPart; - free(buffer); - return Py_BuildValue("KKKK", rcount, wcount, rbytes, wbytes); -} - - /* * Return process CPU affinity as a bitmask */ @@ -2131,12 +2069,11 @@ psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) { DWORD pid; HANDLE hProcess; - PDWORD_PTR proc_mask; - PDWORD_PTR system_mask; + DWORD_PTR proc_mask; + DWORD_PTR system_mask; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } hProcess = psutil_handle_from_pid(pid); if (hProcess == NULL) { return NULL; @@ -2186,8 +2123,7 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) } CloseHandle(hProcess); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } @@ -2203,9 +2139,8 @@ psutil_proc_is_suspended(PyObject *self, PyObject *args) PSYSTEM_PROCESS_INFORMATION process; PVOID buffer; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } if (! psutil_get_proc_info(pid, &process, &buffer)) { return NULL; } @@ -2267,14 +2202,9 @@ psutil_disk_usage(PyObject *self, PyObject *args) static PyObject * psutil_net_io_counters(PyObject *self, PyObject *args) { - int attempts = 0; - int i; - int outBufLen = 15000; char ifname[MAX_PATH]; DWORD dwRetVal = 0; MIB_IFROW *pIfRow = NULL; - ULONG flags = 0; - ULONG family = AF_UNSPEC; PIP_ADAPTER_ADDRESSES pAddresses = NULL; PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; @@ -2282,35 +2212,13 @@ psutil_net_io_counters(PyObject *self, PyObject *args) PyObject *py_nic_info = NULL; PyObject *py_nic_name = NULL; - if (py_retdict == NULL) { + if (py_retdict == NULL) return NULL; - } - do { - pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen); - if (pAddresses == NULL) { - PyErr_NoMemory(); - goto error; - } - - dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, - &outBufLen); - if (dwRetVal == ERROR_BUFFER_OVERFLOW) { - free(pAddresses); - pAddresses = NULL; - } - else { - break; - } - - attempts++; - } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (attempts < 3)); - - if (dwRetVal != NO_ERROR) { - PyErr_SetString(PyExc_RuntimeError, "GetAdaptersAddresses() failed."); + pAddresses = psutil_get_nic_addresses(); + if (pAddresses == NULL) goto error; - } - pCurrAddresses = pAddresses; + while (pCurrAddresses) { py_nic_name = NULL; py_nic_info = NULL; @@ -2340,22 +2248,10 @@ psutil_net_io_counters(PyObject *self, PyObject *args) if (!py_nic_info) goto error; - sprintf(ifname, "%wS", pCurrAddresses->FriendlyName); + sprintf_s(ifname, MAX_PATH, "%wS", pCurrAddresses->FriendlyName); + py_nic_name = PyUnicode_Decode( + ifname, _tcslen(ifname), Py_FileSystemDefaultEncoding, "replace"); -#if PY_MAJOR_VERSION >= 3 - // XXX - Dirty hack to avoid encoding errors on Python 3, see: - // https://github.com/giampaolo/psutil/issues/446#c9 - for (i = 0; i < MAX_PATH; i++) { - if (*(ifname+i) < 0 || *(ifname+i) > 256) { - // replace the non unicode character - *(ifname+i) = '?'; - } - else if (*(ifname+i) == '\0') { - break; - } - } -#endif - py_nic_name = Py_BuildValue("s", ifname); if (py_nic_name == NULL) goto error; if (PyDict_SetItem(py_retdict, py_nic_name, py_nic_info)) @@ -2381,22 +2277,6 @@ psutil_net_io_counters(PyObject *self, PyObject *args) return NULL; } -// fix for mingw32, see -// https://github.com/giampaolo/psutil/issues/351#c2 -typedef struct _DISK_PERFORMANCE_WIN_2008 { - LARGE_INTEGER BytesRead; - LARGE_INTEGER BytesWritten; - LARGE_INTEGER ReadTime; - LARGE_INTEGER WriteTime; - LARGE_INTEGER IdleTime; - DWORD ReadCount; - DWORD WriteCount; - DWORD QueueDepth; - DWORD SplitCount; - LARGE_INTEGER QueryTime; - DWORD StorageDeviceNumber; - WCHAR StorageManagerName[8]; -} DISK_PERFORMANCE_WIN_2008; /* * Return a Python dict of tuples for disk I/O information @@ -2422,7 +2302,7 @@ psutil_disk_io_counters(PyObject *self, PyObject *args) // in the alphabet (from A:\ to Z:\). for (devNum = 0; devNum <= 32; ++devNum) { py_disk_info = NULL; - sprintf(szDevice, "\\\\.\\PhysicalDrive%d", devNum); + sprintf_s(szDevice, MAX_PATH, "\\\\.\\PhysicalDrive%d", devNum); hDevice = CreateFile(szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); @@ -2433,7 +2313,7 @@ psutil_disk_io_counters(PyObject *self, PyObject *args) &diskPerformance, sizeof(diskPerformance), &dwSize, NULL)) { - sprintf(szDeviceDisplay, "PhysicalDrive%d", devNum); + sprintf_s(szDeviceDisplay, MAX_PATH, "PhysicalDrive%d", devNum); py_disk_info = Py_BuildValue( "(IILLKK)", diskPerformance.ReadCount, @@ -2475,22 +2355,22 @@ psutil_disk_io_counters(PyObject *self, PyObject *args) static char *psutil_get_drive_type(int type) { switch (type) { - case DRIVE_FIXED: - return "fixed"; - case DRIVE_CDROM: - return "cdrom"; - case DRIVE_REMOVABLE: - return "removable"; - case DRIVE_UNKNOWN: - return "unknown"; - case DRIVE_NO_ROOT_DIR: - return "unmounted"; - case DRIVE_REMOTE: - return "remote"; - case DRIVE_RAMDISK: - return "ramdisk"; - default: - return "?"; + case DRIVE_FIXED: + return "fixed"; + case DRIVE_CDROM: + return "cdrom"; + case DRIVE_REMOVABLE: + return "removable"; + case DRIVE_UNKNOWN: + return "unknown"; + case DRIVE_NO_ROOT_DIR: + return "unmounted"; + case DRIVE_REMOTE: + return "remote"; + case DRIVE_RAMDISK: + return "ramdisk"; + default: + return "?"; } } @@ -2574,25 +2454,25 @@ psutil_disk_partitions(PyObject *self, PyObject *args) // which case the error is (21, "device not ready"). // Let's pretend it didn't happen as we already have // the drive name and type ('removable'). - strcat(opts, ""); + strcat_s(opts, _countof(opts), ""); SetLastError(0); } else { if (pflags & FILE_READ_ONLY_VOLUME) { - strcat(opts, "ro"); + strcat_s(opts, _countof(opts), "ro"); } else { - strcat(opts, "rw"); + strcat_s(opts, _countof(opts), "rw"); } if (pflags & FILE_VOLUME_IS_COMPRESSED) { - strcat(opts, ",compressed"); + strcat_s(opts, _countof(opts), ",compressed"); } } if (strlen(opts) > 0) { - strcat(opts, ","); + strcat_s(opts, _countof(opts), ","); } - strcat(opts, psutil_get_drive_type(type)); + strcat_s(opts, _countof(opts), psutil_get_drive_type(type)); py_tuple = Py_BuildValue( "(ssss)", @@ -2621,14 +2501,6 @@ psutil_disk_partitions(PyObject *self, PyObject *args) return NULL; } - -#ifdef UNICODE -#define WTSOpenServer WTSOpenServerW -#else -#define WTSOpenServer WTSOpenServerA -#endif - - /* * Return a Python dict of tuples for disk I/O information */ @@ -2655,6 +2527,8 @@ psutil_users(PyObject *self, PyObject *args) PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; PyObject *py_address = NULL; + PyObject *py_buffer_user_encoded = NULL; + if (py_retlist == NULL) { return NULL; } @@ -2709,12 +2583,13 @@ psutil_users(PyObject *self, PyObject *args) address = (PWTS_CLIENT_ADDRESS)buffer_addr; if (address->AddressFamily == 0) { // AF_INET - sprintf(address_str, - "%u.%u.%u.%u", - address->Address[0], - address->Address[1], - address->Address[2], - address->Address[3]); + sprintf_s(address_str, + _countof(address_str), + "%u.%u.%u.%u", + address->Address[0], + address->Address[1], + address->Address[2], + address->Address[3]); py_address = Py_BuildValue("s", address_str); if (!py_address) goto error; @@ -2739,12 +2614,16 @@ psutil_users(PyObject *self, PyObject *args) station_info.ConnectTime.dwLowDateTime - 116444736000000000LL; unix_time /= 10000000; - py_tuple = Py_BuildValue("sOd", buffer_user, py_address, + py_buffer_user_encoded = PyUnicode_Decode( + buffer_user, _tcslen(buffer_user), Py_FileSystemDefaultEncoding, + "replace"); + py_tuple = Py_BuildValue("OOd", py_buffer_user_encoded, py_address, (double)unix_time); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; + Py_XDECREF(py_buffer_user_encoded); Py_XDECREF(py_address); Py_XDECREF(py_tuple); } @@ -2757,6 +2636,7 @@ psutil_users(PyObject *self, PyObject *args) return py_retlist; error: + Py_XDECREF(py_buffer_user_encoded); Py_XDECREF(py_tuple); Py_XDECREF(py_address); Py_DECREF(py_retlist); @@ -2790,9 +2670,8 @@ psutil_proc_num_handles(PyObject *self, PyObject *args) HANDLE hProcess; DWORD handleCount; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } hProcess = psutil_handle_from_pid(pid); if (NULL == hProcess) { return NULL; @@ -2807,75 +2686,102 @@ psutil_proc_num_handles(PyObject *self, PyObject *args) /* - * Alternative implementation of the one above but bypasses ACCESS DENIED. - */ -static PyObject * -psutil_proc_num_handles_2(PyObject *self, PyObject *args) -{ - DWORD pid; - PSYSTEM_PROCESS_INFORMATION process; - PVOID buffer; - ULONG count; - - if (! PyArg_ParseTuple(args, "l", &pid)) { - return NULL; - } - if (! psutil_get_proc_info(pid, &process, &buffer)) { - return NULL; - } - count = process->HandleCount; - free(buffer); - return Py_BuildValue("k", count); -} - - -/* - * Return the number of context switches executed by process. + * Get various process information by using NtQuerySystemInformation. + * We use this as a fallback when faster functions fail with access + * denied. This is slower because it iterates over all processes. + * Returned tuple includes the following process info: + * + * - num_threads + * - ctx_switches + * - num_handles (fallback) + * - user/kernel times (fallback) + * - create time (fallback) + * - io counters (fallback) */ static PyObject * -psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) +psutil_proc_info(PyObject *self, PyObject *args) { DWORD pid; PSYSTEM_PROCESS_INFORMATION process; PVOID buffer; + ULONG num_handles; ULONG i; - ULONG total = 0; + ULONG ctx_switches = 0; + double user_time; + double kernel_time; + long long create_time; + int num_threads; + LONGLONG io_rcount, io_wcount, io_rbytes, io_wbytes; - if (! PyArg_ParseTuple(args, "l", &pid)) { + + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (! psutil_get_proc_info(pid, &process, &buffer)) { + if (! psutil_get_proc_info(pid, &process, &buffer)) return NULL; + + num_handles = process->HandleCount; + for (i = 0; i < process->NumberOfThreads; i++) + ctx_switches += process->Threads[i].ContextSwitches; + user_time = (double)process->UserTime.HighPart * 429.4967296 + \ + (double)process->UserTime.LowPart * 1e-7; + kernel_time = (double)process->KernelTime.HighPart * 429.4967296 + \ + (double)process->KernelTime.LowPart * 1e-7; + // Convert the LARGE_INTEGER union to a Unix time. + // It's the best I could find by googling and borrowing code here + // and there. The time returned has a precision of 1 second. + if (0 == pid || 4 == pid) { + // the python module will translate this into BOOT_TIME later + create_time = 0; } - for (i = 0; i < process->NumberOfThreads; i++) { - total += process->Threads[i].ContextSwitches; - } + else { + create_time = ((LONGLONG)process->CreateTime.HighPart) << 32; + create_time += process->CreateTime.LowPart - 116444736000000000LL; + create_time /= 10000000; + } + num_threads = (int)process->NumberOfThreads; + io_rcount = process->ReadOperationCount.QuadPart; + io_wcount = process->WriteOperationCount.QuadPart; + io_rbytes = process->ReadTransferCount.QuadPart; + io_wbytes = process->WriteTransferCount.QuadPart; free(buffer); - return Py_BuildValue("ki", total, 0); + + return Py_BuildValue( + "kkdddiKKKK", + num_handles, + ctx_switches, + user_time, + kernel_time, + (double)create_time, + num_threads, + io_rcount, + io_wcount, + io_rbytes, + io_wbytes + ); } static char *get_region_protection_string(ULONG protection) { switch (protection & 0xff) { - case PAGE_NOACCESS: - return ""; - case PAGE_READONLY: - return "r"; - case PAGE_READWRITE: - return "rw"; - case PAGE_WRITECOPY: - return "wc"; - case PAGE_EXECUTE: - return "x"; - case PAGE_EXECUTE_READ: - return "xr"; - case PAGE_EXECUTE_READWRITE: - return "xrw"; - case PAGE_EXECUTE_WRITECOPY: - return "xwc"; - default: - return "?"; + case PAGE_NOACCESS: + return ""; + case PAGE_READONLY: + return "r"; + case PAGE_READWRITE: + return "rw"; + case PAGE_WRITECOPY: + return "wc"; + case PAGE_EXECUTE: + return "x"; + case PAGE_EXECUTE_READ: + return "xr"; + case PAGE_EXECUTE_READWRITE: + return "xrw"; + case PAGE_EXECUTE_WRITECOPY: + return "xwc"; + default: + return "?"; } } @@ -3000,6 +2906,273 @@ psutil_ppid_map(PyObject *self, PyObject *args) } +/* + * Return NICs addresses. + */ + +static PyObject * +psutil_net_if_addrs(PyObject *self, PyObject *args) +{ + unsigned int i = 0; + ULONG family; + PCTSTR intRet; + char *ptr; + char buff[100]; + char ifname[MAX_PATH]; + DWORD bufflen = 100; + PIP_ADAPTER_ADDRESSES pAddresses = NULL; + PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; + PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; + + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_address = NULL; + PyObject *py_mac_address = NULL; + + if (py_retlist == NULL) + return NULL; + + pAddresses = psutil_get_nic_addresses(); + if (pAddresses == NULL) + goto error; + pCurrAddresses = pAddresses; + + while (pCurrAddresses) { + pUnicast = pCurrAddresses->FirstUnicastAddress; + sprintf_s(ifname, MAX_PATH, "%wS", pCurrAddresses->FriendlyName); + + // MAC address + if (pCurrAddresses->PhysicalAddressLength != 0) { + ptr = buff; + *ptr = '\0'; + for (i = 0; i < (int) pCurrAddresses->PhysicalAddressLength; i++) { + if (i == (pCurrAddresses->PhysicalAddressLength - 1)) { + sprintf_s(ptr, _countof(buff), "%.2X\n", + (int)pCurrAddresses->PhysicalAddress[i]); + } + else { + sprintf_s(ptr, _countof(buff), "%.2X-", + (int)pCurrAddresses->PhysicalAddress[i]); + } + ptr += 3; + } + *--ptr = '\0'; + +#if PY_MAJOR_VERSION >= 3 + py_mac_address = PyUnicode_FromString(buff); +#else + py_mac_address = PyString_FromString(buff); +#endif + if (py_mac_address == NULL) + goto error; + + Py_INCREF(Py_None); + Py_INCREF(Py_None); + py_tuple = Py_BuildValue( + "(siOOO)", + ifname, + -1, // this will be converted later to AF_LINK + py_mac_address, + Py_None, + Py_None + ); + if (! py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + Py_DECREF(py_mac_address); + } + + // find out the IP address associated with the NIC + if (pUnicast != NULL) { + for (i = 0; pUnicast != NULL; i++) { + family = pUnicast->Address.lpSockaddr->sa_family; + if (family == AF_INET) { + struct sockaddr_in *sa_in = (struct sockaddr_in *) + pUnicast->Address.lpSockaddr; + intRet = inet_ntop(AF_INET, &(sa_in->sin_addr), buff, + bufflen); + } + else if (family == AF_INET6) { + struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *) + pUnicast->Address.lpSockaddr; + intRet = inet_ntop(AF_INET6, &(sa_in6->sin6_addr), + buff, bufflen); + } + else { + // we should never get here + pUnicast = pUnicast->Next; + continue; + } + + if (intRet == NULL) { + PyErr_SetFromWindowsErr(GetLastError()); + goto error; + } +#if PY_MAJOR_VERSION >= 3 + py_address = PyUnicode_FromString(buff); +#else + py_address = PyString_FromString(buff); +#endif + if (py_address == NULL) + goto error; + + Py_INCREF(Py_None); + Py_INCREF(Py_None); + py_tuple = Py_BuildValue( + "(siOOO)", + ifname, + family, + py_address, + Py_None, + Py_None + ); + + if (! py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + Py_DECREF(py_address); + + pUnicast = pUnicast->Next; + } + } + + pCurrAddresses = pCurrAddresses->Next; + } + + free(pAddresses); + return py_retlist; + +error: + if (pAddresses) + free(pAddresses); + Py_DECREF(py_retlist); + Py_XDECREF(py_tuple); + Py_XDECREF(py_address); + return NULL; +} + + +/* + * Provides stats about NIC interfaces installed on the system. + * TODO: get 'duplex' (currently it's hard coded to '2', aka + 'full duplex') + */ +static PyObject * +psutil_net_if_stats(PyObject *self, PyObject *args) +{ + int i; + DWORD dwSize = 0; + DWORD dwRetVal = 0; + MIB_IFTABLE *pIfTable; + MIB_IFROW *pIfRow; + PIP_ADAPTER_ADDRESSES pAddresses = NULL; + PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; + char friendly_name[MAX_PATH]; + char descr[MAX_PATH]; + int ifname_found; + + PyObject *py_retdict = PyDict_New(); + PyObject *py_ifc_info = NULL; + PyObject *py_is_up = NULL; + + if (py_retdict == NULL) + return NULL; + + pAddresses = psutil_get_nic_addresses(); + if (pAddresses == NULL) + goto error; + + pIfTable = (MIB_IFTABLE *) malloc(sizeof (MIB_IFTABLE)); + if (pIfTable == NULL) { + PyErr_NoMemory(); + goto error; + } + dwSize = sizeof(MIB_IFTABLE); + if (GetIfTable(pIfTable, &dwSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) { + free(pIfTable); + pIfTable = (MIB_IFTABLE *) malloc(dwSize); + if (pIfTable == NULL) { + PyErr_NoMemory(); + goto error; + } + } + // Make a second call to GetIfTable to get the actual + // data we want. + if ((dwRetVal = GetIfTable(pIfTable, &dwSize, FALSE)) != NO_ERROR) { + PyErr_SetString(PyExc_RuntimeError, "GetIfTable() failed"); + goto error; + } + + for (i = 0; i < (int) pIfTable->dwNumEntries; i++) { + pIfRow = (MIB_IFROW *) & pIfTable->table[i]; + + // GetIfTable is not able to give us NIC with "friendly names" + // so we determine them via GetAdapterAddresses() which + // provides friendly names *and* descriptions and find the + // ones that match. + ifname_found = 0; + pCurrAddresses = pAddresses; + while (pCurrAddresses) { + sprintf_s(descr, MAX_PATH, "%wS", pCurrAddresses->Description); + if (lstrcmp(descr, pIfRow->bDescr) == 0) { + sprintf_s(friendly_name, MAX_PATH, "%wS", pCurrAddresses->FriendlyName); + ifname_found = 1; + break; + } + pCurrAddresses = pCurrAddresses->Next; + } + if (ifname_found == 0) { + // Name not found means GetAdapterAddresses() doesn't list + // this NIC, only GetIfTable, meaning it's not really a NIC + // interface so we skip it. + continue; + } + + // is up? + if((pIfRow->dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED || + pIfRow->dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL) && + pIfRow->dwAdminStatus == 1 ) { + py_is_up = Py_True; + } + else { + py_is_up = Py_False; + } + Py_INCREF(py_is_up); + + py_ifc_info = Py_BuildValue( + "(Oikk)", + py_is_up, + 2, // there's no way to know duplex so let's assume 'full' + pIfRow->dwSpeed / 1000000, // expressed in bytes, we want Mb + pIfRow->dwMtu + ); + if (!py_ifc_info) + goto error; + if (PyDict_SetItemString(py_retdict, friendly_name, py_ifc_info)) + goto error; + Py_DECREF(py_ifc_info); + } + + free(pIfTable); + free(pAddresses); + return py_retdict; + +error: + Py_XDECREF(py_is_up); + Py_XDECREF(py_ifc_info); + Py_DECREF(py_retdict); + if (pIfTable != NULL) + free(pIfTable); + if (pAddresses != NULL) + free(pAddresses); + return NULL; +} + + // ------------------------ Python init --------------------------- static PyMethodDef @@ -3011,6 +3184,8 @@ PsutilMethods[] = "Return process cmdline as a list of cmdline arguments"}, {"proc_exe", psutil_proc_exe, METH_VARARGS, "Return path of the process executable"}, + {"proc_name", psutil_proc_name, METH_VARARGS, + "Return process name"}, {"proc_kill", psutil_proc_kill, METH_VARARGS, "Kill the process identified by the given PID"}, {"proc_cpu_times", psutil_proc_cpu_times, METH_VARARGS, @@ -3020,6 +3195,8 @@ PsutilMethods[] = "seconds since the epoch"}, {"proc_memory_info", psutil_proc_memory_info, METH_VARARGS, "Return a tuple of process memory information"}, + {"proc_memory_info_2", psutil_proc_memory_info_2, METH_VARARGS, + "Alternate implementation"}, {"proc_cwd", psutil_proc_cwd, METH_VARARGS, "Return process current working directory"}, {"proc_suspend", psutil_proc_suspend, METH_VARARGS, @@ -3030,8 +3207,6 @@ PsutilMethods[] = "Return files opened by process"}, {"proc_username", psutil_proc_username, METH_VARARGS, "Return the username of a process"}, - {"proc_num_threads", psutil_proc_num_threads, METH_VARARGS, - "Return the network connections of a process"}, {"proc_threads", psutil_proc_threads, METH_VARARGS, "Return process threads information as a list of tuple"}, {"proc_wait", psutil_proc_wait, METH_VARARGS, @@ -3056,22 +3231,12 @@ PsutilMethods[] = "Return True if one of the process threads is in a suspended state"}, {"proc_num_handles", psutil_proc_num_handles, METH_VARARGS, "Return the number of handles opened by process."}, - {"proc_num_ctx_switches", psutil_proc_num_ctx_switches, METH_VARARGS, - "Return the number of context switches performed by process."}, {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS, "Return a list of process's memory mappings"}, // --- alternative pinfo interface - {"proc_cpu_times_2", psutil_proc_cpu_times_2, METH_VARARGS, - "Alternative implementation"}, - {"proc_create_time_2", psutil_proc_create_time_2, METH_VARARGS, - "Alternative implementation"}, - {"proc_num_handles_2", psutil_proc_num_handles_2, METH_VARARGS, - "Alternative implementation"}, - {"proc_io_counters_2", psutil_proc_io_counters_2, METH_VARARGS, - "Alternative implementation"}, - {"proc_memory_info_2", psutil_proc_memory_info_2, METH_VARARGS, - "Alternative implementation"}, + {"proc_info", psutil_proc_info, METH_VARARGS, + "Various process information"}, // --- system-related functions {"pids", psutil_pids, METH_VARARGS, @@ -3104,7 +3269,10 @@ PsutilMethods[] = "Return disk partitions."}, {"net_connections", psutil_net_connections, METH_VARARGS, "Return system-wide connections"}, - + {"net_if_addrs", psutil_net_if_addrs, METH_VARARGS, + "Return NICs addresses."}, + {"net_if_stats", psutil_net_if_stats, METH_VARARGS, + "Return NICs stats."}, // --- windows API bindings {"win32_QueryDosDevice", psutil_win32_QueryDosDevice, METH_VARARGS, @@ -3176,6 +3344,8 @@ void init_psutil_windows(void) INITERROR; } + PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); + // process status constants // http://msdn.microsoft.com/en-us/library/ms683211(v=vs.85).aspx PyModule_AddIntConstant( diff --git a/python/psutil/psutil/_psutil_windows.h b/python/psutil/psutil/_psutil_windows.h index 546704e3cc9d..c77f64e9c330 100644 --- a/python/psutil/psutil/_psutil_windows.h +++ b/python/psutil/psutil/_psutil_windows.h @@ -13,22 +13,18 @@ static PyObject* psutil_proc_cmdline(PyObject* self, PyObject* args); static PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args); static PyObject* psutil_proc_cpu_affinity_set(PyObject* self, PyObject* args); static PyObject* psutil_proc_cpu_times(PyObject* self, PyObject* args); -static PyObject* psutil_proc_cpu_times_2(PyObject* self, PyObject* args); static PyObject* psutil_proc_create_time(PyObject* self, PyObject* args); -static PyObject* psutil_proc_create_time_2(PyObject* self, PyObject* args); static PyObject* psutil_proc_cwd(PyObject* self, PyObject* args); static PyObject* psutil_proc_exe(PyObject* self, PyObject* args); +static PyObject* psutil_proc_info(PyObject* self, PyObject* args); static PyObject* psutil_proc_io_counters(PyObject* self, PyObject* args); -static PyObject* psutil_proc_io_counters_2(PyObject* self, PyObject* args); static PyObject* psutil_proc_is_suspended(PyObject* self, PyObject* args); static PyObject* psutil_proc_kill(PyObject* self, PyObject* args); static PyObject* psutil_proc_memory_info(PyObject* self, PyObject* args); static PyObject* psutil_proc_memory_info_2(PyObject* self, PyObject* args); static PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args); -static PyObject* psutil_proc_num_ctx_switches(PyObject* self, PyObject* args); +static PyObject* psutil_proc_name(PyObject* self, PyObject* args); static PyObject* psutil_proc_num_handles(PyObject* self, PyObject* args); -static PyObject* psutil_proc_num_handles_2(PyObject* self, PyObject* args); -static PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args); static PyObject* psutil_proc_open_files(PyObject* self, PyObject* args); static PyObject* psutil_proc_priority_get(PyObject* self, PyObject* args); static PyObject* psutil_proc_priority_set(PyObject* self, PyObject* args); @@ -60,6 +56,8 @@ static PyObject* psutil_pids(PyObject* self, PyObject* args); static PyObject* psutil_ppid_map(PyObject* self, PyObject* args); static PyObject* psutil_users(PyObject* self, PyObject* args); static PyObject* psutil_virtual_mem(PyObject* self, PyObject* args); +static PyObject* psutil_net_if_addrs(PyObject* self, PyObject* args); +static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args); // --- windows API bindings diff --git a/python/psutil/psutil/_pswindows.py b/python/psutil/psutil/_pswindows.py index b540bdac2b2a..2d8babb19cfe 100644 --- a/python/psutil/psutil/_pswindows.py +++ b/python/psutil/psutil/_pswindows.py @@ -7,21 +7,35 @@ """Windows platform implementation.""" import errno +import functools import os import sys - -from psutil import _common -from psutil._common import conn_tmap, usage_percent, isfile_strict -from psutil._compat import PY3, xrange, wraps, lru_cache, namedtuple -import _psutil_windows as cext +from collections import namedtuple + +from . import _common +from . import _psutil_windows as cext +from ._common import conn_tmap, usage_percent, isfile_strict +from ._common import sockfam_to_enum, socktype_to_enum +from ._compat import PY3, xrange, lru_cache, long +from ._psutil_windows import (ABOVE_NORMAL_PRIORITY_CLASS, + BELOW_NORMAL_PRIORITY_CLASS, + HIGH_PRIORITY_CLASS, + IDLE_PRIORITY_CLASS, + NORMAL_PRIORITY_CLASS, + REALTIME_PRIORITY_CLASS) + +if sys.version_info >= (3, 4): + import enum +else: + enum = None # process priority constants, import from __init__.py: # http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx __extra__all__ = ["ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS", "HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS", "NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS", - # "CONN_DELETE_TCB", + "AF_LINK", ] # --- module level constants (gets pushed up to psutil module) @@ -30,6 +44,11 @@ WAIT_TIMEOUT = 0x00000102 # 258 in decimal ACCESS_DENIED_SET = frozenset([errno.EPERM, errno.EACCES, cext.ERROR_ACCESS_DENIED]) +if enum is None: + AF_LINK = -1 +else: + AddressFamily = enum.IntEnum('AddressFamily', {'AF_LINK': -1}) + AF_LINK = AddressFamily.AF_LINK TCP_STATUSES = { cext.MIB_TCP_STATE_ESTAB: _common.CONN_ESTABLISHED, @@ -47,6 +66,16 @@ cext.PSUTIL_CONN_NONE: _common.CONN_NONE, } +if enum is not None: + class Priority(enum.IntEnum): + ABOVE_NORMAL_PRIORITY_CLASS = ABOVE_NORMAL_PRIORITY_CLASS + BELOW_NORMAL_PRIORITY_CLASS = BELOW_NORMAL_PRIORITY_CLASS + HIGH_PRIORITY_CLASS = HIGH_PRIORITY_CLASS + IDLE_PRIORITY_CLASS = IDLE_PRIORITY_CLASS + NORMAL_PRIORITY_CLASS = NORMAL_PRIORITY_CLASS + REALTIME_PRIORITY_CLASS = REALTIME_PRIORITY_CLASS + + globals().update(Priority.__members__) scputimes = namedtuple('scputimes', ['user', 'system', 'idle']) svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free']) @@ -57,6 +86,10 @@ pmmap_grouped = namedtuple('pmmap_grouped', ['path', 'rss']) pmmap_ext = namedtuple( 'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields)) +ntpinfo = namedtuple( + 'ntpinfo', ['num_handles', 'ctx_switches', 'user_time', 'kernel_time', + 'create_time', 'num_threads', 'io_rcount', 'io_wcount', + 'io_rbytes', 'io_wbytes']) # set later from __init__.py NoSuchProcess = None @@ -166,15 +199,27 @@ def net_connections(kind, _pid=-1): % (kind, ', '.join([repr(x) for x in conn_tmap]))) families, types = conn_tmap[kind] rawlist = cext.net_connections(_pid, families, types) - ret = [] + ret = set() for item in rawlist: fd, fam, type, laddr, raddr, status, pid = item status = TCP_STATUSES[status] + fam = sockfam_to_enum(fam) + type = socktype_to_enum(type) if _pid == -1: nt = _common.sconn(fd, fam, type, laddr, raddr, status, pid) else: nt = _common.pconn(fd, fam, type, laddr, raddr, status) - ret.append(nt) + ret.add(nt) + return list(ret) + + +def net_if_stats(): + ret = cext.net_if_stats() + for name, items in ret.items(): + isup, duplex, speed, mtu = items + if hasattr(_common, 'NicDuplex'): + duplex = _common.NicDuplex(duplex) + ret[name] = _common.snicstats(isup, duplex, speed, mtu) return ret @@ -194,21 +239,21 @@ def users(): net_io_counters = cext.net_io_counters disk_io_counters = cext.disk_io_counters ppid_map = cext.ppid_map # not meant to be public +net_if_addrs = cext.net_if_addrs def wrap_exceptions(fun): """Decorator which translates bare OSError and WindowsError exceptions into NoSuchProcess and AccessDenied. """ - @wraps(fun) + @functools.wraps(fun) def wrapper(self, *args, **kwargs): try: return fun(self, *args, **kwargs) - except OSError: + except OSError as err: # support for private module import if NoSuchProcess is None or AccessDenied is None: raise - err = sys.exc_info()[1] if err.errno in ACCESS_DENIED_SET: raise AccessDenied(self.pid, self._name) if err.errno == errno.ESRCH: @@ -220,11 +265,12 @@ def wrapper(self, *args, **kwargs): class Process(object): """Wrapper class around underlying C implementation.""" - __slots__ = ["pid", "_name"] + __slots__ = ["pid", "_name", "_ppid"] def __init__(self, pid): self.pid = pid self._name = None + self._ppid = None @wrap_exceptions def name(self): @@ -238,7 +284,12 @@ def name(self): elif self.pid == 4: return "System" else: - return os.path.basename(self.exe()) + try: + # Note: this will fail with AD for most PIDs owned + # by another user but it's faster. + return os.path.basename(self.exe()) + except AccessDenied: + return cext.proc_name(self.pid) @wrap_exceptions def exe(self): @@ -265,9 +316,10 @@ def ppid(self): def _get_raw_meminfo(self): try: return cext.proc_memory_info(self.pid) - except OSError: - err = sys.exc_info()[1] + except OSError as err: if err.errno in ACCESS_DENIED_SET: + # TODO: the C ext can probably be refactored in order + # to get this from cext.proc_info() return cext.proc_memory_info_2(self.pid) raise @@ -287,10 +339,9 @@ def memory_info_ex(self): def memory_maps(self): try: raw = cext.proc_memory_maps(self.pid) - except OSError: + except OSError as err: # XXX - can't use wrap_exceptions decorator as we're # returning a generator; probably needs refactoring. - err = sys.exc_info()[1] if err.errno in ACCESS_DENIED_SET: raise AccessDenied(self.pid, self._name) if err.errno == errno.ESRCH: @@ -334,15 +385,14 @@ def create_time(self): return boot_time() try: return cext.proc_create_time(self.pid) - except OSError: - err = sys.exc_info()[1] + except OSError as err: if err.errno in ACCESS_DENIED_SET: - return cext.proc_create_time_2(self.pid) + return ntpinfo(*cext.proc_info(self.pid)).create_time raise @wrap_exceptions def num_threads(self): - return cext.proc_num_threads(self.pid) + return ntpinfo(*cext.proc_info(self.pid)).num_threads @wrap_exceptions def threads(self): @@ -357,10 +407,10 @@ def threads(self): def cpu_times(self): try: ret = cext.proc_cpu_times(self.pid) - except OSError: - err = sys.exc_info()[1] + except OSError as err: if err.errno in ACCESS_DENIED_SET: - ret = cext.proc_cpu_times_2(self.pid) + nt = ntpinfo(*cext.proc_info(self.pid)) + ret = (nt.user_time, nt.kernel_time) else: raise return _common.pcputimes(*ret) @@ -392,10 +442,10 @@ def open_files(self): # Convert the first part in the corresponding drive letter # (e.g. "C:\") by using Windows's QueryDosDevice() raw_file_names = cext.proc_open_files(self.pid) - for file in raw_file_names: - file = _convert_raw_path(file) - if isfile_strict(file) and file not in retlist: - ntuple = _common.popenfile(file, -1) + for _file in raw_file_names: + _file = _convert_raw_path(_file) + if isfile_strict(_file) and _file not in retlist: + ntuple = _common.popenfile(_file, -1) retlist.append(ntuple) return retlist @@ -405,7 +455,10 @@ def connections(self, kind='inet'): @wrap_exceptions def nice_get(self): - return cext.proc_priority_get(self.pid) + value = cext.proc_priority_get(self.pid) + if enum is not None: + value = Priority(value) + return value @wrap_exceptions def nice_set(self, value): @@ -431,10 +484,10 @@ def ionice_set(self, value, _): def io_counters(self): try: ret = cext.proc_io_counters(self.pid) - except OSError: - err = sys.exc_info()[1] + except OSError as err: if err.errno in ACCESS_DENIED_SET: - ret = cext.proc_io_counters_2(self.pid) + nt = ntpinfo(*cext.proc_info(self.pid)) + ret = (nt.io_rcount, nt.io_wcount, nt.io_rbytes, nt.io_wbytes) else: raise return _common.pio(*ret) @@ -449,7 +502,8 @@ def status(self): @wrap_exceptions def cpu_affinity_get(self): - from_bitmask = lambda x: [i for i in xrange(64) if (1 << i) & x] + def from_bitmask(x): + return [i for i in xrange(64) if (1 << i) & x] bitmask = cext.proc_cpu_affinity_get(self.pid) return from_bitmask(bitmask) @@ -469,7 +523,11 @@ def to_bitmask(l): allcpus = list(range(len(per_cpu_times()))) for cpu in value: if cpu not in allcpus: - raise ValueError("invalid CPU %r" % cpu) + if not isinstance(cpu, (int, long)): + raise TypeError( + "invalid CPU %r; an integer is required" % cpu) + else: + raise ValueError("invalid CPU %r" % cpu) bitmask = to_bitmask(value) cext.proc_cpu_affinity_set(self.pid, bitmask) @@ -478,13 +536,13 @@ def to_bitmask(l): def num_handles(self): try: return cext.proc_num_handles(self.pid) - except OSError: - err = sys.exc_info()[1] + except OSError as err: if err.errno in ACCESS_DENIED_SET: - return cext.proc_num_handles_2(self.pid) + return ntpinfo(*cext.proc_info(self.pid)).num_handles raise @wrap_exceptions def num_ctx_switches(self): - tupl = cext.proc_num_ctx_switches(self.pid) - return _common.pctxsw(*tupl) + ctx_switches = ntpinfo(*cext.proc_info(self.pid)).ctx_switches + # only voluntary ctx switches are supported + return _common.pctxsw(ctx_switches, 0) diff --git a/python/psutil/psutil/arch/bsd/process_info.c b/python/psutil/psutil/arch/bsd/process_info.c index 1c19556633a1..4d739240617f 100644 --- a/python/psutil/psutil/arch/bsd/process_info.c +++ b/python/psutil/psutil/arch/bsd/process_info.c @@ -128,9 +128,8 @@ char mib[3] = pid; // call with a null buffer first to determine if we need a buffer - if (sysctl(mib, 4, NULL, &size, NULL, 0) == -1) { + if (sysctl(mib, 4, NULL, &size, NULL, 0) == -1) return NULL; - } path = malloc(size); if (path == NULL) { @@ -213,14 +212,11 @@ psutil_get_arg_list(long pid) PyObject *retlist = Py_BuildValue("[]"); PyObject *item = NULL; - if (pid < 0) { + if (pid < 0) return retlist; - } - argstr = psutil_get_cmd_args(pid, &argsize); - if (argstr == NULL) { + if (argstr == NULL) goto error; - } // args are returned as a flattened string with \0 separators between // arguments add each string to the list then step forward to the next @@ -256,30 +252,14 @@ int psutil_pid_exists(long pid) { int kill_ret; - if (pid < 0) { - return 0; - } + if (pid < 0) + return 0; // if kill returns success of permission denied we know it's a valid PID kill_ret = kill(pid , 0); - if ((0 == kill_ret) || (EPERM == errno)) { + if ((0 == kill_ret) || (EPERM == errno)) return 1; - } - // otherwise return 0 for PID not found return 0; } - -/* - * Set exception to AccessDenied if pid exists else NoSuchProcess. - */ -int -psutil_raise_ad_or_nsp(pid) { - if (psutil_pid_exists(pid) == 0) { - NoSuchProcess(); - } - else { - AccessDenied(); - } -} diff --git a/python/psutil/psutil/arch/osx/process_info.c b/python/psutil/psutil/arch/osx/process_info.c index be8092efe78b..b6dd5bb93860 100644 --- a/python/psutil/psutil/arch/osx/process_info.c +++ b/python/psutil/psutil/arch/osx/process_info.c @@ -32,15 +32,12 @@ psutil_pid_exists(long pid) int kill_ret; // save some time if it's an invalid PID - if (pid < 0) { + if (pid < 0) return 0; - } - // if kill returns success of permission denied we know it's a valid PID kill_ret = kill(pid , 0); - if ( (0 == kill_ret) || (EPERM == errno) ) { + if ( (0 == kill_ret) || (EPERM == errno)) return 1; - } // otherwise return 0 for PID not found return 0; @@ -85,34 +82,29 @@ psutil_get_proc_list(kinfo_proc **procList, size_t *procCount) */ while (lim-- > 0) { size = 0; - if (sysctl((int *)mib3, 3, NULL, &size, NULL, 0) == -1) { + if (sysctl((int *)mib3, 3, NULL, &size, NULL, 0) == -1) return errno; - } - size2 = size + (size >> 3); // add some if (size2 > size) { ptr = malloc(size2); - if (ptr == NULL) { + if (ptr == NULL) ptr = malloc(size); - } else { + else size = size2; - } } else { ptr = malloc(size); } - if (ptr == NULL) { + if (ptr == NULL) return ENOMEM; - } if (sysctl((int *)mib3, 3, ptr, &size, NULL, 0) == -1) { err = errno; free(ptr); - if (err != ENOMEM) { + if (err != ENOMEM) return err; - } - - } else { + } + else { *procList = (kinfo_proc *)ptr; *procCount = size / sizeof(kinfo_proc); return 0; @@ -130,9 +122,8 @@ psutil_get_argmax() int mib[] = { CTL_KERN, KERN_ARGMAX }; size_t size = sizeof(argmax); - if (sysctl(mib, 2, &argmax, &size, NULL, 0) == 0) { + if (sysctl(mib, 2, &argmax, &size, NULL, 0) == 0) return argmax; - } return 0; } @@ -153,9 +144,8 @@ psutil_get_arg_list(long pid) PyObject *arglist = NULL; // special case for PID 0 (kernel_task) where cmdline cannot be fetched - if (pid == 0) { + if (pid == 0) return Py_BuildValue("[]"); - } // read argmax and allocate memory for argument space. argmax = psutil_get_argmax(); @@ -177,11 +167,10 @@ psutil_get_arg_list(long pid) if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) { if (EINVAL == errno) { // EINVAL == access denied OR nonexistent PID - if ( psutil_pid_exists(pid) ) { + if (psutil_pid_exists(pid)) AccessDenied(); - } else { + else NoSuchProcess(); - } } goto error; } @@ -201,9 +190,8 @@ psutil_get_arg_list(long pid) // skip ahead to the first argument for (; arg_ptr < arg_end; arg_ptr++) { - if (*arg_ptr != '\0') { + if (*arg_ptr != '\0') break; - } } // iterate through arguments diff --git a/python/psutil/psutil/arch/windows/inet_ntop.c b/python/psutil/psutil/arch/windows/inet_ntop.c new file mode 100644 index 000000000000..b9fffd1c1636 --- /dev/null +++ b/python/psutil/psutil/arch/windows/inet_ntop.c @@ -0,0 +1,41 @@ +#include "inet_ntop.h" + +// From: https://memset.wordpress.com/2010/10/09/inet_ntop-for-win32/ +PCSTR +WSAAPI +inet_ntop( + __in INT Family, + __in PVOID pAddr, + __out_ecount(StringBufSize) PSTR pStringBuf, + __in size_t StringBufSize + ) +{ + DWORD dwAddressLength = 0; + struct sockaddr_storage srcaddr; + struct sockaddr_in *srcaddr4 = (struct sockaddr_in*) &srcaddr; + struct sockaddr_in6 *srcaddr6 = (struct sockaddr_in6*) &srcaddr; + + memset(&srcaddr, 0, sizeof(struct sockaddr_storage)); + srcaddr.ss_family = Family; + + if (Family == AF_INET) + { + dwAddressLength = sizeof(struct sockaddr_in); + memcpy(&(srcaddr4->sin_addr), pAddr, sizeof(struct in_addr)); + } else if (Family == AF_INET6) + { + dwAddressLength = sizeof(struct sockaddr_in6); + memcpy(&(srcaddr6->sin6_addr), pAddr, sizeof(struct in6_addr)); + } else { + return NULL; + } + + if (WSAAddressToString((LPSOCKADDR) &srcaddr, + dwAddressLength, + 0, + pStringBuf, + (LPDWORD) &StringBufSize) != 0) { + return NULL; + } + return pStringBuf; +} \ No newline at end of file diff --git a/python/psutil/psutil/arch/windows/inet_ntop.h b/python/psutil/psutil/arch/windows/inet_ntop.h new file mode 100644 index 000000000000..0d97e28c88bf --- /dev/null +++ b/python/psutil/psutil/arch/windows/inet_ntop.h @@ -0,0 +1,10 @@ +#include + +PCSTR +WSAAPI +inet_ntop( + __in INT Family, + __in PVOID pAddr, + __out_ecount(StringBufSize) PSTR pStringBuf, + __in size_t StringBufSize +); \ No newline at end of file diff --git a/python/psutil/psutil/arch/windows/ntextapi.h b/python/psutil/psutil/arch/windows/ntextapi.h index 298c078004f7..d10432a3e3bf 100644 --- a/python/psutil/psutil/arch/windows/ntextapi.h +++ b/python/psutil/psutil/arch/windows/ntextapi.h @@ -3,6 +3,9 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ +#if !defined(__NTEXTAPI_H__) +#define __NTEXTAPI_H__ +#include typedef enum _KTHREAD_STATE { Initialized, @@ -63,23 +66,6 @@ typedef struct _CLIENT_ID { HANDLE UniqueThread; } CLIENT_ID, *PCLIENT_ID; - -typedef struct _UNICODE_STRING { - USHORT Length; - USHORT MaximumLength; - PWSTR Buffer; -} UNICODE_STRING, *PUNICODE_STRING; - -typedef struct _SYSTEM_TIMEOFDAY_INFORMATION { - LARGE_INTEGER BootTime; - LARGE_INTEGER CurrentTime; - LARGE_INTEGER TimeZoneBias; - ULONG TimeZoneId; - ULONG Reserved; - ULONGLONG BootTimeBias; - ULONGLONG SleepTimeBias; -} SYSTEM_TIMEOFDAY_INFORMATION, *PSYSTEM_TIMEOFDAY_INFORMATION; - typedef struct _SYSTEM_THREAD_INFORMATION { LARGE_INTEGER KernelTime; LARGE_INTEGER UserTime; @@ -108,7 +94,7 @@ typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION { ULONG_PTR Reserved4; } SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION; -typedef struct _SYSTEM_PROCESS_INFORMATION { +typedef struct _SYSTEM_PROCESS_INFORMATION2 { ULONG NextEntryOffset; ULONG NumberOfThreads; LARGE_INTEGER SpareLi1; @@ -143,31 +129,10 @@ typedef struct _SYSTEM_PROCESS_INFORMATION { LARGE_INTEGER WriteTransferCount; LARGE_INTEGER OtherTransferCount; SYSTEM_THREAD_INFORMATION Threads[1]; -} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; - - -// structures and enums from winternl.h (not available under mingw) -typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { - LARGE_INTEGER IdleTime; - LARGE_INTEGER KernelTime; - LARGE_INTEGER UserTime; - LARGE_INTEGER Reserved1[2]; - ULONG Reserved2; -} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, - *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; - +} SYSTEM_PROCESS_INFORMATION2, *PSYSTEM_PROCESS_INFORMATION2; -typedef enum _SYSTEM_INFORMATION_CLASS { - SystemBasicInformation = 0, - SystemPerformanceInformation = 2, - SystemTimeOfDayInformation = 3, - SystemProcessInformation = 5, - SystemProcessorPerformanceInformation = 8, - SystemInterruptInformation = 23, - SystemExceptionInformation = 33, - SystemRegistryQuotaInformation = 37, - SystemLookasideInformation = 45 -} SYSTEM_INFORMATION_CLASS; +#define SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION2 +#define PSYSTEM_PROCESS_INFORMATION PSYSTEM_PROCESS_INFORMATION2 // ================================================ @@ -186,32 +151,9 @@ typedef struct _WINSTATION_INFO { FILETIME CurrentTime; } WINSTATION_INFO, *PWINSTATION_INFO; -typedef enum _WINSTATIONINFOCLASS { - WinStationInformation = 8 -} WINSTATIONINFOCLASS; - typedef BOOLEAN (WINAPI * PWINSTATIONQUERYINFORMATIONW) (HANDLE,ULONG,WINSTATIONINFOCLASS,PVOID,ULONG,PULONG); -typedef struct _WINSTATIONINFORMATIONW { - BYTE Reserved2[70]; - ULONG LogonId; - BYTE Reserved3[1140]; -} WINSTATIONINFORMATIONW, *PWINSTATIONINFORMATIONW; - -// mingw support: -// http://www.koders.com/c/fid7C02CAE627C526914CDEB427405B51DF393A5EFA.aspx -#ifndef _INC_WTSAPI -typedef struct _WTS_CLIENT_ADDRESS { - DWORD AddressFamily; // AF_INET, AF_IPX, AF_NETBIOS, AF_UNSPEC - BYTE Address[20]; // client network address -} WTS_CLIENT_ADDRESS, * PWTS_CLIENT_ADDRESS; - -HANDLE WINAPI WTSOpenServerA(IN LPSTR pServerName); - -VOID WINAPI WTSCloseServer(IN HANDLE hServer); -#endif - /* * NtQueryInformationProcess code taken from @@ -235,16 +177,9 @@ typedef NTSTATUS (NTAPI *_NtSetInformationProcess)( DWORD ProcessInformationLength ); -typedef struct _PROCESS_BASIC_INFORMATION { - PVOID Reserved1; - PVOID PebBaseAddress; - PVOID Reserved2[2]; - ULONG_PTR UniqueProcessId; - PVOID Reserved3; -} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION; -typedef enum _PROCESSINFOCLASS { - ProcessBasicInformation, +typedef enum _PROCESSINFOCLASS2 { + _ProcessBasicInformation, ProcessQuotaLimits, ProcessIoCounters, ProcessVmCounters, @@ -270,7 +205,7 @@ typedef enum _PROCESSINFOCLASS { ProcessDeviceMap, ProcessSessionInformation, ProcessForegroundInformation, - ProcessWow64Information, + _ProcessWow64Information, /* added after XP+ */ ProcessImageFileName, ProcessLUIDDeviceMapsEnabled, @@ -284,4 +219,10 @@ typedef enum _PROCESSINFOCLASS { ProcessCookie, ProcessImageInformation, MaxProcessInfoClass -} PROCESSINFOCLASS; +} PROCESSINFOCLASS2; + +#define PROCESSINFOCLASS PROCESSINFOCLASS2 +#define ProcessBasicInformation _ProcessBasicInformation +#define ProcessWow64Information _ProcessWow64Information + +#endif // __NTEXTAPI_H__ diff --git a/python/psutil/psutil/arch/windows/process_handles.c b/python/psutil/psutil/arch/windows/process_handles.c index f7479e994a33..b3f480af54da 100644 --- a/python/psutil/psutil/arch/windows/process_handles.c +++ b/python/psutil/psutil/arch/windows/process_handles.c @@ -4,108 +4,22 @@ * found in the LICENSE file. * */ - -#ifndef UNICODE -#define UNICODE -#endif - -#include -#include -#include #include "process_handles.h" -#ifndef NT_SUCCESS -#define NT_SUCCESS(x) ((x) >= 0) -#endif -#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004 - -#define SystemHandleInformation 16 -#define ObjectBasicInformation 0 -#define ObjectNameInformation 1 -#define ObjectTypeInformation 2 - - -typedef LONG NTSTATUS; - -typedef struct _UNICODE_STRING { - USHORT Length; - USHORT MaximumLength; - PWSTR Buffer; -} UNICODE_STRING, *PUNICODE_STRING; - -typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)( - ULONG SystemInformationClass, - PVOID SystemInformation, - ULONG SystemInformationLength, - PULONG ReturnLength -); - -typedef NTSTATUS (NTAPI *_NtDuplicateObject)( - HANDLE SourceProcessHandle, - HANDLE SourceHandle, - HANDLE TargetProcessHandle, - PHANDLE TargetHandle, - ACCESS_MASK DesiredAccess, - ULONG Attributes, - ULONG Options -); - -typedef NTSTATUS (NTAPI *_NtQueryObject)( - HANDLE ObjectHandle, - ULONG ObjectInformationClass, - PVOID ObjectInformation, - ULONG ObjectInformationLength, - PULONG ReturnLength -); - -typedef struct _SYSTEM_HANDLE { - ULONG ProcessId; - BYTE ObjectTypeNumber; - BYTE Flags; - USHORT Handle; - PVOID Object; - ACCESS_MASK GrantedAccess; -} SYSTEM_HANDLE, *PSYSTEM_HANDLE; - -typedef struct _SYSTEM_HANDLE_INFORMATION { - ULONG HandleCount; - SYSTEM_HANDLE Handles[1]; -} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; - -typedef enum _POOL_TYPE { - NonPagedPool, - PagedPool, - NonPagedPoolMustSucceed, - DontUseThisType, - NonPagedPoolCacheAligned, - PagedPoolCacheAligned, - NonPagedPoolCacheAlignedMustS -} POOL_TYPE, *PPOOL_TYPE; - -typedef struct _OBJECT_TYPE_INFORMATION { - UNICODE_STRING Name; - ULONG TotalNumberOfObjects; - ULONG TotalNumberOfHandles; - ULONG TotalPagedPoolUsage; - ULONG TotalNonPagedPoolUsage; - ULONG TotalNamePoolUsage; - ULONG TotalHandleTableUsage; - ULONG HighWaterNumberOfObjects; - ULONG HighWaterNumberOfHandles; - ULONG HighWaterPagedPoolUsage; - ULONG HighWaterNonPagedPoolUsage; - ULONG HighWaterNamePoolUsage; - ULONG HighWaterHandleTableUsage; - ULONG InvalidAttributes; - GENERIC_MAPPING GenericMapping; - ULONG ValidAccess; - BOOLEAN SecurityRequired; - BOOLEAN MaintainHandleCount; - USHORT MaintainTypeList; - POOL_TYPE PoolType; - ULONG PagedPoolUsage; - ULONG NonPagedPoolUsage; -} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION; +static _NtQuerySystemInformation __NtQuerySystemInformation = NULL; +static _NtQueryObject __NtQueryObject = NULL; + +CRITICAL_SECTION g_cs; +BOOL g_initialized = FALSE; +NTSTATUS g_status; +HANDLE g_hFile = NULL; +HANDLE g_hEvtStart = NULL; +HANDLE g_hEvtFinish = NULL; +HANDLE g_hThread = NULL; +PUNICODE_STRING g_pNameBuffer = NULL; +ULONG g_dwSize = 0; +ULONG g_dwLength = 0; +PVOID g_fiber = NULL; PVOID @@ -114,224 +28,506 @@ GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName) return GetProcAddress(GetModuleHandleA(LibraryName), ProcName); } - PyObject * -psutil_get_open_files(long pid, HANDLE processHandle) +psutil_get_open_files(long dwPid, HANDLE hProcess) { - _NtQuerySystemInformation NtQuerySystemInformation = + OSVERSIONINFO osvi; + + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + + // Threaded version only works for Vista+ + if (osvi.dwMajorVersion >= 6) + return psutil_get_open_files_ntqueryobject(dwPid, hProcess); + else + return psutil_get_open_files_getmappedfilename(dwPid, hProcess); +} + +VOID +psutil_get_open_files_init(BOOL threaded) +{ + if (g_initialized == TRUE) + return; + + // Resolve the Windows API calls + __NtQuerySystemInformation = GetLibraryProcAddress("ntdll.dll", "NtQuerySystemInformation"); - _NtQueryObject NtQueryObject = - GetLibraryProcAddress("ntdll.dll", "NtQueryObject"); - - NTSTATUS status; - PSYSTEM_HANDLE_INFORMATION handleInfo; - ULONG handleInfoSize = 0x10000; - ULONG i; - ULONG fileNameLength; - PyObject *filesList = Py_BuildValue("[]"); - PyObject *arg = NULL; - PyObject *fileFromWchar = NULL; - - if (filesList == NULL) - return NULL; - - handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize); - if (handleInfo == NULL) { - Py_DECREF(filesList); - PyErr_NoMemory(); - return NULL; + __NtQueryObject = GetLibraryProcAddress("ntdll.dll", "NtQueryObject"); + + // Create events for signalling work between threads + if (threaded == TRUE) { + g_hEvtStart = CreateEvent(NULL, FALSE, FALSE, NULL); + g_hEvtFinish = CreateEvent(NULL, FALSE, FALSE, NULL); + InitializeCriticalSection(&g_cs); } - // NtQuerySystemInformation won't give us the correct buffer size, - // so we guess by doubling the buffer size. - while ((status = NtQuerySystemInformation( - SystemHandleInformation, - handleInfo, - handleInfoSize, - NULL - )) == STATUS_INFO_LENGTH_MISMATCH) + g_initialized = TRUE; +} + +PyObject * +psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess) +{ + NTSTATUS status; + PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL; + DWORD dwInfoSize = 0x10000; + DWORD dwRet = 0; + PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX hHandle = NULL; + DWORD i = 0; + BOOLEAN error = FALSE; + PyObject* pyListFiles = NULL; + PyObject* pyFilePath = NULL; + DWORD dwWait = 0; + + if (g_initialized == FALSE) + psutil_get_open_files_init(TRUE); + + // Due to the use of global variables, ensure only 1 call + // to psutil_get_open_files() is running + EnterCriticalSection(&g_cs); + + if (__NtQuerySystemInformation == NULL || + __NtQueryObject == NULL || + g_hEvtStart == NULL || + g_hEvtFinish == NULL) + { - handleInfo = (PSYSTEM_HANDLE_INFORMATION) \ - realloc(handleInfo, handleInfoSize *= 2); + PyErr_SetFromWindowsErr(0); + error = TRUE; + goto cleanup; + } + + // Py_BuildValue raises an exception if NULL is returned + pyListFiles = PyList_New(0); + if (pyListFiles == NULL) { + error = TRUE; + goto cleanup; } + do { + if (pHandleInfo != NULL) { + HeapFree(GetProcessHeap(), 0, pHandleInfo); + pHandleInfo = NULL; + } + + // NtQuerySystemInformation won't give us the correct buffer size, + // so we guess by doubling the buffer size. + dwInfoSize *= 2; + pHandleInfo = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + dwInfoSize); + + if (pHandleInfo == NULL) { + PyErr_NoMemory(); + error = TRUE; + goto cleanup; + } + } while ((status = __NtQuerySystemInformation( + SystemExtendedHandleInformation, + pHandleInfo, + dwInfoSize, + &dwRet)) == STATUS_INFO_LENGTH_MISMATCH); + // NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH if (!NT_SUCCESS(status)) { - Py_DECREF(filesList); - free(handleInfo); - return NULL; + PyErr_SetFromWindowsErr(HRESULT_FROM_NT(status)); + error = TRUE; + goto cleanup; } - for (i = 0; i < handleInfo->HandleCount; i++) { - SYSTEM_HANDLE handle = handleInfo->Handles[i]; - HANDLE dupHandle = NULL; - HANDLE mapHandle = NULL; - POBJECT_TYPE_INFORMATION objectTypeInfo = NULL; - PVOID objectNameInfo; - UNICODE_STRING objectName; - ULONG returnLength; - DWORD error = 0; - fileFromWchar = NULL; - arg = NULL; - - // Check if this handle belongs to the PID the user specified. - if (handle.ProcessId != pid) - continue; - - // Skip handles with the following access codes as the next call - // to NtDuplicateObject() or NtQueryObject() might hang forever. - if ((handle.GrantedAccess == 0x0012019f) - || (handle.GrantedAccess == 0x001a019f) - || (handle.GrantedAccess == 0x00120189) - || (handle.GrantedAccess == 0x00100000)) { - continue; - } + for (i = 0; i < pHandleInfo->NumberOfHandles; i++) { + hHandle = &pHandleInfo->Handles[i]; - if (!DuplicateHandle(processHandle, - handle.Handle, + // Check if this hHandle belongs to the PID the user specified. + if (hHandle->UniqueProcessId != (HANDLE)dwPid || + hHandle->ObjectTypeIndex != HANDLE_TYPE_FILE) + goto loop_cleanup; + + if (!DuplicateHandle(hProcess, + hHandle->HandleValue, GetCurrentProcess(), - &dupHandle, + &g_hFile, 0, TRUE, DUPLICATE_SAME_ACCESS)) - { - //printf("[%#x] Error: %d \n", handle.Handle, GetLastError()); - continue; - } - - - mapHandle = CreateFileMapping(dupHandle, - NULL, - PAGE_READONLY, - 0, - 0, - NULL); - if (mapHandle == NULL) { - error = GetLastError(); - if (error == ERROR_INVALID_HANDLE || error == ERROR_BAD_EXE_FORMAT) { - CloseHandle(dupHandle); - //printf("CreateFileMapping Error: %d\n", error); - continue; - } - } - CloseHandle(mapHandle); - - // Query the object type. - objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x1000); - if (!NT_SUCCESS(NtQueryObject( - dupHandle, - ObjectTypeInformation, - objectTypeInfo, - 0x1000, - NULL - ))) { - free(objectTypeInfo); - CloseHandle(dupHandle); - continue; + /* + printf("[%d] DuplicateHandle (%#x): %#x \n", + dwPid, + hHandle->HandleValue, + GetLastError()); + */ + goto loop_cleanup; } - objectNameInfo = malloc(0x1000); - if (!NT_SUCCESS(NtQueryObject( - dupHandle, - ObjectNameInformation, - objectNameInfo, - 0x1000, - &returnLength - ))) - { - // Reallocate the buffer and try again. - objectNameInfo = realloc(objectNameInfo, returnLength); - if (!NT_SUCCESS(NtQueryObject( - dupHandle, - ObjectNameInformation, - objectNameInfo, - returnLength, - NULL - ))) - { - // We have the type name, so just display that. + // Guess buffer size is MAX_PATH + 1 + g_dwLength = (MAX_PATH+1) * sizeof(WCHAR); + + do { + // Release any previously allocated buffer + if (g_pNameBuffer != NULL) { + HeapFree(GetProcessHeap(), 0, g_pNameBuffer); + g_pNameBuffer = NULL; + g_dwSize = 0; + } + + // NtQueryObject puts the required buffer size in g_dwLength + // WinXP edge case puts g_dwLength == 0, just skip this handle + if (g_dwLength == 0) + goto loop_cleanup; + + g_dwSize = g_dwLength; + if (g_dwSize > 0) { + g_pNameBuffer = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + g_dwSize); + + if (g_pNameBuffer == NULL) + goto loop_cleanup; + } + + dwWait = psutil_NtQueryObject(); + + // If the call does not return, skip this handle + if (dwWait != WAIT_OBJECT_0) + goto loop_cleanup; + + } while (g_status == STATUS_INFO_LENGTH_MISMATCH); + + // NtQueryObject stopped returning STATUS_INFO_LENGTH_MISMATCH + if (!NT_SUCCESS(g_status)) + goto loop_cleanup; + + // Convert to PyUnicode and append it to the return list + if (g_pNameBuffer->Length > 0) { + /* + printf("[%d] Filename (%#x) %#d bytes: %S\n", + dwPid, + hHandle->HandleValue, + g_pNameBuffer->Length, + g_pNameBuffer->Buffer); + */ + + pyFilePath = PyUnicode_FromWideChar(g_pNameBuffer->Buffer, + g_pNameBuffer->Length/2); + if (pyFilePath == NULL) { /* - printf( - "[%#x] %.*S: (could not get name)\n", - handle.Handle, - objectTypeInfo->Name.Length / 2, - objectTypeInfo->Name.Buffer - ); + printf("[%d] PyUnicode_FromWideChar (%#x): %#x \n", + dwPid, + hHandle->HandleValue, + GetLastError()); */ - free(objectTypeInfo); - free(objectNameInfo); - CloseHandle(dupHandle); - continue; + error = TRUE; + goto loop_cleanup; + } + if (PyList_Append(pyListFiles, pyFilePath)) { + /* + printf("[%d] PyList_Append (%#x): %#x \n", + dwPid, + hHandle->HandleValue, + GetLastError()); + */ + error = TRUE; + goto loop_cleanup; } } - // Cast our buffer into an UNICODE_STRING. - objectName = *(PUNICODE_STRING)objectNameInfo; +loop_cleanup: + Py_XDECREF(pyFilePath); + pyFilePath = NULL; + + if (g_pNameBuffer != NULL) + HeapFree(GetProcessHeap(), 0, g_pNameBuffer); + g_pNameBuffer = NULL; + g_dwSize = 0; + g_dwLength = 0; + + if (g_hFile != NULL) + CloseHandle(g_hFile); + g_hFile = NULL; + } + +cleanup: + if (g_pNameBuffer != NULL) + HeapFree(GetProcessHeap(), 0, g_pNameBuffer); + g_pNameBuffer = NULL; + g_dwSize = 0; + g_dwLength = 0; + + if (g_hFile != NULL) + CloseHandle(g_hFile); + g_hFile = NULL; + + if (pHandleInfo != NULL) + HeapFree(GetProcessHeap(), 0, pHandleInfo); + pHandleInfo = NULL; + + if (error) { + Py_XDECREF(pyListFiles); + pyListFiles = NULL; + } + + LeaveCriticalSection(&g_cs); + + return pyListFiles; +} + +DWORD +psutil_NtQueryObject() +{ + DWORD dwWait = 0; + + if (g_hThread == NULL) + g_hThread = CreateThread(NULL, + 0, + (LPTHREAD_START_ROUTINE)psutil_NtQueryObjectThread, + NULL, + 0, + NULL); + if (g_hThread == NULL) + return GetLastError(); + + // Signal the worker thread to start + SetEvent(g_hEvtStart); + + // Wait for the worker thread to finish + dwWait = WaitForSingleObject(g_hEvtFinish, NTQO_TIMEOUT); + + // If the thread hangs, kill it and cleanup + if (dwWait == WAIT_TIMEOUT) { + SuspendThread(g_hThread); + TerminateThread(g_hThread, 1); + WaitForSingleObject(g_hThread, INFINITE); + CloseHandle(g_hThread); + + // Cleanup Fiber + if (g_fiber != NULL) + DeleteFiber(g_fiber); + g_fiber = NULL; + + g_hThread = NULL; + } + + return dwWait; +} + +void +psutil_NtQueryObjectThread() +{ + // Prevent the thread stack from leaking when this + // thread gets terminated due to NTQueryObject hanging + g_fiber = ConvertThreadToFiber(NULL); + + // Loop infinitely waiting for work + while (TRUE) { + WaitForSingleObject(g_hEvtStart, INFINITE); + + g_status = __NtQueryObject(g_hFile, + ObjectNameInformation, + g_pNameBuffer, + g_dwSize, + &g_dwLength); + SetEvent(g_hEvtFinish); + } +} + +PyObject * +psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess) +{ + NTSTATUS status; + PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL; + DWORD dwInfoSize = 0x10000; + DWORD dwRet = 0; + PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX hHandle = NULL; + HANDLE hFile = NULL; + HANDLE hMap = NULL; + DWORD i = 0; + BOOLEAN error = FALSE; + PyObject* pyListFiles = NULL; + PyObject* pyFilePath = NULL; + ULONG dwSize = 0; + LPVOID pMem = NULL; + TCHAR pszFilename[MAX_PATH+1]; + + if (g_initialized == FALSE) + psutil_get_open_files_init(FALSE); + + if (__NtQuerySystemInformation == NULL || __NtQueryObject == NULL) { + PyErr_SetFromWindowsErr(0); + error = TRUE; + goto cleanup; + } + + // Py_BuildValue raises an exception if NULL is returned + pyListFiles = PyList_New(0); + if (pyListFiles == NULL) { + error = TRUE; + goto cleanup; + } + + do { + if (pHandleInfo != NULL) { + HeapFree(GetProcessHeap(), 0, pHandleInfo); + pHandleInfo = NULL; + } + + // NtQuerySystemInformation won't give us the correct buffer size, + // so we guess by doubling the buffer size. + dwInfoSize *= 2; + pHandleInfo = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + dwInfoSize); + + if (pHandleInfo == NULL) { + PyErr_NoMemory(); + error = TRUE; + goto cleanup; + } + } while ((status = __NtQuerySystemInformation( + SystemExtendedHandleInformation, + pHandleInfo, + dwInfoSize, + &dwRet)) == STATUS_INFO_LENGTH_MISMATCH); + + // NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH + if (!NT_SUCCESS(status)) { + PyErr_SetFromWindowsErr(HRESULT_FROM_NT(status)); + error = TRUE; + goto cleanup; + } + + for (i = 0; i < pHandleInfo->NumberOfHandles; i++) { + hHandle = &pHandleInfo->Handles[i]; + + // Check if this hHandle belongs to the PID the user specified. + if (hHandle->UniqueProcessId != (HANDLE)dwPid || + hHandle->ObjectTypeIndex != HANDLE_TYPE_FILE) + goto loop_cleanup; - // Print the information! - if (objectName.Length) + if (!DuplicateHandle(hProcess, + hHandle->HandleValue, + GetCurrentProcess(), + &hFile, + 0, + TRUE, + DUPLICATE_SAME_ACCESS)) { - // The object has a name. Make sure it is a file otherwise - // ignore it - fileNameLength = objectName.Length / 2; - if (wcscmp(objectTypeInfo->Name.Buffer, L"File") == 0) { - // printf("%.*S\n", objectName.Length / 2, objectName.Buffer); - fileFromWchar = PyUnicode_FromWideChar(objectName.Buffer, - fileNameLength); - if (fileFromWchar == NULL) - goto error_py_fun; -#if PY_MAJOR_VERSION >= 3 - arg = Py_BuildValue("N", - PyUnicode_AsUTF8String(fileFromWchar)); -#else - arg = Py_BuildValue("N", - PyUnicode_FromObject(fileFromWchar)); -#endif - if (!arg) - goto error_py_fun; - Py_XDECREF(fileFromWchar); - fileFromWchar = NULL; - if (PyList_Append(filesList, arg)) - goto error_py_fun; - Py_XDECREF(arg); - } /* - printf( - "[%#x] %.*S: %.*S\n", - handle.Handle, - objectTypeInfo->Name.Length / 2, - objectTypeInfo->Name.Buffer, - objectName.Length / 2, - objectName.Buffer - ); + printf("[%d] DuplicateHandle (%#x): %#x \n", + dwPid, + hHandle->HandleValue, + GetLastError()); */ + goto loop_cleanup; } - else - { - // Print something else. + + hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); + if (hMap == NULL) { /* - printf( - "[%#x] %.*S: (unnamed)\n", - handle.Handle, - objectTypeInfo->Name.Length / 2, - objectTypeInfo->Name.Buffer - ); + printf("[%d] CreateFileMapping (%#x): %#x \n", + dwPid, + hHandle->HandleValue, + GetLastError()); */ - ;; + goto loop_cleanup; } - free(objectTypeInfo); - free(objectNameInfo); - CloseHandle(dupHandle); + + pMem = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 1); + + if (pMem == NULL) { + /* + printf("[%d] MapViewOfFile (%#x): %#x \n", + dwPid, + hHandle->HandleValue, + GetLastError()); + */ + goto loop_cleanup; + } + + dwSize = GetMappedFileName(GetCurrentProcess(), pMem, pszFilename, MAX_PATH); + if (dwSize == 0) { + /* + printf("[%d] GetMappedFileName (%#x): %#x \n", + dwPid, + hHandle->HandleValue, + GetLastError()); + */ + goto loop_cleanup; + } + + pszFilename[dwSize] = '\0'; + /* + printf("[%d] Filename (%#x) %#d bytes: %S\n", + dwPid, + hHandle->HandleValue, + dwSize, + pszFilename); + */ + + pyFilePath = PyUnicode_FromWideChar(pszFilename, dwSize); + if (pyFilePath == NULL) { + /* + printf("[%d] PyUnicode_FromStringAndSize (%#x): %#x \n", + dwPid, + hHandle->HandleValue, + GetLastError()); + */ + error = TRUE; + goto loop_cleanup; + } + + if (PyList_Append(pyListFiles, pyFilePath)) { + /* + printf("[%d] PyList_Append (%#x): %#x \n", + dwPid, + hHandle->HandleValue, + GetLastError()); + */ + error = TRUE; + goto loop_cleanup; + } + +loop_cleanup: + Py_XDECREF(pyFilePath); + pyFilePath = NULL; + + if (pMem != NULL) + UnmapViewOfFile(pMem); + pMem = NULL; + + if (hMap != NULL) + CloseHandle(hMap); + hMap = NULL; + + if (hFile != NULL) + CloseHandle(hFile); + hFile = NULL; + + dwSize = 0; } - free(handleInfo); - CloseHandle(processHandle); - return filesList; - -error_py_fun: - Py_XDECREF(arg); - Py_XDECREF(fileFromWchar); - Py_DECREF(filesList); - return NULL; + +cleanup: + if (pMem != NULL) + UnmapViewOfFile(pMem); + pMem = NULL; + + if (hMap != NULL) + CloseHandle(hMap); + hMap = NULL; + + if (hFile != NULL) + CloseHandle(hFile); + hFile = NULL; + + if (pHandleInfo != NULL) + HeapFree(GetProcessHeap(), 0, pHandleInfo); + pHandleInfo = NULL; + + if (error) { + Py_XDECREF(pyListFiles); + pyListFiles = NULL; + } + + return pyListFiles; } diff --git a/python/psutil/psutil/arch/windows/process_handles.h b/python/psutil/psutil/arch/windows/process_handles.h index 342ce8fd26ad..4cf4023eccbf 100644 --- a/python/psutil/psutil/arch/windows/process_handles.h +++ b/python/psutil/psutil/arch/windows/process_handles.h @@ -4,7 +4,110 @@ * found in the LICENSE file. */ +#ifndef __PROCESS_HANDLES_H__ +#define __PROCESS_HANDLES_H__ + +#ifndef UNICODE +#define UNICODE +#endif + #include +#include #include +#include +#include +#include + + +#ifndef NT_SUCCESS +#define NT_SUCCESS(x) ((x) >= 0) +#endif + +#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004 +#define ObjectBasicInformation 0 +#define ObjectNameInformation 1 +#define ObjectTypeInformation 2 +#define HANDLE_TYPE_FILE 28 +#define NTQO_TIMEOUT 100 + +typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)( + ULONG SystemInformationClass, + PVOID SystemInformation, + ULONG SystemInformationLength, + PULONG ReturnLength +); + +typedef NTSTATUS (NTAPI *_NtQueryObject)( + HANDLE ObjectHandle, + ULONG ObjectInformationClass, + PVOID ObjectInformation, + ULONG ObjectInformationLength, + PULONG ReturnLength +); +// Undocumented FILE_INFORMATION_CLASS: FileNameInformation +static const SYSTEM_INFORMATION_CLASS SystemExtendedHandleInformation = (SYSTEM_INFORMATION_CLASS)64; + +typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX +{ + PVOID Object; + HANDLE UniqueProcessId; + HANDLE HandleValue; + ULONG GrantedAccess; + USHORT CreatorBackTraceIndex; + USHORT ObjectTypeIndex; + ULONG HandleAttributes; + ULONG Reserved; +} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX; + +typedef struct _SYSTEM_HANDLE_INFORMATION_EX +{ + ULONG_PTR NumberOfHandles; + ULONG_PTR Reserved; + SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1]; +} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX; + +typedef enum _POOL_TYPE { + NonPagedPool, + PagedPool, + NonPagedPoolMustSucceed, + DontUseThisType, + NonPagedPoolCacheAligned, + PagedPoolCacheAligned, + NonPagedPoolCacheAlignedMustS +} POOL_TYPE, *PPOOL_TYPE; + +typedef struct _OBJECT_TYPE_INFORMATION { + UNICODE_STRING Name; + ULONG TotalNumberOfObjects; + ULONG TotalNumberOfHandles; + ULONG TotalPagedPoolUsage; + ULONG TotalNonPagedPoolUsage; + ULONG TotalNamePoolUsage; + ULONG TotalHandleTableUsage; + ULONG HighWaterNumberOfObjects; + ULONG HighWaterNumberOfHandles; + ULONG HighWaterPagedPoolUsage; + ULONG HighWaterNonPagedPoolUsage; + ULONG HighWaterNamePoolUsage; + ULONG HighWaterHandleTableUsage; + ULONG InvalidAttributes; + GENERIC_MAPPING GenericMapping; + ULONG ValidAccess; + BOOLEAN SecurityRequired; + BOOLEAN MaintainHandleCount; + USHORT MaintainTypeList; + POOL_TYPE PoolType; + ULONG PagedPoolUsage; + ULONG NonPagedPoolUsage; +} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION; + +PVOID GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName); +VOID psutil_get_open_files_init(BOOL threaded); PyObject* psutil_get_open_files(long pid, HANDLE processHandle); +PyObject* psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess); +PyObject* psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess); +DWORD psutil_NtQueryObject(void); +void psutil_NtQueryObjectThread(void); + +#endif // __PROCESS_HANDLES_H__ diff --git a/python/psutil/psutil/arch/windows/process_info.c b/python/psutil/psutil/arch/windows/process_info.c index 8298b16c5af4..a59cce47a279 100644 --- a/python/psutil/psutil/arch/windows/process_info.c +++ b/python/psutil/psutil/arch/windows/process_info.c @@ -38,12 +38,10 @@ psutil_handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess) hProcess = OpenProcess(dwDesiredAccess, FALSE, pid); if (hProcess == NULL) { - if (GetLastError() == ERROR_INVALID_PARAMETER) { + if (GetLastError() == ERROR_INVALID_PARAMETER) NoSuchProcess(); - } - else { + else PyErr_SetFromWindowsErr(0); - } return NULL; } @@ -129,13 +127,10 @@ psutil_pid_is_running(DWORD pid) DWORD exitCode; // Special case for PID 0 System Idle Process - if (pid == 0) { + if (pid == 0) return 1; - } - - if (pid < 0) { + if (pid < 0) return 0; - } hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); @@ -183,10 +178,8 @@ psutil_pid_in_proclist(DWORD pid) DWORD i; proclist = psutil_get_pids(&numberOfReturnedPIDs); - if (NULL == proclist) { + if (proclist == NULL) return -1; - } - for (i = 0; i < numberOfReturnedPIDs; i++) { if (pid == proclist[i]) { free(proclist); @@ -205,13 +198,12 @@ int handlep_is_running(HANDLE hProcess) { DWORD dwCode; - if (NULL == hProcess) { + + if (NULL == hProcess) return 0; - } if (GetExitCodeProcess(hProcess, &dwCode)) { - if (dwCode == STILL_ACTIVE) { + if (dwCode == STILL_ACTIVE) return 1; - } } return 0; } @@ -236,10 +228,8 @@ psutil_get_arg_list(long pid) PyObject *argList = NULL; hProcess = psutil_handle_from_pid(pid); - if (hProcess == NULL) { + if (hProcess == NULL) return NULL; - } - pebAddress = psutil_get_peb_address(hProcess); // get the address of ProcessParameters @@ -367,7 +357,10 @@ const int STATUS_BUFFER_TOO_SMALL = 0xC0000023L; /* * Given a process PID and a PSYSTEM_PROCESS_INFORMATION structure - * fills the structure with process information. + * fills the structure with various process information by using + * NtQuerySystemInformation. + * We use this as a fallback when faster functions fail with access + * denied. This is slower because it iterates over all processes. * On success return 1, else 0 with Python exception already set. */ int @@ -419,9 +412,8 @@ psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess, goto error; } - if (bufferSize <= 0x20000) { + if (bufferSize <= 0x20000) initialBufferSize = bufferSize; - } process = PH_FIRST_PROCESS(buffer); do { diff --git a/python/psutil/psutil/arch/windows/process_info.h b/python/psutil/psutil/arch/windows/process_info.h index 9544f5d6676b..a44c4aced0ab 100644 --- a/python/psutil/psutil/arch/windows/process_info.h +++ b/python/psutil/psutil/arch/windows/process_info.h @@ -4,8 +4,13 @@ * found in the LICENSE file. */ +#if !defined(__PROCESS_INFO_H) +#define __PROCESS_INFO_H + #include #include +#include "security.h" +#include "ntextapi.h" DWORD* psutil_get_pids(DWORD *numberOfReturnedPIDs); HANDLE psutil_handle_from_pid(DWORD pid); @@ -15,3 +20,7 @@ int psutil_pid_in_proclist(DWORD pid); int psutil_pid_is_running(DWORD pid); PVOID psutil_get_peb_address(HANDLE ProcessHandle); PyObject* psutil_get_arg_list(long pid); +int psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess, + PVOID *retBuffer); + +#endif diff --git a/python/psutil/psutil/arch/windows/security.c b/python/psutil/psutil/arch/windows/security.c index a837dfe4e29b..3aabffd0cb01 100644 --- a/python/psutil/psutil/arch/windows/security.c +++ b/python/psutil/psutil/arch/windows/security.c @@ -18,9 +18,8 @@ HANDLE psutil_token_from_handle(HANDLE hProcess) { HANDLE hToken = NULL; - if (! OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) { + if (! OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) return PyErr_SetFromWindowsErr(0); - } return hToken; } @@ -50,10 +49,8 @@ psutil_has_system_privilege(HANDLE hProcess) { TOKEN_PRIVILEGES *tp = NULL; HANDLE hToken = psutil_token_from_handle(hProcess); - if (NULL == hToken) { + if (NULL == hToken) return -1; - } - // call GetTokenInformation first to get the buffer size if (! GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize)) { dwRetval = GetLastError(); @@ -140,14 +137,11 @@ psutil_set_privilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege) tpPrevious.PrivilegeCount = 1; tpPrevious.Privileges[0].Luid = luid; - if (bEnablePrivilege) { + if (bEnablePrivilege) tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED); - } - - else { + else tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes); - } AdjustTokenPrivileges( hToken, @@ -213,15 +207,12 @@ psutil_unset_se_debug() &hToken) ) { if (GetLastError() == ERROR_NO_TOKEN) { - if (! ImpersonateSelf(SecurityImpersonation)) { + if (! ImpersonateSelf(SecurityImpersonation)) return 0; - } - if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, - &hToken) - ) + &hToken)) { return 0; } @@ -229,9 +220,8 @@ psutil_unset_se_debug() } // now disable SeDebug - if (! psutil_set_privilege(hToken, SE_DEBUG_NAME, FALSE)) { + if (! psutil_set_privilege(hToken, SE_DEBUG_NAME, FALSE)) return 0; - } CloseHandle(hToken); return 1; diff --git a/python/psutil/setup.py b/python/psutil/setup.py index 277ef75b0b8b..4c42548ef3f2 100644 --- a/python/psutil/setup.py +++ b/python/psutil/setup.py @@ -22,8 +22,7 @@ def get_version(): INIT = os.path.join(HERE, 'psutil/__init__.py') - f = open(INIT, 'r') - try: + with open(INIT, 'r') as f: for line in f: if line.startswith('__version__'): ret = eval(line.strip().split(' = ')[1]) @@ -33,24 +32,28 @@ def get_version(): return ret else: raise ValueError("couldn't find version string") - finally: - f.close() def get_description(): README = os.path.join(HERE, 'README.rst') - f = open(README, 'r') - try: + with open(README, 'r') as f: return f.read() - finally: - f.close() + + +VERSION = get_version() +VERSION_MACRO = ('PSUTIL_VERSION', int(VERSION.replace('.', ''))) # POSIX if os.name == 'posix': + libraries = [] + if sys.platform.startswith("sunos"): + libraries.append('socket') + posix_extension = Extension( - '_psutil_posix', + 'psutil._psutil_posix', sources=['psutil/_psutil_posix.c'], + libraries=libraries, ) # Windows if sys.platform.startswith("win32"): @@ -60,25 +63,28 @@ def get_winver(): return '0x0%s' % ((maj * 100) + min) extensions = [Extension( - '_psutil_windows', + 'psutil._psutil_windows', sources=[ 'psutil/_psutil_windows.c', 'psutil/_psutil_common.c', 'psutil/arch/windows/process_info.c', 'psutil/arch/windows/process_handles.c', 'psutil/arch/windows/security.c', + 'psutil/arch/windows/inet_ntop.c', ], define_macros=[ + VERSION_MACRO, # be nice to mingw, see: # http://www.mingw.org/wiki/Use_more_recent_defined_functions ('_WIN32_WINNT', get_winver()), ('_AVAIL_WINVER_', get_winver()), + ('_CRT_SECURE_NO_WARNINGS', None), # see: https://github.com/giampaolo/psutil/issues/348 ('PSAPI_VERSION', 1), ], libraries=[ "psapi", "kernel32", "advapi32", "shell32", "netapi32", "iphlpapi", - "wtsapi32", + "wtsapi32", "ws2_32", ], # extra_compile_args=["/Z7"], # extra_link_args=["/DEBUG"] @@ -86,12 +92,13 @@ def get_winver(): # OS X elif sys.platform.startswith("darwin"): extensions = [Extension( - '_psutil_osx', + 'psutil._psutil_osx', sources=[ 'psutil/_psutil_osx.c', 'psutil/_psutil_common.c', 'psutil/arch/osx/process_info.c' ], + define_macros=[VERSION_MACRO], extra_link_args=[ '-framework', 'CoreFoundation', '-framework', 'IOKit' ], @@ -101,28 +108,31 @@ def get_winver(): # FreeBSD elif sys.platform.startswith("freebsd"): extensions = [Extension( - '_psutil_bsd', + 'psutil._psutil_bsd', sources=[ 'psutil/_psutil_bsd.c', 'psutil/_psutil_common.c', 'psutil/arch/bsd/process_info.c' ], + define_macros=[VERSION_MACRO], libraries=["devstat"]), posix_extension, ] # Linux elif sys.platform.startswith("linux"): extensions = [Extension( - '_psutil_linux', - sources=['psutil/_psutil_linux.c']), + 'psutil._psutil_linux', + sources=['psutil/_psutil_linux.c'], + define_macros=[VERSION_MACRO]), posix_extension, ] # Solaris elif sys.platform.lower().startswith('sunos'): extensions = [Extension( - '_psutil_sunos', + 'psutil._psutil_sunos', sources=['psutil/_psutil_sunos.c'], - libraries=['kstat', 'nsl'],), + define_macros=[VERSION_MACRO], + libraries=['kstat', 'nsl', 'socket']), posix_extension, ] else: @@ -132,14 +142,14 @@ def get_winver(): def main(): setup_args = dict( name='psutil', - version=get_version(), + version=VERSION, description=__doc__.replace('\n', '').strip(), long_description=get_description(), keywords=[ - 'ps', 'top', 'kill', 'free', 'lsof', 'netstat', 'nice', - 'tty', 'ionice', 'uptime', 'taskmgr', 'process', 'df', - 'iotop', 'iostat', 'ifconfig', 'taskset', 'who', 'pidof', - 'pmap', 'smem', 'monitoring', 'ulimit', 'prlimit', + 'ps', 'top', 'kill', 'free', 'lsof', 'netstat', 'nice', 'tty', + 'ionice', 'uptime', 'taskmgr', 'process', 'df', 'iotop', 'iostat', + 'ifconfig', 'taskset', 'who', 'pidof', 'pmap', 'smem', 'pstree', + 'monitoring', 'ulimit', 'prlimit', ], author='Giampaolo Rodola', author_email='g.rodola gmail com', @@ -166,8 +176,6 @@ def main(): 'Operating System :: POSIX', 'Programming Language :: C', 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.4', - 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', diff --git a/python/psutil/test/README b/python/psutil/test/README deleted file mode 100644 index 801f93d1dee5..000000000000 --- a/python/psutil/test/README +++ /dev/null @@ -1,15 +0,0 @@ -- The recommended way to run tests (also on Windows) is to cd into parent - directory and run: - - make test - -- If you're on Python < 2.7 unittest2 module must be installed first: - https://pypi.python.org/pypi/unittest2 - -- The main test script is test_psutil.py, which also imports platform-specific - _*.py scripts (which should be ignored). - -- test_memory_leaks.py looks for memory leaks into C extension modules and must - be run separately with: - - make memtest diff --git a/python/psutil/test/README.rst b/python/psutil/test/README.rst new file mode 100644 index 000000000000..3f2a468efd80 --- /dev/null +++ b/python/psutil/test/README.rst @@ -0,0 +1,21 @@ +- The recommended way to run tests (also on Windows) is to cd into parent + directory and run ``make test`` + +- Dependencies for running tests: + - python 2.6: ipaddress, mock, unittest2 + - python 2.7: ipaddress, mock + - python 3.2: ipaddress, mock + - python 3.3: ipaddress + - python >= 3.4: no deps required + +- The main test script is ``test_psutil.py``, which also imports platform-specific + ``_*.py`` scripts (which should be ignored). + +- ``test_memory_leaks.py`` looks for memory leaks into C extension modules and must + be run separately with ``make test-memleaks``. + +- To run tests on all supported Python version install tox (pip install tox) + then run ``tox``. + +- Every time a commit is pushed tests are automatically run on Travis: + https://travis-ci.org/giampaolo/psutil/ diff --git a/python/psutil/test/__init__.py b/python/psutil/test/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/python/psutil/test/_bsd.py b/python/psutil/test/_bsd.py index 59be49bf0f24..e4a3225d2083 100644 --- a/python/psutil/test/_bsd.py +++ b/python/psutil/test/_bsd.py @@ -8,15 +8,15 @@ """BSD specific tests. These are implicitly run by test_psutil.py.""" +import os import subprocess -import time import sys -import os +import time import psutil from psutil._compat import PY3 -from test_psutil import (TOLERANCE, sh, get_test_subprocess, which, +from test_psutil import (TOLERANCE, BSD, sh, get_test_subprocess, which, retry_before_failing, reap_children, unittest) @@ -50,6 +50,7 @@ def muse(field): return int(line.split()[1]) +@unittest.skipUnless(BSD, "not a BSD system") class BSDSpecificTestCase(unittest.TestCase): @classmethod @@ -106,6 +107,7 @@ def df(path): if abs(usage.used - used) > 10 * 1024 * 1024: self.fail("psutil=%s, df=%s" % (usage.used, used)) + @retry_before_failing() def test_memory_maps(self): out = sh('procstat -v %s' % self.pid) maps = psutil.Process(self.pid).memory_maps(grouped=False) @@ -120,6 +122,29 @@ def test_memory_maps(self): if not map.path.startswith('['): self.assertEqual(fields[10], map.path) + def test_exe(self): + out = sh('procstat -b %s' % self.pid) + self.assertEqual(psutil.Process(self.pid).exe(), + out.split('\n')[1].split()[-1]) + + def test_cmdline(self): + out = sh('procstat -c %s' % self.pid) + self.assertEqual(' '.join(psutil.Process(self.pid).cmdline()), + ' '.join(out.split('\n')[1].split()[2:])) + + def test_uids_gids(self): + out = sh('procstat -s %s' % self.pid) + euid, ruid, suid, egid, rgid, sgid = out.split('\n')[1].split()[2:8] + p = psutil.Process(self.pid) + uids = p.uids() + gids = p.gids() + self.assertEqual(uids.real, int(ruid)) + self.assertEqual(uids.effective, int(euid)) + self.assertEqual(uids.saved, int(suid)) + self.assertEqual(gids.real, int(rgid)) + self.assertEqual(gids.effective, int(egid)) + self.assertEqual(gids.saved, int(sgid)) + # --- virtual_memory(); tests against sysctl def test_vmem_total(self): @@ -162,6 +187,10 @@ def test_vmem_buffers(self): self.assertAlmostEqual(psutil.virtual_memory().buffers, syst, delta=TOLERANCE) + def test_cpu_count_logical(self): + syst = sysctl("hw.ncpu") + self.assertEqual(psutil.cpu_count(logical=True), syst) + # --- virtual_memory(); tests against muse @unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available") @@ -212,12 +241,12 @@ def test_buffers(self): delta=TOLERANCE) -def test_main(): +def main(): test_suite = unittest.TestSuite() test_suite.addTest(unittest.makeSuite(BSDSpecificTestCase)) result = unittest.TextTestRunner(verbosity=2).run(test_suite) return result.wasSuccessful() if __name__ == '__main__': - if not test_main(): + if not main(): sys.exit(1) diff --git a/python/psutil/test/_linux.py b/python/psutil/test/_linux.py index 77f6da273280..c1927ea8b268 100644 --- a/python/psutil/test/_linux.py +++ b/python/psutil/test/_linux.py @@ -7,18 +7,70 @@ """Linux specific tests. These are implicitly run by test_psutil.py.""" from __future__ import division +import contextlib +import errno +import fcntl +import io import os +import pprint import re +import socket +import struct import sys +import tempfile import time +import warnings -from test_psutil import POSIX, TOLERANCE, TRAVIS +try: + from unittest import mock # py3 +except ImportError: + import mock # requires "pip install mock" + +from test_psutil import POSIX, TOLERANCE, TRAVIS, LINUX from test_psutil import (skip_on_not_implemented, sh, get_test_subprocess, - retry_before_failing, get_kernel_version, unittest) + retry_before_failing, get_kernel_version, unittest, + which, call_until) import psutil +import psutil._pslinux +from psutil._compat import PY3, u + + +SIOCGIFADDR = 0x8915 +SIOCGIFCONF = 0x8912 +SIOCGIFHWADDR = 0x8927 + + +def get_ipv4_address(ifname): + ifname = ifname[:15] + if PY3: + ifname = bytes(ifname, 'ascii') + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + with contextlib.closing(s): + return socket.inet_ntoa( + fcntl.ioctl(s.fileno(), + SIOCGIFADDR, + struct.pack('256s', ifname))[20:24]) + + +def get_mac_address(ifname): + ifname = ifname[:15] + if PY3: + ifname = bytes(ifname, 'ascii') + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + with contextlib.closing(s): + info = fcntl.ioctl( + s.fileno(), SIOCGIFHWADDR, struct.pack('256s', ifname)) + if PY3: + def ord(x): + return x + else: + import __builtin__ + ord = __builtin__.ord + return ''.join(['%02x:' % ord(char) for char in info[18:24]])[:-1] +@unittest.skipUnless(LINUX, "not a Linux system") class LinuxSpecificTestCase(unittest.TestCase): @unittest.skipIf( @@ -139,6 +191,241 @@ def test_cpu_times(self): else: self.assertNotIn('guest_nice', fields) + def test_net_if_addrs_ips(self): + for name, addrs in psutil.net_if_addrs().items(): + for addr in addrs: + if addr.family == psutil.AF_LINK: + self.assertEqual(addr.address, get_mac_address(name)) + elif addr.family == socket.AF_INET: + self.assertEqual(addr.address, get_ipv4_address(name)) + # TODO: test for AF_INET6 family + + @unittest.skipUnless(which('ip'), "'ip' utility not available") + @unittest.skipIf(TRAVIS, "skipped on Travis") + def test_net_if_names(self): + out = sh("ip addr").strip() + nics = psutil.net_if_addrs() + found = 0 + for line in out.split('\n'): + line = line.strip() + if re.search("^\d+:", line): + found += 1 + name = line.split(':')[1].strip() + self.assertIn(name, nics.keys()) + self.assertEqual(len(nics), found, msg="%s\n---\n%s" % ( + pprint.pformat(nics), out)) + + @unittest.skipUnless(which("nproc"), "nproc utility not available") + def test_cpu_count_logical_w_nproc(self): + num = int(sh("nproc --all")) + self.assertEqual(psutil.cpu_count(logical=True), num) + + @unittest.skipUnless(which("lscpu"), "lscpu utility not available") + def test_cpu_count_logical_w_lscpu(self): + out = sh("lscpu -p") + num = len([x for x in out.split('\n') if not x.startswith('#')]) + self.assertEqual(psutil.cpu_count(logical=True), num) + + # --- mocked tests + + def test_virtual_memory_mocked_warnings(self): + with mock.patch('psutil._pslinux.open', create=True) as m: + with warnings.catch_warnings(record=True) as ws: + warnings.simplefilter("always") + ret = psutil._pslinux.virtual_memory() + assert m.called + self.assertEqual(len(ws), 1) + w = ws[0] + self.assertTrue(w.filename.endswith('psutil/_pslinux.py')) + self.assertIn( + "'cached', 'active' and 'inactive' memory stats couldn't " + "be determined", str(w.message)) + self.assertEqual(ret.cached, 0) + self.assertEqual(ret.active, 0) + self.assertEqual(ret.inactive, 0) + + def test_swap_memory_mocked_warnings(self): + with mock.patch('psutil._pslinux.open', create=True) as m: + with warnings.catch_warnings(record=True) as ws: + warnings.simplefilter("always") + ret = psutil._pslinux.swap_memory() + assert m.called + self.assertEqual(len(ws), 1) + w = ws[0] + self.assertTrue(w.filename.endswith('psutil/_pslinux.py')) + self.assertIn( + "'sin' and 'sout' swap memory stats couldn't " + "be determined", str(w.message)) + self.assertEqual(ret.sin, 0) + self.assertEqual(ret.sout, 0) + + def test_cpu_count_logical_mocked(self): + import psutil._pslinux + original = psutil._pslinux.cpu_count_logical() + # Here we want to mock os.sysconf("SC_NPROCESSORS_ONLN") in + # order to cause the parsing of /proc/cpuinfo and /proc/stat. + with mock.patch( + 'psutil._pslinux.os.sysconf', side_effect=ValueError) as m: + self.assertEqual(psutil._pslinux.cpu_count_logical(), original) + assert m.called + + # Let's have open() return emtpy data and make sure None is + # returned ('cause we mimick os.cpu_count()). + with mock.patch('psutil._pslinux.open', create=True) as m: + self.assertIsNone(psutil._pslinux.cpu_count_logical()) + self.assertEqual(m.call_count, 2) + # /proc/stat should be the last one + self.assertEqual(m.call_args[0][0], '/proc/stat') + + # Let's push this a bit further and make sure /proc/cpuinfo + # parsing works as expected. + with open('/proc/cpuinfo', 'rb') as f: + cpuinfo_data = f.read() + fake_file = io.BytesIO(cpuinfo_data) + with mock.patch('psutil._pslinux.open', + return_value=fake_file, create=True) as m: + self.assertEqual(psutil._pslinux.cpu_count_logical(), original) + + def test_cpu_count_physical_mocked(self): + # Have open() return emtpy data and make sure None is returned + # ('cause we want to mimick os.cpu_count()) + with mock.patch('psutil._pslinux.open', create=True) as m: + self.assertIsNone(psutil._pslinux.cpu_count_physical()) + assert m.called + + def test_proc_open_files_file_gone(self): + # simulates a file which gets deleted during open_files() + # execution + p = psutil.Process() + files = p.open_files() + with tempfile.NamedTemporaryFile(): + # give the kernel some time to see the new file + call_until(p.open_files, "len(ret) != %i" % len(files)) + with mock.patch('psutil._pslinux.os.readlink', + side_effect=OSError(errno.ENOENT, "")) as m: + files = p.open_files() + assert not files + assert m.called + # also simulate the case where os.readlink() returns EINVAL + # in which case psutil is supposed to 'continue' + with mock.patch('psutil._pslinux.os.readlink', + side_effect=OSError(errno.EINVAL, "")) as m: + self.assertEqual(p.open_files(), []) + assert m.called + + def test_proc_terminal_mocked(self): + with mock.patch('psutil._pslinux._psposix._get_terminal_map', + return_value={}) as m: + self.assertIsNone(psutil._pslinux.Process(os.getpid()).terminal()) + assert m.called + + def test_proc_num_ctx_switches_mocked(self): + with mock.patch('psutil._pslinux.open', create=True) as m: + self.assertRaises( + NotImplementedError, + psutil._pslinux.Process(os.getpid()).num_ctx_switches) + assert m.called + + def test_proc_num_threads_mocked(self): + with mock.patch('psutil._pslinux.open', create=True) as m: + self.assertRaises( + NotImplementedError, + psutil._pslinux.Process(os.getpid()).num_threads) + assert m.called + + def test_proc_ppid_mocked(self): + with mock.patch('psutil._pslinux.open', create=True) as m: + self.assertRaises( + NotImplementedError, + psutil._pslinux.Process(os.getpid()).ppid) + assert m.called + + def test_proc_uids_mocked(self): + with mock.patch('psutil._pslinux.open', create=True) as m: + self.assertRaises( + NotImplementedError, + psutil._pslinux.Process(os.getpid()).uids) + assert m.called + + def test_proc_gids_mocked(self): + with mock.patch('psutil._pslinux.open', create=True) as m: + self.assertRaises( + NotImplementedError, + psutil._pslinux.Process(os.getpid()).gids) + assert m.called + + def test_proc_cmdline_mocked(self): + # see: https://github.com/giampaolo/psutil/issues/639 + p = psutil.Process() + fake_file = io.StringIO(u('foo\x00bar\x00')) + with mock.patch('psutil._pslinux.open', + return_value=fake_file, create=True) as m: + p.cmdline() == ['foo', 'bar'] + assert m.called + fake_file = io.StringIO(u('foo\x00bar\x00\x00')) + with mock.patch('psutil._pslinux.open', + return_value=fake_file, create=True) as m: + p.cmdline() == ['foo', 'bar', ''] + assert m.called + + def test_proc_io_counters_mocked(self): + with mock.patch('psutil._pslinux.open', create=True) as m: + self.assertRaises( + NotImplementedError, + psutil._pslinux.Process(os.getpid()).io_counters) + assert m.called + + def test_boot_time_mocked(self): + with mock.patch('psutil._pslinux.open', create=True) as m: + self.assertRaises( + RuntimeError, + psutil._pslinux.boot_time) + assert m.called + + def test_users_mocked(self): + # Make sure ':0' and ':0.0' (returned by C ext) are converted + # to 'localhost'. + with mock.patch('psutil._pslinux.cext.users', + return_value=[('giampaolo', 'pts/2', ':0', + 1436573184.0, True)]) as m: + self.assertEqual(psutil.users()[0].host, 'localhost') + assert m.called + with mock.patch('psutil._pslinux.cext.users', + return_value=[('giampaolo', 'pts/2', ':0.0', + 1436573184.0, True)]) as m: + self.assertEqual(psutil.users()[0].host, 'localhost') + assert m.called + # ...otherwise it should be returned as-is + with mock.patch('psutil._pslinux.cext.users', + return_value=[('giampaolo', 'pts/2', 'foo', + 1436573184.0, True)]) as m: + self.assertEqual(psutil.users()[0].host, 'foo') + assert m.called + + def test_disk_partitions_mocked(self): + # Test that ZFS partitions are returned. + with open("/proc/filesystems", "r") as f: + data = f.read() + if 'zfs' in data: + for part in psutil.disk_partitions(): + if part.fstype == 'zfs': + break + else: + self.fail("couldn't find any ZFS partition") + else: + # No ZFS partitions on this system. Let's fake one. + fake_file = io.StringIO(u("nodev\tzfs\n")) + with mock.patch('psutil._pslinux.open', + return_value=fake_file, create=True) as m1: + with mock.patch( + 'psutil._pslinux.cext.disk_partitions', + return_value=[('/dev/sdb3', '/', 'zfs', 'rw')]) as m2: + ret = psutil.disk_partitions() + assert m1.called + assert m2.called + assert ret + self.assertEqual(ret[0].fstype, 'zfs') + # --- tests for specific kernel versions @unittest.skipUnless( @@ -175,12 +462,12 @@ def test_resource_consts_kernel_v(self): self.assertTrue(hasattr(psutil, "RLIMIT_SIGPENDING")) -def test_main(): +def main(): test_suite = unittest.TestSuite() test_suite.addTest(unittest.makeSuite(LinuxSpecificTestCase)) result = unittest.TextTestRunner(verbosity=2).run(test_suite) return result.wasSuccessful() if __name__ == '__main__': - if not test_main(): + if not main(): sys.exit(1) diff --git a/python/psutil/test/_osx.py b/python/psutil/test/_osx.py index 784f00e07354..6e6e4380ef03 100644 --- a/python/psutil/test/_osx.py +++ b/python/psutil/test/_osx.py @@ -15,8 +15,8 @@ import psutil from psutil._compat import PY3 -from test_psutil import (TOLERANCE, sh, get_test_subprocess, reap_children, - retry_before_failing, unittest) +from test_psutil import (TOLERANCE, OSX, sh, get_test_subprocess, + reap_children, retry_before_failing, unittest) PAGESIZE = os.sysconf("SC_PAGE_SIZE") @@ -47,6 +47,7 @@ def vm_stat(field): return int(re.search('\d+', line).group(0)) * PAGESIZE +@unittest.skipUnless(OSX, "not an OSX system") class OSXSpecificTestCase(unittest.TestCase): @classmethod @@ -148,12 +149,12 @@ def test_swapmem_total(self): self.assertEqual(tot1, tot2) -def test_main(): +def main(): test_suite = unittest.TestSuite() test_suite.addTest(unittest.makeSuite(OSXSpecificTestCase)) result = unittest.TextTestRunner(verbosity=2).run(test_suite) return result.wasSuccessful() if __name__ == '__main__': - if not test_main(): + if not main(): sys.exit(1) diff --git a/python/psutil/test/_posix.py b/python/psutil/test/_posix.py index 8cbd629a5cac..e6c56aac3e60 100644 --- a/python/psutil/test/_posix.py +++ b/python/psutil/test/_posix.py @@ -14,8 +14,8 @@ import psutil -from psutil._compat import PY3 -from test_psutil import LINUX, SUNOS, OSX, BSD, PYTHON +from psutil._compat import PY3, callable +from test_psutil import LINUX, SUNOS, OSX, BSD, PYTHON, POSIX, TRAVIS from test_psutil import (get_test_subprocess, skip_on_access_denied, retry_before_failing, reap_children, sh, unittest, get_kernel_version, wait_for_pid) @@ -42,6 +42,7 @@ def ps(cmd): return output +@unittest.skipUnless(POSIX, "not a POSIX system") class PosixSpecificTestCase(unittest.TestCase): """Compare psutil results against 'ps' command line utility.""" @@ -111,11 +112,14 @@ def test_process_name(self): def test_process_create_time(self): time_ps = ps("ps --no-headers -o start -p %s" % self.pid).split(' ')[0] time_psutil = psutil.Process(self.pid).create_time() - if SUNOS: - time_psutil = round(time_psutil) time_psutil_tstamp = datetime.datetime.fromtimestamp( time_psutil).strftime("%H:%M:%S") - self.assertEqual(time_ps, time_psutil_tstamp) + # sometimes ps shows the time rounded up instead of down, so we check + # for both possible values + round_time_psutil = round(time_psutil) + round_time_psutil_tstamp = datetime.datetime.fromtimestamp( + round_time_psutil).strftime("%H:%M:%S") + self.assertIn(time_ps, [time_psutil_tstamp, round_time_psutil_tstamp]) def test_process_exe(self): ps_pathname = ps("ps --no-headers -o command -p %s" % @@ -173,9 +177,10 @@ def test_pids(self): [x for x in pids_ps if x not in pids_psutil] self.fail("difference: " + str(difference)) - # for some reason ifconfig -a does not report differente interfaces - # psutil does + # for some reason ifconfig -a does not report all interfaces + # returned by psutil @unittest.skipIf(SUNOS, "test not reliable on SUNOS") + @unittest.skipIf(TRAVIS, "test not reliable on Travis") def test_nic_names(self): p = subprocess.Popen("ifconfig -a", shell=1, stdout=subprocess.PIPE) output = p.communicate()[0].strip() @@ -186,7 +191,9 @@ def test_nic_names(self): if line.startswith(nic): break else: - self.fail("couldn't find %s nic in 'ifconfig -a' output" % nic) + self.fail( + "couldn't find %s nic in 'ifconfig -a' output\n%s" % ( + nic, output)) @retry_before_failing() def test_users(self): @@ -208,8 +215,6 @@ def call(p, attr): if attr is not None and callable(attr): if name == 'rlimit': args = (psutil.RLIMIT_NOFILE,) - elif name == 'set_rlimit': - args = (psutil.RLIMIT_NOFILE, (5, 5)) attr(*args) else: attr @@ -220,11 +225,10 @@ def call(p, attr): 'send_signal', 'wait', 'children', 'as_dict'] if LINUX and get_kernel_version() < (2, 6, 36): ignored_names.append('rlimit') + if LINUX and get_kernel_version() < (2, 6, 23): + ignored_names.append('num_ctx_switches') for name in dir(psutil.Process): - if (name.startswith('_') - or name.startswith('set_') - or name.startswith('get') # deprecated APIs - or name in ignored_names): + if (name.startswith('_') or name in ignored_names): continue else: try: @@ -243,12 +247,12 @@ def call(p, attr): self.fail('\n' + '\n'.join(failures)) -def test_main(): +def main(): test_suite = unittest.TestSuite() test_suite.addTest(unittest.makeSuite(PosixSpecificTestCase)) result = unittest.TextTestRunner(verbosity=2).run(test_suite) return result.wasSuccessful() if __name__ == '__main__': - if not test_main(): + if not main(): sys.exit(1) diff --git a/python/psutil/test/_sunos.py b/python/psutil/test/_sunos.py index 7fdc50b6c0b4..3d54ccd8cfb5 100644 --- a/python/psutil/test/_sunos.py +++ b/python/psutil/test/_sunos.py @@ -7,15 +7,17 @@ """Sun OS specific tests. These are implicitly run by test_psutil.py.""" import sys +import os -from test_psutil import sh, unittest +from test_psutil import SUNOS, sh, unittest import psutil +@unittest.skipUnless(SUNOS, "not a SunOS system") class SunOSSpecificTestCase(unittest.TestCase): def test_swap_memory(self): - out = sh('swap -l -k') + out = sh('env PATH=/usr/sbin:/sbin:%s swap -l -k' % os.environ['PATH']) lines = out.strip().split('\n')[1:] if not lines: raise ValueError('no swap device(s) configured') @@ -35,12 +37,12 @@ def test_swap_memory(self): self.assertEqual(psutil_swap.free, free) -def test_main(): +def main(): test_suite = unittest.TestSuite() test_suite.addTest(unittest.makeSuite(SunOSSpecificTestCase)) result = unittest.TextTestRunner(verbosity=2).run(test_suite) return result.wasSuccessful() if __name__ == '__main__': - if not test_main(): + if not main(): sys.exit(1) diff --git a/python/psutil/test/_windows.py b/python/psutil/test/_windows.py index e1b27cc0a1c6..b7477bfeb499 100644 --- a/python/psutil/test/_windows.py +++ b/python/psutil/test/_windows.py @@ -15,8 +15,10 @@ import time import traceback -from test_psutil import (get_test_subprocess, reap_children, unittest) +from test_psutil import APPVEYOR, WINDOWS +from test_psutil import get_test_subprocess, reap_children, unittest +import mock try: import wmi except ImportError: @@ -28,17 +30,18 @@ win32api = win32con = None from psutil._compat import PY3, callable, long -from psutil._pswindows import ACCESS_DENIED_SET -import _psutil_windows import psutil +cext = psutil._psplatform.cext + + def wrap_exceptions(fun): def wrapper(self, *args, **kwargs): try: return fun(self, *args, **kwargs) - except OSError: - err = sys.exc_info()[1] + except OSError as err: + from psutil._pswindows import ACCESS_DENIED_SET if err.errno in ACCESS_DENIED_SET: raise psutil.AccessDenied(None, None) if err.errno == errno.ESRCH: @@ -47,6 +50,7 @@ def wrapper(self, *args, **kwargs): return wrapper +@unittest.skipUnless(WINDOWS, "not a Windows system") class WindowsSpecificTestCase(unittest.TestCase): @classmethod @@ -114,7 +118,9 @@ def test_process_name(self): def test_process_exe(self): w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] p = psutil.Process(self.pid) - self.assertEqual(p.exe(), w.ExecutablePath) + # Note: wmi reports the exe as a lower case string. + # Being Windows paths case-insensitive we ignore that. + self.assertEqual(p.exe().lower(), w.ExecutablePath.lower()) @unittest.skipIf(wmi is None, "wmi module is not installed") def test_process_cmdline(self): @@ -164,7 +170,7 @@ def test_process_create_time(self): # --- psutil namespace functions and constants tests - @unittest.skipUnless(hasattr(os, 'NUMBER_OF_PROCESSORS'), + @unittest.skipUnless('NUMBER_OF_PROCESSORS' in os.environ, 'NUMBER_OF_PROCESSORS env var is not available') def test_cpu_count(self): num_cpus = int(os.environ['NUMBER_OF_PROCESSORS']) @@ -188,20 +194,16 @@ def test_total_phymem(self): # time.localtime(p.create_time())) # + # Note: this test is not very reliable @unittest.skipIf(wmi is None, "wmi module is not installed") + @unittest.skipIf(APPVEYOR, "test not relieable on appveyor") def test_pids(self): # Note: this test might fail if the OS is starting/killing # other processes in the meantime w = wmi.WMI().Win32_Process() - wmi_pids = [x.ProcessId for x in w] - wmi_pids.sort() - psutil_pids = psutil.pids() - psutil_pids.sort() - if wmi_pids != psutil_pids: - difference = \ - filter(lambda x: x not in wmi_pids, psutil_pids) + \ - filter(lambda x: x not in psutil_pids, wmi_pids) - self.fail("difference: " + str(difference)) + wmi_pids = set([x.ProcessId for x in w]) + psutil_pids = set(psutil.pids()) + self.assertEqual(wmi_pids, psutil_pids) @unittest.skipIf(wmi is None, "wmi module is not installed") def test_disks(self): @@ -215,8 +217,7 @@ def test_disks(self): break try: usage = psutil.disk_usage(ps_part.mountpoint) - except OSError: - err = sys.exc_info()[1] + except OSError as err: if err.errno == errno.ENOENT: # usually this is the floppy break @@ -259,8 +260,6 @@ def call(p, attr): failures = [] for name in dir(psutil.Process): if name.startswith('_') \ - or name.startswith('set_') \ - or name.startswith('get') \ or name in ('terminate', 'kill', 'suspend', 'resume', 'nice', 'send_signal', 'wait', 'children', 'as_dict'): @@ -282,29 +281,42 @@ def call(p, attr): if failures: self.fail('\n' + '\n'.join(failures)) + def test_name_always_available(self): + # On Windows name() is never supposed to raise AccessDenied, + # see https://github.com/giampaolo/psutil/issues/627 + for p in psutil.process_iter(): + try: + p.name() + except psutil.NoSuchProcess(): + pass + +@unittest.skipUnless(WINDOWS, "not a Windows system") class TestDualProcessImplementation(unittest.TestCase): + """ + Certain APIs on Windows have 2 internal implementations, one + based on documented Windows APIs, another one based + NtQuerySystemInformation() which gets called as fallback in + case the first fails because of limited permission error. + Here we test that the two methods return the exact same value, + see: + https://github.com/giampaolo/psutil/issues/304 + """ + fun_names = [ # function name, tolerance ('proc_cpu_times', 0.2), ('proc_create_time', 0.5), ('proc_num_handles', 1), # 1 because impl #1 opens a handle - ('proc_io_counters', 0), ('proc_memory_info', 1024), # KB + ('proc_io_counters', 0), ] def test_compare_values(self): - # Certain APIs on Windows have 2 internal implementations, one - # based on documented Windows APIs, another one based - # NtQuerySystemInformation() which gets called as fallback in - # case the first fails because of limited permission error. - # Here we test that the two methods return the exact same value, - # see: - # https://github.com/giampaolo/psutil/issues/304 def assert_ge_0(obj): if isinstance(obj, tuple): for value in obj: - self.assertGreaterEqual(value, 0) + self.assertGreaterEqual(value, 0, msg=obj) elif isinstance(obj, (int, long, float)): self.assertGreaterEqual(obj, 0) else: @@ -322,55 +334,125 @@ def compare_with_tolerance(ret1, ret2, tolerance): diff = abs(a - b) self.assertLessEqual(diff, tolerance) + from psutil._pswindows import ntpinfo failures = [] - for name, tolerance in self.fun_names: - meth1 = wrap_exceptions(getattr(_psutil_windows, name)) - meth2 = wrap_exceptions(getattr(_psutil_windows, name + '_2')) - for p in psutil.process_iter(): + for p in psutil.process_iter(): + try: + nt = ntpinfo(*cext.proc_info(p.pid)) + except psutil.NoSuchProcess: + continue + assert_ge_0(nt) + + for name, tolerance in self.fun_names: if name == 'proc_memory_info' and p.pid == os.getpid(): continue - # - try: - ret1 = meth1(p.pid) - except psutil.NoSuchProcess: + if name == 'proc_create_time' and p.pid in (0, 4): continue - except psutil.AccessDenied: - ret1 = None - # + meth = wrap_exceptions(getattr(cext, name)) try: - ret2 = meth2(p.pid) - except psutil.NoSuchProcess: - # this is supposed to fail only in case of zombie process - # never for permission error + ret = meth(p.pid) + except (psutil.NoSuchProcess, psutil.AccessDenied): continue - # compare values try: - if ret1 is None: - assert_ge_0(ret2) - else: - compare_with_tolerance(ret1, ret2, tolerance) - assert_ge_0(ret1) - assert_ge_0(ret2) + if name == 'proc_cpu_times': + compare_with_tolerance(ret[0], nt.user_time, tolerance) + compare_with_tolerance(ret[1], + nt.kernel_time, tolerance) + elif name == 'proc_create_time': + compare_with_tolerance(ret, nt.create_time, tolerance) + elif name == 'proc_num_handles': + compare_with_tolerance(ret, nt.num_handles, tolerance) + elif name == 'proc_io_counters': + compare_with_tolerance(ret[0], nt.io_rcount, tolerance) + compare_with_tolerance(ret[1], nt.io_wcount, tolerance) + compare_with_tolerance(ret[2], nt.io_rbytes, tolerance) + compare_with_tolerance(ret[3], nt.io_wbytes, tolerance) + elif name == 'proc_memory_info': + try: + rawtupl = cext.proc_memory_info_2(p.pid) + except psutil.NoSuchProcess: + continue + compare_with_tolerance(ret, rawtupl, tolerance) except AssertionError: trace = traceback.format_exc() msg = '%s\npid=%s, method=%r, ret_1=%r, ret_2=%r' % ( - trace, p.pid, name, ret1, ret2) + trace, p.pid, name, ret, nt) failures.append(msg) break + if failures: self.fail('\n\n'.join(failures)) + # --- + # same tests as above but mimicks the AccessDenied failure of + # the first (fast) method failing with AD. + # TODO: currently does not take tolerance into account. + + def test_name(self): + name = psutil.Process().name() + with mock.patch("psutil._psplatform.cext.proc_exe", + side_effect=psutil.AccessDenied(os.getpid())) as fun: + psutil.Process().name() == name + assert fun.called + + def test_memory_info(self): + mem = psutil.Process().memory_info() + with mock.patch("psutil._psplatform.cext.proc_memory_info", + side_effect=OSError(errno.EPERM, "msg")) as fun: + psutil.Process().memory_info() == mem + assert fun.called + + def test_create_time(self): + ctime = psutil.Process().create_time() + with mock.patch("psutil._psplatform.cext.proc_create_time", + side_effect=OSError(errno.EPERM, "msg")) as fun: + psutil.Process().create_time() == ctime + assert fun.called + + def test_cpu_times(self): + cpu_times = psutil.Process().cpu_times() + with mock.patch("psutil._psplatform.cext.proc_cpu_times", + side_effect=OSError(errno.EPERM, "msg")) as fun: + psutil.Process().cpu_times() == cpu_times + assert fun.called + + def test_io_counters(self): + io_counters = psutil.Process().io_counters() + with mock.patch("psutil._psplatform.cext.proc_io_counters", + side_effect=OSError(errno.EPERM, "msg")) as fun: + psutil.Process().io_counters() == io_counters + assert fun.called + + def test_num_handles(self): + io_counters = psutil.Process().io_counters() + with mock.patch("psutil._psplatform.cext.proc_io_counters", + side_effect=OSError(errno.EPERM, "msg")) as fun: + psutil.Process().io_counters() == io_counters + assert fun.called + + # --- other tests + + def test_compare_name_exe(self): + for p in psutil.process_iter(): + try: + a = os.path.basename(p.exe()) + b = p.name() + except (psutil.NoSuchProcess, psutil.AccessDenied): + pass + else: + self.assertEqual(a, b) + def test_zombies(self): # test that NPS is raised by the 2nd implementation in case a # process no longer exists ZOMBIE_PID = max(psutil.pids()) + 5000 for name, _ in self.fun_names: - meth = wrap_exceptions(getattr(_psutil_windows, name)) + meth = wrap_exceptions(getattr(cext, name)) self.assertRaises(psutil.NoSuchProcess, meth, ZOMBIE_PID) -def test_main(): +def main(): test_suite = unittest.TestSuite() test_suite.addTest(unittest.makeSuite(WindowsSpecificTestCase)) test_suite.addTest(unittest.makeSuite(TestDualProcessImplementation)) @@ -378,5 +460,5 @@ def test_main(): return result.wasSuccessful() if __name__ == '__main__': - if not test_main(): + if not main(): sys.exit(1) diff --git a/python/psutil/test/test_memory_leaks.py b/python/psutil/test/test_memory_leaks.py index c33d37f049d7..6f02dc0acf38 100644 --- a/python/psutil/test/test_memory_leaks.py +++ b/python/psutil/test/test_memory_leaks.py @@ -10,6 +10,7 @@ after the calls. It might produce false positives. """ +import functools import gc import os import socket @@ -17,20 +18,20 @@ import threading import time -if sys.version_info < (2, 7): - import unittest2 as unittest # https://pypi.python.org/pypi/unittest2 -else: - import unittest - import psutil import psutil._common -from psutil._compat import callable, xrange -from test_psutil import (WINDOWS, POSIX, OSX, LINUX, SUNOS, TESTFN, - RLIMIT_SUPPORT) +from psutil._compat import xrange, callable +from test_psutil import (WINDOWS, POSIX, OSX, LINUX, SUNOS, BSD, TESTFN, + RLIMIT_SUPPORT, TRAVIS) from test_psutil import (reap_children, supports_ipv6, safe_remove, get_test_subprocess) +if sys.version_info < (2, 7): + import unittest2 as unittest # https://pypi.python.org/pypi/unittest2 +else: + import unittest + LOOPS = 1000 TOLERANCE = 4096 @@ -43,7 +44,7 @@ def skip_if_linux(): class Base(unittest.TestCase): - proc = psutil.Process(os.getpid()) + proc = psutil.Process() def execute(self, function, *args, **kwargs): def call_many_times(): @@ -73,7 +74,7 @@ def call_many_times(): # Let's keep calling fun for 3 more seconds and fail if # we notice any difference. stop_at = time.time() + 3 - while 1: + while True: self.call(function, *args, **kwargs) if time.time() >= stop_at: break @@ -85,10 +86,14 @@ def call_many_times(): self.fail("rss2=%s, rss3=%s, difference=%s" % (rss2, rss3, difference)) + def execute_w_exc(self, exc, function, *args, **kwargs): + kwargs['_exc'] = exc + self.execute(function, *args, **kwargs) + def get_mem(self): - return psutil.Process(os.getpid()).memory_info()[0] + return psutil.Process().memory_info()[0] - def call(self, *args, **kwargs): + def call(self, function, *args, **kwargs): raise NotImplementedError("must be implemented in subclass") @@ -102,12 +107,25 @@ def tearDown(self): reap_children() def call(self, function, *args, **kwargs): - try: - obj = getattr(self.proc, function) - if callable(obj): - obj(*args, **kwargs) - except psutil.Error: - pass + if callable(function): + if '_exc' in kwargs: + exc = kwargs.pop('_exc') + self.assertRaises(exc, function, *args, **kwargs) + else: + try: + function(*args, **kwargs) + except psutil.Error: + pass + else: + meth = getattr(self.proc, function) + if '_exc' in kwargs: + exc = kwargs.pop('_exc') + self.assertRaises(exc, meth, *args, **kwargs) + else: + try: + meth(*args, **kwargs) + except psutil.Error: + pass @skip_if_linux() def test_name(self): @@ -143,7 +161,7 @@ def test_nice_get(self): self.execute('nice') def test_nice_set(self): - niceness = psutil.Process(os.getpid()).nice() + niceness = psutil.Process().nice() self.execute('nice', niceness) @unittest.skipUnless(hasattr(psutil.Process, 'ionice'), @@ -155,16 +173,20 @@ def test_ionice_get(self): "Linux and Windows Vista only") def test_ionice_set(self): if WINDOWS: - value = psutil.Process(os.getpid()).ionice() + value = psutil.Process().ionice() self.execute('ionice', value) else: + from psutil._pslinux import cext self.execute('ionice', psutil.IOPRIO_CLASS_NONE) + fun = functools.partial(cext.proc_ioprio_set, os.getpid(), -1, 0) + self.execute_w_exc(OSError, fun) - @unittest.skipIf(OSX, "feature not supported on this platform") + @unittest.skipIf(OSX or SUNOS, "feature not supported on this platform") @skip_if_linux() def test_io_counters(self): self.execute('io_counters') + @unittest.skipUnless(WINDOWS, "not worth being tested on posix") def test_username(self): self.execute('username') @@ -215,23 +237,24 @@ def test_resume(self): def test_cwd(self): self.execute('cwd') - @unittest.skipUnless(WINDOWS or LINUX, "Windows or Linux only") + @unittest.skipUnless(WINDOWS or LINUX or BSD, + "Windows or Linux or BSD only") def test_cpu_affinity_get(self): self.execute('cpu_affinity') - @unittest.skipUnless(WINDOWS or LINUX, "Windows or Linux only") + @unittest.skipUnless(WINDOWS or LINUX or BSD, + "Windows or Linux or BSD only") def test_cpu_affinity_set(self): - affinity = psutil.Process(os.getpid()).cpu_affinity() + affinity = psutil.Process().cpu_affinity() self.execute('cpu_affinity', affinity) + if not TRAVIS: + self.execute_w_exc(ValueError, 'cpu_affinity', [-1]) @skip_if_linux() def test_open_files(self): safe_remove(TESTFN) # needed after UNIX socket test has run - f = open(TESTFN, 'w') - try: + with open(TESTFN, 'w'): self.execute('open_files') - finally: - f.close() # OSX implementation is unbelievably slow @unittest.skipIf(OSX, "OSX implementation is too slow") @@ -251,6 +274,7 @@ def test_rlimit_get(self): def test_rlimit_set(self): limit = psutil.Process().rlimit(psutil.RLIMIT_NOFILE) self.execute('rlimit', psutil.RLIMIT_NOFILE, limit) + self.execute_w_exc(OSError, 'rlimit', -1) @skip_if_linux() # Windows implementation is based on a single system-wide function @@ -301,6 +325,12 @@ class TestProcessObjectLeaksZombie(TestProcessObjectLeaks): """ proc = DEAD_PROC + def call(self, *args, **kwargs): + try: + TestProcessObjectLeaks.call(self, *args, **kwargs) + except psutil.NoSuchProcess: + pass + if not POSIX: def test_kill(self): self.execute('kill') @@ -325,9 +355,8 @@ def setUp(self): gc.collect() def call(self, function, *args, **kwargs): - obj = getattr(psutil, function) - if callable(obj): - obj(*args, **kwargs) + fun = getattr(psutil, function) + fun(*args, **kwargs) @skip_if_linux() def test_cpu_count_logical(self): @@ -393,8 +422,15 @@ def test_users(self): def test_net_connections(self): self.execute('net_connections') + def test_net_if_addrs(self): + self.execute('net_if_addrs') + + @unittest.skipIf(TRAVIS, "EPERM on travis") + def test_net_if_stats(self): + self.execute('net_if_stats') + -def test_main(): +def main(): test_suite = unittest.TestSuite() tests = [TestProcessObjectLeaksZombie, TestProcessObjectLeaks, @@ -405,5 +441,5 @@ def test_main(): return result.wasSuccessful() if __name__ == '__main__': - if not test_main(): + if not main(): sys.exit(1) diff --git a/python/psutil/test/test_psutil.py b/python/psutil/test/test_psutil.py index 2aec16899652..3b2e3587ae9d 100644 --- a/python/psutil/test/test_psutil.py +++ b/python/psutil/test/test_psutil.py @@ -15,11 +15,18 @@ from __future__ import division +import ast import atexit +import collections +import contextlib import datetime import errno +import functools +import imp +import json import os import pickle +import pprint import re import select import shutil @@ -37,21 +44,25 @@ import warnings from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM try: - import ast # python >= 2.6 + import ipaddress # python >= 3.3 except ImportError: - ast = None + ipaddress = None try: - import json # python >= 2.6 + from unittest import mock # py3 except ImportError: - json = None + import mock # requires "pip install mock" + +import psutil +from psutil._compat import PY3, callable, long, unicode if sys.version_info < (2, 7): import unittest2 as unittest # https://pypi.python.org/pypi/unittest2 else: import unittest - -import psutil -from psutil._compat import PY3, callable, long, wraps, unicode +if sys.version_info >= (3, 4): + import enum +else: + enum = None # =================================================================== @@ -93,6 +104,14 @@ if x.startswith('STATUS_')] # whether we're running this test suite on Travis (https://travis-ci.org/) TRAVIS = bool(os.environ.get('TRAVIS')) +# whether we're running this test suite on Appveyor for Windows +# (http://www.appveyor.com/) +APPVEYOR = bool(os.environ.get('APPVEYOR')) + +if TRAVIS or 'tox' in sys.argv[0]: + import ipaddress +if TRAVIS or APPVEYOR: + GLOBAL_TIMEOUT = GLOBAL_TIMEOUT * 4 # =================================================================== @@ -128,7 +147,7 @@ def get_test_subprocess(cmd=None, stdout=DEVNULL, stderr=DEVNULL, pyline = "" if wait: pyline += "open(r'%s', 'w'); " % TESTFN - pyline += "import time; time.sleep(2);" + pyline += "import time; time.sleep(60);" cmd_ = [PYTHON, "-c", pyline] else: cmd_ = cmd @@ -157,20 +176,15 @@ def pyrun(src): """ if PY3: src = bytes(src, 'ascii') - # could have used NamedTemporaryFile(delete=False) but it's - # >= 2.6 only - fd, path = tempfile.mkstemp(prefix=TESTFILE_PREFIX) - _testfiles.append(path) - f = open(path, 'wb') - try: + with tempfile.NamedTemporaryFile( + prefix=TESTFILE_PREFIX, delete=False) as f: + _testfiles.append(f.name) f.write(src) f.flush() - subp = get_test_subprocess([PYTHON, f.name], stdout=None, stderr=None) + subp = get_test_subprocess([PYTHON, f.name], stdout=None, + stderr=None) wait_for_pid(subp.pid) return subp - finally: - os.close(fd) - f.close() def warn(msg): @@ -244,7 +258,7 @@ def wait_for_pid(pid, timeout=GLOBAL_TIMEOUT): Used in the test suite to give time the sub process to initialize. """ raise_at = time.time() + timeout - while 1: + while True: if pid in psutil.pids(): # give it one more iteration to allow full initialization time.sleep(0.01) @@ -254,6 +268,23 @@ def wait_for_pid(pid, timeout=GLOBAL_TIMEOUT): raise RuntimeError("Timed out") +def wait_for_file(fname, timeout=GLOBAL_TIMEOUT, delete_file=True): + """Wait for a file to be written on disk.""" + stop_at = time.time() + 3 + while time.time() < stop_at: + try: + with open(fname, "r") as f: + data = f.read() + if not data: + continue + if delete_file: + os.remove(fname) + return data + except IOError: + time.sleep(0.001) + raise RuntimeError("timed out (couldn't read file)") + + def reap_children(search_all=False): """Kill any subprocess started by this test suite and ensure that no zombies stick around to hog resources and create problems when @@ -285,34 +316,57 @@ def reap_children(search_all=False): def check_ip_address(addr, family): """Attempts to check IP address's validity.""" - if not addr: - return - if family in (AF_INET, AF_INET6): - assert isinstance(addr, tuple), addr - ip, port = addr - assert isinstance(port, int), port - if family == AF_INET: - ip = list(map(int, ip.split('.'))) - assert len(ip) == 4, ip - for num in ip: - assert 0 <= num <= 255, ip - assert 0 <= port <= 65535, port - elif family == AF_UNIX: - assert isinstance(addr, (str, None)), addr + if enum and PY3: + assert isinstance(family, enum.IntEnum), family + if family == AF_INET: + octs = [int(x) for x in addr.split('.')] + assert len(octs) == 4, addr + for num in octs: + assert 0 <= num <= 255, addr + if ipaddress: + if not PY3: + addr = unicode(addr) + ipaddress.IPv4Address(addr) + elif family == AF_INET6: + assert isinstance(addr, str), addr + if ipaddress: + if not PY3: + addr = unicode(addr) + ipaddress.IPv6Address(addr) + elif family == psutil.AF_LINK: + assert re.match('([a-fA-F0-9]{2}[:|\-]?){6}', addr) is not None, addr else: raise ValueError("unknown family %r", family) -def check_connection(conn): +def check_connection_ntuple(conn): """Check validity of a connection namedtuple.""" valid_conn_states = [getattr(psutil, x) for x in dir(psutil) if x.startswith('CONN_')] - + assert conn[0] == conn.fd + assert conn[1] == conn.family + assert conn[2] == conn.type + assert conn[3] == conn.laddr + assert conn[4] == conn.raddr + assert conn[5] == conn.status assert conn.type in (SOCK_STREAM, SOCK_DGRAM), repr(conn.type) assert conn.family in (AF_INET, AF_INET6, AF_UNIX), repr(conn.family) assert conn.status in valid_conn_states, conn.status - check_ip_address(conn.laddr, conn.family) - check_ip_address(conn.raddr, conn.family) + + # check IP address and port sanity + for addr in (conn.laddr, conn.raddr): + if not addr: + continue + if conn.family in (AF_INET, AF_INET6): + assert isinstance(addr, tuple), addr + ip, port = addr + assert isinstance(port, int), port + assert 0 <= port <= 65535, port + check_ip_address(ip, conn.family) + elif conn.family == AF_UNIX: + assert isinstance(addr, (str, None)), addr + else: + raise ValueError("unknown family %r", conn.family) if conn.family in (AF_INET, AF_INET6): # actually try to bind the local socket; ignore IPv6 @@ -321,13 +375,12 @@ def check_connection(conn): # and that's rejected by bind() if conn.family == AF_INET: s = socket.socket(conn.family, conn.type) - try: - s.bind((conn.laddr[0], 0)) - except socket.error: - err = sys.exc_info()[1] - if err.errno != errno.EADDRNOTAVAIL: - raise - s.close() + with contextlib.closing(s): + try: + s.bind((conn.laddr[0], 0)) + except socket.error as err: + if err.errno != errno.EADDRNOTAVAIL: + raise elif conn.family == AF_UNIX: assert not conn.raddr, repr(conn.raddr) assert conn.status == psutil.CONN_NONE, conn.status @@ -335,30 +388,22 @@ def check_connection(conn): if getattr(conn, 'fd', -1) != -1: assert conn.fd > 0, conn if hasattr(socket, 'fromfd') and not WINDOWS: - dupsock = None try: - try: - dupsock = socket.fromfd(conn.fd, conn.family, conn.type) - except (socket.error, OSError): - err = sys.exc_info()[1] - if err.args[0] != errno.EBADF: - raise - else: - # python >= 2.5 - if hasattr(dupsock, "family"): - assert dupsock.family == conn.family - assert dupsock.type == conn.type - finally: - if dupsock is not None: - dupsock.close() + dupsock = socket.fromfd(conn.fd, conn.family, conn.type) + except (socket.error, OSError) as err: + if err.args[0] != errno.EBADF: + raise + else: + with contextlib.closing(dupsock): + assert dupsock.family == conn.family + assert dupsock.type == conn.type def safe_remove(file): "Convenience function for removing temporary test files" try: os.remove(file) - except OSError: - err = sys.exc_info()[1] + except OSError as err: if err.errno != errno.ENOENT: # file is being used by another process if WINDOWS and isinstance(err, WindowsError) and err.errno == 13: @@ -370,8 +415,7 @@ def safe_rmdir(dir): "Convenience function for removing temporary test directories" try: os.rmdir(dir) - except OSError: - err = sys.exc_info()[1] + except OSError as err: if err.errno != errno.ENOENT: raise @@ -394,7 +438,7 @@ def retry_before_failing(ntimes=None): actually failing. """ def decorator(fun): - @wraps(fun) + @functools.wraps(fun) def wrapper(*args, **kwargs): for x in range(ntimes or NO_RETRIES): try: @@ -409,7 +453,7 @@ def wrapper(*args, **kwargs): def skip_on_access_denied(only_if=None): """Decorator to Ignore AccessDenied exceptions.""" def decorator(fun): - @wraps(fun) + @functools.wraps(fun) def wrapper(*args, **kwargs): try: return fun(*args, **kwargs) @@ -419,8 +463,7 @@ def wrapper(*args, **kwargs): raise msg = "%r was skipped because it raised AccessDenied" \ % fun.__name__ - self = args[0] - self.skip(msg) + raise unittest.SkipTest(msg) return wrapper return decorator @@ -428,7 +471,7 @@ def wrapper(*args, **kwargs): def skip_on_not_implemented(only_if=None): """Decorator to Ignore NotImplementedError exceptions.""" def decorator(fun): - @wraps(fun) + @functools.wraps(fun) def wrapper(*args, **kwargs): try: return fun(*args, **kwargs) @@ -438,8 +481,7 @@ def wrapper(*args, **kwargs): raise msg = "%r was skipped because it raised NotImplementedError" \ % fun.__name__ - self = args[0] - self.skip(msg) + raise unittest.SkipTest(msg) return wrapper return decorator @@ -450,13 +492,12 @@ def supports_ipv6(): return False sock = None try: - try: - sock = socket.socket(AF_INET6, SOCK_STREAM) - sock.bind(("::1", 0)) - except (socket.error, socket.gaierror): - return False - else: - return True + sock = socket.socket(AF_INET6, SOCK_STREAM) + sock.bind(("::1", 0)) + except (socket.error, socket.gaierror): + return False + else: + return True finally: if sock is not None: sock.close() @@ -513,12 +554,6 @@ def stop(self): self.join() -# python 2.4 -if not hasattr(subprocess.Popen, 'terminate'): - subprocess.Popen.terminate = \ - lambda self: psutil.Process(self.pid).terminate() - - # =================================================================== # --- System-related API tests # =================================================================== @@ -542,14 +577,16 @@ def test_process_iter(self): self.assertNotIn(sproc.pid, [x.pid for x in psutil.process_iter()]) def test_wait_procs(self): - l = [] - callback = lambda p: l.append(p.pid) + def callback(p): + l.append(p.pid) + l = [] sproc1 = get_test_subprocess() sproc2 = get_test_subprocess() sproc3 = get_test_subprocess() procs = [psutil.Process(x.pid) for x in (sproc1, sproc2, sproc3)] self.assertRaises(ValueError, psutil.wait_procs, procs, timeout=-1) + self.assertRaises(TypeError, psutil.wait_procs, procs, callback=1) t = time.time() gone, alive = psutil.wait_procs(procs, timeout=0.01, callback=callback) @@ -560,10 +597,16 @@ def test_wait_procs(self): for p in alive: self.assertFalse(hasattr(p, 'returncode')) + @retry_before_failing(30) + def test(procs, callback): + gone, alive = psutil.wait_procs(procs, timeout=0.03, + callback=callback) + self.assertEqual(len(gone), 1) + self.assertEqual(len(alive), 2) + return gone, alive + sproc3.terminate() - gone, alive = psutil.wait_procs(procs, timeout=0.03, callback=callback) - self.assertEqual(len(gone), 1) - self.assertEqual(len(alive), 2) + gone, alive = test(procs, callback) self.assertIn(sproc3.pid, [x.pid for x in gone]) if POSIX: self.assertEqual(gone.pop().returncode, signal.SIGTERM) @@ -573,11 +616,17 @@ def test_wait_procs(self): for p in alive: self.assertFalse(hasattr(p, 'returncode')) + @retry_before_failing(30) + def test(procs, callback): + gone, alive = psutil.wait_procs(procs, timeout=0.03, + callback=callback) + self.assertEqual(len(gone), 3) + self.assertEqual(len(alive), 0) + return gone, alive + sproc1.terminate() sproc2.terminate() - gone, alive = psutil.wait_procs(procs, timeout=0.03, callback=callback) - self.assertEqual(len(gone), 3) - self.assertEqual(len(alive), 0) + gone, alive = test(procs, callback) self.assertEqual(set(l), set([sproc1.pid, sproc2.pid, sproc3.pid])) for p in gone: self.assertTrue(hasattr(p, 'returncode')) @@ -605,99 +654,6 @@ def test_PAGESIZE(self): import resource self.assertEqual(os.sysconf("SC_PAGE_SIZE"), resource.getpagesize()) - def test_deprecated_apis(self): - s = socket.socket() - s.bind(('localhost', 0)) - s.listen(1) - warnings.filterwarnings("error") - p = psutil.Process() - try: - # system APIs - self.assertRaises(DeprecationWarning, getattr, psutil, 'NUM_CPUS') - self.assertRaises(DeprecationWarning, getattr, psutil, 'BOOT_TIME') - self.assertRaises(DeprecationWarning, getattr, psutil, - 'TOTAL_PHYMEM') - self.assertRaises(DeprecationWarning, psutil.get_pid_list) - self.assertRaises(DeprecationWarning, psutil.get_users) - self.assertRaises(DeprecationWarning, psutil.virtmem_usage) - self.assertRaises(DeprecationWarning, psutil.used_phymem) - self.assertRaises(DeprecationWarning, psutil.avail_phymem) - self.assertRaises(DeprecationWarning, psutil.total_virtmem) - self.assertRaises(DeprecationWarning, psutil.used_virtmem) - self.assertRaises(DeprecationWarning, psutil.avail_virtmem) - self.assertRaises(DeprecationWarning, psutil.phymem_usage) - self.assertRaises(DeprecationWarning, psutil.get_process_list) - self.assertRaises(DeprecationWarning, psutil.network_io_counters) - if LINUX: - self.assertRaises(DeprecationWarning, psutil.phymem_buffers) - self.assertRaises(DeprecationWarning, psutil.cached_phymem) - - # Process class - names = dir(psutil.Process) - self.assertRaises(DeprecationWarning, p.get_children) - self.assertRaises(DeprecationWarning, p.get_connections) - if 'cpu_affinity' in names: - self.assertRaises(DeprecationWarning, p.get_cpu_affinity) - self.assertRaises(DeprecationWarning, p.get_cpu_percent) - self.assertRaises(DeprecationWarning, p.get_cpu_times) - self.assertRaises(DeprecationWarning, p.getcwd) - self.assertRaises(DeprecationWarning, p.get_ext_memory_info) - if 'io_counters' in names: - self.assertRaises(DeprecationWarning, p.get_io_counters) - if 'ionice' in names: - self.assertRaises(DeprecationWarning, p.get_ionice) - self.assertRaises(DeprecationWarning, p.get_memory_info) - self.assertRaises(DeprecationWarning, p.get_memory_maps) - self.assertRaises(DeprecationWarning, p.get_memory_percent) - self.assertRaises(DeprecationWarning, p.get_nice) - self.assertRaises(DeprecationWarning, p.get_num_ctx_switches) - if 'num_fds' in names: - self.assertRaises(DeprecationWarning, p.get_num_fds) - if 'num_handles' in names: - self.assertRaises(DeprecationWarning, p.get_num_handles) - self.assertRaises(DeprecationWarning, p.get_num_threads) - self.assertRaises(DeprecationWarning, p.get_open_files) - if 'rlimit' in names: - self.assertRaises(DeprecationWarning, p.get_rlimit) - self.assertRaises(DeprecationWarning, p.get_threads) - # ...just to be extra sure: - for name in names: - if name.startswith('get'): - meth = getattr(p, name) - try: - self.assertRaises(DeprecationWarning, meth) - except AssertionError: - self.fail("%s did not raise DeprecationWarning" % name) - - # named tuples - ret = call_until(p.connections, "len(ret) != 0") - self.assertRaises(DeprecationWarning, - getattr, ret[0], 'local_address') - self.assertRaises(DeprecationWarning, - getattr, ret[0], 'remote_address') - finally: - s.close() - warnings.resetwarnings() - - # check value against new APIs - warnings.filterwarnings("ignore") - try: - self.assertEqual(psutil.get_pid_list(), psutil.pids()) - self.assertEqual(psutil.NUM_CPUS, psutil.cpu_count()) - self.assertEqual(psutil.BOOT_TIME, psutil.boot_time()) - self.assertEqual(psutil.TOTAL_PHYMEM, - psutil.virtual_memory().total) - finally: - warnings.resetwarnings() - - def test_deprecated_apis_retval(self): - warnings.filterwarnings("ignore") - try: - self.assertEqual(psutil.total_virtmem(), - psutil.swap_memory().total) - finally: - warnings.resetwarnings() - def test_virtual_memory(self): mem = psutil.virtual_memory() assert mem.total > 0, mem @@ -738,6 +694,8 @@ def test_pid_exists(self): self.assertFalse(psutil.pid_exists(sproc.pid)) self.assertFalse(psutil.pid_exists(-1)) self.assertEqual(psutil.pid_exists(0), 0 in psutil.pids()) + # pid 0 + psutil.pid_exists(0) == 0 in psutil.pids() def test_pid_exists_2(self): reap_children() @@ -753,7 +711,7 @@ def test_pid_exists_2(self): self.fail(pid) pids = range(max(pids) + 5000, max(pids) + 6000) for pid in pids: - self.assertFalse(psutil.pid_exists(pid)) + self.assertFalse(psutil.pid_exists(pid), msg=pid) def test_pids(self): plist = [x.pid for x in psutil.process_iter()] @@ -776,6 +734,11 @@ def test_cpu_count(self): self.assertEqual(logical, len(psutil.cpu_times(percpu=True))) self.assertGreaterEqual(logical, 1) # + if LINUX: + with open("/proc/cpuinfo") as fd: + cpuinfo_data = fd.read() + if "physical id" not in cpuinfo_data: + raise unittest.SkipTest("cpuinfo doesn't include physical id") physical = psutil.cpu_count(logical=False) self.assertGreaterEqual(physical, 1) self.assertGreaterEqual(logical, physical) @@ -824,27 +787,30 @@ def test_sys_per_cpu_times(self): str(times) self.assertEqual(len(psutil.cpu_times(percpu=True)[0]), len(psutil.cpu_times(percpu=False))) - if not WINDOWS: - # CPU times are always supposed to increase over time or - # remain the same but never go backwards, see: - # https://github.com/giampaolo/psutil/issues/392 - last = psutil.cpu_times(percpu=True) - for x in range(100): - new = psutil.cpu_times(percpu=True) - for index in range(len(new)): - newcpu = new[index] - lastcpu = last[index] - for field in newcpu._fields: - new_t = getattr(newcpu, field) - last_t = getattr(lastcpu, field) - self.assertGreaterEqual( - new_t, last_t, msg="%s %s" % (lastcpu, newcpu)) - last = new - def test_sys_per_cpu_times2(self): + # Note: in theory CPU times are always supposed to increase over + # time or remain the same but never go backwards. In practice + # sometimes this is not the case. + # This issue seemd to be afflict Windows: + # https://github.com/giampaolo/psutil/issues/392 + # ...but it turns out also Linux (rarely) behaves the same. + # last = psutil.cpu_times(percpu=True) + # for x in range(100): + # new = psutil.cpu_times(percpu=True) + # for index in range(len(new)): + # newcpu = new[index] + # lastcpu = last[index] + # for field in newcpu._fields: + # new_t = getattr(newcpu, field) + # last_t = getattr(lastcpu, field) + # self.assertGreaterEqual( + # new_t, last_t, msg="%s %s" % (lastcpu, newcpu)) + # last = new + + def test_sys_per_cpu_times_2(self): tot1 = psutil.cpu_times(percpu=True) stop_at = time.time() + 0.1 - while 1: + while True: if time.time() >= stop_at: break tot2 = psutil.cpu_times(percpu=True) @@ -855,42 +821,61 @@ def test_sys_per_cpu_times2(self): return self.fail() - def _test_cpu_percent(self, percent): - self.assertIsInstance(percent, float) - self.assertGreaterEqual(percent, 0.0) - self.assertLessEqual(percent, 100.0 * psutil.cpu_count()) + def _test_cpu_percent(self, percent, last_ret, new_ret): + try: + self.assertIsInstance(percent, float) + self.assertGreaterEqual(percent, 0.0) + self.assertIsNot(percent, -0.0) + self.assertLessEqual(percent, 100.0 * psutil.cpu_count()) + except AssertionError as err: + raise AssertionError("\n%s\nlast=%s\nnew=%s" % ( + err, pprint.pformat(last_ret), pprint.pformat(new_ret))) def test_sys_cpu_percent(self): - psutil.cpu_percent(interval=0.001) - for x in range(1000): - self._test_cpu_percent(psutil.cpu_percent(interval=None)) + last = psutil.cpu_percent(interval=0.001) + for x in range(100): + new = psutil.cpu_percent(interval=None) + self._test_cpu_percent(new, last, new) + last = new def test_sys_per_cpu_percent(self): - self.assertEqual(len(psutil.cpu_percent(interval=0.001, percpu=True)), - psutil.cpu_count()) - for x in range(1000): - percents = psutil.cpu_percent(interval=None, percpu=True) - for percent in percents: - self._test_cpu_percent(percent) + last = psutil.cpu_percent(interval=0.001, percpu=True) + self.assertEqual(len(last), psutil.cpu_count()) + for x in range(100): + new = psutil.cpu_percent(interval=None, percpu=True) + for percent in new: + self._test_cpu_percent(percent, last, new) + last = new def test_sys_cpu_times_percent(self): - psutil.cpu_times_percent(interval=0.001) - for x in range(1000): - cpu = psutil.cpu_times_percent(interval=None) - for percent in cpu: - self._test_cpu_percent(percent) - self._test_cpu_percent(sum(cpu)) + last = psutil.cpu_times_percent(interval=0.001) + for x in range(100): + new = psutil.cpu_times_percent(interval=None) + for percent in new: + self._test_cpu_percent(percent, last, new) + self._test_cpu_percent(sum(new), last, new) + last = new def test_sys_per_cpu_times_percent(self): - self.assertEqual(len(psutil.cpu_times_percent(interval=0.001, - percpu=True)), - psutil.cpu_count()) - for x in range(1000): - cpus = psutil.cpu_times_percent(interval=None, percpu=True) - for cpu in cpus: + last = psutil.cpu_times_percent(interval=0.001, percpu=True) + self.assertEqual(len(last), psutil.cpu_count()) + for x in range(100): + new = psutil.cpu_times_percent(interval=None, percpu=True) + for cpu in new: + for percent in cpu: + self._test_cpu_percent(percent, last, new) + self._test_cpu_percent(sum(cpu), last, new) + last = new + + def test_sys_per_cpu_times_percent_negative(self): + # see: https://github.com/giampaolo/psutil/issues/645 + psutil.cpu_times_percent(percpu=True) + zero_times = [x._make([0 for x in range(len(x._fields))]) + for x in psutil.cpu_times(percpu=True)] + with mock.patch('psutil.cpu_times', return_value=zero_times): + for cpu in psutil.cpu_times_percent(percpu=True): for percent in cpu: - self._test_cpu_percent(percent) - self._test_cpu_percent(sum(cpu)) + self._test_cpu_percent(percent, None, None) @unittest.skipIf(POSIX and not hasattr(os, 'statvfs'), "os.statvfs() function not available on this platform") @@ -917,8 +902,7 @@ def test_disk_usage(self): fname = tempfile.mktemp() try: psutil.disk_usage(fname) - except OSError: - err = sys.exc_info()[1] + except OSError as err: if err.args[0] != errno.ENOENT: raise else: @@ -972,10 +956,9 @@ def test_disk_partitions(self): if not WINDOWS: try: os.stat(disk.mountpoint) - except OSError: + except OSError as err: # http://mail.python.org/pipermail/python-dev/ # 2012-June/120787.html - err = sys.exc_info()[1] if err.errno not in (errno.EPERM, errno.EACCES): raise else: @@ -998,6 +981,7 @@ def find_mount_point(path): self.assertIn(mount, mounts) psutil.disk_usage(mount) + @skip_on_access_denied() def test_net_connections(self): def check(cons, families, types_): for conn in cons: @@ -1011,6 +995,7 @@ def check(cons, families, types_): continue families, types_ = groups cons = psutil.net_connections(kind) + self.assertEqual(len(cons), len(set(cons))) check(cons, families, types_) def test_net_io_counters(self): @@ -1040,8 +1025,73 @@ def check_ntuple(nt): self.assertTrue(key) check_ntuple(ret[key]) + def test_net_if_addrs(self): + nics = psutil.net_if_addrs() + assert nics, nics + + # Not reliable on all platforms (net_if_addrs() reports more + # interfaces). + # self.assertEqual(sorted(nics.keys()), + # sorted(psutil.net_io_counters(pernic=True).keys())) + + families = set([socket.AF_INET, AF_INET6, psutil.AF_LINK]) + for nic, addrs in nics.items(): + self.assertEqual(len(set(addrs)), len(addrs)) + for addr in addrs: + self.assertIsInstance(addr.family, int) + self.assertIsInstance(addr.address, str) + self.assertIsInstance(addr.netmask, (str, type(None))) + self.assertIsInstance(addr.broadcast, (str, type(None))) + self.assertIn(addr.family, families) + if sys.version_info >= (3, 4): + self.assertIsInstance(addr.family, enum.IntEnum) + if addr.family == socket.AF_INET: + s = socket.socket(addr.family) + with contextlib.closing(s): + s.bind((addr.address, 0)) + elif addr.family == socket.AF_INET6: + info = socket.getaddrinfo( + addr.address, 0, socket.AF_INET6, socket.SOCK_STREAM, + 0, socket.AI_PASSIVE)[0] + af, socktype, proto, canonname, sa = info + s = socket.socket(af, socktype, proto) + with contextlib.closing(s): + s.bind(sa) + for ip in (addr.address, addr.netmask, addr.broadcast): + if ip is not None: + # TODO: skip AF_INET6 for now because I get: + # AddressValueError: Only hex digits permitted in + # u'c6f3%lxcbr0' in u'fe80::c8e0:fff:fe54:c6f3%lxcbr0' + if addr.family != AF_INET6: + check_ip_address(ip, addr.family) + + if BSD or OSX or SUNOS: + if hasattr(socket, "AF_LINK"): + self.assertEqual(psutil.AF_LINK, socket.AF_LINK) + elif LINUX: + self.assertEqual(psutil.AF_LINK, socket.AF_PACKET) + elif WINDOWS: + self.assertEqual(psutil.AF_LINK, -1) + + @unittest.skipIf(TRAVIS, "EPERM on travis") + def test_net_if_stats(self): + nics = psutil.net_if_stats() + assert nics, nics + all_duplexes = (psutil.NIC_DUPLEX_FULL, + psutil.NIC_DUPLEX_HALF, + psutil.NIC_DUPLEX_UNKNOWN) + for nic, stats in nics.items(): + isup, duplex, speed, mtu = stats + self.assertIsInstance(isup, bool) + self.assertIn(duplex, all_duplexes) + self.assertIn(duplex, all_duplexes) + self.assertGreaterEqual(speed, 0) + self.assertGreaterEqual(mtu, 0) + @unittest.skipIf(LINUX and not os.path.exists('/proc/diskstats'), '/proc/diskstats not available on this linux version') + @unittest.skipIf(APPVEYOR, + "can't find any physical disk on Appveyor") def test_disk_io_counters(self): def check_ntuple(nt): self.assertEqual(nt[0], nt.read_count) @@ -1074,7 +1124,8 @@ def check_ntuple(nt): def test_users(self): users = psutil.users() - self.assertNotEqual(users, []) + if not APPVEYOR: + self.assertNotEqual(users, []) for user in users: assert user.name, user user.terminal @@ -1106,28 +1157,48 @@ def test_kill(self): test_pid = sproc.pid p = psutil.Process(test_pid) p.kill() - p.wait() + sig = p.wait() self.assertFalse(psutil.pid_exists(test_pid)) + if POSIX: + self.assertEqual(sig, signal.SIGKILL) def test_terminate(self): sproc = get_test_subprocess(wait=True) test_pid = sproc.pid p = psutil.Process(test_pid) p.terminate() - p.wait() + sig = p.wait() self.assertFalse(psutil.pid_exists(test_pid)) + if POSIX: + self.assertEqual(sig, signal.SIGTERM) def test_send_signal(self): - if POSIX: - sig = signal.SIGKILL - else: - sig = signal.SIGTERM + sig = signal.SIGKILL if POSIX else signal.SIGTERM sproc = get_test_subprocess() - test_pid = sproc.pid - p = psutil.Process(test_pid) + p = psutil.Process(sproc.pid) p.send_signal(sig) - p.wait() - self.assertFalse(psutil.pid_exists(test_pid)) + exit_sig = p.wait() + self.assertFalse(psutil.pid_exists(p.pid)) + if POSIX: + self.assertEqual(exit_sig, sig) + # + sproc = get_test_subprocess() + p = psutil.Process(sproc.pid) + p.send_signal(sig) + with mock.patch('psutil.os.kill', + side_effect=OSError(errno.ESRCH, "")) as fun: + with self.assertRaises(psutil.NoSuchProcess): + p.send_signal(sig) + assert fun.called + # + sproc = get_test_subprocess() + p = psutil.Process(sproc.pid) + p.send_signal(sig) + with mock.patch('psutil.os.kill', + side_effect=OSError(errno.EPERM, "")) as fun: + with self.assertRaises(psutil.AccessDenied): + p.send_signal(sig) + assert fun.called def test_wait(self): # check exit code signal @@ -1182,7 +1253,7 @@ def test_wait_non_children(self): # test wait() against processes which are not our children code = "import sys;" code += "from subprocess import Popen, PIPE;" - code += "cmd = ['%s', '-c', 'import time; time.sleep(2)'];" % PYTHON + code += "cmd = ['%s', '-c', 'import time; time.sleep(60)'];" % PYTHON code += "sp = Popen(cmd, stdout=PIPE);" code += "sys.stdout.write(str(sp.pid));" sproc = get_test_subprocess([PYTHON, "-c", code], @@ -1205,7 +1276,7 @@ def test_wait_timeout_0(self): self.assertRaises(psutil.TimeoutExpired, p.wait, 0) p.kill() stop_at = time.time() + 2 - while 1: + while True: try: code = p.wait(0) except psutil.TimeoutExpired: @@ -1292,9 +1363,8 @@ def test_io_counters(self): p = psutil.Process() # test reads io1 = p.io_counters() - f = open(PYTHON, 'rb') - f.read() - f.close() + with open(PYTHON, 'rb') as f: + f.read() io2 = p.io_counters() if not BSD: assert io2.read_count > io1.read_count, (io1, io2) @@ -1303,12 +1373,11 @@ def test_io_counters(self): assert io2.write_bytes >= io1.write_bytes, (io1, io2) # test writes io1 = p.io_counters() - f = tempfile.TemporaryFile(prefix=TESTFILE_PREFIX) - if PY3: - f.write(bytes("x" * 1000000, 'ascii')) - else: - f.write("x" * 1000000) - f.close() + with tempfile.TemporaryFile(prefix=TESTFILE_PREFIX) as f: + if PY3: + f.write(bytes("x" * 1000000, 'ascii')) + else: + f.write("x" * 1000000) io2 = p.io_counters() assert io2.write_count >= io1.write_count, (io1, io2) assert io2.write_bytes >= io1.write_bytes, (io1, io2) @@ -1330,6 +1399,8 @@ def test_ionice(self): try: p.ionice(2) ioclass, value = p.ionice() + if enum is not None: + self.assertIsInstance(ioclass, enum.IntEnum) self.assertEqual(ioclass, 2) self.assertEqual(value, 4) # @@ -1346,12 +1417,26 @@ def test_ionice(self): ioclass, value = p.ionice() self.assertEqual(ioclass, 2) self.assertEqual(value, 7) + # self.assertRaises(ValueError, p.ionice, 2, 10) + self.assertRaises(ValueError, p.ionice, 2, -1) + self.assertRaises(ValueError, p.ionice, 4) + self.assertRaises(TypeError, p.ionice, 2, "foo") + self.assertRaisesRegexp( + ValueError, "can't specify value with IOPRIO_CLASS_NONE", + p.ionice, psutil.IOPRIO_CLASS_NONE, 1) + self.assertRaisesRegexp( + ValueError, "can't specify value with IOPRIO_CLASS_IDLE", + p.ionice, psutil.IOPRIO_CLASS_IDLE, 1) + self.assertRaisesRegexp( + ValueError, "'ioclass' argument must be specified", + p.ionice, value=1) finally: p.ionice(IOPRIO_CLASS_NONE) else: p = psutil.Process() original = p.ionice() + self.assertIsInstance(original, int) try: value = 0 # very low if original == value: @@ -1370,14 +1455,13 @@ def test_rlimit_get(self): import resource p = psutil.Process(os.getpid()) names = [x for x in dir(psutil) if x.startswith('RLIMIT')] - assert names + assert names, names for name in names: value = getattr(psutil, name) self.assertGreaterEqual(value, 0) if name in dir(resource): self.assertEqual(value, getattr(resource, name)) - self.assertEqual(p.rlimit(value), - resource.getrlimit(value)) + self.assertEqual(p.rlimit(value), resource.getrlimit(value)) else: ret = p.rlimit(value) self.assertEqual(len(ret), 2) @@ -1391,6 +1475,12 @@ def test_rlimit_set(self): p = psutil.Process(sproc.pid) p.rlimit(psutil.RLIMIT_NOFILE, (5, 5)) self.assertEqual(p.rlimit(psutil.RLIMIT_NOFILE), (5, 5)) + # If pid is 0 prlimit() applies to the calling process and + # we don't want that. + with self.assertRaises(ValueError): + psutil._psplatform.Process(0).rlimit(0) + with self.assertRaises(ValueError): + p.rlimit(psutil.RLIMIT_NOFILE, (5, 5, 5)) def test_num_threads(self): # on certain platforms such as Linux we might test for exact @@ -1525,7 +1615,7 @@ def test_exe(self): self.assertEqual(exe.replace(ver, ''), PYTHON.replace(ver, '')) def test_cmdline(self): - cmdline = [PYTHON, "-c", "import time; time.sleep(2)"] + cmdline = [PYTHON, "-c", "import time; time.sleep(60)"] sproc = get_test_subprocess(cmdline, wait=True) self.assertEqual(' '.join(psutil.Process(sproc.pid).cmdline()), ' '.join(cmdline)) @@ -1536,6 +1626,30 @@ def test_name(self): pyexe = os.path.basename(os.path.realpath(sys.executable)).lower() assert pyexe.startswith(name), (pyexe, name) + @unittest.skipUnless(POSIX, "posix only") + # TODO: add support for other compilers + @unittest.skipUnless(which("gcc"), "gcc not available") + def test_prog_w_funky_name(self): + # Test that name(), exe() and cmdline() correctly handle programs + # with funky chars such as spaces and ")", see: + # https://github.com/giampaolo/psutil/issues/628 + funky_name = "/tmp/foo bar )" + _, c_file = tempfile.mkstemp(prefix='psutil-', suffix='.c', dir="/tmp") + self.addCleanup(lambda: safe_remove(c_file)) + self.addCleanup(lambda: safe_remove(funky_name)) + with open(c_file, "w") as f: + f.write("void main() { pause(); }") + subprocess.check_call(["gcc", c_file, "-o", funky_name]) + sproc = get_test_subprocess( + [funky_name, "arg1", "arg2", "", "arg3", ""]) + p = psutil.Process(sproc.pid) + # ...in order to try to prevent occasional failures on travis + wait_for_pid(p.pid) + self.assertEqual(p.name(), "foo bar )") + self.assertEqual(p.exe(), "/tmp/foo bar )") + self.assertEqual( + p.cmdline(), ["/tmp/foo bar )", "arg1", "arg2", "", "arg3", ""]) + @unittest.skipUnless(POSIX, 'posix only') def test_uids(self): p = psutil.Process() @@ -1567,7 +1681,12 @@ def test_nice(self): self.assertRaises(TypeError, p.nice, "str") if WINDOWS: try: - self.assertEqual(p.nice(), psutil.NORMAL_PRIORITY_CLASS) + init = p.nice() + if sys.version_info > (3, 4): + self.assertIsInstance(init, enum.IntEnum) + else: + self.assertIsInstance(init, int) + self.assertEqual(init, psutil.NORMAL_PRIORITY_CLASS) p.nice(psutil.HIGH_PRIORITY_CLASS) self.assertEqual(p.nice(), psutil.HIGH_PRIORITY_CLASS) p.nice(psutil.NORMAL_PRIORITY_CLASS) @@ -1576,17 +1695,16 @@ def test_nice(self): p.nice(psutil.NORMAL_PRIORITY_CLASS) else: try: - try: - first_nice = p.nice() - p.nice(1) - self.assertEqual(p.nice(), 1) - # going back to previous nice value raises - # AccessDenied on OSX - if not OSX: - p.nice(0) - self.assertEqual(p.nice(), 0) - except psutil.AccessDenied: - pass + first_nice = p.nice() + p.nice(1) + self.assertEqual(p.nice(), 1) + # going back to previous nice value raises + # AccessDenied on OSX + if not OSX: + p.nice(0) + self.assertEqual(p.nice(), 0) + except psutil.AccessDenied: + pass finally: try: p.nice(first_nice) @@ -1603,6 +1721,11 @@ def test_username(self): if POSIX: import pwd self.assertEqual(p.username(), pwd.getpwuid(os.getuid()).pw_name) + with mock.patch("psutil.pwd.getpwuid", + side_effect=KeyError) as fun: + p.username() == str(p.uids().real) + assert fun.called + elif WINDOWS and 'USERNAME' in os.environ: expected_username = os.environ['USERNAME'] expected_domain = os.environ['USERDOMAIN'] @@ -1618,18 +1741,20 @@ def test_cwd(self): self.assertEqual(p.cwd(), os.getcwd()) def test_cwd_2(self): - cmd = [PYTHON, "-c", "import os, time; os.chdir('..'); time.sleep(2)"] + cmd = [PYTHON, "-c", "import os, time; os.chdir('..'); time.sleep(60)"] sproc = get_test_subprocess(cmd, wait=True) p = psutil.Process(sproc.pid) call_until(p.cwd, "ret == os.path.dirname(os.getcwd())") - @unittest.skipUnless(WINDOWS or LINUX, 'not available on this platform') + @unittest.skipUnless(WINDOWS or LINUX or BSD, + 'not available on this platform') @unittest.skipIf(LINUX and TRAVIS, "unknown failure on travis") def test_cpu_affinity(self): p = psutil.Process() initial = p.cpu_affinity() if hasattr(os, "sched_getaffinity"): self.assertEqual(initial, list(os.sched_getaffinity(p.pid))) + self.assertEqual(len(initial), len(set(initial))) all_cpus = list(range(len(psutil.cpu_percent(percpu=True)))) # setting on travis doesn't seem to work (always return all # CPUs on get): @@ -1649,25 +1774,33 @@ def test_cpu_affinity(self): # self.assertRaises(TypeError, p.cpu_affinity, 1) p.cpu_affinity(initial) + # it should work with all iterables, not only lists + p.cpu_affinity(set(all_cpus)) + p.cpu_affinity(tuple(all_cpus)) invalid_cpu = [len(psutil.cpu_times(percpu=True)) + 10] self.assertRaises(ValueError, p.cpu_affinity, invalid_cpu) self.assertRaises(ValueError, p.cpu_affinity, range(10000, 11000)) + self.assertRaises(TypeError, p.cpu_affinity, [0, "1"]) + # TODO + @unittest.skipIf(BSD, "broken on BSD, see #595") + @unittest.skipIf(APPVEYOR, + "can't find any process file on Appveyor") def test_open_files(self): # current process p = psutil.Process() files = p.open_files() self.assertFalse(TESTFN in files) - f = open(TESTFN, 'w') - call_until(p.open_files, "len(ret) != %i" % len(files)) - filenames = [x.path for x in p.open_files()] - self.assertIn(TESTFN, filenames) - f.close() + with open(TESTFN, 'w'): + # give the kernel some time to see the new file + call_until(p.open_files, "len(ret) != %i" % len(files)) + filenames = [x.path for x in p.open_files()] + self.assertIn(TESTFN, filenames) for file in filenames: assert os.path.isfile(file), file # another process - cmdline = "import time; f = open(r'%s', 'r'); time.sleep(2);" % TESTFN + cmdline = "import time; f = open(r'%s', 'r'); time.sleep(60);" % TESTFN sproc = get_test_subprocess([PYTHON, "-c", cmdline], wait=True) p = psutil.Process(sproc.pid) @@ -1681,27 +1814,30 @@ def test_open_files(self): for file in filenames: assert os.path.isfile(file), file + # TODO + @unittest.skipIf(BSD, "broken on BSD, see #595") + @unittest.skipIf(APPVEYOR, + "can't find any process file on Appveyor") def test_open_files2(self): # test fd and path fields - fileobj = open(TESTFN, 'w') - p = psutil.Process() - for path, fd in p.open_files(): - if path == fileobj.name or fd == fileobj.fileno(): - break - else: - self.fail("no file found; files=%s" % repr(p.open_files())) - self.assertEqual(path, fileobj.name) - if WINDOWS: - self.assertEqual(fd, -1) - else: - self.assertEqual(fd, fileobj.fileno()) - # test positions - ntuple = p.open_files()[0] - self.assertEqual(ntuple[0], ntuple.path) - self.assertEqual(ntuple[1], ntuple.fd) - # test file is gone - fileobj.close() - self.assertTrue(fileobj.name not in p.open_files()) + with open(TESTFN, 'w') as fileobj: + p = psutil.Process() + for path, fd in p.open_files(): + if path == fileobj.name or fd == fileobj.fileno(): + break + else: + self.fail("no file found; files=%s" % repr(p.open_files())) + self.assertEqual(path, fileobj.name) + if WINDOWS: + self.assertEqual(fd, -1) + else: + self.assertEqual(fd, fileobj.fileno()) + # test positions + ntuple = p.open_files()[0] + self.assertEqual(ntuple[0], ntuple.path) + self.assertEqual(ntuple[1], ntuple.fd) + # test file is gone + self.assertTrue(fileobj.name not in p.open_files()) def compare_proc_sys_cons(self, pid, proc_cons): from psutil._common import pconn @@ -1714,199 +1850,172 @@ def compare_proc_sys_cons(self, pid, proc_cons): proc_cons = [pconn(*[-1] + list(x[1:])) for x in proc_cons] self.assertEqual(sorted(proc_cons), sorted(sys_cons)) - def test_connection_constants(self): - ints = [] - strs = [] - for name in dir(psutil): - if name.startswith('CONN_'): - num = getattr(psutil, name) - str_ = str(num) - assert str_.isupper(), str_ - assert str_ not in strs, str_ - assert num not in ints, num - ints.append(num) - strs.append(str_) - if SUNOS: - psutil.CONN_IDLE - psutil.CONN_BOUND - if WINDOWS: - psutil.CONN_DELETE_TCB - + @skip_on_access_denied(only_if=OSX) def test_connections(self): - arg = "import socket, time;" \ - "s = socket.socket();" \ - "s.bind(('127.0.0.1', 0));" \ - "s.listen(1);" \ - "conn, addr = s.accept();" \ - "time.sleep(2);" - sproc = get_test_subprocess([PYTHON, "-c", arg]) - p = psutil.Process(sproc.pid) - cons = call_until(p.connections, "len(ret) != 0") - self.assertEqual(len(cons), 1) - con = cons[0] - check_connection(con) - self.assertEqual(con.family, AF_INET) - self.assertEqual(con.type, SOCK_STREAM) - self.assertEqual(con.status, psutil.CONN_LISTEN, con.status) - self.assertEqual(con.laddr[0], '127.0.0.1') - self.assertEqual(con.raddr, ()) - # test positions - self.assertEqual(con[0], con.fd) - self.assertEqual(con[1], con.family) - self.assertEqual(con[2], con.type) - self.assertEqual(con[3], con.laddr) - self.assertEqual(con[4], con.raddr) - self.assertEqual(con[5], con.status) - # test kind arg - self.assertRaises(ValueError, p.connections, 'foo') - # compare against system-wide connections - self.compare_proc_sys_cons(p.pid, cons) - - @unittest.skipUnless(supports_ipv6(), 'IPv6 is not supported') - def test_connections_ipv6(self): - s = socket.socket(AF_INET6, SOCK_STREAM) - self.addCleanup(s.close) - s.bind(('::1', 0)) - s.listen(1) - cons = psutil.Process().connections() - self.assertEqual(len(cons), 1) - self.assertEqual(cons[0].laddr[0], '::1') - self.compare_proc_sys_cons(os.getpid(), cons) - - @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), - 'AF_UNIX is not supported') - def test_connections_unix(self): - def check(type): - safe_remove(TESTFN) - sock = socket.socket(AF_UNIX, type) - try: - sock.bind(TESTFN) - cons = psutil.Process().connections(kind='unix') - conn = cons[0] - check_connection(conn) - if conn.fd != -1: # != sunos and windows - self.assertEqual(conn.fd, sock.fileno()) - self.assertEqual(conn.family, AF_UNIX) - self.assertEqual(conn.type, type) - self.assertEqual(conn.laddr, TESTFN) - if not SUNOS: - # XXX Solaris can't retrieve system-wide UNIX - # sockets. - self.compare_proc_sys_cons(os.getpid(), cons) - finally: - sock.close() - - check(SOCK_STREAM) - check(SOCK_DGRAM) - - @unittest.skipUnless(hasattr(socket, "fromfd"), - 'socket.fromfd() is not availble') - @unittest.skipIf(WINDOWS or SUNOS, - 'connection fd not available on this platform') - def test_connection_fromfd(self): - sock = socket.socket() - sock.bind(('localhost', 0)) - sock.listen(1) - p = psutil.Process() - for conn in p.connections(): - if conn.fd == sock.fileno(): - break - else: - sock.close() - self.fail("couldn't find socket fd") - dupsock = socket.fromfd(conn.fd, conn.family, conn.type) - try: - self.assertEqual(dupsock.getsockname(), conn.laddr) - self.assertNotEqual(sock.fileno(), dupsock.fileno()) - finally: - sock.close() - dupsock.close() + def check_conn(proc, conn, family, type, laddr, raddr, status, kinds): + all_kinds = ("all", "inet", "inet4", "inet6", "tcp", "tcp4", + "tcp6", "udp", "udp4", "udp6") + check_connection_ntuple(conn) + self.assertEqual(conn.family, family) + self.assertEqual(conn.type, type) + self.assertEqual(conn.laddr, laddr) + self.assertEqual(conn.raddr, raddr) + self.assertEqual(conn.status, status) + for kind in all_kinds: + cons = proc.connections(kind=kind) + if kind in kinds: + self.assertNotEqual(cons, []) + else: + self.assertEqual(cons, []) + # compare against system-wide connections + # XXX Solaris can't retrieve system-wide UNIX + # sockets. + if not SUNOS: + self.compare_proc_sys_cons(proc.pid, [conn]) - def test_connections_all(self): tcp_template = textwrap.dedent(""" - import socket + import socket, time s = socket.socket($family, socket.SOCK_STREAM) s.bind(('$addr', 0)) s.listen(1) - conn, addr = s.accept() + with open('$testfn', 'w') as f: + f.write(str(s.getsockname()[:2])) + time.sleep(60) """) udp_template = textwrap.dedent(""" import socket, time s = socket.socket($family, socket.SOCK_DGRAM) s.bind(('$addr', 0)) - time.sleep(2) + with open('$testfn', 'w') as f: + f.write(str(s.getsockname()[:2])) + time.sleep(60) """) from string import Template + testfile = os.path.basename(TESTFN) tcp4_template = Template(tcp_template).substitute( - family=int(AF_INET), addr="127.0.0.1") + family=int(AF_INET), addr="127.0.0.1", testfn=testfile) udp4_template = Template(udp_template).substitute( - family=int(AF_INET), addr="127.0.0.1") + family=int(AF_INET), addr="127.0.0.1", testfn=testfile) tcp6_template = Template(tcp_template).substitute( - family=int(AF_INET6), addr="::1") + family=int(AF_INET6), addr="::1", testfn=testfile) udp6_template = Template(udp_template).substitute( - family=int(AF_INET6), addr="::1") + family=int(AF_INET6), addr="::1", testfn=testfile) # launch various subprocess instantiating a socket of various # families and types to enrich psutil results tcp4_proc = pyrun(tcp4_template) + tcp4_addr = eval(wait_for_file(testfile)) udp4_proc = pyrun(udp4_template) + udp4_addr = eval(wait_for_file(testfile)) if supports_ipv6(): tcp6_proc = pyrun(tcp6_template) + tcp6_addr = eval(wait_for_file(testfile)) udp6_proc = pyrun(udp6_template) + udp6_addr = eval(wait_for_file(testfile)) else: tcp6_proc = None udp6_proc = None - - # check matches against subprocesses just created - all_kinds = ("all", "inet", "inet4", "inet6", "tcp", "tcp4", "tcp6", - "udp", "udp4", "udp6") - - def check_conn(proc, conn, family, type, laddr, raddr, status, kinds): - self.assertEqual(conn.family, family) - self.assertEqual(conn.type, type) - self.assertIn(conn.laddr[0], laddr) - self.assertEqual(conn.raddr, raddr) - self.assertEqual(conn.status, status) - for kind in all_kinds: - cons = proc.connections(kind=kind) - if kind in kinds: - self.assertNotEqual(cons, []) - else: - self.assertEqual(cons, []) + tcp6_addr = None + udp6_addr = None for p in psutil.Process().children(): cons = p.connections() + self.assertEqual(len(cons), 1) for conn in cons: # TCP v4 if p.pid == tcp4_proc.pid: - check_conn(p, conn, AF_INET, SOCK_STREAM, "127.0.0.1", (), + check_conn(p, conn, AF_INET, SOCK_STREAM, tcp4_addr, (), psutil.CONN_LISTEN, ("all", "inet", "inet4", "tcp", "tcp4")) # UDP v4 elif p.pid == udp4_proc.pid: - check_conn(p, conn, AF_INET, SOCK_DGRAM, "127.0.0.1", (), + check_conn(p, conn, AF_INET, SOCK_DGRAM, udp4_addr, (), psutil.CONN_NONE, ("all", "inet", "inet4", "udp", "udp4")) # TCP v6 elif p.pid == getattr(tcp6_proc, "pid", None): - check_conn(p, conn, AF_INET6, SOCK_STREAM, ("::", "::1"), - (), psutil.CONN_LISTEN, + check_conn(p, conn, AF_INET6, SOCK_STREAM, tcp6_addr, (), + psutil.CONN_LISTEN, ("all", "inet", "inet6", "tcp", "tcp6")) # UDP v6 elif p.pid == getattr(udp6_proc, "pid", None): - check_conn(p, conn, AF_INET6, SOCK_DGRAM, ("::", "::1"), - (), psutil.CONN_NONE, + check_conn(p, conn, AF_INET6, SOCK_DGRAM, udp6_addr, (), + psutil.CONN_NONE, ("all", "inet", "inet6", "udp", "udp6")) + @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), + 'AF_UNIX is not supported') + @skip_on_access_denied(only_if=OSX) + def test_connections_unix(self): + def check(type): + safe_remove(TESTFN) + sock = socket.socket(AF_UNIX, type) + with contextlib.closing(sock): + sock.bind(TESTFN) + cons = psutil.Process().connections(kind='unix') + conn = cons[0] + check_connection_ntuple(conn) + if conn.fd != -1: # != sunos and windows + self.assertEqual(conn.fd, sock.fileno()) + self.assertEqual(conn.family, AF_UNIX) + self.assertEqual(conn.type, type) + self.assertEqual(conn.laddr, TESTFN) + if not SUNOS: + # XXX Solaris can't retrieve system-wide UNIX + # sockets. + self.compare_proc_sys_cons(os.getpid(), cons) + + check(SOCK_STREAM) + check(SOCK_DGRAM) + + @unittest.skipUnless(hasattr(socket, "fromfd"), + 'socket.fromfd() is not availble') + @unittest.skipIf(WINDOWS or SUNOS, + 'connection fd not available on this platform') + def test_connection_fromfd(self): + with contextlib.closing(socket.socket()) as sock: + sock.bind(('localhost', 0)) + sock.listen(1) + p = psutil.Process() + for conn in p.connections(): + if conn.fd == sock.fileno(): + break + else: + self.fail("couldn't find socket fd") + dupsock = socket.fromfd(conn.fd, conn.family, conn.type) + with contextlib.closing(dupsock): + self.assertEqual(dupsock.getsockname(), conn.laddr) + self.assertNotEqual(sock.fileno(), dupsock.fileno()) + + def test_connection_constants(self): + ints = [] + strs = [] + for name in dir(psutil): + if name.startswith('CONN_'): + num = getattr(psutil, name) + str_ = str(num) + assert str_.isupper(), str_ + assert str_ not in strs, str_ + assert num not in ints, num + ints.append(num) + strs.append(str_) + if SUNOS: + psutil.CONN_IDLE + psutil.CONN_BOUND + if WINDOWS: + psutil.CONN_DELETE_TCB + @unittest.skipUnless(POSIX, 'posix only') def test_num_fds(self): p = psutil.Process() start = p.num_fds() file = open(TESTFN, 'w') + self.addCleanup(file.close) self.assertEqual(p.num_fds(), start + 1) sock = socket.socket() + self.addCleanup(sock.close) self.assertEqual(p.num_fds(), start + 2) file.close() sock.close() @@ -1951,14 +2060,14 @@ def test_children_recursive(self): # A (parent) -> B (child) -> C (grandchild) s = "import subprocess, os, sys, time;" s += "PYTHON = os.path.realpath(sys.executable);" - s += "cmd = [PYTHON, '-c', 'import time; time.sleep(2);'];" + s += "cmd = [PYTHON, '-c', 'import time; time.sleep(60);'];" s += "subprocess.Popen(cmd);" - s += "time.sleep(2);" + s += "time.sleep(60);" get_test_subprocess(cmd=[PYTHON, "-c", s]) p = psutil.Process() self.assertEqual(len(p.children(recursive=False)), 1) # give the grandchild some time to start - stop_at = time.time() + 1.5 + stop_at = time.time() + GLOBAL_TIMEOUT while time.time() < stop_at: children = p.children(recursive=True) if len(children) > 1: @@ -1969,8 +2078,7 @@ def test_children_recursive(self): def test_children_duplicates(self): # find the process which has the highest number of children - from psutil._compat import defaultdict - table = defaultdict(int) + table = collections.defaultdict(int) for p in psutil.process_iter(): try: table[p.ppid()] += 1 @@ -2021,95 +2129,140 @@ def test_halfway_terminated_process(self): # Refers to Issue #15 sproc = get_test_subprocess() p = psutil.Process(sproc.pid) - p.kill() + p.terminate() p.wait() + if WINDOWS: + wait_for_pid(p.pid) + self.assertFalse(p.is_running()) + self.assertFalse(p.pid in psutil.pids()) excluded_names = ['pid', 'is_running', 'wait', 'create_time'] if LINUX and not RLIMIT_SUPPORT: excluded_names.append('rlimit') for name in dir(p): - if (name.startswith('_') - or name.startswith('get') # deprecated APIs - or name.startswith('set') # deprecated APIs - or name in excluded_names): + if (name.startswith('_') or + name in excluded_names): continue try: meth = getattr(p, name) # get/set methods if name == 'nice': if POSIX: - meth(1) + ret = meth(1) else: - meth(psutil.NORMAL_PRIORITY_CLASS) + ret = meth(psutil.NORMAL_PRIORITY_CLASS) elif name == 'ionice': - meth() - meth(2) + ret = meth() + ret = meth(2) elif name == 'rlimit': - meth(psutil.RLIMIT_NOFILE) - meth(psutil.RLIMIT_NOFILE, (5, 5)) + ret = meth(psutil.RLIMIT_NOFILE) + ret = meth(psutil.RLIMIT_NOFILE, (5, 5)) elif name == 'cpu_affinity': - meth() - meth([0]) + ret = meth() + ret = meth([0]) elif name == 'send_signal': - meth(signal.SIGTERM) + ret = meth(signal.SIGTERM) else: - meth() + ret = meth() + except psutil.ZombieProcess: + self.fail("ZombieProcess for %r was not supposed to happen" % + name) except psutil.NoSuchProcess: pass except NotImplementedError: pass else: - self.fail("NoSuchProcess exception not raised for %r" % name) - - self.assertFalse(p.is_running()) + self.fail( + "NoSuchProcess exception not raised for %r, retval=%s" % ( + name, ret)) @unittest.skipUnless(POSIX, 'posix only') def test_zombie_process(self): + def succeed_or_zombie_p_exc(fun, *args, **kwargs): + try: + fun(*args, **kwargs) + except (psutil.ZombieProcess, psutil.AccessDenied): + pass + # Note: in this test we'll be creating two sub processes. # Both of them are supposed to be freed / killed by # reap_children() as they are attributable to 'us' # (os.getpid()) via children(recursive=True). src = textwrap.dedent("""\ - import os, sys, time, socket + import os, sys, time, socket, contextlib child_pid = os.fork() if child_pid > 0: time.sleep(3000) else: # this is the zombie process s = socket.socket(socket.AF_UNIX) - s.connect('%s') - if sys.version_info < (3, ): - pid = str(os.getpid()) - else: - pid = bytes(str(os.getpid()), 'ascii') - s.sendall(pid) - s.close() + with contextlib.closing(s): + s.connect('%s') + if sys.version_info < (3, ): + pid = str(os.getpid()) + else: + pid = bytes(str(os.getpid()), 'ascii') + s.sendall(pid) """ % TESTFN) - sock = None - try: - sock = socket.socket(socket.AF_UNIX) - sock.settimeout(GLOBAL_TIMEOUT) - sock.bind(TESTFN) - sock.listen(1) - pyrun(src) - conn, _ = sock.accept() - select.select([conn.fileno()], [], [], GLOBAL_TIMEOUT) - zpid = int(conn.recv(1024)) - zproc = psutil.Process(zpid) - # Make sure we can re-instantiate the process after its - # status changed to zombie and at least be able to - # query its status. - # XXX should we also assume ppid should be querable? - call_until(lambda: zproc.status(), "ret == psutil.STATUS_ZOMBIE") - self.assertTrue(psutil.pid_exists(zpid)) - zproc = psutil.Process(zpid) - descendants = [x.pid for x in psutil.Process().children( - recursive=True)] - self.assertIn(zpid, descendants) - finally: - if sock is not None: - sock.close() - reap_children(search_all=True) + with contextlib.closing(socket.socket(socket.AF_UNIX)) as sock: + try: + sock.settimeout(GLOBAL_TIMEOUT) + sock.bind(TESTFN) + sock.listen(1) + pyrun(src) + conn, _ = sock.accept() + select.select([conn.fileno()], [], [], GLOBAL_TIMEOUT) + zpid = int(conn.recv(1024)) + zproc = psutil.Process(zpid) + call_until(lambda: zproc.status(), + "ret == psutil.STATUS_ZOMBIE") + # A zombie process should always be instantiable + zproc = psutil.Process(zpid) + # ...and at least its status always be querable + self.assertEqual(zproc.status(), psutil.STATUS_ZOMBIE) + # ...and it should be considered 'running' + self.assertTrue(zproc.is_running()) + # ...and as_dict() shouldn't crash + zproc.as_dict() + if hasattr(zproc, "rlimit"): + succeed_or_zombie_p_exc(zproc.rlimit, psutil.RLIMIT_NOFILE) + succeed_or_zombie_p_exc(zproc.rlimit, psutil.RLIMIT_NOFILE, + (5, 5)) + # set methods + succeed_or_zombie_p_exc(zproc.parent) + if hasattr(zproc, 'cpu_affinity'): + succeed_or_zombie_p_exc(zproc.cpu_affinity, [0]) + succeed_or_zombie_p_exc(zproc.nice, 0) + if hasattr(zproc, 'ionice'): + if LINUX: + succeed_or_zombie_p_exc(zproc.ionice, 2, 0) + else: + succeed_or_zombie_p_exc(zproc.ionice, 0) # Windows + if hasattr(zproc, 'rlimit'): + succeed_or_zombie_p_exc(zproc.rlimit, + psutil.RLIMIT_NOFILE, (5, 5)) + succeed_or_zombie_p_exc(zproc.suspend) + succeed_or_zombie_p_exc(zproc.resume) + succeed_or_zombie_p_exc(zproc.terminate) + succeed_or_zombie_p_exc(zproc.kill) + + # ...its parent should 'see' it + # edit: not true on BSD and OSX + # descendants = [x.pid for x in psutil.Process().children( + # recursive=True)] + # self.assertIn(zpid, descendants) + # XXX should we also assume ppid be usable? Note: this + # would be an important use case as the only way to get + # rid of a zombie is to kill its parent. + # self.assertEqual(zpid.ppid(), os.getpid()) + # ...and all other APIs should be able to deal with it + self.assertTrue(psutil.pid_exists(zpid)) + self.assertIn(zpid, psutil.pids()) + self.assertIn(zpid, [x.pid for x in psutil.process_iter()]) + psutil._pmap = {} + self.assertIn(zpid, [x.pid for x in psutil.process_iter()]) + finally: + reap_children(search_all=True) def test_pid_0(self): # Process(0) is supposed to work on all platforms except Linux @@ -2127,6 +2280,10 @@ def test_pid_0(self): except psutil.AccessDenied: pass + self.assertRaisesRegexp( + ValueError, "preventing sending signal to process with PID 0", + p.send_signal, signal.SIGTERM) + self.assertIn(p.ppid(), (0, 1)) # self.assertEqual(p.exe(), "") p.cmdline() @@ -2140,7 +2297,6 @@ def test_pid_0(self): except psutil.AccessDenied: pass - # username property try: if POSIX: self.assertEqual(p.username(), 'root') @@ -2159,7 +2315,7 @@ def test_Popen(self): # XXX this test causes a ResourceWarning on Python 3 because # psutil.__subproc instance doesn't get propertly freed. # Not sure what to do though. - cmd = [PYTHON, "-c", "import time; time.sleep(2);"] + cmd = [PYTHON, "-c", "import time; time.sleep(60);"] proc = psutil.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) try: @@ -2167,6 +2323,7 @@ def test_Popen(self): proc.stdin self.assertTrue(hasattr(proc, 'name')) self.assertTrue(hasattr(proc, 'stdin')) + self.assertTrue(dir(proc)) self.assertRaises(AttributeError, getattr, proc, 'foo') finally: proc.kill() @@ -2201,11 +2358,6 @@ def test_fetch_all(self): for name in dir(psutil.Process): if name.startswith("_"): continue - if name.startswith("get"): - # deprecated APIs - continue - if name.startswith("set_"): - continue if name in excluded_names: continue attrs.append(name) @@ -2230,8 +2382,7 @@ def test_fetch_all(self): msg = "%r was skipped because not implemented" % ( self.__class__.__name__ + '.test_' + name) warn(msg) - except (psutil.NoSuchProcess, psutil.AccessDenied): - err = sys.exc_info()[1] + except (psutil.NoSuchProcess, psutil.AccessDenied) as err: self.assertEqual(err.pid, p.pid) if err.name: # make sure exception's name attr is set @@ -2244,8 +2395,7 @@ def test_fetch_all(self): assert ret, ret meth = getattr(self, name) meth(ret) - except Exception: - err = sys.exc_info()[1] + except Exception as err: s = '\n' + '=' * 70 + '\n' s += "FAIL: test_%s (proc=%s" % (name, p) if ret != default: @@ -2375,16 +2525,16 @@ def num_fds(self, ret): self.assertTrue(ret >= 0) def connections(self, ret): + self.assertEqual(len(ret), len(set(ret))) for conn in ret: - check_connection(conn) + check_connection_ntuple(conn) def cwd(self, ret): if ret is not None: # BSD may return None assert os.path.isabs(ret), ret try: st = os.stat(ret) - except OSError: - err = sys.exc_info()[1] + except OSError as err: # directory has been removed in mean time if err.errno != errno.ENOENT: raise @@ -2449,58 +2599,55 @@ def rlimit(self, ret): # --- Limited user tests # =================================================================== -if hasattr(os, 'getuid') and os.getuid() == 0: - - class LimitedUserTestCase(TestProcess): - """Repeat the previous tests by using a limited user. - Executed only on UNIX and only if the user who run the test script - is root. - """ - # the uid/gid the test suite runs under +@unittest.skipUnless(POSIX, "UNIX only") +@unittest.skipUnless(hasattr(os, 'getuid') and os.getuid() == 0, + "super user privileges are required") +class LimitedUserTestCase(TestProcess): + """Repeat the previous tests by using a limited user. + Executed only on UNIX and only if the user who run the test script + is root. + """ + # the uid/gid the test suite runs under + if hasattr(os, 'getuid'): PROCESS_UID = os.getuid() PROCESS_GID = os.getgid() - def __init__(self, *args, **kwargs): - TestProcess.__init__(self, *args, **kwargs) - # re-define all existent test methods in order to - # ignore AccessDenied exceptions - for attr in [x for x in dir(self) if x.startswith('test')]: - meth = getattr(self, attr) - - def test_(self): - try: - meth() - except psutil.AccessDenied: - pass - setattr(self, attr, types.MethodType(test_, self)) + def __init__(self, *args, **kwargs): + TestProcess.__init__(self, *args, **kwargs) + # re-define all existent test methods in order to + # ignore AccessDenied exceptions + for attr in [x for x in dir(self) if x.startswith('test')]: + meth = getattr(self, attr) - def setUp(self): - safe_remove(TESTFN) - os.setegid(1000) - os.seteuid(1000) - TestProcess.setUp(self) + def test_(self): + try: + meth() + except psutil.AccessDenied: + pass + setattr(self, attr, types.MethodType(test_, self)) - def tearDown(self): - os.setegid(self.PROCESS_UID) - os.seteuid(self.PROCESS_GID) - TestProcess.tearDown(self) + def setUp(self): + safe_remove(TESTFN) + TestProcess.setUp(self) + os.setegid(1000) + os.seteuid(1000) - def test_nice(self): - try: - psutil.Process().nice(-1) - except psutil.AccessDenied: - pass - else: - self.fail("exception not raised") + def tearDown(self): + os.setegid(self.PROCESS_UID) + os.seteuid(self.PROCESS_GID) + TestProcess.tearDown(self) - def test_zombie_process(self): - # causes problems if test test suite is run as root + def test_nice(self): + try: + psutil.Process().nice(-1) + except psutil.AccessDenied: pass -else: + else: + self.fail("exception not raised") - class LimitedUserTestCase(unittest.TestCase): - def test_it(self): - unittest.skip("super user privileges are required") + def test_zombie_process(self): + # causes problems if test test suite is run as root + pass # =================================================================== @@ -2510,22 +2657,84 @@ def test_it(self): class TestMisc(unittest.TestCase): """Misc / generic tests.""" - def test__str__(self): - sproc = get_test_subprocess() - p = psutil.Process(sproc.pid) - self.assertIn(str(sproc.pid), str(p)) - # python shows up as 'Python' in cmdline on OS X so - # test fails on OS X - if not OSX: - self.assertIn(os.path.basename(PYTHON), str(p)) - sproc = get_test_subprocess() - p = psutil.Process(sproc.pid) - p.kill() - p.wait() - self.assertIn(str(sproc.pid), str(p)) - self.assertIn("terminated", str(p)) - - def test__eq__(self): + def test_process__repr__(self, func=repr): + p = psutil.Process() + r = func(p) + self.assertIn("psutil.Process", r) + self.assertIn("pid=%s" % p.pid, r) + self.assertIn("name=", r) + self.assertIn(p.name(), r) + with mock.patch.object(psutil.Process, "name", + side_effect=psutil.ZombieProcess(os.getpid())): + p = psutil.Process() + r = func(p) + self.assertIn("pid=%s" % p.pid, r) + self.assertIn("zombie", r) + self.assertNotIn("name=", r) + with mock.patch.object(psutil.Process, "name", + side_effect=psutil.NoSuchProcess(os.getpid())): + p = psutil.Process() + r = func(p) + self.assertIn("pid=%s" % p.pid, r) + self.assertIn("terminated", r) + self.assertNotIn("name=", r) + + def test_process__str__(self): + self.test_process__repr__(func=str) + + def test_no_such_process__repr__(self, func=repr): + self.assertEqual( + repr(psutil.NoSuchProcess(321)), + "psutil.NoSuchProcess process no longer exists (pid=321)") + self.assertEqual( + repr(psutil.NoSuchProcess(321, name='foo')), + "psutil.NoSuchProcess process no longer exists (pid=321, " + "name='foo')") + self.assertEqual( + repr(psutil.NoSuchProcess(321, msg='foo')), + "psutil.NoSuchProcess foo") + + def test_zombie_process__repr__(self, func=repr): + self.assertEqual( + repr(psutil.ZombieProcess(321)), + "psutil.ZombieProcess process still exists but it's a zombie " + "(pid=321)") + self.assertEqual( + repr(psutil.ZombieProcess(321, name='foo')), + "psutil.ZombieProcess process still exists but it's a zombie " + "(pid=321, name='foo')") + self.assertEqual( + repr(psutil.ZombieProcess(321, name='foo', ppid=1)), + "psutil.ZombieProcess process still exists but it's a zombie " + "(pid=321, name='foo', ppid=1)") + self.assertEqual( + repr(psutil.ZombieProcess(321, msg='foo')), + "psutil.ZombieProcess foo") + + def test_access_denied__repr__(self, func=repr): + self.assertEqual( + repr(psutil.AccessDenied(321)), + "psutil.AccessDenied (pid=321)") + self.assertEqual( + repr(psutil.AccessDenied(321, name='foo')), + "psutil.AccessDenied (pid=321, name='foo')") + self.assertEqual( + repr(psutil.AccessDenied(321, msg='foo')), + "psutil.AccessDenied foo") + + def test_timeout_expired__repr__(self, func=repr): + self.assertEqual( + repr(psutil.TimeoutExpired(321)), + "psutil.TimeoutExpired timeout after 321 seconds") + self.assertEqual( + repr(psutil.TimeoutExpired(321, pid=111)), + "psutil.TimeoutExpired timeout after 321 seconds (pid=111)") + self.assertEqual( + repr(psutil.TimeoutExpired(321, pid=111, name='foo')), + "psutil.TimeoutExpired timeout after 321 seconds " + "(pid=111, name='foo')") + + def test_process__eq__(self): p1 = psutil.Process() p2 = psutil.Process() self.assertEqual(p1, p2) @@ -2533,13 +2742,14 @@ def test__eq__(self): self.assertNotEqual(p1, p2) self.assertNotEqual(p1, 'foo') - def test__hash__(self): + def test_process__hash__(self): s = set([psutil.Process(), psutil.Process()]) self.assertEqual(len(s), 1) def test__all__(self): - for name in dir(psutil): - if name in ('callable', 'defaultdict', 'error', 'namedtuple', + dir_psutil = dir(psutil) + for name in dir_psutil: + if name in ('callable', 'error', 'namedtuple', 'long', 'test', 'NUM_CPUS', 'BOOT_TIME', 'TOTAL_PHYMEM'): continue @@ -2555,6 +2765,17 @@ def test__all__(self): 'deprecated' not in fun.__doc__.lower()): self.fail('%r not in psutil.__all__' % name) + # Import 'star' will break if __all__ is inconsistent, see: + # https://github.com/giampaolo/psutil/issues/656 + # Can't do `from psutil import *` as it won't work on python 3 + # so we simply iterate over __all__. + for name in psutil.__all__: + self.assertIn(name, dir_psutil) + + def test_version(self): + self.assertEqual('.'.join([str(x) for x in psutil.version_info]), + psutil.__version__) + def test_memoize(self): from psutil._common import memoize @@ -2592,6 +2813,23 @@ def foo(*args, **kwargs): # docstring self.assertEqual(foo.__doc__, "foo docstring") + def test_isfile_strict(self): + from psutil._common import isfile_strict + this_file = os.path.abspath(__file__) + assert isfile_strict(this_file) + assert not isfile_strict(os.path.dirname(this_file)) + with mock.patch('psutil._common.os.stat', + side_effect=OSError(errno.EPERM, "foo")): + self.assertRaises(OSError, isfile_strict, this_file) + with mock.patch('psutil._common.os.stat', + side_effect=OSError(errno.EACCES, "foo")): + self.assertRaises(OSError, isfile_strict, this_file) + with mock.patch('psutil._common.os.stat', + side_effect=OSError(errno.EINVAL, "foo")): + assert not isfile_strict(this_file) + with mock.patch('psutil._common.stat.S_ISREG', return_value=False): + assert not isfile_strict(this_file) + def test_serialization(self): def check(ret): if json is not None: @@ -2609,11 +2847,36 @@ def check(ret): if LINUX and not os.path.exists('/proc/diskstats'): pass else: - check(psutil.disk_io_counters()) + if not APPVEYOR: + check(psutil.disk_io_counters()) check(psutil.disk_partitions()) check(psutil.disk_usage(os.getcwd())) check(psutil.users()) + def test_setup_script(self): + here = os.path.abspath(os.path.dirname(__file__)) + setup_py = os.path.realpath(os.path.join(here, '..', 'setup.py')) + module = imp.load_source('setup', setup_py) + self.assertRaises(SystemExit, module.setup) + self.assertEqual(module.get_version(), psutil.__version__) + + def test_ad_on_process_creation(self): + # We are supposed to be able to instantiate Process also in case + # of zombie processes or access denied. + with mock.patch.object(psutil.Process, 'create_time', + side_effect=psutil.AccessDenied) as meth: + psutil.Process() + assert meth.called + with mock.patch.object(psutil.Process, 'create_time', + side_effect=psutil.ZombieProcess(1)) as meth: + psutil.Process() + assert meth.called + with mock.patch.object(psutil.Process, 'create_time', + side_effect=ValueError) as meth: + with self.assertRaises(ValueError): + psutil.Process() + assert meth.called + # =================================================================== # --- Example script tests @@ -2628,8 +2891,7 @@ def assert_stdout(self, exe, args=None): exe = exe + ' ' + args try: out = sh(sys.executable + ' ' + exe).strip() - except RuntimeError: - err = sys.exc_info()[1] + except RuntimeError as err: if 'AccessDenied' in str(err): return str(err) else: @@ -2639,11 +2901,8 @@ def assert_stdout(self, exe, args=None): def assert_syntax(self, exe, args=None): exe = os.path.join(EXAMPLES_DIR, exe) - f = open(exe, 'r') - try: + with open(exe, 'r') as f: src = f.read() - finally: - f.close() ast.parse(src) def test_check_presence(self): @@ -2668,15 +2927,23 @@ def test_meminfo(self): def test_process_detail(self): self.assert_stdout('process_detail.py') + @unittest.skipIf(APPVEYOR, "can't find users on Appveyor") def test_who(self): self.assert_stdout('who.py') def test_ps(self): self.assert_stdout('ps.py') + def test_pstree(self): + self.assert_stdout('pstree.py') + def test_netstat(self): self.assert_stdout('netstat.py') + @unittest.skipIf(TRAVIS, "permission denied on travis") + def test_ifconfig(self): + self.assert_stdout('ifconfig.py') + def test_pmap(self): self.assert_stdout('pmap.py', args=str(os.getpid())) @@ -2700,8 +2967,12 @@ def test_top(self): def test_iotop(self): self.assert_syntax('iotop.py') + def test_pidof(self): + output = self.assert_stdout('pidof.py %s' % psutil.Process().name()) + self.assertIn(str(os.getpid()), output) + -def test_main(): +def main(): tests = [] test_suite = unittest.TestSuite() tests.append(TestSystemAPIs) @@ -2738,5 +3009,5 @@ def test_main(): return result.wasSuccessful() if __name__ == '__main__': - if not test_main(): + if not main(): sys.exit(1) diff --git a/python/psutil/tox.ini b/python/psutil/tox.ini index 8f6d7f9415cc..d80dd174b8c3 100644 --- a/python/psutil/tox.ini +++ b/python/psutil/tox.ini @@ -9,16 +9,24 @@ envlist = py26, py27, py32, py33, py34 [testenv] deps = - pytest flake8 + pytest + py26: ipaddress + py26: mock==1.0.1 + py26: unittest2 + py27: ipaddress + py27: mock + py32: ipaddress + py32: mock + py33: ipaddress + setenv = PYTHONPATH = {toxinidir}/test + commands = py.test {posargs} - flake8 --exclude=build,.tox,.git + git ls-files | grep \\.py$ | xargs flake8 -[testenv:py26] -deps = - flake8 - pytest - unittest2 +# suppress "WARNING: 'git' command found but not installed in testenv +whitelist_externals = git +usedevelop = True From 151d1c8bebcc76c25a79763408109072feab80c7 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Thu, 20 Aug 2015 00:59:28 -0400 Subject: [PATCH 003/208] Bug 1196451 - tweak comment in nsRefPtr.h to be more clear; r=botond DONTBUILD because this is a comment-only fix. --- mfbt/nsRefPtr.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mfbt/nsRefPtr.h b/mfbt/nsRefPtr.h index 6b70cc97aa07..c3440b289c81 100644 --- a/mfbt/nsRefPtr.h +++ b/mfbt/nsRefPtr.h @@ -348,12 +348,14 @@ class nsRefPtr private: // This helper class makes |nsRefPtr| possible by casting away // the constness from the pointer when calling AddRef() and Release(). + // // This is necessary because AddRef() and Release() implementations can't // generally expected to be const themselves (without heavy use of |mutable| // and |const_cast| in their own implementations). - // This should be sound because while |nsRefPtr| provides a const - // view of an object, the object itself should be const (it would have to be - // allocated as |new const T| or similar to itself be const). + // + // This should be sound because while |nsRefPtr| provides a + // const view of an object, the object itself should not be const (it + // would have to be allocated as |new const T| or similar to be const). template struct AddRefTraits { From afc3830e655ce3d23673e0a1cb411f732b9a8970 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Thu, 20 Aug 2015 15:52:40 +0100 Subject: [PATCH 004/208] Bug 1196206 - Add Windows 10 font Yu Gothic to the font list in fwid-spaces.html. r=jdaggett. --- layout/reftests/font-features/fwid-spaces-ref.html | 2 +- layout/reftests/font-features/fwid-spaces.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/layout/reftests/font-features/fwid-spaces-ref.html b/layout/reftests/font-features/fwid-spaces-ref.html index eab0f670a646..5183bf1d4209 100644 --- a/layout/reftests/font-features/fwid-spaces-ref.html +++ b/layout/reftests/font-features/fwid-spaces-ref.html @@ -11,7 +11,7 @@ } #test, #test pre { - font: 150% Hiragino Kaku Gothic ProN, Meiryo, sans-serif; + font: 150% Hiragino Kaku Gothic ProN, Meiryo, Yu Gothic, sans-serif; } #test pre span { diff --git a/layout/reftests/font-features/fwid-spaces.html b/layout/reftests/font-features/fwid-spaces.html index 5715886d2585..7c8c55fe0300 100644 --- a/layout/reftests/font-features/fwid-spaces.html +++ b/layout/reftests/font-features/fwid-spaces.html @@ -11,7 +11,7 @@ } #test, #test pre { - font: 150% Hiragino Kaku Gothic ProN, Meiryo, sans-serif; + font: 150% Hiragino Kaku Gothic ProN, Meiryo, Yu Gothic, sans-serif; -webkit-font-feature-settings: "fwid" on; font-feature-settings: "fwid" on; } From 8988e881943618b643f1b640cf9f4d34c5b1578e Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Thu, 20 Aug 2015 11:36:04 -0400 Subject: [PATCH 005/208] Bug 1196409 - Disable D3D11-DXVA for resolutions not supported in hardware. r=jya --- dom/media/platforms/wmf/DXVA2Manager.cpp | 64 ++++++++++++++++++++++++ dom/media/platforms/wmf/DXVA2Manager.h | 2 +- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/dom/media/platforms/wmf/DXVA2Manager.cpp b/dom/media/platforms/wmf/DXVA2Manager.cpp index 2b696c7d82b6..323081fb8c0e 100644 --- a/dom/media/platforms/wmf/DXVA2Manager.cpp +++ b/dom/media/platforms/wmf/DXVA2Manager.cpp @@ -412,6 +412,8 @@ class D3D11DXVA2Manager : public DXVA2Manager virtual bool IsD3D11() override { return true; } + virtual bool SupportsConfig(IMFMediaType* aType) override; + private: HRESULT CreateFormatConverter(); @@ -428,6 +430,43 @@ class D3D11DXVA2Manager : public DXVA2Manager UINT mDeviceManagerToken; }; +bool +D3D11DXVA2Manager::SupportsConfig(IMFMediaType* aType) +{ + RefPtr videoDevice; + HRESULT hr = mDevice->QueryInterface(static_cast(byRef(videoDevice))); + NS_ENSURE_TRUE(SUCCEEDED(hr), false); + + D3D11_VIDEO_DECODER_DESC desc; + desc.Guid = DXVA2_ModeH264_E; + + UINT32 width = 0; + UINT32 height = 0; + hr = MFGetAttributeSize(aType, MF_MT_FRAME_SIZE, &width, &height); + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + desc.SampleWidth = width; + desc.SampleHeight = height; + + desc.OutputFormat = DXGI_FORMAT_NV12; + + UINT configCount = 0; + hr = videoDevice->GetVideoDecoderConfigCount(&desc, &configCount); + NS_ENSURE_TRUE(SUCCEEDED(hr), false); + + for (UINT i = 0; i < configCount; i++) { + D3D11_VIDEO_DECODER_CONFIG config; + hr = videoDevice->GetVideoDecoderConfig(&desc, i, &config); + if (SUCCEEDED(hr)) { + nsRefPtr decoder; + hr = videoDevice->CreateVideoDecoder(&desc, &config, decoder.StartAssignment()); + if (SUCCEEDED(hr) && decoder) { + return true; + } + } + } + return false; +} + D3D11DXVA2Manager::D3D11DXVA2Manager() : mWidth(0) , mHeight(0) @@ -488,6 +527,31 @@ D3D11DXVA2Manager::Init(nsACString& aFailureReason) return hr; } + RefPtr videoDevice; + hr = mDevice->QueryInterface(static_cast(byRef(videoDevice))); + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + + bool found = false; + UINT profileCount = videoDevice->GetVideoDecoderProfileCount(); + for (UINT i = 0; i < profileCount; i++) { + GUID id; + hr = videoDevice->GetVideoDecoderProfile(i, &id); + if (SUCCEEDED(hr) && id == DXVA2_ModeH264_E) { + found = true; + break; + } + } + if (!found) { + return E_FAIL; + } + + BOOL nv12Support = false; + hr = videoDevice->CheckVideoDecoderFormat(&DXVA2_ModeH264_E, DXGI_FORMAT_NV12, &nv12Support); + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + if (!nv12Support) { + return E_FAIL; + } + mTextureClientAllocator = new D3D11RecycleAllocator(layers::ImageBridgeChild::GetSingleton(), mDevice); mTextureClientAllocator->SetMaxPoolSize(5); diff --git a/dom/media/platforms/wmf/DXVA2Manager.h b/dom/media/platforms/wmf/DXVA2Manager.h index 2b2d8ade85b1..cb361a297627 100644 --- a/dom/media/platforms/wmf/DXVA2Manager.h +++ b/dom/media/platforms/wmf/DXVA2Manager.h @@ -44,7 +44,7 @@ class DXVA2Manager { virtual ~DXVA2Manager(); - virtual bool SupportsConfig(IMFMediaType* aType) { return true; } + virtual bool SupportsConfig(IMFMediaType* aType) = 0; protected: Mutex mLock; From 72cf183b759241776e065c9bb2c441285051372c Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Thu, 20 Aug 2015 11:37:26 -0400 Subject: [PATCH 006/208] Bug 1196411 - Disable DXVA on 60fps 1080p videos for AMD cards that can't decode quick enough. r=jya --- dom/media/platforms/wmf/DXVA2Manager.cpp | 93 ++++++++++++++++++- dom/media/platforms/wmf/DXVA2Manager.h | 2 +- .../platforms/wmf/WMFVideoMFTManager.cpp | 8 +- dom/media/platforms/wmf/WMFVideoMFTManager.h | 1 + 4 files changed, 98 insertions(+), 6 deletions(-) diff --git a/dom/media/platforms/wmf/DXVA2Manager.cpp b/dom/media/platforms/wmf/DXVA2Manager.cpp index 323081fb8c0e..5d70fcd754ea 100644 --- a/dom/media/platforms/wmf/DXVA2Manager.cpp +++ b/dom/media/platforms/wmf/DXVA2Manager.cpp @@ -37,6 +37,35 @@ const GUID MF_XVP_PLAYBACK_MODE = DEFINE_GUID(MF_LOW_LATENCY, 0x9c27891a, 0xed7a, 0x40e1, 0x88, 0xe8, 0xb2, 0x27, 0x27, 0xa0, 0x24, 0xee); +// R600, R700, Evergreen and Cayman AMD cards. These support DXVA via UVD3 or earlier, and don't +// handle 1080p60 well. +static const DWORD sAMDPreUVD4[] = { + 0x9400, 0x9401, 0x9402, 0x9403, 0x9405, 0x940a, 0x940b, 0x940f, 0x94c0, 0x94c1, 0x94c3, 0x94c4, 0x94c5, + 0x94c6, 0x94c7, 0x94c8, 0x94c9, 0x94cb, 0x94cc, 0x94cd, 0x9580, 0x9581, 0x9583, 0x9586, 0x9587, 0x9588, + 0x9589, 0x958a, 0x958b, 0x958c, 0x958d, 0x958e, 0x958f, 0x9500, 0x9501, 0x9504, 0x9505, 0x9506, 0x9507, + 0x9508, 0x9509, 0x950f, 0x9511, 0x9515, 0x9517, 0x9519, 0x95c0, 0x95c2, 0x95c4, 0x95c5, 0x95c6, 0x95c7, + 0x95c9, 0x95cc, 0x95cd, 0x95ce, 0x95cf, 0x9590, 0x9591, 0x9593, 0x9595, 0x9596, 0x9597, 0x9598, 0x9599, + 0x959b, 0x9610, 0x9611, 0x9612, 0x9613, 0x9614, 0x9615, 0x9616, 0x9710, 0x9711, 0x9712, 0x9713, 0x9714, + 0x9715, 0x9440, 0x9441, 0x9442, 0x9443, 0x9444, 0x9446, 0x944a, 0x944b, 0x944c, 0x944e, 0x9450, 0x9452, + 0x9456, 0x945a, 0x945b, 0x945e, 0x9460, 0x9462, 0x946a, 0x946b, 0x947a, 0x947b, 0x9480, 0x9487, 0x9488, + 0x9489, 0x948a, 0x948f, 0x9490, 0x9491, 0x9495, 0x9498, 0x949c, 0x949e, 0x949f, 0x9540, 0x9541, 0x9542, + 0x954e, 0x954f, 0x9552, 0x9553, 0x9555, 0x9557, 0x955f, 0x94a0, 0x94a1, 0x94a3, 0x94b1, 0x94b3, 0x94b4, + 0x94b5, 0x94b9, 0x68e0, 0x68e1, 0x68e4, 0x68e5, 0x68e8, 0x68e9, 0x68f1, 0x68f2, 0x68f8, 0x68f9, 0x68fa, + 0x68fe, 0x68c0, 0x68c1, 0x68c7, 0x68c8, 0x68c9, 0x68d8, 0x68d9, 0x68da, 0x68de, 0x68a0, 0x68a1, 0x68a8, + 0x68a9, 0x68b0, 0x68b8, 0x68b9, 0x68ba, 0x68be, 0x68bf, 0x6880, 0x6888, 0x6889, 0x688a, 0x688c, 0x688d, + 0x6898, 0x6899, 0x689b, 0x689e, 0x689c, 0x689d, 0x9802, 0x9803, 0x9804, 0x9805, 0x9806, 0x9807, 0x9808, + 0x9809, 0x980a, 0x9640, 0x9641, 0x9647, 0x9648, 0x964a, 0x964b, 0x964c, 0x964e, 0x964f, 0x9642, 0x9643, + 0x9644, 0x9645, 0x9649, 0x6720, 0x6721, 0x6722, 0x6723, 0x6724, 0x6725, 0x6726, 0x6727, 0x6728, 0x6729, + 0x6738, 0x6739, 0x673e, 0x6740, 0x6741, 0x6742, 0x6743, 0x6744, 0x6745, 0x6746, 0x6747, 0x6748, 0x6749, + 0x674a, 0x6750, 0x6751, 0x6758, 0x6759, 0x675b, 0x675d, 0x675f, 0x6840, 0x6841, 0x6842, 0x6843, 0x6849, + 0x6850, 0x6858, 0x6859, 0x6760, 0x6761, 0x6762, 0x6763, 0x6764, 0x6765, 0x6766, 0x6767, 0x6768, 0x6770, + 0x6771, 0x6772, 0x6778, 0x6779, 0x677b, 0x6700, 0x6701, 0x6702, 0x6703, 0x6704, 0x6705, 0x6706, 0x6707, + 0x6708, 0x6709, 0x6718, 0x6719, 0x671c, 0x671d, 0x671f, 0x9900, 0x9901, 0x9903, 0x9904, 0x9905, 0x9906, + 0x9907, 0x9908, 0x9909, 0x990a, 0x990b, 0x990c, 0x990d, 0x990e, 0x990f, 0x9910, 0x9913, 0x9917, 0x9918, + 0x9919, 0x9990, 0x9991, 0x9992, 0x9993, 0x9994, 0x9995, 0x9996, 0x9997, 0x9998, 0x9999, 0x999a, 0x999b, + 0x999c, 0x999d, 0x99a0, 0x99a2, 0x99a4 +}; + namespace mozilla { using layers::Image; @@ -63,7 +92,7 @@ class D3D9DXVA2Manager : public DXVA2Manager ImageContainer* aContainer, Image** aOutImage) override; - virtual bool SupportsConfig(IMFMediaType* aType) override; + virtual bool SupportsConfig(IMFMediaType* aType, float aFramerate) override; private: nsRefPtr mD3D9; @@ -73,6 +102,7 @@ class D3D9DXVA2Manager : public DXVA2Manager nsRefPtr mDecoderService; UINT32 mResetToken; bool mFirstFrame; + bool mIsAMDPreUVD4; }; void GetDXVA2ExtendedFormatFromMFMediaType(IMFMediaType *pType, @@ -145,12 +175,21 @@ static const GUID DXVA2_ModeH264_E = { // decoder MFT provided by windows (CLSID_CMSH264DecoderMFT) uses, so we can use it to determine // if the MFT will use software fallback or not. bool -D3D9DXVA2Manager::SupportsConfig(IMFMediaType* aType) +D3D9DXVA2Manager::SupportsConfig(IMFMediaType* aType, float aFramerate) { DXVA2_VideoDesc desc; HRESULT hr = ConvertMFTypeToDXVAType(aType, &desc); NS_ENSURE_TRUE(SUCCEEDED(hr), false); + // AMD cards with UVD3 or earlier perform poorly trying to decode 1080p60 in hardware, + // so use software instead. Pick 45 as an arbitrary upper bound for the framerate we can + // handle. + if (mIsAMDPreUVD4 && + (desc.SampleWidth >= 1920 || desc.SampleHeight >= 1088) && + aFramerate > 45) { + return false; + } + UINT configCount; DXVA2_ConfigPictureDecode* configs = nullptr; hr = mDecoderService->GetDecoderConfigurations(DXVA2_ModeH264_E, &desc, nullptr, &configCount, &configs); @@ -181,6 +220,7 @@ D3D9DXVA2Manager::SupportsConfig(IMFMediaType* aType) D3D9DXVA2Manager::D3D9DXVA2Manager() : mResetToken(0) , mFirstFrame(true) + , mIsAMDPreUVD4(false) { MOZ_COUNT_CTOR(D3D9DXVA2Manager); MOZ_ASSERT(NS_IsMainThread()); @@ -316,6 +356,19 @@ D3D9DXVA2Manager::Init(nsACString& aFailureReason) return E_FAIL; } + D3DADAPTER_IDENTIFIER9 adapter; + hr = d3d9Ex->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &adapter); + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + + if (adapter.VendorId = 0x1022) { + for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sAMDPreUVD4); i++) { + if (adapter.DeviceId == sAMDPreUVD4[i]) { + mIsAMDPreUVD4 = true; + break; + } + } + } + mDecoderService = decoderService; mResetToken = resetToken; @@ -412,7 +465,7 @@ class D3D11DXVA2Manager : public DXVA2Manager virtual bool IsD3D11() override { return true; } - virtual bool SupportsConfig(IMFMediaType* aType) override; + virtual bool SupportsConfig(IMFMediaType* aType, float aFramerate) override; private: HRESULT CreateFormatConverter(); @@ -428,10 +481,11 @@ class D3D11DXVA2Manager : public DXVA2Manager uint32_t mWidth; uint32_t mHeight; UINT mDeviceManagerToken; + bool mIsAMDPreUVD4; }; bool -D3D11DXVA2Manager::SupportsConfig(IMFMediaType* aType) +D3D11DXVA2Manager::SupportsConfig(IMFMediaType* aType, float aFramerate) { RefPtr videoDevice; HRESULT hr = mDevice->QueryInterface(static_cast(byRef(videoDevice))); @@ -449,6 +503,15 @@ D3D11DXVA2Manager::SupportsConfig(IMFMediaType* aType) desc.OutputFormat = DXGI_FORMAT_NV12; + // AMD cards with UVD3 or earlier perform poorly trying to decode 1080p60 in hardware, + // so use software instead. Pick 45 as an arbitrary upper bound for the framerate we can + // handle. + if (mIsAMDPreUVD4 && + (desc.SampleWidth >= 1920 || desc.SampleHeight >= 1088) && + aFramerate > 45) { + return false; + } + UINT configCount = 0; hr = videoDevice->GetVideoDecoderConfigCount(&desc, &configCount); NS_ENSURE_TRUE(SUCCEEDED(hr), false); @@ -471,6 +534,7 @@ D3D11DXVA2Manager::D3D11DXVA2Manager() : mWidth(0) , mHeight(0) , mDeviceManagerToken(0) + , mIsAMDPreUVD4(false) { } @@ -552,6 +616,27 @@ D3D11DXVA2Manager::Init(nsACString& aFailureReason) return E_FAIL; } + RefPtr dxgiDevice; + hr = mDevice->QueryInterface(static_cast(byRef(dxgiDevice))); + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + + nsRefPtr adapter; + hr = dxgiDevice->GetAdapter(adapter.StartAssignment()); + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + + DXGI_ADAPTER_DESC adapterDesc; + hr = adapter->GetDesc(&adapterDesc); + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + + if (adapterDesc.VendorId = 0x1022) { + for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sAMDPreUVD4); i++) { + if (adapterDesc.DeviceId == sAMDPreUVD4[i]) { + mIsAMDPreUVD4 = true; + break; + } + } + } + mTextureClientAllocator = new D3D11RecycleAllocator(layers::ImageBridgeChild::GetSingleton(), mDevice); mTextureClientAllocator->SetMaxPoolSize(5); diff --git a/dom/media/platforms/wmf/DXVA2Manager.h b/dom/media/platforms/wmf/DXVA2Manager.h index cb361a297627..c44d1859fdf5 100644 --- a/dom/media/platforms/wmf/DXVA2Manager.h +++ b/dom/media/platforms/wmf/DXVA2Manager.h @@ -44,7 +44,7 @@ class DXVA2Manager { virtual ~DXVA2Manager(); - virtual bool SupportsConfig(IMFMediaType* aType) = 0; + virtual bool SupportsConfig(IMFMediaType* aType, float aFramerate) = 0; protected: Mutex mLock; diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp index 386f44e14348..742bd9dfe104 100644 --- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp +++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp @@ -307,6 +307,8 @@ WMFVideoMFTManager::Input(MediaRawData* aSample) &mLastInput); NS_ENSURE_TRUE(SUCCEEDED(hr) && mLastInput != nullptr, hr); + mLastDuration = aSample->mDuration; + // Forward sample data to the decoder. return mDecoder->Input(mLastInput); } @@ -330,7 +332,11 @@ WMFVideoMFTManager::MaybeToggleDXVA(IMFMediaType* aType) return false; } - if (mDXVA2Manager->SupportsConfig(aType)) { + // Assume the current samples duration is representative for the + // entire video. + float framerate = 1000000.0 / mLastDuration; + + if (mDXVA2Manager->SupportsConfig(aType, framerate)) { if (!mUseHwAccel) { // DXVA disabled, but supported for this resolution ULONG_PTR manager = ULONG_PTR(mDXVA2Manager->GetDXVADeviceManager()); diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.h b/dom/media/platforms/wmf/WMFVideoMFTManager.h index 467b70a63c32..8a209b49b69c 100644 --- a/dom/media/platforms/wmf/WMFVideoMFTManager.h +++ b/dom/media/platforms/wmf/WMFVideoMFTManager.h @@ -72,6 +72,7 @@ class WMFVideoMFTManager : public MFTManager { nsAutoPtr mDXVA2Manager; RefPtr mLastInput; + float mLastDuration; const bool mDXVAEnabled; const layers::LayersBackend mLayersBackend; From 447f51d637856eb94dbfcad2dbd968267d1d7c7f Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Thu, 20 Aug 2015 11:39:49 -0400 Subject: [PATCH 007/208] Bug 1196408 - Make sure we only report a corrupt/slow video frame once. r=cpearce --- dom/media/MediaDecoderStateMachine.cpp | 18 ++++++++++++++++-- dom/media/MediaDecoderStateMachine.h | 2 +- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index 5f361e7c3b8a..6bdd1fb290df 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -2463,11 +2463,17 @@ MediaDecoderStateMachine::Reset() DecodeTaskQueue()->Dispatch(resetTask.forget()); } -void MediaDecoderStateMachine::CheckTurningOffHardwareDecoder(VideoData* aData) +bool MediaDecoderStateMachine::CheckFrameValidity(VideoData* aData) { MOZ_ASSERT(OnTaskQueue()); AssertCurrentThreadInMonitor(); + // If we've sent this frame before then only return the valid state, + // don't update the statistics. + if (aData->mSentToCompositor) { + return !aData->mImage || aData->mImage->IsValid(); + } + // Update corrupt-frames statistics if (aData->mImage && !aData->mImage->IsValid()) { MediaDecoder::FrameStatistics& frameStats = mDecoder->GetFrameStatistics(); @@ -2486,8 +2492,10 @@ void MediaDecoderStateMachine::CheckTurningOffHardwareDecoder(VideoData* aData) mDisabledHardwareAcceleration = true; gfxCriticalNote << "Too many dropped/corrupted frames, disabling DXVA"; } + return false; } else { mCorruptFrames.insert(0); + return true; } } @@ -2509,14 +2517,21 @@ void MediaDecoderStateMachine::RenderVideoFrames(int32_t aMaxFrames, TimeStamp lastFrameTime; for (uint32_t i = 0; i < frames.Length(); ++i) { VideoData* frame = frames[i]->As(); + + bool valid = CheckFrameValidity(frame); frame->mSentToCompositor = true; + if (!valid) { + continue; + } + int64_t frameTime = frame->mTime; if (frameTime < 0) { // Frame times before the start time are invalid; drop such frames continue; } + TimeStamp t; if (aMaxFrames > 1) { MOZ_ASSERT(!aClockTimeStamp.IsNull()); @@ -2663,7 +2678,6 @@ void MediaDecoderStateMachine::UpdateRenderedVideoFrames() VERBOSE_LOG("discarding video frame mTime=%lld clock_time=%lld", currentFrame->mTime, clockTime); } - CheckTurningOffHardwareDecoder(currentFrame->As()); currentFrame = VideoQueue().PopFront(); } diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h index bb5829351d45..1190a0d8a454 100644 --- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -493,7 +493,7 @@ class MediaDecoderStateMachine void UpdatePlaybackPositionInternal(int64_t aTime); // Decode monitor must be held. - void CheckTurningOffHardwareDecoder(VideoData* aData); + bool CheckFrameValidity(VideoData* aData); // Sets VideoQueue images into the VideoFrameContainer. Called on the shared // state machine thread. Decode monitor must be held. The first aMaxFrames From dfec541c83ffa8898b382ea102894360e218d8d5 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Thu, 20 Aug 2015 11:43:36 -0400 Subject: [PATCH 008/208] Bug 1196417 - Make video software fallback only affect the current video instead of the entire browser. r=cpearce --- dom/media/MediaDecoderStateMachine.cpp | 6 ++---- dom/media/MediaDecoderStateMachine.h | 2 -- dom/media/MediaFormatReader.cpp | 15 +++++++++++---- dom/media/MediaFormatReader.h | 2 ++ dom/media/platforms/PlatformDecoderModule.h | 2 -- dom/media/platforms/SharedDecoderManager.cpp | 7 ------- dom/media/platforms/SharedDecoderManager.h | 1 - dom/media/platforms/wmf/WMFDecoderModule.cpp | 15 --------------- dom/media/platforms/wmf/WMFDecoderModule.h | 3 --- 9 files changed, 15 insertions(+), 38 deletions(-) diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index 6bdd1fb290df..f6d7fa47b0ea 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -218,7 +218,6 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder, mCurrentTimeBeforeSeek(0), mCorruptFrames(30), mDecodingFirstFrame(true), - mDisabledHardwareAcceleration(false), mSentLoadedMetadataEvent(false), mSentFirstFrameLoadedEvent(false), mSentPlaybackEndedEvent(false), @@ -2482,14 +2481,13 @@ bool MediaDecoderStateMachine::CheckFrameValidity(VideoData* aData) // hardware acceleration. We use 10 as the corrupt value because RollingMean<> // only supports integer types. mCorruptFrames.insert(10); - if (!mDisabledHardwareAcceleration && - mReader->VideoIsHardwareAccelerated() && + if (mReader->VideoIsHardwareAccelerated() && frameStats.GetPresentedFrames() > 30 && mCorruptFrames.mean() >= 1 /* 10% */) { nsCOMPtr task = NS_NewRunnableMethod(mReader, &MediaDecoderReader::DisableHardwareAcceleration); DecodeTaskQueue()->Dispatch(task.forget()); - mDisabledHardwareAcceleration = true; + mCorruptFrames.clear(); gfxCriticalNote << "Too many dropped/corrupted frames, disabling DXVA"; } return false; diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h index 1190a0d8a454..0da374d4e9d2 100644 --- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -1271,8 +1271,6 @@ class MediaDecoderStateMachine // successeeding. bool mDecodingFirstFrame; - bool mDisabledHardwareAcceleration; - // True if we are back from DECODER_STATE_DORMANT state and // LoadedMetadataEvent was already sent. bool mSentLoadedMetadataEvent; diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index f0d95ae37cea..45bd09a624ec 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -73,6 +73,7 @@ MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder, , mSeekable(false) , mIsEncrypted(false) , mTrackDemuxersMayBlock(false) + , mHardwareAccelerationDisabled(false) { MOZ_ASSERT(aDemuxer); MOZ_COUNT_CTOR(MediaFormatReader); @@ -467,8 +468,11 @@ MediaFormatReader::EnsureDecodersCreated() false); mVideo.mDecoderInitialized = false; + // If we've disabled hardware acceleration for this reader, then we can't use + // the shared decoder. if (mSharedDecoderManager && - mPlatform->SupportsSharedDecoders(mInfo.mVideo)) { + mPlatform->SupportsSharedDecoders(mInfo.mVideo) && + !mHardwareAccelerationDisabled) { mVideo.mDecoder = mSharedDecoderManager->CreateVideoDecoder(mPlatform, mVideo.mInfo ? @@ -479,13 +483,16 @@ MediaFormatReader::EnsureDecodersCreated() mVideo.mTaskQueue, mVideo.mCallback); } else { + // Decoders use the layers backend to decide if they can use hardware decoding, + // so specify LAYERS_NONE if we want to forcibly disable it. mVideo.mDecoder = mPlatform->CreateDecoder(mVideo.mInfo ? *mVideo.mInfo->GetAsVideoInfo() : mInfo.mVideo, mVideo.mTaskQueue, mVideo.mCallback, - mLayersBackendType, + mHardwareAccelerationDisabled ? LayersBackend::LAYERS_NONE : + mLayersBackendType, mDecoder->GetImageContainer()); } NS_ENSURE_TRUE(mVideo.mDecoder != nullptr, false); @@ -590,8 +597,8 @@ void MediaFormatReader::DisableHardwareAcceleration() { MOZ_ASSERT(OnTaskQueue()); - if (HasVideo()) { - mPlatform->DisableHardwareAcceleration(); + if (HasVideo() && !mHardwareAccelerationDisabled) { + mHardwareAccelerationDisabled = true; Flush(TrackInfo::kVideoTrack); mVideo.mDecoder->Shutdown(); mVideo.mDecoder = nullptr; diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index 6431e9d4823a..485dd1ba4b3c 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -399,6 +399,8 @@ class MediaFormatReader final : public MediaDecoderReader // Set to true if any of our track buffers may be blocking. bool mTrackDemuxersMayBlock; + bool mHardwareAccelerationDisabled; + // Seeking objects. bool IsSeeking() const { return mPendingSeekTime.isSome(); } void AttemptSeek(); diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index c2f985e2bf61..e41dc54f0bed 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -110,8 +110,6 @@ class PlatformDecoderModule { // feeding it to MediaDataDecoder::Input. virtual ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const = 0; - virtual void DisableHardwareAcceleration() {} - virtual bool SupportsSharedDecoders(const VideoInfo& aConfig) const { return !AgnosticMimeType(aConfig.mMimeType); } diff --git a/dom/media/platforms/SharedDecoderManager.cpp b/dom/media/platforms/SharedDecoderManager.cpp index d538abf27752..29fde2c34fe2 100644 --- a/dom/media/platforms/SharedDecoderManager.cpp +++ b/dom/media/platforms/SharedDecoderManager.cpp @@ -120,13 +120,6 @@ SharedDecoderManager::CreateVideoDecoder( return proxy.forget(); } -void -SharedDecoderManager::DisableHardwareAcceleration() -{ - MOZ_ASSERT(mPDM); - mPDM->DisableHardwareAcceleration(); -} - bool SharedDecoderManager::Recreate(const VideoInfo& aConfig) { diff --git a/dom/media/platforms/SharedDecoderManager.h b/dom/media/platforms/SharedDecoderManager.h index 43944e040cc6..25775289c44c 100644 --- a/dom/media/platforms/SharedDecoderManager.h +++ b/dom/media/platforms/SharedDecoderManager.h @@ -41,7 +41,6 @@ class SharedDecoderManager friend class SharedDecoderProxy; friend class SharedDecoderCallback; - void DisableHardwareAcceleration(); bool Recreate(const VideoInfo& aConfig); private: diff --git a/dom/media/platforms/wmf/WMFDecoderModule.cpp b/dom/media/platforms/wmf/WMFDecoderModule.cpp index 3aa21d75d031..697998cc6bd6 100644 --- a/dom/media/platforms/wmf/WMFDecoderModule.cpp +++ b/dom/media/platforms/wmf/WMFDecoderModule.cpp @@ -41,13 +41,6 @@ WMFDecoderModule::~WMFDecoderModule() } } -void -WMFDecoderModule::DisableHardwareAcceleration() -{ - sDXVAEnabled = false; - sIsIntelDecoderEnabled = false; -} - static void SetNumOfDecoderThreads() { @@ -133,14 +126,6 @@ WMFDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, return decoder.forget(); } -bool -WMFDecoderModule::SupportsSharedDecoders(const VideoInfo& aConfig) const -{ - // If DXVA is enabled, but we're not going to use it for this specific config, then - // we can't use the shared decoder. - return !AgnosticMimeType(aConfig.mMimeType); -} - bool WMFDecoderModule::SupportsMimeType(const nsACString& aMimeType) { diff --git a/dom/media/platforms/wmf/WMFDecoderModule.h b/dom/media/platforms/wmf/WMFDecoderModule.h index e4f5e886572e..e68d60c8e536 100644 --- a/dom/media/platforms/wmf/WMFDecoderModule.h +++ b/dom/media/platforms/wmf/WMFDecoderModule.h @@ -33,9 +33,6 @@ class WMFDecoderModule : public PlatformDecoderModule { bool SupportsMimeType(const nsACString& aMimeType) override; - virtual void DisableHardwareAcceleration() override; - virtual bool SupportsSharedDecoders(const VideoInfo& aConfig) const override; - virtual ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const override; From 96bf73ad644e8e1533f291986d9da114222d5a91 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Wed, 19 Aug 2015 21:04:07 -0400 Subject: [PATCH 009/208] Bug 1192449 - Re-enable browser_audioTabIcon.js in e10s mode; r=billm --- browser/base/content/test/general/browser.ini | 1 - browser/base/content/test/general/browser_audioTabIcon.js | 3 --- 2 files changed, 4 deletions(-) diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index 0a33f5249cc7..a192bbb08ab5 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -136,7 +136,6 @@ skip-if = e10s # Bug 1093153 - no about:home support yet [browser_search_favicon.js] [browser_alltabslistener.js] [browser_audioTabIcon.js] -skip-if = e10s # Bug 1192449 [browser_autocomplete_a11y_label.js] skip-if = e10s # Bug 1101993 - times out for unknown reasons when run in the dir (works on its own) [browser_autocomplete_cursor.js] diff --git a/browser/base/content/test/general/browser_audioTabIcon.js b/browser/base/content/test/general/browser_audioTabIcon.js index f56dd09c961f..742509687881 100644 --- a/browser/base/content/test/general/browser_audioTabIcon.js +++ b/browser/base/content/test/general/browser_audioTabIcon.js @@ -173,9 +173,6 @@ function* test_browser_swapping(tab, browser) { }, function*(newBrowser) { yield test_swapped_browser(tab, newBrowser, true) - // FIXME: this is needed to work around bug 1190903. - yield new Promise(resolve => setTimeout(resolve, 3000)); - // Now, test swapping with a muted but not playing tab. // Note that the tab remains muted, so we only need to pause playback. tab = gBrowser.getTabForBrowser(newBrowser); From 202b3532d407909bdd93d925df6a6e3accf36b43 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Thu, 20 Aug 2015 18:36:06 +0300 Subject: [PATCH 010/208] Bug 1196317 - Optimize CallbackObject::mCreationStack out from cycle collection graph when possible, r=mccr8 --- dom/base/nsGlobalWindow.cpp | 5 +---- dom/bindings/CallbackObject.h | 10 ++++++++++ dom/events/EventListenerManager.cpp | 5 ++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 854e1cdd74c4..60cff4fcf9e5 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -1918,10 +1918,7 @@ nsGlobalWindow::UnmarkGrayTimers() if (timeout->mScriptHandler) { Function* f = timeout->mScriptHandler->GetCallback(); if (f) { - // Callable() already does xpc_UnmarkGrayObject. - DebugOnly > o = f->Callable(); - MOZ_ASSERT(!JS::ObjectIsMarkedGray(o.value), - "Should have been unmarked"); + f->MarkForCC(); } } } diff --git a/dom/bindings/CallbackObject.h b/dom/bindings/CallbackObject.h index ff1bdcbf039f..99958876c990 100644 --- a/dom/bindings/CallbackObject.h +++ b/dom/bindings/CallbackObject.h @@ -83,6 +83,16 @@ class CallbackObject : public nsISupports return result; } + void MarkForCC() + { + if (mCallback) { + JS::ExposeObjectToActiveJS(mCallback); + } + if (mCreationStack) { + JS::ExposeObjectToActiveJS(mCreationStack); + } + } + /* * This getter does not change the color of the JSObject meaning that the * object returned is not guaranteed to be kept alive past the next CC. diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index e6a824d4a438..e5d2ca1a87f0 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -1469,13 +1469,12 @@ EventListenerManager::MarkForCC() const TypedEventHandler& typedHandler = jsEventHandler->GetTypedEventHandler(); if (typedHandler.HasEventHandler()) { - JS::ExposeObjectToActiveJS(typedHandler.Ptr()->Callable()); + typedHandler.Ptr()->MarkForCC(); } } else if (listener.mListenerType == Listener::eWrappedJSListener) { xpc_TryUnmarkWrappedGrayObject(listener.mListener.GetXPCOMCallback()); } else if (listener.mListenerType == Listener::eWebIDLListener) { - // Callback() unmarks gray - listener.mListener.GetWebIDLCallback()->Callback(); + listener.mListener.GetWebIDLCallback()->MarkForCC(); } } if (mRefCnt.IsPurple()) { From 2e7f2fdb61dd1b03be5a2587eeccf2a94c06c5f4 Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Thu, 20 Aug 2015 18:45:17 +0200 Subject: [PATCH 011/208] Bug 1194733 - Don't honor DefaultPrevented for mouseup events in list control frames. r=enndeakin@gmail.com --- layout/forms/nsListControlFrame.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/layout/forms/nsListControlFrame.cpp b/layout/forms/nsListControlFrame.cpp index af16d76c5003..a18689a9beb0 100644 --- a/layout/forms/nsListControlFrame.cpp +++ b/layout/forms/nsListControlFrame.cpp @@ -2461,11 +2461,8 @@ nsListEventListener::HandleEvent(nsIDOMEvent* aEvent) return mFrame->nsListControlFrame::MouseDown(aEvent); } if (eventType.EqualsLiteral("mouseup")) { - bool defaultPrevented = false; - aEvent->GetDefaultPrevented(&defaultPrevented); - if (defaultPrevented) { - return NS_OK; - } + // Don't try to honor defaultPrevented here - it's not web compatible. + // (bug 1194733) return mFrame->nsListControlFrame::MouseUp(aEvent); } if (eventType.EqualsLiteral("mousemove")) { From a2415a6c2405411c8321d673253f2c550f77c894 Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Thu, 20 Aug 2015 18:45:18 +0200 Subject: [PATCH 012/208] Bug 1189814. r=enndeakin@gmail.com --- dom/base/nsContentAreaDragDrop.cpp | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/dom/base/nsContentAreaDragDrop.cpp b/dom/base/nsContentAreaDragDrop.cpp index 6ded419e2b6e..0256e9f4710e 100644 --- a/dom/base/nsContentAreaDragDrop.cpp +++ b/dom/base/nsContentAreaDragDrop.cpp @@ -534,6 +534,14 @@ DragDataProducer::Produce(DataTransfer* aDataTransfer, // grab the href as the url, use alt text as the title of the // area if it's there. the drag data is the image tag and src // attribute. + nsCOMPtr imageURI; + image->GetCurrentURI(getter_AddRefs(imageURI)); + if (imageURI) { + nsAutoCString spec; + imageURI->GetSpec(spec); + CopyUTF8toUTF16(spec, mUrlString); + } + nsCOMPtr imageElement(do_QueryInterface(image)); // XXXbz Shouldn't we use the "title" attr for title? Using // "alt" seems very wrong.... @@ -541,10 +549,13 @@ DragDataProducer::Produce(DataTransfer* aDataTransfer, imageElement->GetAttribute(NS_LITERAL_STRING("alt"), mTitleString); } - mUrlString.Truncate(); + if (mTitleString.IsEmpty()) { + mTitleString = mUrlString; + } - // grab the image data, and its request. nsCOMPtr imgRequest; + + // grab the image data, and its request. nsCOMPtr img = nsContentUtils::GetImageFromContent(image, getter_AddRefs(imgRequest)); @@ -555,7 +566,7 @@ DragDataProducer::Produce(DataTransfer* aDataTransfer, // Fix the file extension in the URL if necessary if (imgRequest && mimeService) { nsCOMPtr imgUri; - imgRequest->GetCurrentURI(getter_AddRefs(imgUri)); + imgRequest->GetURI(getter_AddRefs(imgUri)); nsCOMPtr imgUrl(do_QueryInterface(imgUri)); @@ -576,7 +587,6 @@ DragDataProducer::Produce(DataTransfer* aDataTransfer, // pass out the image source string CopyUTF8toUTF16(spec, mImageSourceString); - mUrlString = mImageSourceString; bool validExtension; if (extension.IsEmpty() || @@ -611,18 +621,6 @@ DragDataProducer::Produce(DataTransfer* aDataTransfer, } } } - if (mUrlString.IsEmpty()) { - nsCOMPtr imageURI; - image->GetCurrentURI(getter_AddRefs(imageURI)); - if (imageURI) { - nsAutoCString spec; - imageURI->GetSpec(spec); - CopyUTF8toUTF16(spec, mUrlString); - } - } - if (mTitleString.IsEmpty()) { - mTitleString = mUrlString; - } if (parentLink) { // If we are dragging around an image in an anchor, then we From 412d288fcaf878750eb78a0a413d1d8761fb10eb Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Thu, 20 Aug 2015 17:45:34 +0100 Subject: [PATCH 013/208] Bug 1184807 - TextTrackList should check if we are shutting down before dispatching events, r=mccr8 --- dom/media/TextTrackList.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dom/media/TextTrackList.cpp b/dom/media/TextTrackList.cpp index 59d5ecdfa7b2..f1f1630d26db 100644 --- a/dom/media/TextTrackList.cpp +++ b/dom/media/TextTrackList.cpp @@ -181,6 +181,13 @@ void TextTrackList::CreateAndDispatchTrackEventRunner(TextTrack* aTrack, const nsAString& aEventName) { + nsCOMPtr thread; + nsresult rv = NS_GetMainThread(getter_AddRefs(thread)); + if (NS_FAILED(rv)) { + // If we are not able to get the main-thread object we are shutting down. + return; + } + TrackEventInit eventInit; eventInit.mTrack.SetValue().SetAsTextTrack() = aTrack; nsRefPtr event = From 39945a4fcaa291a876349a3f6667334f1f977ad0 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Wed, 19 Aug 2015 17:08:41 -0400 Subject: [PATCH 014/208] Bug 1186662 - Part 1: Add SuppressDisplayport painting and use it during tab switch. r=kats,mconley --- browser/base/content/tabbrowser.xml | 17 +++++++++++++++++ dom/interfaces/base/nsITabParent.idl | 10 +++++++++- dom/ipc/PBrowser.ipdl | 11 +++++++++++ dom/ipc/TabChild.cpp | 20 ++++++++++++++++++++ dom/ipc/TabChild.h | 3 +++ dom/ipc/TabParent.cpp | 20 ++++++++++++++++++++ dom/ipc/TabParent.h | 2 ++ gfx/layers/apz/util/APZCCallbackHelper.cpp | 21 +++++++++++++++++++++ gfx/layers/apz/util/APZCCallbackHelper.h | 4 ++++ layout/base/nsLayoutUtils.cpp | 6 +++++- 10 files changed, 112 insertions(+), 2 deletions(-) diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index ecc852166570..fde36c6ee001 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -3077,6 +3077,11 @@ // Map from tabs to STATE_* (below). tabState: new Map(), + // Keep an exact list of content processes (tabParent) in which + // we're actively suppressing the display port. This gives a robust + // way to make sure we don't forget to un-suppress. + activeSuppressDisplayport: new Set(), + // Set of tabs that might be visible right now. We maintain // this set because we can't be sure when a tab is actually // drawn. A tab is added to this set when we ask to make it @@ -3140,6 +3145,11 @@ window.removeEventListener("TabRemotenessChange", this); this.tabbrowser._switcher = null; + + this.activeSuppressDisplayport.forEach(function(tabParent) { + tabParent.suppressDisplayport(false); + }); + this.activeSuppressDisplayport.clear(); }, finish: function() { @@ -3438,6 +3448,13 @@ this.requestedTab = tab; + let browser = this.requestedTab.linkedBrowser; + let fl = browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader; + if (fl && fl.tabParent && !this.activeSuppressDisplayport.has(fl.tabParent)) { + fl.tabParent.suppressDisplayport(true); + this.activeSuppressDisplayport.add(fl.tabParent); + } + this.preActions(); clearTimeout(this.unloadTimer); diff --git a/dom/interfaces/base/nsITabParent.idl b/dom/interfaces/base/nsITabParent.idl index c09fba5d5524..a53a46f8850f 100644 --- a/dom/interfaces/base/nsITabParent.idl +++ b/dom/interfaces/base/nsITabParent.idl @@ -5,7 +5,7 @@ #include "domstubs.idl" -[scriptable, uuid(CE6F563B-BD77-4EF2-9D7C-A94C587353E4)] +[scriptable, uuid(531b902b-b551-4faa-9814-1a73e8299ac4)] interface nsITabParent : nsISupports { void injectTouchEvent(in AString aType, @@ -25,6 +25,14 @@ interface nsITabParent : nsISupports void setIsDocShellActive(in bool aIsActive); + /** + * During interactions where painting performance + * is more important than scrolling, we may temporarily + * suppress the displayport. Each enable called must be matched + * with a disable call. + */ + void suppressDisplayport(in bool aEnabled); + readonly attribute uint64_t tabId; /** diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index 2ba56babdc3e..70017a953783 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -709,6 +709,17 @@ child: */ SetIsDocShellActive(bool aIsActive); + /** + * Notify the child that it shouldn't paint the offscreen displayport. + * This is useful to speed up interactive operations over async + * scrolling performance like resize, tabswitch, pageload. + * + * Each enable call must be matched with a disable call. The child + * will remain in the suppress mode as long as there's + * a single unmatched call. + */ + async SuppressDisplayport(bool aEnabled); + /** * Navigate by key (Tab/Shift+Tab/F6/Shift+f6). */ diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index c20fa1bec7da..5c94d7c9713d 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -554,6 +554,7 @@ TabChild::TabChild(nsIContentChild* aManager, , mRemoteFrame(nullptr) , mManager(aManager) , mChromeFlags(aChromeFlags) + , mActiveSuppressDisplayport(0) , mLayersId(0) , mActivePointerId(-1) , mAppPackageFileDescriptorRecved(false) @@ -1693,6 +1694,20 @@ TabChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics) return TabChildBase::UpdateFrameHandler(aFrameMetrics); } +bool +TabChild::RecvSuppressDisplayport(const bool& aEnabled) +{ + if (aEnabled) { + mActiveSuppressDisplayport++; + } else { + mActiveSuppressDisplayport--; + } + + MOZ_ASSERT(mActiveSuppressDisplayport >= 0); + APZCCallbackHelper::SuppressDisplayport(aEnabled); + return true; +} + bool TabChild::RecvRequestFlingSnap(const FrameMetrics::ViewID& aScrollId, const mozilla::CSSPoint& aDestination) @@ -2413,6 +2428,11 @@ TabChild::RecvDestroy() MOZ_ASSERT(mDestroyed == false); mDestroyed = true; + while (mActiveSuppressDisplayport > 0) { + APZCCallbackHelper::SuppressDisplayport(false); + mActiveSuppressDisplayport--; + } + if (mTabChildGlobal) { // Message handlers are called from the event loop, so it better be safe to // run script. diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index 0520562df94a..00d85ee4a393 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -512,6 +512,8 @@ class TabChild final : public TabChildBase, virtual bool RecvRequestNotifyAfterRemotePaint() override; + virtual bool RecvSuppressDisplayport(const bool& aEnabled) override; + virtual bool RecvParentActivated(const bool& aActivated) override; virtual bool RecvStopIMEStateManagement() override; @@ -608,6 +610,7 @@ class TabChild final : public TabChildBase, RenderFrameChild* mRemoteFrame; nsRefPtr mManager; uint32_t mChromeFlags; + int32_t mActiveSuppressDisplayport; uint64_t mLayersId; CSSRect mUnscaledOuterRect; // When we're tracking a possible tap gesture, this is the "down" diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index e79b3e1d6420..3265ec35b83f 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -287,6 +287,7 @@ TabParent::TabParent(nsIContentParent* aManager, , mCursor(nsCursor(-1)) , mTabSetsCursor(false) , mHasContentOpener(false) + , mActiveSupressDisplayportCount(0) { MOZ_ASSERT(aManager); } @@ -2955,6 +2956,25 @@ TabParent::SetIsDocShellActive(bool isActive) return NS_OK; } +NS_IMETHODIMP +TabParent::SuppressDisplayport(bool aEnabled) +{ + if (IsDestroyed()) { + return NS_OK; + } + + if (aEnabled) { + mActiveSupressDisplayportCount++; + } else { + mActiveSupressDisplayportCount--; + } + + MOZ_ASSERT(mActiveSupressDisplayportCount >= 0); + + unused << SendSuppressDisplayport(aEnabled); + return NS_OK; +} + NS_IMETHODIMP TabParent::GetTabId(uint64_t* aId) { diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index 3c53f0251d1d..f0a04b0d8ed1 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -609,6 +609,8 @@ class TabParent final : public PBrowserParent nsRefPtr mPresShellWithRefreshListener; bool mHasContentOpener; + + DebugOnly mActiveSupressDisplayportCount; private: // This is used when APZ needs to find the TabParent associated with a layer // to dispatch events. diff --git a/gfx/layers/apz/util/APZCCallbackHelper.cpp b/gfx/layers/apz/util/APZCCallbackHelper.cpp index da4377ff25fb..dbb4e81d4afb 100644 --- a/gfx/layers/apz/util/APZCCallbackHelper.cpp +++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp @@ -810,6 +810,27 @@ APZCCallbackHelper::NotifyFlushComplete() observerService->NotifyObservers(nullptr, "apz-repaints-flushed", nullptr); } +static int32_t sActiveSuppressDisplayport = 0; + +void +APZCCallbackHelper::SuppressDisplayport(const bool& aEnabled) +{ + if (aEnabled) { + sActiveSuppressDisplayport++; + } else { + sActiveSuppressDisplayport--; + } + + MOZ_ASSERT(sActiveSuppressDisplayport >= 0); +} + +bool +APZCCallbackHelper::IsDisplayportSuppressed() +{ + return sActiveSuppressDisplayport > 0; +} + + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/apz/util/APZCCallbackHelper.h b/gfx/layers/apz/util/APZCCallbackHelper.h index a2d8f49f668b..a655f08a6e75 100644 --- a/gfx/layers/apz/util/APZCCallbackHelper.h +++ b/gfx/layers/apz/util/APZCCallbackHelper.h @@ -169,6 +169,10 @@ class APZCCallbackHelper /* Notify content that the repaint flush is complete. */ static void NotifyFlushComplete(); + + /* Temporarily ignore the Displayport for better paint performance. */ + static void SuppressDisplayport(const bool& aEnabled); + static bool IsDisplayportSuppressed(); }; } // namespace layers diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 612115e3e3c2..ae9aa41e5142 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -62,6 +62,7 @@ #include "mozilla/dom/HTMLImageElement.h" #include "mozilla/dom/DOMRect.h" #include "mozilla/dom/KeyframeEffect.h" +#include "mozilla/layers/APZCCallbackHelper.h" #include "imgIRequest.h" #include "nsIImageLoadingContent.h" #include "nsCOMPtr.h" @@ -1038,7 +1039,10 @@ GetDisplayPortImpl(nsIContent* aContent, nsRect *aResult, float aMultiplier) "Only one of rectData or marginsData should be set!"); nsRect result; - if (rectData) { + if (APZCCallbackHelper::IsDisplayportSuppressed()) { + DisplayPortMarginsPropertyData noMargins(ScreenMargin(), 1); + result = GetDisplayPortFromMarginsData(aContent, &noMargins, aMultiplier); + } else if (rectData) { result = GetDisplayPortFromRectData(aContent, rectData, aMultiplier); } else { result = GetDisplayPortFromMarginsData(aContent, marginsData, aMultiplier); From 6c3bcc340c4fc20e2f3ea1e68dd24348e6e9dfbc Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 19 Aug 2015 09:50:07 +0100 Subject: [PATCH 015/208] Bug 1183195 - Fix assertion at the start of InnerViewTable::sweepAfterMinorGC() r=sfink --- js/src/vm/ArrayBufferObject.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index dae69d741d7c..eb34f0860dd4 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -1056,8 +1056,10 @@ InnerViewTable::addView(JSContext* cx, ArrayBufferObject* obj, ArrayBufferViewOb } } - if (!views.append(view)) + if (!views.append(view)) { + ReportOutOfMemory(cx); return false; + } } else { if (!map.add(p, obj, ViewVector())) return false; @@ -1128,7 +1130,7 @@ InnerViewTable::sweep(JSRuntime* rt) void InnerViewTable::sweepAfterMinorGC(JSRuntime* rt) { - MOZ_ASSERT(!nurseryKeys.empty()); + MOZ_ASSERT(needsSweepAfterMinorGC()); if (nurseryKeysValid) { for (size_t i = 0; i < nurseryKeys.length(); i++) { From 26561395c979c3e3a6685ea67e8f3521a4c0e015 Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Thu, 20 Aug 2015 10:30:10 -0700 Subject: [PATCH 016/208] Bug 1194886 - Don't create files in tests. r=jld --- dom/html/test/mochitest.ini | 2 +- dom/html/test/test_bug523771.html | 35 +++++++------------------------ 2 files changed, 8 insertions(+), 29 deletions(-) diff --git a/dom/html/test/mochitest.ini b/dom/html/test/mochitest.ini index 4a0a7660ae32..cfefd3701e78 100644 --- a/dom/html/test/mochitest.ini +++ b/dom/html/test/mochitest.ini @@ -286,7 +286,7 @@ skip-if = toolkit == 'android' [test_bug518122.html] [test_bug519987.html] [test_bug523771.html] -skip-if = buildapp == 'b2g' || e10s # b2g(onload of iframe not firing, because submit not working?) b2g-debug(onload of iframe not firing, because submit not working?) b2g-desktop(onload of iframe not firing, because submit not working?) +skip-if = buildapp == 'b2g' # b2g(onload of iframe not firing, because submit not working?) b2g-debug(onload of iframe not firing, because submit not working?) b2g-desktop(onload of iframe not firing, because submit not working?) [test_bug529819.html] [test_bug529859.html] [test_bug535043.html] diff --git a/dom/html/test/test_bug523771.html b/dom/html/test/test_bug523771.html index 497b5e63ff82..80527ff93a57 100644 --- a/dom/html/test/test_bug523771.html +++ b/dom/html/test/test_bug523771.html @@ -20,7 +20,6 @@
 

From 88e84dec2b4b25cee07426779f6ef06f85a8826e Mon Sep 17 00:00:00 2001
From: Andrea Marchesini 
Date: Thu, 20 Aug 2015 12:48:57 +0100
Subject: [PATCH 019/208] Bug 1191814 - WebSpeech synthesis API and
 AudioChannelService, r=eeejay

---
 .../synth/ipc/PSpeechSynthesisRequest.ipdl    |  2 +
 .../synth/ipc/SpeechSynthesisChild.cpp        |  8 ++
 .../synth/ipc/SpeechSynthesisChild.h          |  2 +
 .../synth/ipc/SpeechSynthesisParent.cpp       |  8 ++
 .../synth/ipc/SpeechSynthesisParent.h         |  2 +
 dom/media/webspeech/synth/nsSpeechTask.cpp    | 94 +++++++++++++++----
 dom/media/webspeech/synth/nsSpeechTask.h      | 13 ++-
 7 files changed, 108 insertions(+), 21 deletions(-)

diff --git a/dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl b/dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl
index 9a146145bbd7..d244b1708ca5 100644
--- a/dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl
+++ b/dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl
@@ -23,6 +23,8 @@ async protocol PSpeechSynthesisRequest
 
   ForceEnd();
 
+  SetAudioOutputVolume(uint32_t aVolume);
+
  child:
 
   __delete__(bool aIsError, float aElapsedTime, uint32_t aCharIndex);
diff --git a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp
index c6f4e60258ac..04acb3e9e5d5 100644
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp
@@ -191,5 +191,13 @@ SpeechTaskChild::ForceEnd()
   mActor->SendForceEnd();
 }
 
+void
+SpeechTaskChild::SetAudioOutputVolume(uint32_t aVolume)
+{
+  if (mActor) {
+    mActor->SendSetAudioOutputVolume(aVolume);
+  }
+}
+
 } // namespace dom
 } // namespace mozilla
diff --git a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h
index a89cbaa43814..cb0d7d78f848 100644
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h
@@ -92,6 +92,8 @@ class SpeechTaskChild : public nsSpeechTask
 
   virtual void ForceEnd() override;
 
+  virtual void SetAudioOutputVolume(uint32_t aVolume) override;
+
 private:
   SpeechSynthesisRequestChild* mActor;
 };
diff --git a/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.cpp b/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.cpp
index e6ef6d654618..6729f3bbf628 100644
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.cpp
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.cpp
@@ -127,6 +127,14 @@ SpeechSynthesisRequestParent::RecvForceEnd()
   return true;
 }
 
+bool
+SpeechSynthesisRequestParent::RecvSetAudioOutputVolume(const uint32_t& aVolume)
+{
+  MOZ_ASSERT(mTask);
+  mTask->SetAudioOutputVolume(aVolume);
+  return true;
+}
+
 // SpeechTaskParent
 
 nsresult
diff --git a/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.h b/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.h
index 67272583c5d6..95417666f218 100644
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.h
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.h
@@ -69,6 +69,8 @@ class SpeechSynthesisRequestParent : public PSpeechSynthesisRequestParent
   virtual bool RecvCancel() override;
 
   virtual bool RecvForceEnd() override;
+
+  virtual bool RecvSetAudioOutputVolume(const uint32_t& aVolume) override;
 };
 
 class SpeechTaskParent : public nsSpeechTask
diff --git a/dom/media/webspeech/synth/nsSpeechTask.cpp b/dom/media/webspeech/synth/nsSpeechTask.cpp
index efe7c66c0ecb..f4f4bba304b1 100644
--- a/dom/media/webspeech/synth/nsSpeechTask.cpp
+++ b/dom/media/webspeech/synth/nsSpeechTask.cpp
@@ -4,10 +4,13 @@
  * 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/. */
 
+#include "AudioChannelAgent.h"
+#include "AudioChannelService.h"
 #include "AudioSegment.h"
+#include "mozilla/Preferences.h"
 #include "nsSpeechTask.h"
-#include "SpeechSynthesis.h"
 #include "nsSynthVoiceRegistry.h"
+#include "SpeechSynthesis.h"
 
 // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
 // GetTickCount() and conflicts with nsSpeechTask::GetCurrentTime().
@@ -22,6 +25,11 @@ extern PRLogModuleInfo* GetSpeechSynthLog();
 namespace mozilla {
 namespace dom {
 
+static bool UseAudioChannelService()
+{
+  return Preferences::GetBool("media.useAudioChannelService");
+}
+
 class SynthStreamListener : public MediaStreamListener
 {
 public:
@@ -89,6 +97,7 @@ NS_IMPL_CYCLE_COLLECTION(nsSpeechTask, mSpeechSynthesis, mUtterance, mCallback);
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSpeechTask)
   NS_INTERFACE_MAP_ENTRY(nsISpeechTask)
+  NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechTask)
 NS_INTERFACE_MAP_END
 
@@ -101,7 +110,6 @@ nsSpeechTask::nsSpeechTask(SpeechSynthesisUtterance* aUtterance)
   , mPrePaused(false)
   , mPreCanceled(false)
   , mCallback(nullptr)
-  , mIndirectAudio(false)
 {
   mText = aUtterance->mText;
   mVolume = aUtterance->Volume();
@@ -115,7 +123,6 @@ nsSpeechTask::nsSpeechTask(float aVolume, const nsAString& aText)
   , mPrePaused(false)
   , mPreCanceled(false)
   , mCallback(nullptr)
-  , mIndirectAudio(false)
 {
 }
 
@@ -142,9 +149,7 @@ nsSpeechTask::Init(ProcessedMediaStream* aStream)
   if (aStream) {
     mStream = MediaStreamGraph::GetInstance()->CreateSourceStream(nullptr);
     mPort = aStream->AllocateInputPort(mStream, 0);
-    mIndirectAudio = false;
   } else {
-    mIndirectAudio = true;
   }
   mInited = true;
 }
@@ -165,8 +170,7 @@ nsSpeechTask::Setup(nsISpeechTaskCallback* aCallback,
 
   mCallback = aCallback;
 
-  if (mIndirectAudio) {
-    MOZ_ASSERT(!mStream);
+  if (!mStream) {
     if (argc > 0) {
       NS_WARNING("Audio info arguments in Setup() are ignored for indirect audio services.");
     }
@@ -226,7 +230,7 @@ nsSpeechTask::SendAudio(JS::Handle aData, JS::Handle aLand
     return NS_ERROR_INVALID_ARG;
   }
 
-  if (mIndirectAudio) {
+  if (!mStream) {
     NS_WARNING("Can't call SendAudio from an indirect audio speech service.");
     return NS_ERROR_FAILURE;
   }
@@ -273,7 +277,7 @@ nsSpeechTask::SendAudioNative(int16_t* aData, uint32_t aDataLen)
     return NS_ERROR_FAILURE;
   }
 
-  if (mIndirectAudio) {
+  if (!mStream) {
     NS_WARNING("Can't call SendAudio from an indirect audio speech service.");
     return NS_ERROR_FAILURE;
   }
@@ -303,7 +307,7 @@ nsSpeechTask::SendAudioImpl(nsRefPtr& aSamples, uint32_t
 NS_IMETHODIMP
 nsSpeechTask::DispatchStart()
 {
-  if (!mIndirectAudio) {
+  if (mStream) {
     NS_WARNING("Can't call DispatchStart() from a direct audio speech service");
     return NS_ERROR_FAILURE;
   }
@@ -314,6 +318,8 @@ nsSpeechTask::DispatchStart()
 nsresult
 nsSpeechTask::DispatchStartInner()
 {
+  CreateAudioChannelAgent();
+
   nsSynthVoiceRegistry::GetInstance()->SetIsSpeaking(true);
   return DispatchStartImpl();
 }
@@ -345,7 +351,7 @@ nsSpeechTask::DispatchStartImpl(const nsAString& aUri)
 NS_IMETHODIMP
 nsSpeechTask::DispatchEnd(float aElapsedTime, uint32_t aCharIndex)
 {
-  if (!mIndirectAudio) {
+  if (mStream) {
     NS_WARNING("Can't call DispatchEnd() from a direct audio speech service");
     return NS_ERROR_FAILURE;
   }
@@ -356,6 +362,8 @@ nsSpeechTask::DispatchEnd(float aElapsedTime, uint32_t aCharIndex)
 nsresult
 nsSpeechTask::DispatchEndInner(float aElapsedTime, uint32_t aCharIndex)
 {
+  DestroyAudioChannelAgent();
+
   if (!mPreCanceled) {
     nsSynthVoiceRegistry::GetInstance()->SpeakNext();
   }
@@ -399,7 +407,7 @@ nsSpeechTask::DispatchEndImpl(float aElapsedTime, uint32_t aCharIndex)
 NS_IMETHODIMP
 nsSpeechTask::DispatchPause(float aElapsedTime, uint32_t aCharIndex)
 {
-  if (!mIndirectAudio) {
+  if (mStream) {
     NS_WARNING("Can't call DispatchPause() from a direct audio speech service");
     return NS_ERROR_FAILURE;
   }
@@ -431,7 +439,7 @@ nsSpeechTask::DispatchPauseImpl(float aElapsedTime, uint32_t aCharIndex)
 NS_IMETHODIMP
 nsSpeechTask::DispatchResume(float aElapsedTime, uint32_t aCharIndex)
 {
-  if (!mIndirectAudio) {
+  if (mStream) {
     NS_WARNING("Can't call DispatchResume() from a direct audio speech service");
     return NS_ERROR_FAILURE;
   }
@@ -464,7 +472,7 @@ nsSpeechTask::DispatchResumeImpl(float aElapsedTime, uint32_t aCharIndex)
 NS_IMETHODIMP
 nsSpeechTask::DispatchError(float aElapsedTime, uint32_t aCharIndex)
 {
-  if (!mIndirectAudio) {
+  if (mStream) {
     NS_WARNING("Can't call DispatchError() from a direct audio speech service");
     return NS_ERROR_FAILURE;
   }
@@ -491,7 +499,7 @@ NS_IMETHODIMP
 nsSpeechTask::DispatchBoundary(const nsAString& aName,
                                float aElapsedTime, uint32_t aCharIndex)
 {
-  if (!mIndirectAudio) {
+  if (mStream) {
     NS_WARNING("Can't call DispatchBoundary() from a direct audio speech service");
     return NS_ERROR_FAILURE;
   }
@@ -518,7 +526,7 @@ NS_IMETHODIMP
 nsSpeechTask::DispatchMark(const nsAString& aName,
                            float aElapsedTime, uint32_t aCharIndex)
 {
-  if (!mIndirectAudio) {
+  if (mStream) {
     NS_WARNING("Can't call DispatchMark() from a direct audio speech service");
     return NS_ERROR_FAILURE;
   }
@@ -559,7 +567,7 @@ nsSpeechTask::Pause()
     mPrePaused = true;
   }
 
-  if (!mIndirectAudio) {
+  if (mStream) {
     DispatchPauseImpl(GetCurrentTime(), GetCurrentCharOffset());
   }
 }
@@ -583,7 +591,7 @@ nsSpeechTask::Resume()
     nsSynthVoiceRegistry::GetInstance()->ResumeQueue();
   }
 
-  if (!mIndirectAudio) {
+  if (mStream) {
     DispatchResumeImpl(GetCurrentTime(), GetCurrentCharOffset());
   }
 }
@@ -608,7 +616,7 @@ nsSpeechTask::Cancel()
     mPreCanceled = true;
   }
 
-  if (!mIndirectAudio) {
+  if (mStream) {
     DispatchEndInner(GetCurrentTime(), GetCurrentCharOffset());
   }
 }
@@ -645,5 +653,53 @@ nsSpeechTask::SetSpeechSynthesis(SpeechSynthesis* aSpeechSynthesis)
   mSpeechSynthesis = aSpeechSynthesis;
 }
 
+void
+nsSpeechTask::CreateAudioChannelAgent()
+{
+  if (!mUtterance || !UseAudioChannelService()) {
+    return;
+  }
+
+  if (mAudioChannelAgent) {
+    mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY);
+  }
+
+  mAudioChannelAgent = new AudioChannelAgent();
+  mAudioChannelAgent->InitWithWeakCallback(mUtterance->GetOwner(),
+                                           static_cast(AudioChannelService::GetDefaultAudioChannel()),
+                                           this);
+}
+
+void
+nsSpeechTask::DestroyAudioChannelAgent()
+{
+  if (mAudioChannelAgent) {
+    mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY);
+    mAudioChannelAgent = nullptr;
+  }
+}
+
+NS_IMETHODIMP
+nsSpeechTask::WindowVolumeChanged(float aVolume, bool aMuted)
+{
+  SetAudioOutputVolume(mVolume * aVolume * aMuted);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSpeechTask::WindowAudioCaptureChanged()
+{
+  // This is not supported yet.
+  return NS_OK;
+}
+
+void
+nsSpeechTask::SetAudioOutputVolume(uint32_t aVolume)
+{
+  if (mStream) {
+    mStream->SetAudioOutputVolume(this, aVolume);
+  }
+}
+
 } // namespace dom
 } // namespace mozilla
diff --git a/dom/media/webspeech/synth/nsSpeechTask.h b/dom/media/webspeech/synth/nsSpeechTask.h
index 70e7929ef6a4..b362f4af4420 100644
--- a/dom/media/webspeech/synth/nsSpeechTask.h
+++ b/dom/media/webspeech/synth/nsSpeechTask.h
@@ -9,6 +9,7 @@
 
 #include "MediaStreamGraph.h"
 #include "SpeechSynthesisUtterance.h"
+#include "nsIAudioChannelAgent.h"
 #include "nsISpeechService.h"
 
 namespace mozilla {
@@ -19,6 +20,7 @@ class SpeechSynthesis;
 class SynthStreamListener;
 
 class nsSpeechTask : public nsISpeechTask
+                   , public nsIAudioChannelAgentCallback
 {
   friend class SynthStreamListener;
 
@@ -27,6 +29,7 @@ class nsSpeechTask : public nsISpeechTask
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsSpeechTask, nsISpeechTask)
 
   NS_DECL_NSISPEECHTASK
+  NS_DECL_NSIAUDIOCHANNELAGENTCALLBACK
 
   explicit nsSpeechTask(SpeechSynthesisUtterance* aUtterance);
   nsSpeechTask(float aVolume, const nsAString& aText);
@@ -49,6 +52,8 @@ class nsSpeechTask : public nsISpeechTask
 
   void SetChosenVoiceURI(const nsAString& aUri);
 
+  virtual void SetAudioOutputVolume(uint32_t aVolume);
+
   bool IsPreCanceled()
   {
     return mPreCanceled;
@@ -102,18 +107,22 @@ class nsSpeechTask : public nsISpeechTask
 
   nsresult DispatchEndInner(float aElapsedTime, uint32_t aCharIndex);
 
+  void CreateAudioChannelAgent();
+
+  void DestroyAudioChannelAgent();
+
   nsRefPtr mStream;
 
   nsRefPtr mPort;
 
   nsCOMPtr mCallback;
 
+  nsCOMPtr mAudioChannelAgent;
+
   uint32_t mChannels;
 
   nsRefPtr mSpeechSynthesis;
 
-  bool mIndirectAudio;
-
   nsString mChosenVoiceURI;
 };
 

From 130332ddbb3bdf8513df6aa07cb67bb90167acf6 Mon Sep 17 00:00:00 2001
From: Terrence Cole 
Date: Tue, 18 Aug 2015 09:17:13 -0700
Subject: [PATCH 020/208] Bug 1194832 - Use a one element cache in the store
 buffer; r=jonco

---
 js/src/gc/Marking.cpp   |  2 +-
 js/src/gc/StoreBuffer.h | 59 ++++++++++++++++++++++-------------------
 2 files changed, 32 insertions(+), 29 deletions(-)

diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp
index 7f48bfda44aa..49d83ddca4c3 100644
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -1900,7 +1900,7 @@ js::gc::StoreBuffer::MonoTypeBuffer::trace(StoreBuffer* owner, TenuringTracer
     mozilla::ReentrancyGuard g(*owner);
     MOZ_ASSERT(owner->isEnabled());
     MOZ_ASSERT(stores_.initialized());
-    sinkStores(owner);
+    sinkStore(owner);
     for (typename StoreSet::Range r = stores_.all(); !r.empty(); r.popFront())
         r.front().trace(mover);
 }
diff --git a/js/src/gc/StoreBuffer.h b/js/src/gc/StoreBuffer.h
index 2b1243e065cd..d0484524d18a 100644
--- a/js/src/gc/StoreBuffer.h
+++ b/js/src/gc/StoreBuffer.h
@@ -62,17 +62,15 @@ class StoreBuffer
         StoreSet stores_;
 
         /*
-         * A small, fixed-size buffer in front of the canonical set to simplify
-         * insertion via jit code.
+         * A one element cache in front of the canonical set to speed up
+         * temporary instances of RelocatablePtr.
          */
-        const static size_t NumBufferEntries = 4096 / sizeof(T);
-        T buffer_[NumBufferEntries];
-        T* insert_;
+        T last_;
 
         /* Maximum number of entries before we request a minor GC. */
         const static size_t MaxEntries = 48 * 1024 / sizeof(T);
 
-        explicit MonoTypeBuffer() { clearBuffer(); }
+        explicit MonoTypeBuffer() : last_(T()) {}
         ~MonoTypeBuffer() { stores_.finish(); }
 
         bool init() {
@@ -82,13 +80,8 @@ class StoreBuffer
             return true;
         }
 
-        void clearBuffer() {
-            JS_POISON(buffer_, JS_EMPTY_STOREBUFFER_PATTERN, NumBufferEntries * sizeof(T));
-            insert_ = buffer_;
-        }
-
         void clear() {
-            clearBuffer();
+            last_ = T();
             if (stores_.initialized())
                 stores_.clear();
         }
@@ -96,33 +89,35 @@ class StoreBuffer
         /* Add one item to the buffer. */
         void put(StoreBuffer* owner, const T& t) {
             MOZ_ASSERT(stores_.initialized());
-            *insert_++ = t;
-            if (MOZ_UNLIKELY(insert_ == buffer_ + NumBufferEntries))
-                sinkStores(owner);
+            sinkStore(owner);
+            last_ = t;
+        }
+
+        /* Remove an item from the store buffer. */
+        void unput(StoreBuffer* owner, const T& v) {
+            // Fast, hashless remove of last put.
+            if (last_ == v) {
+                last_ = T();
+                return;
+            }
+            stores_.remove(v);
         }
 
         /* Move any buffered stores to the canonical store set. */
-        void sinkStores(StoreBuffer* owner) {
+        void sinkStore(StoreBuffer* owner) {
             MOZ_ASSERT(stores_.initialized());
-
-            for (T* p = buffer_; p < insert_; ++p) {
-                if (!stores_.put(*p))
-                    CrashAtUnhandlableOOM("Failed to allocate for MonoTypeBuffer::sinkStores.");
+            if (last_) {
+                if (!stores_.put(last_))
+                    CrashAtUnhandlableOOM("Failed to allocate for MonoTypeBuffer::put.");
             }
-            clearBuffer();
+            last_ = T();
 
             if (MOZ_UNLIKELY(stores_.count() > MaxEntries))
                 owner->setAboutToOverflow();
         }
 
-        /* Remove an item from the store buffer. */
-        void unput(StoreBuffer* owner, const T& v) {
-            sinkStores(owner);
-            stores_.remove(v);
-        }
-
         bool has(StoreBuffer* owner, const T& v) {
-            sinkStores(owner);
+            sinkStore(owner);
             return stores_.has(v);
         }
 
@@ -226,6 +221,8 @@ class StoreBuffer
         CellPtrEdge untagged() const { return CellPtrEdge((Cell**)(uintptr_t(edge) & ~1)); }
         bool isTagged() const { return bool(uintptr_t(edge) & 1); }
 
+        explicit operator bool() const { return edge != nullptr; }
+
         typedef PointerEdgeHasher Hasher;
     };
 
@@ -251,6 +248,8 @@ class StoreBuffer
         ValueEdge untagged() const { return ValueEdge((JS::Value*)(uintptr_t(edge) & ~1)); }
         bool isTagged() const { return bool(uintptr_t(edge) & 1); }
 
+        explicit operator bool() const { return edge != nullptr; }
+
         typedef PointerEdgeHasher Hasher;
     };
 
@@ -293,6 +292,8 @@ class StoreBuffer
 
         void trace(TenuringTracer& mover) const;
 
+        explicit operator bool() const { return objectAndKind_ != 0; }
+
         typedef struct {
             typedef SlotsEdge Lookup;
             static HashNumber hash(const Lookup& l) { return l.objectAndKind_ ^ l.start_ ^ l.count_; }
@@ -319,6 +320,8 @@ class StoreBuffer
 
         void trace(TenuringTracer& mover) const;
 
+        explicit operator bool() const { return edge != nullptr; }
+
         typedef PointerEdgeHasher Hasher;
     };
 

From 483ead59f96b4364aa3b69b2894d33c65c6a74fc Mon Sep 17 00:00:00 2001
From: Ehsan Akhgari 
Date: Wed, 19 Aug 2015 18:01:57 -0400
Subject: [PATCH 021/208] Bug 1196524 - Add assertions to enforce that we don't
 attempt to perform a CORS preflight for fetches of no-cors requests; r=nsm

---
 dom/fetch/FetchDriver.cpp | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp
index a45428f42573..d812c6fd2e40 100644
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -160,6 +160,10 @@ FetchDriver::ContinueFetch(bool aCORSFlag)
       (mRequest->UnsafeRequest() && (!mRequest->HasSimpleMethod() || !mRequest->Headers()->HasOnlySimpleHeaders()))) {
     corsPreflight = true;
   }
+  // The Request constructor should ensure that no-cors requests have simple
+  // method and headers, so we should never attempt to preflight for such
+  // Requests.
+  MOZ_ASSERT_IF(mRequest->Mode() == RequestMode::No_cors, !corsPreflight);
 
   mRequest->SetResponseTainting(InternalRequest::RESPONSETAINT_CORS);
   return HttpFetch(true /* aCORSFlag */, corsPreflight);
@@ -541,6 +545,8 @@ FetchDriver::HttpFetch(bool aCORSFlag, bool aCORSPreflightFlag, bool aAuthentica
   // unsafeHeaders so they can be verified against the response's
   // "Access-Control-Allow-Headers" header.
   if (aCORSPreflightFlag) {
+    MOZ_ASSERT(mRequest->Mode() != RequestMode::No_cors,
+               "FetchDriver::ContinueFetch() should ensure that the request is not no-cors");
     nsCOMPtr preflightChannel;
     nsAutoTArray unsafeHeaders;
     mRequest->Headers()->GetUnsafeHeaders(unsafeHeaders);

From dd4cf34ffcc44628eff54971040eee18a7d2b8e9 Mon Sep 17 00:00:00 2001
From: Steve Fink 
Date: Fri, 14 Aug 2015 14:06:09 -0700
Subject: [PATCH 022/208] Bug 1196467 - Suppress mercurial-setup check for
 hazard analysis builds, r=gps

---
 testing/mozharness/configs/hazards/common.py | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/testing/mozharness/configs/hazards/common.py b/testing/mozharness/configs/hazards/common.py
index f47dc425e565..7033eb62ee70 100644
--- a/testing/mozharness/configs/hazards/common.py
+++ b/testing/mozharness/configs/hazards/common.py
@@ -85,5 +85,11 @@
     "partial_env": {
         "PATH": "%(pythondir)s/bin:%(gccdir)s/bin:%(PATH)s",
         "LD_LIBRARY_PATH": "%(sixgilldir)s/usr/lib64",
+
+        # Suppress the mercurial-setup check. When running in automation, this
+        # is redundant with MOZ_AUTOMATION, but a local developer-mode build
+        # will have the mach state directory set to a nonstandard location and
+        # therefore will always claim that mercurial-setup has not been run.
+        "I_PREFER_A_SUBOPTIMAL_MERCURIAL_EXPERIENCE": "1",
     },
 }

From cd21b010909ce157f63c44e84993c2312902f049 Mon Sep 17 00:00:00 2001
From: Jan Gerber 
Date: Sat, 8 Aug 2015 09:28:52 +0200
Subject: [PATCH 023/208] Bug 1192226 - Enable libvpx size limit in update.py.
 r=rillian

Limits match those in VideoUtils.h.
---
 media/libvpx/update.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/media/libvpx/update.py b/media/libvpx/update.py
index 9fbc6d17ee57..917cfb788ec7 100755
--- a/media/libvpx/update.py
+++ b/media/libvpx/update.py
@@ -398,6 +398,7 @@ def prepare_upstream(prefix, commit=None):
         configure = ['../../configure', '--target=%s' % target,
             '--disable-examples', '--disable-install-docs',
             '--enable-multi-res-encoding',
+            '--size-limit=4000x3000'
         ]
 
         if 'darwin9' in target:

From 6d70bf2b9341c3733654a808a15784ed37d2ed38 Mon Sep 17 00:00:00 2001
From: Jan Gerber 
Date: Sat, 8 Aug 2015 09:34:39 +0200
Subject: [PATCH 024/208] Bug 1192226 - Apply libvpx size limit. r=rillian

---
 media/libvpx/vpx_config_armv7-android-gcc.asm  | 4 +++-
 media/libvpx/vpx_config_armv7-android-gcc.h    | 4 +++-
 media/libvpx/vpx_config_generic-gnu.asm        | 4 +++-
 media/libvpx/vpx_config_generic-gnu.h          | 4 +++-
 media/libvpx/vpx_config_x86-darwin9-gcc.asm    | 4 +++-
 media/libvpx/vpx_config_x86-darwin9-gcc.h      | 4 +++-
 media/libvpx/vpx_config_x86-linux-gcc.asm      | 4 +++-
 media/libvpx/vpx_config_x86-linux-gcc.h        | 4 +++-
 media/libvpx/vpx_config_x86-win32-gcc.asm      | 4 +++-
 media/libvpx/vpx_config_x86-win32-gcc.h        | 4 +++-
 media/libvpx/vpx_config_x86-win32-vs12.asm     | 4 +++-
 media/libvpx/vpx_config_x86-win32-vs12.h       | 4 +++-
 media/libvpx/vpx_config_x86_64-darwin9-gcc.asm | 4 +++-
 media/libvpx/vpx_config_x86_64-darwin9-gcc.h   | 4 +++-
 media/libvpx/vpx_config_x86_64-linux-gcc.asm   | 4 +++-
 media/libvpx/vpx_config_x86_64-linux-gcc.h     | 4 +++-
 media/libvpx/vpx_config_x86_64-win64-gcc.asm   | 4 +++-
 media/libvpx/vpx_config_x86_64-win64-gcc.h     | 4 +++-
 media/libvpx/vpx_config_x86_64-win64-vs12.asm  | 4 +++-
 media/libvpx/vpx_config_x86_64-win64-vs12.h    | 4 +++-
 20 files changed, 60 insertions(+), 20 deletions(-)

diff --git a/media/libvpx/vpx_config_armv7-android-gcc.asm b/media/libvpx/vpx_config_armv7-android-gcc.asm
index 6a21c78ecdd6..23e1ded4f0d1 100644
--- a/media/libvpx/vpx_config_armv7-android-gcc.asm
+++ b/media/libvpx/vpx_config_armv7-android-gcc.asm
@@ -79,10 +79,12 @@
 .equ CONFIG_COEFFICIENT_RANGE_CHECKING ,  0
 .equ CONFIG_VP9_HIGHBITDEPTH ,  0
 .equ CONFIG_EXPERIMENTAL ,  0
-.equ CONFIG_SIZE_LIMIT ,  0
+.equ CONFIG_SIZE_LIMIT ,  1
 .equ CONFIG_SPATIAL_SVC ,  0
 .equ CONFIG_FP_MB_STATS ,  0
 .equ CONFIG_EMULATE_HARDWARE ,  0
+.equ DECODE_WIDTH_LIMIT ,  4000
+.equ DECODE_HEIGHT_LIMIT ,  3000
 	.section	.note.GNU-stack,"",%progbits
 @ This file was created from a .asm file
 @  using the ads2gas.pl script.
diff --git a/media/libvpx/vpx_config_armv7-android-gcc.h b/media/libvpx/vpx_config_armv7-android-gcc.h
index 468099c3a90f..ff7e42f715c2 100644
--- a/media/libvpx/vpx_config_armv7-android-gcc.h
+++ b/media/libvpx/vpx_config_armv7-android-gcc.h
@@ -88,8 +88,10 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 0
+#define CONFIG_SIZE_LIMIT 1
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
+#define DECODE_WIDTH_LIMIT 4000
+#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */
diff --git a/media/libvpx/vpx_config_generic-gnu.asm b/media/libvpx/vpx_config_generic-gnu.asm
index ac108f9eb0f3..21a7312caad0 100644
--- a/media/libvpx/vpx_config_generic-gnu.asm
+++ b/media/libvpx/vpx_config_generic-gnu.asm
@@ -79,10 +79,12 @@
 .equ CONFIG_COEFFICIENT_RANGE_CHECKING ,  0
 .equ CONFIG_VP9_HIGHBITDEPTH ,  0
 .equ CONFIG_EXPERIMENTAL ,  0
-.equ CONFIG_SIZE_LIMIT ,  0
+.equ CONFIG_SIZE_LIMIT ,  1
 .equ CONFIG_SPATIAL_SVC ,  0
 .equ CONFIG_FP_MB_STATS ,  0
 .equ CONFIG_EMULATE_HARDWARE ,  0
+.equ DECODE_WIDTH_LIMIT ,  4000
+.equ DECODE_HEIGHT_LIMIT ,  3000
 	.section	.note.GNU-stack,"",%progbits
 @ This file was created from a .asm file
 @  using the ads2gas.pl script.
diff --git a/media/libvpx/vpx_config_generic-gnu.h b/media/libvpx/vpx_config_generic-gnu.h
index db883cf060f1..724edd6ede8f 100644
--- a/media/libvpx/vpx_config_generic-gnu.h
+++ b/media/libvpx/vpx_config_generic-gnu.h
@@ -88,8 +88,10 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 0
+#define CONFIG_SIZE_LIMIT 1
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
+#define DECODE_WIDTH_LIMIT 4000
+#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */
diff --git a/media/libvpx/vpx_config_x86-darwin9-gcc.asm b/media/libvpx/vpx_config_x86-darwin9-gcc.asm
index 9b6b8509b0f0..a525a410d487 100644
--- a/media/libvpx/vpx_config_x86-darwin9-gcc.asm
+++ b/media/libvpx/vpx_config_x86-darwin9-gcc.asm
@@ -76,7 +76,9 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0
 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
 CONFIG_VP9_HIGHBITDEPTH equ 0
 CONFIG_EXPERIMENTAL equ 0
-CONFIG_SIZE_LIMIT equ 0
+CONFIG_SIZE_LIMIT equ 1
 CONFIG_SPATIAL_SVC equ 0
 CONFIG_FP_MB_STATS equ 0
 CONFIG_EMULATE_HARDWARE equ 0
+DECODE_WIDTH_LIMIT ,  4000
+DECODE_HEIGHT_LIMIT ,  3000
diff --git a/media/libvpx/vpx_config_x86-darwin9-gcc.h b/media/libvpx/vpx_config_x86-darwin9-gcc.h
index 40502b410daa..7cca4b699d2a 100644
--- a/media/libvpx/vpx_config_x86-darwin9-gcc.h
+++ b/media/libvpx/vpx_config_x86-darwin9-gcc.h
@@ -88,8 +88,10 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 0
+#define CONFIG_SIZE_LIMIT 1
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
+#define DECODE_WIDTH_LIMIT 4000
+#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */
diff --git a/media/libvpx/vpx_config_x86-linux-gcc.asm b/media/libvpx/vpx_config_x86-linux-gcc.asm
index 5400f57d5a5f..23cdb4b71532 100644
--- a/media/libvpx/vpx_config_x86-linux-gcc.asm
+++ b/media/libvpx/vpx_config_x86-linux-gcc.asm
@@ -76,7 +76,9 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0
 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
 CONFIG_VP9_HIGHBITDEPTH equ 0
 CONFIG_EXPERIMENTAL equ 0
-CONFIG_SIZE_LIMIT equ 0
+CONFIG_SIZE_LIMIT equ 1
 CONFIG_SPATIAL_SVC equ 0
 CONFIG_FP_MB_STATS equ 0
 CONFIG_EMULATE_HARDWARE equ 0
+DECODE_WIDTH_LIMIT ,  4000
+DECODE_HEIGHT_LIMIT ,  3000
diff --git a/media/libvpx/vpx_config_x86-linux-gcc.h b/media/libvpx/vpx_config_x86-linux-gcc.h
index e7b472e84fea..edcf0ee9fc69 100644
--- a/media/libvpx/vpx_config_x86-linux-gcc.h
+++ b/media/libvpx/vpx_config_x86-linux-gcc.h
@@ -88,8 +88,10 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 0
+#define CONFIG_SIZE_LIMIT 1
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
+#define DECODE_WIDTH_LIMIT 4000
+#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */
diff --git a/media/libvpx/vpx_config_x86-win32-gcc.asm b/media/libvpx/vpx_config_x86-win32-gcc.asm
index 29c89a5186b1..9b5252e1a401 100644
--- a/media/libvpx/vpx_config_x86-win32-gcc.asm
+++ b/media/libvpx/vpx_config_x86-win32-gcc.asm
@@ -76,7 +76,9 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0
 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
 CONFIG_VP9_HIGHBITDEPTH equ 0
 CONFIG_EXPERIMENTAL equ 0
-CONFIG_SIZE_LIMIT equ 0
+CONFIG_SIZE_LIMIT equ 1
 CONFIG_SPATIAL_SVC equ 0
 CONFIG_FP_MB_STATS equ 0
 CONFIG_EMULATE_HARDWARE equ 0
+DECODE_WIDTH_LIMIT ,  4000
+DECODE_HEIGHT_LIMIT ,  3000
diff --git a/media/libvpx/vpx_config_x86-win32-gcc.h b/media/libvpx/vpx_config_x86-win32-gcc.h
index e60f84d8c171..abc34be9d6dd 100644
--- a/media/libvpx/vpx_config_x86-win32-gcc.h
+++ b/media/libvpx/vpx_config_x86-win32-gcc.h
@@ -89,8 +89,10 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 0
+#define CONFIG_SIZE_LIMIT 1
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
+#define DECODE_WIDTH_LIMIT 4000
+#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */
diff --git a/media/libvpx/vpx_config_x86-win32-vs12.asm b/media/libvpx/vpx_config_x86-win32-vs12.asm
index da0e226da7de..0acee0e2a6e5 100644
--- a/media/libvpx/vpx_config_x86-win32-vs12.asm
+++ b/media/libvpx/vpx_config_x86-win32-vs12.asm
@@ -76,7 +76,9 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0
 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
 CONFIG_VP9_HIGHBITDEPTH equ 0
 CONFIG_EXPERIMENTAL equ 0
-CONFIG_SIZE_LIMIT equ 0
+CONFIG_SIZE_LIMIT equ 1
 CONFIG_SPATIAL_SVC equ 0
 CONFIG_FP_MB_STATS equ 0
 CONFIG_EMULATE_HARDWARE equ 0
+DECODE_WIDTH_LIMIT ,  4000
+DECODE_HEIGHT_LIMIT ,  3000
diff --git a/media/libvpx/vpx_config_x86-win32-vs12.h b/media/libvpx/vpx_config_x86-win32-vs12.h
index a91bb8396eac..9c1d36df8405 100644
--- a/media/libvpx/vpx_config_x86-win32-vs12.h
+++ b/media/libvpx/vpx_config_x86-win32-vs12.h
@@ -88,8 +88,10 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 0
+#define CONFIG_SIZE_LIMIT 1
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
+#define DECODE_WIDTH_LIMIT 4000
+#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */
diff --git a/media/libvpx/vpx_config_x86_64-darwin9-gcc.asm b/media/libvpx/vpx_config_x86_64-darwin9-gcc.asm
index 3dbb38fc2e61..842607a66728 100644
--- a/media/libvpx/vpx_config_x86_64-darwin9-gcc.asm
+++ b/media/libvpx/vpx_config_x86_64-darwin9-gcc.asm
@@ -76,7 +76,9 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0
 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
 CONFIG_VP9_HIGHBITDEPTH equ 0
 CONFIG_EXPERIMENTAL equ 0
-CONFIG_SIZE_LIMIT equ 0
+CONFIG_SIZE_LIMIT equ 1
 CONFIG_SPATIAL_SVC equ 0
 CONFIG_FP_MB_STATS equ 0
 CONFIG_EMULATE_HARDWARE equ 0
+DECODE_WIDTH_LIMIT ,  4000
+DECODE_HEIGHT_LIMIT ,  3000
diff --git a/media/libvpx/vpx_config_x86_64-darwin9-gcc.h b/media/libvpx/vpx_config_x86_64-darwin9-gcc.h
index 0d0477ceeca1..d04556d4585f 100644
--- a/media/libvpx/vpx_config_x86_64-darwin9-gcc.h
+++ b/media/libvpx/vpx_config_x86_64-darwin9-gcc.h
@@ -88,8 +88,10 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 0
+#define CONFIG_SIZE_LIMIT 1
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
+#define DECODE_WIDTH_LIMIT 4000
+#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */
diff --git a/media/libvpx/vpx_config_x86_64-linux-gcc.asm b/media/libvpx/vpx_config_x86_64-linux-gcc.asm
index 6da93489bfb4..a5b8cb4bf351 100644
--- a/media/libvpx/vpx_config_x86_64-linux-gcc.asm
+++ b/media/libvpx/vpx_config_x86_64-linux-gcc.asm
@@ -76,7 +76,9 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0
 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
 CONFIG_VP9_HIGHBITDEPTH equ 0
 CONFIG_EXPERIMENTAL equ 0
-CONFIG_SIZE_LIMIT equ 0
+CONFIG_SIZE_LIMIT equ 1
 CONFIG_SPATIAL_SVC equ 0
 CONFIG_FP_MB_STATS equ 0
 CONFIG_EMULATE_HARDWARE equ 0
+DECODE_WIDTH_LIMIT ,  4000
+DECODE_HEIGHT_LIMIT ,  3000
diff --git a/media/libvpx/vpx_config_x86_64-linux-gcc.h b/media/libvpx/vpx_config_x86_64-linux-gcc.h
index 21228cd1dd09..dcd1ad82a9f5 100644
--- a/media/libvpx/vpx_config_x86_64-linux-gcc.h
+++ b/media/libvpx/vpx_config_x86_64-linux-gcc.h
@@ -88,8 +88,10 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 0
+#define CONFIG_SIZE_LIMIT 1
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
+#define DECODE_WIDTH_LIMIT 4000
+#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */
diff --git a/media/libvpx/vpx_config_x86_64-win64-gcc.asm b/media/libvpx/vpx_config_x86_64-win64-gcc.asm
index 20ba15baee06..ffebcf1d5171 100644
--- a/media/libvpx/vpx_config_x86_64-win64-gcc.asm
+++ b/media/libvpx/vpx_config_x86_64-win64-gcc.asm
@@ -76,7 +76,9 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0
 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
 CONFIG_VP9_HIGHBITDEPTH equ 0
 CONFIG_EXPERIMENTAL equ 0
-CONFIG_SIZE_LIMIT equ 0
+CONFIG_SIZE_LIMIT equ 1
 CONFIG_SPATIAL_SVC equ 0
 CONFIG_FP_MB_STATS equ 0
 CONFIG_EMULATE_HARDWARE equ 0
+DECODE_WIDTH_LIMIT ,  4000
+DECODE_HEIGHT_LIMIT ,  3000
diff --git a/media/libvpx/vpx_config_x86_64-win64-gcc.h b/media/libvpx/vpx_config_x86_64-win64-gcc.h
index b056a0ea3850..cf8a66268eb1 100644
--- a/media/libvpx/vpx_config_x86_64-win64-gcc.h
+++ b/media/libvpx/vpx_config_x86_64-win64-gcc.h
@@ -89,8 +89,10 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 0
+#define CONFIG_SIZE_LIMIT 1
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
+#define DECODE_WIDTH_LIMIT 4000
+#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */
diff --git a/media/libvpx/vpx_config_x86_64-win64-vs12.asm b/media/libvpx/vpx_config_x86_64-win64-vs12.asm
index 39c17a07c3ee..40d594793734 100644
--- a/media/libvpx/vpx_config_x86_64-win64-vs12.asm
+++ b/media/libvpx/vpx_config_x86_64-win64-vs12.asm
@@ -76,7 +76,9 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0
 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
 CONFIG_VP9_HIGHBITDEPTH equ 0
 CONFIG_EXPERIMENTAL equ 0
-CONFIG_SIZE_LIMIT equ 0
+CONFIG_SIZE_LIMIT equ 1
 CONFIG_SPATIAL_SVC equ 0
 CONFIG_FP_MB_STATS equ 0
 CONFIG_EMULATE_HARDWARE equ 0
+DECODE_WIDTH_LIMIT ,  4000
+DECODE_HEIGHT_LIMIT ,  3000
diff --git a/media/libvpx/vpx_config_x86_64-win64-vs12.h b/media/libvpx/vpx_config_x86_64-win64-vs12.h
index 4ad69bdb8445..17cd9421ed24 100644
--- a/media/libvpx/vpx_config_x86_64-win64-vs12.h
+++ b/media/libvpx/vpx_config_x86_64-win64-vs12.h
@@ -88,8 +88,10 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 0
+#define CONFIG_SIZE_LIMIT 1
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
+#define DECODE_WIDTH_LIMIT 4000
+#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */

From 1ef8a2b1dc18f120e6097d75b067503c117f14f5 Mon Sep 17 00:00:00 2001
From: Steve Fink 
Date: Tue, 18 Aug 2015 12:25:01 -0700
Subject: [PATCH 025/208] Bug 1195957 - Implement a Swap for Heap that does
 not put temporaries on the stack, r=terrence

---
 js/public/RootingAPI.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h
index 4740d328e02a..8995115d8737 100644
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -1157,6 +1157,30 @@ CallTraceCallbackOnNonHeap(T* v, const TraceCallbacks& aCallbacks, const char* a
 } /* namespace gc */
 } /* namespace js */
 
+// mozilla::Swap uses a stack temporary, which prevents classes like Heap
+// from being declared MOZ_HEAP_CLASS.
+namespace mozilla {
+
+template 
+inline void
+Swap(JS::Heap& aX, JS::Heap& aY)
+{
+    T tmp = aX;
+    aX = aY;
+    aY = tmp;
+}
+
+template 
+inline void
+Swap(JS::TenuredHeap& aX, JS::TenuredHeap& aY)
+{
+    T tmp = aX;
+    aX = aY;
+    aY = tmp;
+}
+
+} /* namespace mozilla */
+
 #undef DELETE_ASSIGNMENT_OPS
 
 #endif  /* js_RootingAPI_h */

From 0155ccf8cc067797d47967b00fc6bca596a11d24 Mon Sep 17 00:00:00 2001
From: Wes Kocher 
Date: Thu, 20 Aug 2015 11:19:03 -0700
Subject: [PATCH 026/208] Backed out 2 changesets (bug 1192226) for vpx_config
 bustage

Backed out changeset 92d172a5d403 (bug 1192226)
Backed out changeset 4e7adb955673 (bug 1192226)
---
 media/libvpx/update.py                         | 1 -
 media/libvpx/vpx_config_armv7-android-gcc.asm  | 4 +---
 media/libvpx/vpx_config_armv7-android-gcc.h    | 4 +---
 media/libvpx/vpx_config_generic-gnu.asm        | 4 +---
 media/libvpx/vpx_config_generic-gnu.h          | 4 +---
 media/libvpx/vpx_config_x86-darwin9-gcc.asm    | 4 +---
 media/libvpx/vpx_config_x86-darwin9-gcc.h      | 4 +---
 media/libvpx/vpx_config_x86-linux-gcc.asm      | 4 +---
 media/libvpx/vpx_config_x86-linux-gcc.h        | 4 +---
 media/libvpx/vpx_config_x86-win32-gcc.asm      | 4 +---
 media/libvpx/vpx_config_x86-win32-gcc.h        | 4 +---
 media/libvpx/vpx_config_x86-win32-vs12.asm     | 4 +---
 media/libvpx/vpx_config_x86-win32-vs12.h       | 4 +---
 media/libvpx/vpx_config_x86_64-darwin9-gcc.asm | 4 +---
 media/libvpx/vpx_config_x86_64-darwin9-gcc.h   | 4 +---
 media/libvpx/vpx_config_x86_64-linux-gcc.asm   | 4 +---
 media/libvpx/vpx_config_x86_64-linux-gcc.h     | 4 +---
 media/libvpx/vpx_config_x86_64-win64-gcc.asm   | 4 +---
 media/libvpx/vpx_config_x86_64-win64-gcc.h     | 4 +---
 media/libvpx/vpx_config_x86_64-win64-vs12.asm  | 4 +---
 media/libvpx/vpx_config_x86_64-win64-vs12.h    | 4 +---
 21 files changed, 20 insertions(+), 61 deletions(-)

diff --git a/media/libvpx/update.py b/media/libvpx/update.py
index 917cfb788ec7..9fbc6d17ee57 100755
--- a/media/libvpx/update.py
+++ b/media/libvpx/update.py
@@ -398,7 +398,6 @@ def prepare_upstream(prefix, commit=None):
         configure = ['../../configure', '--target=%s' % target,
             '--disable-examples', '--disable-install-docs',
             '--enable-multi-res-encoding',
-            '--size-limit=4000x3000'
         ]
 
         if 'darwin9' in target:
diff --git a/media/libvpx/vpx_config_armv7-android-gcc.asm b/media/libvpx/vpx_config_armv7-android-gcc.asm
index 23e1ded4f0d1..6a21c78ecdd6 100644
--- a/media/libvpx/vpx_config_armv7-android-gcc.asm
+++ b/media/libvpx/vpx_config_armv7-android-gcc.asm
@@ -79,12 +79,10 @@
 .equ CONFIG_COEFFICIENT_RANGE_CHECKING ,  0
 .equ CONFIG_VP9_HIGHBITDEPTH ,  0
 .equ CONFIG_EXPERIMENTAL ,  0
-.equ CONFIG_SIZE_LIMIT ,  1
+.equ CONFIG_SIZE_LIMIT ,  0
 .equ CONFIG_SPATIAL_SVC ,  0
 .equ CONFIG_FP_MB_STATS ,  0
 .equ CONFIG_EMULATE_HARDWARE ,  0
-.equ DECODE_WIDTH_LIMIT ,  4000
-.equ DECODE_HEIGHT_LIMIT ,  3000
 	.section	.note.GNU-stack,"",%progbits
 @ This file was created from a .asm file
 @  using the ads2gas.pl script.
diff --git a/media/libvpx/vpx_config_armv7-android-gcc.h b/media/libvpx/vpx_config_armv7-android-gcc.h
index ff7e42f715c2..468099c3a90f 100644
--- a/media/libvpx/vpx_config_armv7-android-gcc.h
+++ b/media/libvpx/vpx_config_armv7-android-gcc.h
@@ -88,10 +88,8 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SIZE_LIMIT 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
-#define DECODE_WIDTH_LIMIT 4000
-#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */
diff --git a/media/libvpx/vpx_config_generic-gnu.asm b/media/libvpx/vpx_config_generic-gnu.asm
index 21a7312caad0..ac108f9eb0f3 100644
--- a/media/libvpx/vpx_config_generic-gnu.asm
+++ b/media/libvpx/vpx_config_generic-gnu.asm
@@ -79,12 +79,10 @@
 .equ CONFIG_COEFFICIENT_RANGE_CHECKING ,  0
 .equ CONFIG_VP9_HIGHBITDEPTH ,  0
 .equ CONFIG_EXPERIMENTAL ,  0
-.equ CONFIG_SIZE_LIMIT ,  1
+.equ CONFIG_SIZE_LIMIT ,  0
 .equ CONFIG_SPATIAL_SVC ,  0
 .equ CONFIG_FP_MB_STATS ,  0
 .equ CONFIG_EMULATE_HARDWARE ,  0
-.equ DECODE_WIDTH_LIMIT ,  4000
-.equ DECODE_HEIGHT_LIMIT ,  3000
 	.section	.note.GNU-stack,"",%progbits
 @ This file was created from a .asm file
 @  using the ads2gas.pl script.
diff --git a/media/libvpx/vpx_config_generic-gnu.h b/media/libvpx/vpx_config_generic-gnu.h
index 724edd6ede8f..db883cf060f1 100644
--- a/media/libvpx/vpx_config_generic-gnu.h
+++ b/media/libvpx/vpx_config_generic-gnu.h
@@ -88,10 +88,8 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SIZE_LIMIT 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
-#define DECODE_WIDTH_LIMIT 4000
-#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */
diff --git a/media/libvpx/vpx_config_x86-darwin9-gcc.asm b/media/libvpx/vpx_config_x86-darwin9-gcc.asm
index a525a410d487..9b6b8509b0f0 100644
--- a/media/libvpx/vpx_config_x86-darwin9-gcc.asm
+++ b/media/libvpx/vpx_config_x86-darwin9-gcc.asm
@@ -76,9 +76,7 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0
 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
 CONFIG_VP9_HIGHBITDEPTH equ 0
 CONFIG_EXPERIMENTAL equ 0
-CONFIG_SIZE_LIMIT equ 1
+CONFIG_SIZE_LIMIT equ 0
 CONFIG_SPATIAL_SVC equ 0
 CONFIG_FP_MB_STATS equ 0
 CONFIG_EMULATE_HARDWARE equ 0
-DECODE_WIDTH_LIMIT ,  4000
-DECODE_HEIGHT_LIMIT ,  3000
diff --git a/media/libvpx/vpx_config_x86-darwin9-gcc.h b/media/libvpx/vpx_config_x86-darwin9-gcc.h
index 7cca4b699d2a..40502b410daa 100644
--- a/media/libvpx/vpx_config_x86-darwin9-gcc.h
+++ b/media/libvpx/vpx_config_x86-darwin9-gcc.h
@@ -88,10 +88,8 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SIZE_LIMIT 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
-#define DECODE_WIDTH_LIMIT 4000
-#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */
diff --git a/media/libvpx/vpx_config_x86-linux-gcc.asm b/media/libvpx/vpx_config_x86-linux-gcc.asm
index 23cdb4b71532..5400f57d5a5f 100644
--- a/media/libvpx/vpx_config_x86-linux-gcc.asm
+++ b/media/libvpx/vpx_config_x86-linux-gcc.asm
@@ -76,9 +76,7 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0
 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
 CONFIG_VP9_HIGHBITDEPTH equ 0
 CONFIG_EXPERIMENTAL equ 0
-CONFIG_SIZE_LIMIT equ 1
+CONFIG_SIZE_LIMIT equ 0
 CONFIG_SPATIAL_SVC equ 0
 CONFIG_FP_MB_STATS equ 0
 CONFIG_EMULATE_HARDWARE equ 0
-DECODE_WIDTH_LIMIT ,  4000
-DECODE_HEIGHT_LIMIT ,  3000
diff --git a/media/libvpx/vpx_config_x86-linux-gcc.h b/media/libvpx/vpx_config_x86-linux-gcc.h
index edcf0ee9fc69..e7b472e84fea 100644
--- a/media/libvpx/vpx_config_x86-linux-gcc.h
+++ b/media/libvpx/vpx_config_x86-linux-gcc.h
@@ -88,10 +88,8 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SIZE_LIMIT 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
-#define DECODE_WIDTH_LIMIT 4000
-#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */
diff --git a/media/libvpx/vpx_config_x86-win32-gcc.asm b/media/libvpx/vpx_config_x86-win32-gcc.asm
index 9b5252e1a401..29c89a5186b1 100644
--- a/media/libvpx/vpx_config_x86-win32-gcc.asm
+++ b/media/libvpx/vpx_config_x86-win32-gcc.asm
@@ -76,9 +76,7 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0
 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
 CONFIG_VP9_HIGHBITDEPTH equ 0
 CONFIG_EXPERIMENTAL equ 0
-CONFIG_SIZE_LIMIT equ 1
+CONFIG_SIZE_LIMIT equ 0
 CONFIG_SPATIAL_SVC equ 0
 CONFIG_FP_MB_STATS equ 0
 CONFIG_EMULATE_HARDWARE equ 0
-DECODE_WIDTH_LIMIT ,  4000
-DECODE_HEIGHT_LIMIT ,  3000
diff --git a/media/libvpx/vpx_config_x86-win32-gcc.h b/media/libvpx/vpx_config_x86-win32-gcc.h
index abc34be9d6dd..e60f84d8c171 100644
--- a/media/libvpx/vpx_config_x86-win32-gcc.h
+++ b/media/libvpx/vpx_config_x86-win32-gcc.h
@@ -89,10 +89,8 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SIZE_LIMIT 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
-#define DECODE_WIDTH_LIMIT 4000
-#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */
diff --git a/media/libvpx/vpx_config_x86-win32-vs12.asm b/media/libvpx/vpx_config_x86-win32-vs12.asm
index 0acee0e2a6e5..da0e226da7de 100644
--- a/media/libvpx/vpx_config_x86-win32-vs12.asm
+++ b/media/libvpx/vpx_config_x86-win32-vs12.asm
@@ -76,9 +76,7 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0
 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
 CONFIG_VP9_HIGHBITDEPTH equ 0
 CONFIG_EXPERIMENTAL equ 0
-CONFIG_SIZE_LIMIT equ 1
+CONFIG_SIZE_LIMIT equ 0
 CONFIG_SPATIAL_SVC equ 0
 CONFIG_FP_MB_STATS equ 0
 CONFIG_EMULATE_HARDWARE equ 0
-DECODE_WIDTH_LIMIT ,  4000
-DECODE_HEIGHT_LIMIT ,  3000
diff --git a/media/libvpx/vpx_config_x86-win32-vs12.h b/media/libvpx/vpx_config_x86-win32-vs12.h
index 9c1d36df8405..a91bb8396eac 100644
--- a/media/libvpx/vpx_config_x86-win32-vs12.h
+++ b/media/libvpx/vpx_config_x86-win32-vs12.h
@@ -88,10 +88,8 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SIZE_LIMIT 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
-#define DECODE_WIDTH_LIMIT 4000
-#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */
diff --git a/media/libvpx/vpx_config_x86_64-darwin9-gcc.asm b/media/libvpx/vpx_config_x86_64-darwin9-gcc.asm
index 842607a66728..3dbb38fc2e61 100644
--- a/media/libvpx/vpx_config_x86_64-darwin9-gcc.asm
+++ b/media/libvpx/vpx_config_x86_64-darwin9-gcc.asm
@@ -76,9 +76,7 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0
 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
 CONFIG_VP9_HIGHBITDEPTH equ 0
 CONFIG_EXPERIMENTAL equ 0
-CONFIG_SIZE_LIMIT equ 1
+CONFIG_SIZE_LIMIT equ 0
 CONFIG_SPATIAL_SVC equ 0
 CONFIG_FP_MB_STATS equ 0
 CONFIG_EMULATE_HARDWARE equ 0
-DECODE_WIDTH_LIMIT ,  4000
-DECODE_HEIGHT_LIMIT ,  3000
diff --git a/media/libvpx/vpx_config_x86_64-darwin9-gcc.h b/media/libvpx/vpx_config_x86_64-darwin9-gcc.h
index d04556d4585f..0d0477ceeca1 100644
--- a/media/libvpx/vpx_config_x86_64-darwin9-gcc.h
+++ b/media/libvpx/vpx_config_x86_64-darwin9-gcc.h
@@ -88,10 +88,8 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SIZE_LIMIT 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
-#define DECODE_WIDTH_LIMIT 4000
-#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */
diff --git a/media/libvpx/vpx_config_x86_64-linux-gcc.asm b/media/libvpx/vpx_config_x86_64-linux-gcc.asm
index a5b8cb4bf351..6da93489bfb4 100644
--- a/media/libvpx/vpx_config_x86_64-linux-gcc.asm
+++ b/media/libvpx/vpx_config_x86_64-linux-gcc.asm
@@ -76,9 +76,7 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0
 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
 CONFIG_VP9_HIGHBITDEPTH equ 0
 CONFIG_EXPERIMENTAL equ 0
-CONFIG_SIZE_LIMIT equ 1
+CONFIG_SIZE_LIMIT equ 0
 CONFIG_SPATIAL_SVC equ 0
 CONFIG_FP_MB_STATS equ 0
 CONFIG_EMULATE_HARDWARE equ 0
-DECODE_WIDTH_LIMIT ,  4000
-DECODE_HEIGHT_LIMIT ,  3000
diff --git a/media/libvpx/vpx_config_x86_64-linux-gcc.h b/media/libvpx/vpx_config_x86_64-linux-gcc.h
index dcd1ad82a9f5..21228cd1dd09 100644
--- a/media/libvpx/vpx_config_x86_64-linux-gcc.h
+++ b/media/libvpx/vpx_config_x86_64-linux-gcc.h
@@ -88,10 +88,8 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SIZE_LIMIT 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
-#define DECODE_WIDTH_LIMIT 4000
-#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */
diff --git a/media/libvpx/vpx_config_x86_64-win64-gcc.asm b/media/libvpx/vpx_config_x86_64-win64-gcc.asm
index ffebcf1d5171..20ba15baee06 100644
--- a/media/libvpx/vpx_config_x86_64-win64-gcc.asm
+++ b/media/libvpx/vpx_config_x86_64-win64-gcc.asm
@@ -76,9 +76,7 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0
 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
 CONFIG_VP9_HIGHBITDEPTH equ 0
 CONFIG_EXPERIMENTAL equ 0
-CONFIG_SIZE_LIMIT equ 1
+CONFIG_SIZE_LIMIT equ 0
 CONFIG_SPATIAL_SVC equ 0
 CONFIG_FP_MB_STATS equ 0
 CONFIG_EMULATE_HARDWARE equ 0
-DECODE_WIDTH_LIMIT ,  4000
-DECODE_HEIGHT_LIMIT ,  3000
diff --git a/media/libvpx/vpx_config_x86_64-win64-gcc.h b/media/libvpx/vpx_config_x86_64-win64-gcc.h
index cf8a66268eb1..b056a0ea3850 100644
--- a/media/libvpx/vpx_config_x86_64-win64-gcc.h
+++ b/media/libvpx/vpx_config_x86_64-win64-gcc.h
@@ -89,10 +89,8 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SIZE_LIMIT 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
-#define DECODE_WIDTH_LIMIT 4000
-#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */
diff --git a/media/libvpx/vpx_config_x86_64-win64-vs12.asm b/media/libvpx/vpx_config_x86_64-win64-vs12.asm
index 40d594793734..39c17a07c3ee 100644
--- a/media/libvpx/vpx_config_x86_64-win64-vs12.asm
+++ b/media/libvpx/vpx_config_x86_64-win64-vs12.asm
@@ -76,9 +76,7 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0
 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
 CONFIG_VP9_HIGHBITDEPTH equ 0
 CONFIG_EXPERIMENTAL equ 0
-CONFIG_SIZE_LIMIT equ 1
+CONFIG_SIZE_LIMIT equ 0
 CONFIG_SPATIAL_SVC equ 0
 CONFIG_FP_MB_STATS equ 0
 CONFIG_EMULATE_HARDWARE equ 0
-DECODE_WIDTH_LIMIT ,  4000
-DECODE_HEIGHT_LIMIT ,  3000
diff --git a/media/libvpx/vpx_config_x86_64-win64-vs12.h b/media/libvpx/vpx_config_x86_64-win64-vs12.h
index 17cd9421ed24..4ad69bdb8445 100644
--- a/media/libvpx/vpx_config_x86_64-win64-vs12.h
+++ b/media/libvpx/vpx_config_x86_64-win64-vs12.h
@@ -88,10 +88,8 @@
 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0
 #define CONFIG_VP9_HIGHBITDEPTH 0
 #define CONFIG_EXPERIMENTAL 0
-#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SIZE_LIMIT 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
-#define DECODE_WIDTH_LIMIT 4000
-#define DECODE_HEIGHT_LIMIT 3000
 #endif /* VPX_CONFIG_H */

From 20a1bde88b5f69caf7081240abe2bfafe1e5e019 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Julien=20Pag=C3=A8s?= 
Date: Thu, 20 Aug 2015 16:14:01 +0200
Subject: [PATCH 027/208] Bug 1194074 - allow Talos test jobs to install psutil
 as a dependency. r=gps

---
 testing/mozharness/mozharness/base/python.py           | 2 +-
 testing/mozharness/mozharness/mozilla/testing/talos.py | 9 ++++++---
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/testing/mozharness/mozharness/base/python.py b/testing/mozharness/mozharness/base/python.py
index 855deb1129db..539689bc4d5f 100644
--- a/testing/mozharness/mozharness/base/python.py
+++ b/testing/mozharness/mozharness/base/python.py
@@ -440,7 +440,7 @@ class ResourceMonitoringMixin(object):
     def __init__(self, *args, **kwargs):
         super(ResourceMonitoringMixin, self).__init__(*args, **kwargs)
 
-        self.register_virtualenv_module('psutil==0.7.1', method='pip',
+        self.register_virtualenv_module('psutil>=0.7.1', method='pip',
                                         optional=True)
         self.register_virtualenv_module('mozsystemmonitor==0.0.0',
                                         method='pip', optional=True)
diff --git a/testing/mozharness/mozharness/mozilla/testing/talos.py b/testing/mozharness/mozharness/mozilla/testing/talos.py
index 8c2c74187093..8f1c8bbda9cf 100755
--- a/testing/mozharness/mozharness/mozilla/testing/talos.py
+++ b/testing/mozharness/mozharness/mozilla/testing/talos.py
@@ -522,15 +522,18 @@ def create_virtualenv(self, **kwargs):
         talos from its source, we have to wrap that method here."""
         # XXX This method could likely be replaced with a PreScriptAction hook.
         if self.has_cloned_talos:
+            # require pip >= 1.5 so pip will prefer .whl files to install
+            super(Talos, self).create_virtualenv(
+                modules=['mozinstall', 'pip>=1.5']
+            )
             # talos in harness requires mozinstall and what is
             # listed in talos requirements.txt file.
-            return super(Talos, self).create_virtualenv(
-                modules=['mozinstall'],
+            self.install_module(
                 requirements=[os.path.join(self.talos_path,
                                            'requirements.txt')]
             )
         else:
-            return super(Talos, self).create_virtualenv(**kwargs)
+            super(Talos, self).create_virtualenv(**kwargs)
 
     def postflight_create_virtualenv(self):
         """ This belongs in download_and_install() but requires the

From f98ca7db645846fc38b941ec93d029dfcff1f642 Mon Sep 17 00:00:00 2001
From: Kit Cambridge 
Date: Wed, 19 Aug 2015 16:03:15 -0700
Subject: [PATCH 028/208] Bug 1196512 - Use principals to test for push
 permissions. r=nsm

---
 dom/push/PushRecord.jsm  | 63 +++++++++++++++++++++++++++++++++-------
 dom/push/PushService.jsm |  6 ++--
 2 files changed, 54 insertions(+), 15 deletions(-)

diff --git a/dom/push/PushRecord.jsm b/dom/push/PushRecord.jsm
index 5268c6c4e82d..a9afc72960cc 100644
--- a/dom/push/PushRecord.jsm
+++ b/dom/push/PushRecord.jsm
@@ -19,11 +19,14 @@ XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
                                   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
+                                  "resource://gre/modules/BrowserUtils.jsm");
+
 this.EXPORTED_SYMBOLS = ["PushRecord"];
 
 const prefs = new Preferences("dom.push.");
 
-// History transition types that can fire an `pushsubscriptionchange` event
+// History transition types that can fire a `pushsubscriptionchange` event
 // when the user visits a site with expired push registrations. Visits only
 // count if the user sees the origin in the address bar. This excludes embedded
 // resources, downloads, and framed links.
@@ -38,7 +41,6 @@ const QUOTA_REFRESH_TRANSITIONS_SQL = [
 function PushRecord(props) {
   this.pushEndpoint = props.pushEndpoint;
   this.scope = props.scope;
-  this.origin = Services.io.newURI(this.scope, null, null).prePath;
   this.originAttributes = props.originAttributes;
   this.pushCount = props.pushCount || 0;
   this.lastPush = props.lastPush || 0;
@@ -116,8 +118,8 @@ PushRecord.prototype = {
         `,
         {
           // Restrict the query to all pages for this origin.
-          urlLowerBound: this.origin,
-          urlUpperBound: this.origin + "\x7f"
+          urlLowerBound: this.uri.prePath,
+          urlUpperBound: this.uri.prePath + "\x7f",
         }
       );
     }).then(rows => {
@@ -143,7 +145,7 @@ PushRecord.prototype = {
       for (let tab of tabs) {
         // `linkedBrowser` on Desktop; `browser` on Fennec.
         let tabURI = (tab.linkedBrowser || tab.browser).currentURI;
-        if (tabURI.prePath == this.origin) {
+        if (tabURI.prePath == this.uri.prePath) {
           return true;
         }
       }
@@ -151,6 +153,24 @@ PushRecord.prototype = {
     return false;
   },
 
+  /**
+   * Returns the push permission state for the principal associated with
+   * this registration.
+   */
+  pushPermission() {
+    return Services.perms.testExactPermissionFromPrincipal(
+           this.principal, "push");
+  },
+
+  /**
+   * Indicates whether the registration can deliver push messages to its
+   * associated service worker.
+   */
+  hasPermission() {
+    let permission = this.pushPermission();
+    return permission == Ci.nsIPermissionManager.ALLOW_ACTION;
+  },
+
   quotaApplies() {
     return Number.isFinite(this.quota);
   },
@@ -174,10 +194,31 @@ PushRecord.prototype = {
   },
 };
 
-// Mark the `origin` property as non-enumerable to avoid storing the
-// registration origin in IndexedDB.
-Object.defineProperty(PushRecord.prototype, "origin", {
-  configurable: true,
-  enumerable: false,
-  writable: true,
+// Define lazy getters for the principal and scope URI. IndexedDB can't store
+// `nsIPrincipal` objects, so we keep them in a private weak map.
+let principals = new WeakMap();
+Object.defineProperties(PushRecord.prototype, {
+  principal: {
+    get() {
+      let principal = principals.get(this);
+      if (!principal) {
+        let url = this.scope;
+        if (this.originAttributes) {
+          // Allow tests to omit origin attributes.
+          url += this.originAttributes;
+        }
+        principal = BrowserUtils.principalFromOrigin(url);
+        principals.set(this, principal);
+      }
+      return principal;
+    },
+    configurable: true,
+  },
+
+  uri: {
+    get() {
+      return this.principal.URI;
+    },
+    configurable: true,
+  },
 });
diff --git a/dom/push/PushService.jsm b/dom/push/PushService.jsm
index c16d521860ba..d7e79b777ac0 100644
--- a/dom/push/PushService.jsm
+++ b/dom/push/PushService.jsm
@@ -789,7 +789,6 @@ this.PushService = {
     }
 
     debug("notifyApp() " + aPushRecord.scope);
-    let scopeURI = Services.io.newURI(aPushRecord.scope, null, null);
     // Notify XPCOM observers.
     let notification = Cc["@mozilla.org/push/ObserverNotification;1"]
                          .createInstance(Ci.nsIPushObserverNotification);
@@ -806,8 +805,7 @@ this.PushService = {
     );
 
     // If permission has been revoked, trash the message.
-    if (Services.perms.testExactPermission(scopeURI, "push") !=
-        Ci.nsIPermissionManager.ALLOW_ACTION) {
+    if (!aPushRecord.hasPermission()) {
       debug("Does not have permission for push.");
       return;
     }
@@ -1096,7 +1094,7 @@ this.PushService = {
 
     let clear = (db, domain) => {
       db.clearIf(record => {
-        return hasRootDomain(record.origin, domain);
+        return hasRootDomain(record.uri.prePath, domain);
       });
     }
 

From 02aa7db2d6dcd96bda5284ac8ceef3bc6b5b60a1 Mon Sep 17 00:00:00 2001
From: Andrea Marchesini 
Date: Thu, 20 Aug 2015 19:54:50 +0100
Subject: [PATCH 029/208] Bug 1184807 - better management of the dispatching of
 events when shutting down, r=rjesup

---
 dom/media/TextTrackList.cpp | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/dom/media/TextTrackList.cpp b/dom/media/TextTrackList.cpp
index f1f1630d26db..838d45704528 100644
--- a/dom/media/TextTrackList.cpp
+++ b/dom/media/TextTrackList.cpp
@@ -194,8 +194,11 @@ TextTrackList::CreateAndDispatchTrackEventRunner(TextTrack* aTrack,
     TrackEvent::Constructor(this, aEventName, eventInit);
 
   // Dispatch the TrackEvent asynchronously.
-  nsCOMPtr eventRunner = new TrackEventRunner(this, event);
-  NS_DispatchToMainThread(eventRunner);
+  rv = thread->Dispatch(do_AddRef(new TrackEventRunner(this, event)),
+                        NS_DISPATCH_NORMAL);
+
+  // If we are shutting down this can file but it's still ok.
+  NS_WARN_IF(NS_FAILED(rv));
 }
 
 HTMLMediaElement*

From bde135c99c29037581a2b9d513579c09bfc10d8d Mon Sep 17 00:00:00 2001
From: Wes Kocher 
Date: Thu, 20 Aug 2015 12:05:37 -0700
Subject: [PATCH 030/208] Backed out changeset 91cc337bef3b (bug 1191814) for
 m-e10s(3) failures in test_global_queue_pause.html

---
 .../synth/ipc/PSpeechSynthesisRequest.ipdl    |  2 -
 .../synth/ipc/SpeechSynthesisChild.cpp        |  8 --
 .../synth/ipc/SpeechSynthesisChild.h          |  2 -
 .../synth/ipc/SpeechSynthesisParent.cpp       |  8 --
 .../synth/ipc/SpeechSynthesisParent.h         |  2 -
 dom/media/webspeech/synth/nsSpeechTask.cpp    | 94 ++++---------------
 dom/media/webspeech/synth/nsSpeechTask.h      | 13 +--
 7 files changed, 21 insertions(+), 108 deletions(-)

diff --git a/dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl b/dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl
index d244b1708ca5..9a146145bbd7 100644
--- a/dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl
+++ b/dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl
@@ -23,8 +23,6 @@ async protocol PSpeechSynthesisRequest
 
   ForceEnd();
 
-  SetAudioOutputVolume(uint32_t aVolume);
-
  child:
 
   __delete__(bool aIsError, float aElapsedTime, uint32_t aCharIndex);
diff --git a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp
index 04acb3e9e5d5..c6f4e60258ac 100644
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp
@@ -191,13 +191,5 @@ SpeechTaskChild::ForceEnd()
   mActor->SendForceEnd();
 }
 
-void
-SpeechTaskChild::SetAudioOutputVolume(uint32_t aVolume)
-{
-  if (mActor) {
-    mActor->SendSetAudioOutputVolume(aVolume);
-  }
-}
-
 } // namespace dom
 } // namespace mozilla
diff --git a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h
index cb0d7d78f848..a89cbaa43814 100644
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h
@@ -92,8 +92,6 @@ class SpeechTaskChild : public nsSpeechTask
 
   virtual void ForceEnd() override;
 
-  virtual void SetAudioOutputVolume(uint32_t aVolume) override;
-
 private:
   SpeechSynthesisRequestChild* mActor;
 };
diff --git a/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.cpp b/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.cpp
index 6729f3bbf628..e6ef6d654618 100644
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.cpp
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.cpp
@@ -127,14 +127,6 @@ SpeechSynthesisRequestParent::RecvForceEnd()
   return true;
 }
 
-bool
-SpeechSynthesisRequestParent::RecvSetAudioOutputVolume(const uint32_t& aVolume)
-{
-  MOZ_ASSERT(mTask);
-  mTask->SetAudioOutputVolume(aVolume);
-  return true;
-}
-
 // SpeechTaskParent
 
 nsresult
diff --git a/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.h b/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.h
index 95417666f218..67272583c5d6 100644
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.h
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.h
@@ -69,8 +69,6 @@ class SpeechSynthesisRequestParent : public PSpeechSynthesisRequestParent
   virtual bool RecvCancel() override;
 
   virtual bool RecvForceEnd() override;
-
-  virtual bool RecvSetAudioOutputVolume(const uint32_t& aVolume) override;
 };
 
 class SpeechTaskParent : public nsSpeechTask
diff --git a/dom/media/webspeech/synth/nsSpeechTask.cpp b/dom/media/webspeech/synth/nsSpeechTask.cpp
index f4f4bba304b1..efe7c66c0ecb 100644
--- a/dom/media/webspeech/synth/nsSpeechTask.cpp
+++ b/dom/media/webspeech/synth/nsSpeechTask.cpp
@@ -4,13 +4,10 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "AudioChannelAgent.h"
-#include "AudioChannelService.h"
 #include "AudioSegment.h"
-#include "mozilla/Preferences.h"
 #include "nsSpeechTask.h"
-#include "nsSynthVoiceRegistry.h"
 #include "SpeechSynthesis.h"
+#include "nsSynthVoiceRegistry.h"
 
 // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
 // GetTickCount() and conflicts with nsSpeechTask::GetCurrentTime().
@@ -25,11 +22,6 @@ extern PRLogModuleInfo* GetSpeechSynthLog();
 namespace mozilla {
 namespace dom {
 
-static bool UseAudioChannelService()
-{
-  return Preferences::GetBool("media.useAudioChannelService");
-}
-
 class SynthStreamListener : public MediaStreamListener
 {
 public:
@@ -97,7 +89,6 @@ NS_IMPL_CYCLE_COLLECTION(nsSpeechTask, mSpeechSynthesis, mUtterance, mCallback);
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSpeechTask)
   NS_INTERFACE_MAP_ENTRY(nsISpeechTask)
-  NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechTask)
 NS_INTERFACE_MAP_END
 
@@ -110,6 +101,7 @@ nsSpeechTask::nsSpeechTask(SpeechSynthesisUtterance* aUtterance)
   , mPrePaused(false)
   , mPreCanceled(false)
   , mCallback(nullptr)
+  , mIndirectAudio(false)
 {
   mText = aUtterance->mText;
   mVolume = aUtterance->Volume();
@@ -123,6 +115,7 @@ nsSpeechTask::nsSpeechTask(float aVolume, const nsAString& aText)
   , mPrePaused(false)
   , mPreCanceled(false)
   , mCallback(nullptr)
+  , mIndirectAudio(false)
 {
 }
 
@@ -149,7 +142,9 @@ nsSpeechTask::Init(ProcessedMediaStream* aStream)
   if (aStream) {
     mStream = MediaStreamGraph::GetInstance()->CreateSourceStream(nullptr);
     mPort = aStream->AllocateInputPort(mStream, 0);
+    mIndirectAudio = false;
   } else {
+    mIndirectAudio = true;
   }
   mInited = true;
 }
@@ -170,7 +165,8 @@ nsSpeechTask::Setup(nsISpeechTaskCallback* aCallback,
 
   mCallback = aCallback;
 
-  if (!mStream) {
+  if (mIndirectAudio) {
+    MOZ_ASSERT(!mStream);
     if (argc > 0) {
       NS_WARNING("Audio info arguments in Setup() are ignored for indirect audio services.");
     }
@@ -230,7 +226,7 @@ nsSpeechTask::SendAudio(JS::Handle aData, JS::Handle aLand
     return NS_ERROR_INVALID_ARG;
   }
 
-  if (!mStream) {
+  if (mIndirectAudio) {
     NS_WARNING("Can't call SendAudio from an indirect audio speech service.");
     return NS_ERROR_FAILURE;
   }
@@ -277,7 +273,7 @@ nsSpeechTask::SendAudioNative(int16_t* aData, uint32_t aDataLen)
     return NS_ERROR_FAILURE;
   }
 
-  if (!mStream) {
+  if (mIndirectAudio) {
     NS_WARNING("Can't call SendAudio from an indirect audio speech service.");
     return NS_ERROR_FAILURE;
   }
@@ -307,7 +303,7 @@ nsSpeechTask::SendAudioImpl(nsRefPtr& aSamples, uint32_t
 NS_IMETHODIMP
 nsSpeechTask::DispatchStart()
 {
-  if (mStream) {
+  if (!mIndirectAudio) {
     NS_WARNING("Can't call DispatchStart() from a direct audio speech service");
     return NS_ERROR_FAILURE;
   }
@@ -318,8 +314,6 @@ nsSpeechTask::DispatchStart()
 nsresult
 nsSpeechTask::DispatchStartInner()
 {
-  CreateAudioChannelAgent();
-
   nsSynthVoiceRegistry::GetInstance()->SetIsSpeaking(true);
   return DispatchStartImpl();
 }
@@ -351,7 +345,7 @@ nsSpeechTask::DispatchStartImpl(const nsAString& aUri)
 NS_IMETHODIMP
 nsSpeechTask::DispatchEnd(float aElapsedTime, uint32_t aCharIndex)
 {
-  if (mStream) {
+  if (!mIndirectAudio) {
     NS_WARNING("Can't call DispatchEnd() from a direct audio speech service");
     return NS_ERROR_FAILURE;
   }
@@ -362,8 +356,6 @@ nsSpeechTask::DispatchEnd(float aElapsedTime, uint32_t aCharIndex)
 nsresult
 nsSpeechTask::DispatchEndInner(float aElapsedTime, uint32_t aCharIndex)
 {
-  DestroyAudioChannelAgent();
-
   if (!mPreCanceled) {
     nsSynthVoiceRegistry::GetInstance()->SpeakNext();
   }
@@ -407,7 +399,7 @@ nsSpeechTask::DispatchEndImpl(float aElapsedTime, uint32_t aCharIndex)
 NS_IMETHODIMP
 nsSpeechTask::DispatchPause(float aElapsedTime, uint32_t aCharIndex)
 {
-  if (mStream) {
+  if (!mIndirectAudio) {
     NS_WARNING("Can't call DispatchPause() from a direct audio speech service");
     return NS_ERROR_FAILURE;
   }
@@ -439,7 +431,7 @@ nsSpeechTask::DispatchPauseImpl(float aElapsedTime, uint32_t aCharIndex)
 NS_IMETHODIMP
 nsSpeechTask::DispatchResume(float aElapsedTime, uint32_t aCharIndex)
 {
-  if (mStream) {
+  if (!mIndirectAudio) {
     NS_WARNING("Can't call DispatchResume() from a direct audio speech service");
     return NS_ERROR_FAILURE;
   }
@@ -472,7 +464,7 @@ nsSpeechTask::DispatchResumeImpl(float aElapsedTime, uint32_t aCharIndex)
 NS_IMETHODIMP
 nsSpeechTask::DispatchError(float aElapsedTime, uint32_t aCharIndex)
 {
-  if (mStream) {
+  if (!mIndirectAudio) {
     NS_WARNING("Can't call DispatchError() from a direct audio speech service");
     return NS_ERROR_FAILURE;
   }
@@ -499,7 +491,7 @@ NS_IMETHODIMP
 nsSpeechTask::DispatchBoundary(const nsAString& aName,
                                float aElapsedTime, uint32_t aCharIndex)
 {
-  if (mStream) {
+  if (!mIndirectAudio) {
     NS_WARNING("Can't call DispatchBoundary() from a direct audio speech service");
     return NS_ERROR_FAILURE;
   }
@@ -526,7 +518,7 @@ NS_IMETHODIMP
 nsSpeechTask::DispatchMark(const nsAString& aName,
                            float aElapsedTime, uint32_t aCharIndex)
 {
-  if (mStream) {
+  if (!mIndirectAudio) {
     NS_WARNING("Can't call DispatchMark() from a direct audio speech service");
     return NS_ERROR_FAILURE;
   }
@@ -567,7 +559,7 @@ nsSpeechTask::Pause()
     mPrePaused = true;
   }
 
-  if (mStream) {
+  if (!mIndirectAudio) {
     DispatchPauseImpl(GetCurrentTime(), GetCurrentCharOffset());
   }
 }
@@ -591,7 +583,7 @@ nsSpeechTask::Resume()
     nsSynthVoiceRegistry::GetInstance()->ResumeQueue();
   }
 
-  if (mStream) {
+  if (!mIndirectAudio) {
     DispatchResumeImpl(GetCurrentTime(), GetCurrentCharOffset());
   }
 }
@@ -616,7 +608,7 @@ nsSpeechTask::Cancel()
     mPreCanceled = true;
   }
 
-  if (mStream) {
+  if (!mIndirectAudio) {
     DispatchEndInner(GetCurrentTime(), GetCurrentCharOffset());
   }
 }
@@ -653,53 +645,5 @@ nsSpeechTask::SetSpeechSynthesis(SpeechSynthesis* aSpeechSynthesis)
   mSpeechSynthesis = aSpeechSynthesis;
 }
 
-void
-nsSpeechTask::CreateAudioChannelAgent()
-{
-  if (!mUtterance || !UseAudioChannelService()) {
-    return;
-  }
-
-  if (mAudioChannelAgent) {
-    mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY);
-  }
-
-  mAudioChannelAgent = new AudioChannelAgent();
-  mAudioChannelAgent->InitWithWeakCallback(mUtterance->GetOwner(),
-                                           static_cast(AudioChannelService::GetDefaultAudioChannel()),
-                                           this);
-}
-
-void
-nsSpeechTask::DestroyAudioChannelAgent()
-{
-  if (mAudioChannelAgent) {
-    mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY);
-    mAudioChannelAgent = nullptr;
-  }
-}
-
-NS_IMETHODIMP
-nsSpeechTask::WindowVolumeChanged(float aVolume, bool aMuted)
-{
-  SetAudioOutputVolume(mVolume * aVolume * aMuted);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSpeechTask::WindowAudioCaptureChanged()
-{
-  // This is not supported yet.
-  return NS_OK;
-}
-
-void
-nsSpeechTask::SetAudioOutputVolume(uint32_t aVolume)
-{
-  if (mStream) {
-    mStream->SetAudioOutputVolume(this, aVolume);
-  }
-}
-
 } // namespace dom
 } // namespace mozilla
diff --git a/dom/media/webspeech/synth/nsSpeechTask.h b/dom/media/webspeech/synth/nsSpeechTask.h
index b362f4af4420..70e7929ef6a4 100644
--- a/dom/media/webspeech/synth/nsSpeechTask.h
+++ b/dom/media/webspeech/synth/nsSpeechTask.h
@@ -9,7 +9,6 @@
 
 #include "MediaStreamGraph.h"
 #include "SpeechSynthesisUtterance.h"
-#include "nsIAudioChannelAgent.h"
 #include "nsISpeechService.h"
 
 namespace mozilla {
@@ -20,7 +19,6 @@ class SpeechSynthesis;
 class SynthStreamListener;
 
 class nsSpeechTask : public nsISpeechTask
-                   , public nsIAudioChannelAgentCallback
 {
   friend class SynthStreamListener;
 
@@ -29,7 +27,6 @@ class nsSpeechTask : public nsISpeechTask
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsSpeechTask, nsISpeechTask)
 
   NS_DECL_NSISPEECHTASK
-  NS_DECL_NSIAUDIOCHANNELAGENTCALLBACK
 
   explicit nsSpeechTask(SpeechSynthesisUtterance* aUtterance);
   nsSpeechTask(float aVolume, const nsAString& aText);
@@ -52,8 +49,6 @@ class nsSpeechTask : public nsISpeechTask
 
   void SetChosenVoiceURI(const nsAString& aUri);
 
-  virtual void SetAudioOutputVolume(uint32_t aVolume);
-
   bool IsPreCanceled()
   {
     return mPreCanceled;
@@ -107,22 +102,18 @@ class nsSpeechTask : public nsISpeechTask
 
   nsresult DispatchEndInner(float aElapsedTime, uint32_t aCharIndex);
 
-  void CreateAudioChannelAgent();
-
-  void DestroyAudioChannelAgent();
-
   nsRefPtr mStream;
 
   nsRefPtr mPort;
 
   nsCOMPtr mCallback;
 
-  nsCOMPtr mAudioChannelAgent;
-
   uint32_t mChannels;
 
   nsRefPtr mSpeechSynthesis;
 
+  bool mIndirectAudio;
+
   nsString mChosenVoiceURI;
 };
 

From 28cac2868bb0b305aecb06b9c8b023d9df8fb60f Mon Sep 17 00:00:00 2001
From: David Burns 
Date: Wed, 19 Aug 2015 15:57:06 +0100
Subject: [PATCH 031/208] Bug 1156070: Rename test class to prevent test
 harnesses thinking there is a failure; r=jgriffin

Mozharness appears to do a check for the word exception and is seeing these
tests as failures when they are not.
---
 .../marionette/client/marionette/tests/unit/test_errors.py    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/testing/marionette/client/marionette/tests/unit/test_errors.py b/testing/marionette/client/marionette/tests/unit/test_errors.py
index 3f3feae44623..fe410f82e0f1 100644
--- a/testing/marionette/client/marionette/tests/unit/test_errors.py
+++ b/testing/marionette/client/marionette/tests/unit/test_errors.py
@@ -17,7 +17,7 @@ def fake_cause():
 cause = fake_cause()
 stacktrace = "first\nsecond"
 
-class TestExceptionType(marionette_test.MarionetteTestCase):
+class TestErrors(marionette_test.MarionetteTestCase):
     def test_defaults(self):
         exc = errors.MarionetteException()
         self.assertIsNone(exc.msg)
@@ -72,7 +72,7 @@ def test_by_known_unicode_string(self):
             errors.lookup(u"no such element"))
 
 
-class TestAllExceptions(marionette_test.MarionetteTestCase):
+class TestAllErrors(marionette_test.MarionetteTestCase):
     def test_properties(self):
         for exc in errors.es_:
             self.assertTrue(hasattr(exc, "code"),

From 341e4e7551ae39fa6e6aa8d7fd9b1c85ea614bda Mon Sep 17 00:00:00 2001
From: Trevor Saunders 
Date: Thu, 20 Aug 2015 15:38:37 -0400
Subject: [PATCH 032/208] bug 1196880 - correctly compute interfaces for
 proxies r=davidb

interfaces is supposed to be a bit mask indexed by MAI_INTERFACE_X, so when
adding interfaces MAI_INTERFACE_X should be used as an index of the bit to set,
       not the mask to add.
---
 accessible/atk/AccessibleWrap.cpp | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/accessible/atk/AccessibleWrap.cpp b/accessible/atk/AccessibleWrap.cpp
index 7a57d99d3495..e379b371370e 100644
--- a/accessible/atk/AccessibleWrap.cpp
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -1089,19 +1089,19 @@ GetInterfacesForProxy(ProxyAccessible* aProxy, uint32_t aInterfaces)
         | (1 << MAI_INTERFACE_EDITABLE_TEXT);
 
   if (aInterfaces & Interfaces::HYPERLINK)
-    interfaces |= MAI_INTERFACE_HYPERLINK_IMPL;
+    interfaces |= 1 << MAI_INTERFACE_HYPERLINK_IMPL;
 
   if (aInterfaces & Interfaces::VALUE)
-    interfaces |= MAI_INTERFACE_VALUE;
+    interfaces |= 1 << MAI_INTERFACE_VALUE;
 
   if (aInterfaces & Interfaces::TABLE)
-    interfaces |= MAI_INTERFACE_TABLE;
+    interfaces |= 1 << MAI_INTERFACE_TABLE;
 
   if (aInterfaces & Interfaces::IMAGE)
-    interfaces |= MAI_INTERFACE_IMAGE;
+    interfaces |= 1 << MAI_INTERFACE_IMAGE;
 
   if (aInterfaces & Interfaces::DOCUMENT)
-    interfaces |= MAI_INTERFACE_DOCUMENT;
+    interfaces |= 1 << MAI_INTERFACE_DOCUMENT;
 
   return interfaces;
 }

From b24f93b7cd5c2817c1023097bdf88aa0e2f8fe9e Mon Sep 17 00:00:00 2001
From: Bas Schouten 
Date: Thu, 20 Aug 2015 20:03:44 +0000
Subject: [PATCH 033/208] Bug 1189891: Only include STL wrapper requirements on
 the first include. r=glandium

---
 config/msvc-stl-wrapper.template.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/config/msvc-stl-wrapper.template.h b/config/msvc-stl-wrapper.template.h
index 0a01a6dd1b5f..c42da266ed0d 100644
--- a/config/msvc-stl-wrapper.template.h
+++ b/config/msvc-stl-wrapper.template.h
@@ -8,6 +8,9 @@
 #ifndef mozilla_${HEADER}_h
 #define mozilla_${HEADER}_h
 
+#ifndef MOZ_HAVE_INCLUDED_ALLOC
+#define MOZ_HAVE_INCLUDED_ALLOC
+
 #if _HAS_EXCEPTIONS
 #  error "STL code can only be used with -fno-exceptions"
 #endif
@@ -32,6 +35,7 @@
 #else
 #  error "STL code can only be used with infallible ::operator new()"
 #endif
+#endif /* MOZ_HAVE_INCLUDED_ALLOC */
 
 #ifdef _DEBUG
 // From

From 21d8a8d44619f24f9f8de13137d13c8813e2dc60 Mon Sep 17 00:00:00 2001
From: Kartikaya Gupta 
Date: Thu, 20 Aug 2015 16:29:01 -0400
Subject: [PATCH 034/208] Bug 1196594 - Complete the toolbar transition as soon
 as the finger is lifted rather than waiting for the pan/zoom animation to
 stop. r=rbarker

---
 mobile/android/base/BrowserApp.java                 | 6 +-----
 mobile/android/base/gfx/DynamicToolbarAnimator.java | 9 +++++++++
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/mobile/android/base/BrowserApp.java b/mobile/android/base/BrowserApp.java
index 51de8603dbef..4bf4f62a27ae 100644
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -1582,16 +1582,12 @@ public void onPanZoomStopped() {
         float toolbarTranslation = mLayerView.getDynamicToolbarAnimator().getToolbarTranslation();
 
         boolean shortPage = metrics.getPageHeight() < metrics.getHeight();
-        boolean toolbarMostlyVisible = toolbarTranslation < (mToolbarHeight / 2);
         boolean atBottomOfLongPage = (metrics.pageRectBottom == metrics.viewportRectBottom())
             && (metrics.pageRectBottom > 2 * metrics.getHeight());
         Log.v(LOGTAG, "On pan/zoom stopped, short page: " + shortPage
-            + "; toolbarMostlyVisible: " + toolbarMostlyVisible
             + "; atBottomOfLongPage: " + atBottomOfLongPage);
-        if (shortPage || toolbarMostlyVisible || atBottomOfLongPage) {
+        if (shortPage || atBottomOfLongPage) {
             mDynamicToolbar.setVisible(true, VisibilityTransition.ANIMATE);
-        } else {
-            mDynamicToolbar.setVisible(false, VisibilityTransition.ANIMATE);
         }
     }
 
diff --git a/mobile/android/base/gfx/DynamicToolbarAnimator.java b/mobile/android/base/gfx/DynamicToolbarAnimator.java
index feb0e8848f94..079f7fdb66c4 100644
--- a/mobile/android/base/gfx/DynamicToolbarAnimator.java
+++ b/mobile/android/base/gfx/DynamicToolbarAnimator.java
@@ -359,6 +359,15 @@ boolean onInterceptTouchEvent(MotionEvent event) {
                 Log.v(LOGTAG, "Resetting touch sequence due to non-move");
                 mTouchStart = null;
             }
+
+            if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+                // We need to do this even if the toolbar is already fully
+                // visible or fully hidden, because this is what triggers the
+                // viewport resize in content and updates the viewport metrics.
+                boolean toolbarMostlyVisible = mToolbarTranslation < (mMaxTranslation / 2);
+                Log.v(LOGTAG, "All fingers lifted, completing " + (toolbarMostlyVisible ? "show" : "hide"));
+                animateToolbar(toolbarMostlyVisible, false);
+            }
             return false;
         }
 

From db3d1d82a4b61aa62f2ab3f218fda0f4d6f1e5c0 Mon Sep 17 00:00:00 2001
From: Kartikaya Gupta 
Date: Thu, 20 Aug 2015 16:29:05 -0400
Subject: [PATCH 035/208] Bug 1196593 - Account for some rounding error when
 determining if we've reached the bottom of the page. r=rbarker

---
 mobile/android/base/BrowserApp.java | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/mobile/android/base/BrowserApp.java b/mobile/android/base/BrowserApp.java
index 4bf4f62a27ae..6eea64b8fdd1 100644
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -74,6 +74,7 @@
 import org.mozilla.gecko.util.ActivityUtils;
 import org.mozilla.gecko.util.Clipboard;
 import org.mozilla.gecko.util.EventCallback;
+import org.mozilla.gecko.util.FloatUtils;
 import org.mozilla.gecko.util.GamepadUtils;
 import org.mozilla.gecko.util.GeckoEventListener;
 import org.mozilla.gecko.util.HardwareUtils;
@@ -1582,7 +1583,8 @@ public void onPanZoomStopped() {
         float toolbarTranslation = mLayerView.getDynamicToolbarAnimator().getToolbarTranslation();
 
         boolean shortPage = metrics.getPageHeight() < metrics.getHeight();
-        boolean atBottomOfLongPage = (metrics.pageRectBottom == metrics.viewportRectBottom())
+        boolean atBottomOfLongPage =
+            FloatUtils.fuzzyEquals(metrics.pageRectBottom, metrics.viewportRectBottom())
             && (metrics.pageRectBottom > 2 * metrics.getHeight());
         Log.v(LOGTAG, "On pan/zoom stopped, short page: " + shortPage
             + "; atBottomOfLongPage: " + atBottomOfLongPage);

From 4905222aef0f337ef67584e87888fd22ed9dacd3 Mon Sep 17 00:00:00 2001
From: Wes Kocher 
Date: Thu, 20 Aug 2015 13:57:58 -0700
Subject: [PATCH 036/208] Backed out changeset 151d70cfe45f (bug 1189891) for
 windows build bustage

---
 config/msvc-stl-wrapper.template.h | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/config/msvc-stl-wrapper.template.h b/config/msvc-stl-wrapper.template.h
index c42da266ed0d..0a01a6dd1b5f 100644
--- a/config/msvc-stl-wrapper.template.h
+++ b/config/msvc-stl-wrapper.template.h
@@ -8,9 +8,6 @@
 #ifndef mozilla_${HEADER}_h
 #define mozilla_${HEADER}_h
 
-#ifndef MOZ_HAVE_INCLUDED_ALLOC
-#define MOZ_HAVE_INCLUDED_ALLOC
-
 #if _HAS_EXCEPTIONS
 #  error "STL code can only be used with -fno-exceptions"
 #endif
@@ -35,7 +32,6 @@
 #else
 #  error "STL code can only be used with infallible ::operator new()"
 #endif
-#endif /* MOZ_HAVE_INCLUDED_ALLOC */
 
 #ifdef _DEBUG
 // From

From ff6831ad69428a04a3f7693ac5cb1112db326d88 Mon Sep 17 00:00:00 2001
From: Roman Reiss 
Date: Thu, 20 Aug 2015 14:14:11 -0700
Subject: [PATCH 037/208] Bug 875573 - Add video/x-m4v mime type to MP4Decoder
 r=kentuckyfriedtakahe

---
 dom/media/DecoderTraits.cpp                 | 3 ++-
 dom/media/fmp4/MP4Decoder.cpp               | 2 +-
 dom/media/test/test_can_play_type_mpeg.html | 2 ++
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/dom/media/DecoderTraits.cpp b/dom/media/DecoderTraits.cpp
index 8700fe3e16b2..e7af7c56b2df 100644
--- a/dom/media/DecoderTraits.cpp
+++ b/dom/media/DecoderTraits.cpp
@@ -226,6 +226,7 @@ static const char* const gOmxTypes[] = {
   "audio/3gpp",
   "audio/flac",
   "video/mp4",
+  "video/x-m4v",
   "video/3gpp",
   "video/3gpp2",
   "video/quicktime",
@@ -332,7 +333,7 @@ IsAndroidMediaType(const nsACString& aType)
   }
 
   static const char* supportedTypes[] = {
-    "audio/mpeg", "audio/mp4", "video/mp4", nullptr
+    "audio/mpeg", "audio/mp4", "video/mp4", "video/x-m4v", nullptr
   };
   return CodecListContains(supportedTypes, aType);
 }
diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp
index 11ccdaeb063e..6baaa093526b 100644
--- a/dom/media/fmp4/MP4Decoder.cpp
+++ b/dom/media/fmp4/MP4Decoder.cpp
@@ -148,7 +148,7 @@ MP4Decoder::CanHandleMediaType(const nsACString& aType,
   }
 #endif
 
-  if (!aType.EqualsASCII("video/mp4") ||
+  if ((!aType.EqualsASCII("video/mp4") && !aType.EqualsASCII("video/x-m4v")) ||
       !MP4Decoder::CanCreateH264Decoder()) {
     return false;
   }
diff --git a/dom/media/test/test_can_play_type_mpeg.html b/dom/media/test/test_can_play_type_mpeg.html
index bb03d7ab948c..8b822644fc9d 100644
--- a/dom/media/test/test_can_play_type_mpeg.html
+++ b/dom/media/test/test_can_play_type_mpeg.html
@@ -26,11 +26,13 @@
   }
 
   check("video/mp4", "maybe");
+  check("video/x-m4v", "maybe");
   check("audio/mp4", "maybe");
   check("audio/x-m4a", "maybe");
 
   // Not the MIME type that other browsers respond to, so we won't either.
   check("audio/m4a", "");
+  check("video/m4v", "");
   // Only Safari responds affirmatively to "audio/aac",
   // so we'll let x-m4a cover aac support.
   check("audio/aac", "");

From 5bcce87497c8acce3569b84bffdb2ba53380c47e Mon Sep 17 00:00:00 2001
From: Wei-Cheng Pan 
Date: Thu, 20 Aug 2015 15:39:47 +0800
Subject: [PATCH 038/208] Bug 1050749 - Expose BatteryManager via getBattery()
 returning a Promise r=bz,baku

---
 dom/base/Navigator.cpp                        | 34 ++++++-
 dom/base/Navigator.h                          |  4 +-
 dom/battery/BatteryManager.cpp                | 53 ++++++++++-
 dom/battery/BatteryManager.h                  | 10 +-
 dom/battery/test/marionette/manifest.ini      |  6 ++
 .../test/marionette/test_battery_level.js     | 25 ++---
 .../test_battery_status_charging.js           | 17 ++--
 .../test_battery_status_discharging.js        | 17 ++--
 .../marionette/test_battery_status_full.js    | 15 +--
 .../test_battery_status_not_charging.js       | 15 +--
 .../marionette/test_battery_status_unknown.js | 15 +--
 .../test_deprecated_battery_level.js          | 68 ++++++++++++++
 ...test_deprecated_battery_status_charging.js | 85 +++++++++++++++++
 ...t_deprecated_battery_status_discharging.js | 93 +++++++++++++++++++
 .../test_deprecated_battery_status_full.js    | 87 +++++++++++++++++
 ..._deprecated_battery_status_not_charging.js | 93 +++++++++++++++++++
 .../test_deprecated_battery_unknown.js        | 93 +++++++++++++++++++
 dom/battery/test/mochitest.ini                |  6 ++
 dom/battery/test/test_battery_basics.html     | 23 +++--
 dom/battery/test/test_battery_charging.html   | 33 +++++++
 .../test/test_battery_discharging.html        | 33 +++++++
 .../test/test_deprecated_battery_basics.html  | 32 +++++++
 dom/webidl/Navigator.webidl                   | 15 +--
 toolkit/modules/Battery.jsm                   | 21 ++++-
 .../modules/tests/browser/browser_Battery.js  | 37 +++++++-
 25 files changed, 852 insertions(+), 78 deletions(-)
 create mode 100644 dom/battery/test/marionette/test_deprecated_battery_level.js
 create mode 100644 dom/battery/test/marionette/test_deprecated_battery_status_charging.js
 create mode 100644 dom/battery/test/marionette/test_deprecated_battery_status_discharging.js
 create mode 100644 dom/battery/test/marionette/test_deprecated_battery_status_full.js
 create mode 100644 dom/battery/test/marionette/test_deprecated_battery_status_not_charging.js
 create mode 100644 dom/battery/test/marionette/test_deprecated_battery_unknown.js
 create mode 100644 dom/battery/test/test_battery_charging.html
 create mode 100644 dom/battery/test/test_battery_discharging.html
 create mode 100644 dom/battery/test/test_deprecated_battery_basics.html

diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp
index a11988d58126..7687784f5edd 100644
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -185,6 +185,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotification)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryPromise)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCellBroadcast)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager)
@@ -252,6 +253,8 @@ Navigator::Invalidate()
     mBatteryManager = nullptr;
   }
 
+  mBatteryPromise = nullptr;
+
 #ifdef MOZ_B2G_FM
   if (mFMRadio) {
     mFMRadio->Shutdown();
@@ -1455,8 +1458,37 @@ Navigator::GetMozFMRadio(ErrorResult& aRv)
 //    Navigator::nsINavigatorBattery
 //*****************************************************************************
 
-battery::BatteryManager*
+Promise*
 Navigator::GetBattery(ErrorResult& aRv)
+{
+  if (mBatteryPromise) {
+    return mBatteryPromise;
+  }
+
+  if (!mWindow || !mWindow->GetDocShell()) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+
+  nsCOMPtr go = do_QueryInterface(mWindow);
+  nsRefPtr batteryPromise = Promise::Create(go, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+  mBatteryPromise = batteryPromise;
+
+  if (!mBatteryManager) {
+    mBatteryManager = new battery::BatteryManager(mWindow);
+    mBatteryManager->Init();
+  }
+
+  mBatteryPromise->MaybeResolve(mBatteryManager);
+
+  return mBatteryPromise;
+}
+
+battery::BatteryManager*
+Navigator::GetDeprecatedBattery(ErrorResult& aRv)
 {
   if (!mBatteryManager) {
     if (!mWindow) {
diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h
index b32c40d97d5d..cd1114a1a832 100644
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -160,7 +160,8 @@ class Navigator final : public nsIDOMNavigator
   Permissions* GetPermissions(ErrorResult& aRv);
   // The XPCOM GetDoNotTrack is ok
   Geolocation* GetGeolocation(ErrorResult& aRv);
-  battery::BatteryManager* GetBattery(ErrorResult& aRv);
+  Promise* GetBattery(ErrorResult& aRv);
+  battery::BatteryManager* GetDeprecatedBattery(ErrorResult& aRv);
 
   static already_AddRefed GetDataStores(nsPIDOMWindow* aWindow,
                                                  const nsAString& aName,
@@ -371,6 +372,7 @@ class Navigator final : public nsIDOMNavigator
   nsRefPtr mGeolocation;
   nsRefPtr mNotification;
   nsRefPtr mBatteryManager;
+  nsRefPtr mBatteryPromise;
 #ifdef MOZ_B2G_FM
   nsRefPtr mFMRadio;
 #endif
diff --git a/dom/battery/BatteryManager.cpp b/dom/battery/BatteryManager.cpp
index bc9928c23207..f72736f16476 100644
--- a/dom/battery/BatteryManager.cpp
+++ b/dom/battery/BatteryManager.cpp
@@ -10,6 +10,7 @@
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/Hal.h"
 #include "mozilla/dom/BatteryManagerBinding.h"
+#include "mozilla/Preferences.h"
 #include "nsIDOMClassInfo.h"
 
 /**
@@ -56,10 +57,37 @@ BatteryManager::WrapObject(JSContext* aCx, JS::Handle aGivenProto)
   return BatteryManagerBinding::Wrap(aCx, this, aGivenProto);
 }
 
+bool
+BatteryManager::Charging() const
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  // For testing, unable to report the battery status information
+  if (Preferences::GetBool("dom.battery.test.default", false)) {
+    return true;
+  }
+  if (Preferences::GetBool("dom.battery.test.charging", false)) {
+    return true;
+  }
+  if (Preferences::GetBool("dom.battery.test.discharging", false)) {
+    return false;
+  }
+
+  return mCharging;
+}
+
 double
 BatteryManager::DischargingTime() const
 {
-  if (mCharging || mRemainingTime == kUnknownRemainingTime) {
+  MOZ_ASSERT(NS_IsMainThread());
+  // For testing, unable to report the battery status information
+  if (Preferences::GetBool("dom.battery.test.default", false)) {
+    return std::numeric_limits::infinity();
+  }
+  if (Preferences::GetBool("dom.battery.test.discharging", false)) {
+    return 42.0;
+  }
+
+  if (Charging() || mRemainingTime == kUnknownRemainingTime) {
     return std::numeric_limits::infinity();
   }
 
@@ -69,13 +97,34 @@ BatteryManager::DischargingTime() const
 double
 BatteryManager::ChargingTime() const
 {
-  if (!mCharging || mRemainingTime == kUnknownRemainingTime) {
+  MOZ_ASSERT(NS_IsMainThread());
+  // For testing, unable to report the battery status information
+  if (Preferences::GetBool("dom.battery.test.default", false)) {
+    return 0.0;
+  }
+  if (Preferences::GetBool("dom.battery.test.charging", false)) {
+    return 42.0;
+  }
+
+  if (!Charging() || mRemainingTime == kUnknownRemainingTime) {
     return std::numeric_limits::infinity();
   }
 
   return mRemainingTime;
 }
 
+double
+BatteryManager::Level() const
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  // For testing, unable to report the battery status information
+  if (Preferences::GetBool("dom.battery.test.default")) {
+    return 1.0;
+  }
+
+  return mLevel;
+}
+
 void
 BatteryManager::UpdateFromBatteryInfo(const hal::BatteryInformation& aBatteryInfo)
 {
diff --git a/dom/battery/BatteryManager.h b/dom/battery/BatteryManager.h
index 0ef526ce0a70..2660d642da04 100644
--- a/dom/battery/BatteryManager.h
+++ b/dom/battery/BatteryManager.h
@@ -46,19 +46,13 @@ class BatteryManager : public DOMEventTargetHelper
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override;
 
-  bool Charging() const
-  {
-    return mCharging;
-  }
+  bool Charging() const;
 
   double ChargingTime() const;
 
   double DischargingTime() const;
 
-  double Level() const
-  {
-    return mLevel;
-  }
+  double Level() const;
 
   IMPL_EVENT_HANDLER(chargingchange)
   IMPL_EVENT_HANDLER(chargingtimechange)
diff --git a/dom/battery/test/marionette/manifest.ini b/dom/battery/test/marionette/manifest.ini
index b74ec64e768d..87ce1a3a5577 100644
--- a/dom/battery/test/marionette/manifest.ini
+++ b/dom/battery/test/marionette/manifest.ini
@@ -9,3 +9,9 @@ qemu = true
 [test_battery_status_full.js]
 [test_battery_status_not_charging.js]
 [test_battery_status_unknown.js]
+[test_deprecated_battery_level.js]
+[test_deprecated_battery_status_charging.js]
+[test_deprecated_battery_status_discharging.js]
+[test_deprecated_battery_status_full.js]
+[test_deprecated_battery_status_not_charging.js]
+[test_deprecated_battery_status_unknown.js]
diff --git a/dom/battery/test/marionette/test_battery_level.js b/dom/battery/test/marionette/test_battery_level.js
index b344a26e6171..74b1ec70a74c 100644
--- a/dom/battery/test/marionette/test_battery_level.js
+++ b/dom/battery/test/marionette/test_battery_level.js
@@ -3,15 +3,18 @@
 
 MARIONETTE_TIMEOUT = 10000;
 
-let battery = window.navigator.battery;
+let battery = null;
 
 function verifyInitialState() {
-  ok(battery, "battery");
-  is(battery.level, 0.5, "battery.level");
-  runEmulatorCmd("power display", function (result) {
-    is(result.pop(), "OK", "power display successful");
-    ok(result.indexOf("capacity: 50") !== -1, "power capacity");
-    setUp();
+  window.navigator.getBattery().then(function (b) {
+    battery = b;
+    ok(battery, "battery");
+    is(battery.level, 0.5, "battery.level");
+    runEmulatorCmd("power display", function (result) {
+      is(result.pop(), "OK", "power display successful");
+      ok(result.indexOf("capacity: 50") !== -1, "power capacity");
+      setUp();
+    });
   });
 }
 
@@ -29,10 +32,10 @@ function changeCapacity(capacity, changeExpected, nextFunction) {
   log("Changing power capacity to " + capacity);
   if (changeExpected) {
     battery.onlevelchange = function (event) {
-     battery.onlevelchange = unexpectedEvent;
-     is(event.type, "levelchange", "event.type");
-     is(battery.level, capacity / 100, "battery.level");
-     nextFunction();
+      battery.onlevelchange = unexpectedEvent;
+      is(event.type, "levelchange", "event.type");
+      is(battery.level, capacity / 100, "battery.level");
+      nextFunction();
     };
     runEmulatorCmd("power capacity " + capacity);
   }
diff --git a/dom/battery/test/marionette/test_battery_status_charging.js b/dom/battery/test/marionette/test_battery_status_charging.js
index 2d7469d9f340..714f73d10ec6 100644
--- a/dom/battery/test/marionette/test_battery_status_charging.js
+++ b/dom/battery/test/marionette/test_battery_status_charging.js
@@ -3,17 +3,20 @@
 
 MARIONETTE_TIMEOUT = 10000;
 
-let battery = window.navigator.battery;
+let battery = null;
 let fromStatus = "charging";
 let fromCharging = true;
 
 function verifyInitialState() {
-  ok(battery, "battery");
-  ok(battery.charging, "battery.charging");
-  runEmulatorCmd("power display", function (result) {
-    is(result.pop(), "OK", "power display successful");
-    ok(result.indexOf("status: Charging") !== -1, "power status charging");
-    setUp();
+  window.navigator.getBattery().then(function (b) {
+    battery = b;
+    ok(battery, "battery");
+    ok(battery.charging, "battery.charging");
+    runEmulatorCmd("power display", function (result) {
+      is(result.pop(), "OK", "power display successful");
+      ok(result.indexOf("status: Charging") !== -1, "power status charging");
+      setUp();
+    });
   });
 }
 
diff --git a/dom/battery/test/marionette/test_battery_status_discharging.js b/dom/battery/test/marionette/test_battery_status_discharging.js
index b6a45f2b8467..972c034927c9 100644
--- a/dom/battery/test/marionette/test_battery_status_discharging.js
+++ b/dom/battery/test/marionette/test_battery_status_discharging.js
@@ -3,17 +3,20 @@
 
 MARIONETTE_TIMEOUT = 10000;
 
-let battery = window.navigator.battery;
+let battery = null;
 let fromStatus = "discharging";
 let fromCharging = false;
 
 function verifyInitialState() {
-  ok(battery, "battery");
-  ok(battery.charging, "battery.charging");
-  runEmulatorCmd("power display", function (result) {
-    is(result.pop(), "OK", "power display successful");
-    ok(result.indexOf("status: Charging") !== -1, "power status charging");
-    setUp();
+  window.navigator.getBattery().then(function (b) {
+    battery = b;
+    ok(battery, "battery");
+    ok(battery.charging, "battery.charging");
+    runEmulatorCmd("power display", function (result) {
+      is(result.pop(), "OK", "power display successful");
+      ok(result.indexOf("status: Charging") !== -1, "power status charging");
+      setUp();
+    });
   });
 }
 
diff --git a/dom/battery/test/marionette/test_battery_status_full.js b/dom/battery/test/marionette/test_battery_status_full.js
index 80d0fa1129f5..a636a6eaca9a 100644
--- a/dom/battery/test/marionette/test_battery_status_full.js
+++ b/dom/battery/test/marionette/test_battery_status_full.js
@@ -8,12 +8,15 @@ let fromStatus = "full";
 let fromCharging = true;
 
 function verifyInitialState() {
-  ok(battery, "battery");
-  ok(battery.charging, "battery.charging");
-  runEmulatorCmd("power display", function (result) {
-    is(result.pop(), "OK", "power display successful");
-    ok(result.indexOf("status: Charging") !== -1, "power status charging");
-    setUp();
+  window.navigator.getBattery().then(function (b) {
+    battery = b;
+    ok(battery, "battery");
+    ok(battery.charging, "battery.charging");
+    runEmulatorCmd("power display", function (result) {
+      is(result.pop(), "OK", "power display successful");
+      ok(result.indexOf("status: Charging") !== -1, "power status charging");
+      setUp();
+    });
   });
 }
 
diff --git a/dom/battery/test/marionette/test_battery_status_not_charging.js b/dom/battery/test/marionette/test_battery_status_not_charging.js
index 113017f76e41..9b7b38eeb72c 100644
--- a/dom/battery/test/marionette/test_battery_status_not_charging.js
+++ b/dom/battery/test/marionette/test_battery_status_not_charging.js
@@ -8,12 +8,15 @@ let fromStatus = "not-charging";
 let fromCharging = false;
 
 function verifyInitialState() {
-  ok(battery, "battery");
-  ok(battery.charging, "battery.charging");
-  runEmulatorCmd("power display", function (result) {
-    is(result.pop(), "OK", "power display successful");
-    ok(result.indexOf("status: Charging") !== -1, "power status charging");
-    setUp();
+  window.navigator.getBattery().then(function (b) {
+    battery = b;
+    ok(battery, "battery");
+    ok(battery.charging, "battery.charging");
+    runEmulatorCmd("power display", function (result) {
+      is(result.pop(), "OK", "power display successful");
+      ok(result.indexOf("status: Charging") !== -1, "power status charging");
+      setUp();
+    });
   });
 }
 
diff --git a/dom/battery/test/marionette/test_battery_status_unknown.js b/dom/battery/test/marionette/test_battery_status_unknown.js
index 42a315a04cb1..a86581e38176 100644
--- a/dom/battery/test/marionette/test_battery_status_unknown.js
+++ b/dom/battery/test/marionette/test_battery_status_unknown.js
@@ -8,12 +8,15 @@ let fromStatus = "unknown";
 let fromCharging = false;
 
 function verifyInitialState() {
-  ok(battery, "battery");
-  ok(battery.charging, "battery.charging");
-  runEmulatorCmd("power display", function (result) {
-    is(result.pop(), "OK", "power display successful");
-    ok(result.indexOf("status: Charging") !== -1, "power status charging");
-    setUp();
+  window.navigator.getBattery().then(function (b) {
+    battery = b;
+    ok(battery, "battery");
+    ok(battery.charging, "battery.charging");
+    runEmulatorCmd("power display", function (result) {
+      is(result.pop(), "OK", "power display successful");
+      ok(result.indexOf("status: Charging") !== -1, "power status charging");
+      setUp();
+    });
   });
 }
 
diff --git a/dom/battery/test/marionette/test_deprecated_battery_level.js b/dom/battery/test/marionette/test_deprecated_battery_level.js
new file mode 100644
index 000000000000..b344a26e6171
--- /dev/null
+++ b/dom/battery/test/marionette/test_deprecated_battery_level.js
@@ -0,0 +1,68 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+let battery = window.navigator.battery;
+
+function verifyInitialState() {
+  ok(battery, "battery");
+  is(battery.level, 0.5, "battery.level");
+  runEmulatorCmd("power display", function (result) {
+    is(result.pop(), "OK", "power display successful");
+    ok(result.indexOf("capacity: 50") !== -1, "power capacity");
+    setUp();
+  });
+}
+
+function unexpectedEvent(event) {
+  ok(false, "Unexpected " + event.type + " event");
+}
+
+function setUp() {
+  battery.onchargingchange = unexpectedEvent;
+  battery.onlevelchange = unexpectedEvent;
+  levelUp();
+}
+
+function changeCapacity(capacity, changeExpected, nextFunction) {
+  log("Changing power capacity to " + capacity);
+  if (changeExpected) {
+    battery.onlevelchange = function (event) {
+     battery.onlevelchange = unexpectedEvent;
+     is(event.type, "levelchange", "event.type");
+     is(battery.level, capacity / 100, "battery.level");
+     nextFunction();
+    };
+    runEmulatorCmd("power capacity " + capacity);
+  }
+  else {
+    runEmulatorCmd("power capacity " + capacity, function () {
+      is(battery.level, capacity / 100, "battery.level");
+      nextFunction();
+    });
+  }
+}
+
+function levelUp() {
+  changeCapacity("90", true, levelDown);
+}
+
+function levelDown() {
+  changeCapacity("10", true, levelSame);
+}
+
+function levelSame() {
+  changeCapacity("10", false, cleanUp);
+}
+
+function cleanUp() {
+  battery.onchargingchange = null;
+  battery.onlevelchange = function () {
+    battery.onlevelchange = null;
+    finish();
+  };
+  runEmulatorCmd("power capacity 50");
+}
+
+verifyInitialState();
diff --git a/dom/battery/test/marionette/test_deprecated_battery_status_charging.js b/dom/battery/test/marionette/test_deprecated_battery_status_charging.js
new file mode 100644
index 000000000000..2d7469d9f340
--- /dev/null
+++ b/dom/battery/test/marionette/test_deprecated_battery_status_charging.js
@@ -0,0 +1,85 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+let battery = window.navigator.battery;
+let fromStatus = "charging";
+let fromCharging = true;
+
+function verifyInitialState() {
+  ok(battery, "battery");
+  ok(battery.charging, "battery.charging");
+  runEmulatorCmd("power display", function (result) {
+    is(result.pop(), "OK", "power display successful");
+    ok(result.indexOf("status: Charging") !== -1, "power status charging");
+    setUp();
+  });
+}
+
+function unexpectedEvent(event) {
+  ok(false, "Unexpected " + event.type + " event");
+}
+
+function setUp() {
+  battery.onchargingchange = unexpectedEvent;
+  battery.onlevelchange = unexpectedEvent;
+  toDischarging();
+}
+
+function resetStatus(charging, nextFunction) {
+  log("Resetting power status to " + fromStatus);
+  if (charging !== fromCharging) {
+    battery.onchargingchange = function () {
+      battery.onchargingchange = unexpectedEvent;
+      nextFunction();
+    };
+    runEmulatorCmd("power status " + fromStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + fromStatus, nextFunction);
+  }
+}
+
+function changeStatus(toStatus, toCharging, nextFunction) {
+  log("Changing power status to " + toStatus);
+  if (fromCharging !== toCharging) {
+    battery.onchargingchange = function (event) {
+      battery.onchargingchange = unexpectedEvent;
+      is(event.type, "chargingchange", "event type");
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    };
+    runEmulatorCmd("power status " + toStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + toStatus, function () {
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    });
+  }
+}
+
+function toDischarging() {
+  changeStatus("discharging", false, toFull);
+}
+
+function toFull() {
+  changeStatus("full", true, toNotCharging);
+}
+
+function toNotCharging() {
+  changeStatus("not-charging", false, toUnknown);
+}
+
+function toUnknown() {
+  changeStatus("unknown", false, cleanUp);
+}
+
+function cleanUp() {
+  battery.onchargingchange = null;
+  battery.onlevelchange = null;
+  finish();
+}
+
+verifyInitialState();
diff --git a/dom/battery/test/marionette/test_deprecated_battery_status_discharging.js b/dom/battery/test/marionette/test_deprecated_battery_status_discharging.js
new file mode 100644
index 000000000000..b6a45f2b8467
--- /dev/null
+++ b/dom/battery/test/marionette/test_deprecated_battery_status_discharging.js
@@ -0,0 +1,93 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+let battery = window.navigator.battery;
+let fromStatus = "discharging";
+let fromCharging = false;
+
+function verifyInitialState() {
+  ok(battery, "battery");
+  ok(battery.charging, "battery.charging");
+  runEmulatorCmd("power display", function (result) {
+    is(result.pop(), "OK", "power display successful");
+    ok(result.indexOf("status: Charging") !== -1, "power status charging");
+    setUp();
+  });
+}
+
+function unexpectedEvent(event) {
+  ok(false, "Unexpected " + event.type + " event");
+}
+
+function setUp() {
+  battery.onchargingchange = function () {
+    battery.onchargingchange = unexpectedEvent;
+    toCharging();
+  };
+  battery.onlevelchange = unexpectedEvent;
+  log("Changing power status to " + fromStatus);
+  runEmulatorCmd("power status " + fromStatus);
+}
+
+function resetStatus(charging, nextFunction) {
+  log("Resetting power status to " + fromStatus);
+  if (charging !== fromCharging) {
+    battery.onchargingchange = function () {
+      battery.onchargingchange = unexpectedEvent;
+      nextFunction();
+    };
+    runEmulatorCmd("power status " + fromStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + fromStatus, nextFunction);
+  }
+}
+
+function changeStatus(toStatus, toCharging, nextFunction) {
+  log("Changing power status to " + toStatus);
+  if (fromCharging !== toCharging) {
+    battery.onchargingchange = function (event) {
+      battery.onchargingchange = unexpectedEvent;
+      is(event.type, "chargingchange", "event type");
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    };
+    runEmulatorCmd("power status " + toStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + toStatus, function () {
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    });
+  }
+}
+
+function toCharging() {
+  changeStatus("charging", true, toFull);
+}
+
+function toFull() {
+  changeStatus("full", true, toNotCharging);
+}
+
+function toNotCharging() {
+  changeStatus("not-charging", false, toUnknown);
+}
+
+function toUnknown() {
+  changeStatus("unknown", false, cleanUp);
+}
+
+function cleanUp() {
+  battery.onchargingchange = function () {
+    battery.onchargingchange = null;
+    finish();
+  };
+  battery.onlevelchange = null;
+  log("Resetting power status to charging");
+  runEmulatorCmd("power status charging");
+}
+
+verifyInitialState();
diff --git a/dom/battery/test/marionette/test_deprecated_battery_status_full.js b/dom/battery/test/marionette/test_deprecated_battery_status_full.js
new file mode 100644
index 000000000000..80d0fa1129f5
--- /dev/null
+++ b/dom/battery/test/marionette/test_deprecated_battery_status_full.js
@@ -0,0 +1,87 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+let battery = window.navigator.battery;
+let fromStatus = "full";
+let fromCharging = true;
+
+function verifyInitialState() {
+  ok(battery, "battery");
+  ok(battery.charging, "battery.charging");
+  runEmulatorCmd("power display", function (result) {
+    is(result.pop(), "OK", "power display successful");
+    ok(result.indexOf("status: Charging") !== -1, "power status charging");
+    setUp();
+  });
+}
+
+function unexpectedEvent(event) {
+  ok(false, "Unexpected " + event.type + " event");
+}
+
+function setUp() {
+  battery.onchargingchange = unexpectedEvent;
+  battery.onlevelchange = unexpectedEvent;
+  log("Changing power status to " + fromStatus);
+  runEmulatorCmd("power status " + fromStatus, toCharging);
+}
+
+function resetStatus(charging, nextFunction) {
+  log("Resetting power status to " + fromStatus);
+  if (charging !== fromCharging) {
+    battery.onchargingchange = function () {
+      battery.onchargingchange = unexpectedEvent;
+      nextFunction();
+    };
+    runEmulatorCmd("power status " + fromStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + fromStatus, nextFunction);
+  }
+}
+
+function changeStatus(toStatus, toCharging, nextFunction) {
+  log("Changing power status to " + toStatus);
+  if (fromCharging !== toCharging) {
+    battery.onchargingchange = function (event) {
+      battery.onchargingchange = unexpectedEvent;
+      is(event.type, "chargingchange", "event type");
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    };
+    runEmulatorCmd("power status " + toStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + toStatus, function () {
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    });
+  }
+}
+
+function toCharging() {
+  changeStatus("charging", true, toDischarging);
+}
+
+function toDischarging() {
+  changeStatus("discharging", false, toNotCharging);
+}
+
+function toNotCharging() {
+  changeStatus("not-charging", false, toUnknown);
+}
+
+function toUnknown() {
+  changeStatus("unknown", false, cleanUp);
+}
+
+function cleanUp() {
+  battery.onchargingchange = null;
+  battery.onlevelchange = null;
+  log("Resetting power status to charging");
+  runEmulatorCmd("power status charging", finish);
+}
+
+verifyInitialState();
diff --git a/dom/battery/test/marionette/test_deprecated_battery_status_not_charging.js b/dom/battery/test/marionette/test_deprecated_battery_status_not_charging.js
new file mode 100644
index 000000000000..113017f76e41
--- /dev/null
+++ b/dom/battery/test/marionette/test_deprecated_battery_status_not_charging.js
@@ -0,0 +1,93 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+let battery = window.navigator.battery;
+let fromStatus = "not-charging";
+let fromCharging = false;
+
+function verifyInitialState() {
+  ok(battery, "battery");
+  ok(battery.charging, "battery.charging");
+  runEmulatorCmd("power display", function (result) {
+    is(result.pop(), "OK", "power display successful");
+    ok(result.indexOf("status: Charging") !== -1, "power status charging");
+    setUp();
+  });
+}
+
+function unexpectedEvent(event) {
+  ok(false, "Unexpected " + event.type + " event");
+}
+
+function setUp() {
+  battery.onchargingchange = function () {
+    battery.onchargingchange = unexpectedEvent;
+    toCharging();
+  };
+  battery.onlevelchange = unexpectedEvent;
+  log("Changing power status to " + fromStatus);
+  runEmulatorCmd("power status " + fromStatus);
+}
+
+function resetStatus(charging, nextFunction) {
+  log("Resetting power status to " + fromStatus);
+  if (charging !== fromCharging) {
+    battery.onchargingchange = function () {
+      battery.onchargingchange = unexpectedEvent;
+      nextFunction();
+    };
+    runEmulatorCmd("power status " + fromStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + fromStatus, nextFunction);
+  }
+}
+
+function changeStatus(toStatus, toCharging, nextFunction) {
+  log("Changing power status to " + toStatus);
+  if (fromCharging !== toCharging) {
+    battery.onchargingchange = function (event) {
+      battery.onchargingchange = unexpectedEvent;
+      is(event.type, "chargingchange", "event type");
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    };
+    runEmulatorCmd("power status " + toStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + toStatus, function () {
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    });
+  }
+}
+
+function toCharging() {
+  changeStatus("charging", true, toDischarging);
+}
+
+function toDischarging() {
+  changeStatus("discharging", false, toFull);
+}
+
+function toFull() {
+  changeStatus("full", true, toUnknown);
+}
+
+function toUnknown() {
+  changeStatus("unknown", false, cleanUp);
+}
+
+function cleanUp() {
+  battery.onchargingchange = function () {
+    battery.onchargingchange = null;
+    finish();
+  };
+  battery.onlevelchange = null;
+  log("Resetting power status to charging");
+  runEmulatorCmd("power status charging");
+}
+
+verifyInitialState();
diff --git a/dom/battery/test/marionette/test_deprecated_battery_unknown.js b/dom/battery/test/marionette/test_deprecated_battery_unknown.js
new file mode 100644
index 000000000000..42a315a04cb1
--- /dev/null
+++ b/dom/battery/test/marionette/test_deprecated_battery_unknown.js
@@ -0,0 +1,93 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+let battery = window.navigator.battery;
+let fromStatus = "unknown";
+let fromCharging = false;
+
+function verifyInitialState() {
+  ok(battery, "battery");
+  ok(battery.charging, "battery.charging");
+  runEmulatorCmd("power display", function (result) {
+    is(result.pop(), "OK", "power display successful");
+    ok(result.indexOf("status: Charging") !== -1, "power status charging");
+    setUp();
+  });
+}
+
+function unexpectedEvent(event) {
+  ok(false, "Unexpected " + event.type + " event");
+}
+
+function setUp() {
+  battery.onchargingchange = function () {
+    battery.onchargingchange = unexpectedEvent;
+    toCharging();
+  };
+  battery.onlevelchange = unexpectedEvent;
+  log("Changing power status to " + fromStatus);
+  runEmulatorCmd("power status " + fromStatus);
+}
+
+function resetStatus(charging, nextFunction) {
+  log("Resetting power status to " + fromStatus);
+  if (charging !== fromCharging) {
+    battery.onchargingchange = function () {
+      battery.onchargingchange = unexpectedEvent;
+      nextFunction();
+    };
+    runEmulatorCmd("power status " + fromStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + fromStatus, nextFunction);
+  }
+}
+
+function changeStatus(toStatus, toCharging, nextFunction) {
+  log("Changing power status to " + toStatus);
+  if (fromCharging !== toCharging) {
+    battery.onchargingchange = function (event) {
+      battery.onchargingchange = unexpectedEvent;
+      is(event.type, "chargingchange", "event type");
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    };
+    runEmulatorCmd("power status " + toStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + toStatus, function () {
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    });
+  }
+}
+
+function toCharging() {
+  changeStatus("charging", true, toDischarging);
+}
+
+function toDischarging() {
+  changeStatus("discharging", false, toFull);
+}
+
+function toFull() {
+  changeStatus("full", true, toNotCharging);
+}
+
+function toNotCharging() {
+  changeStatus("not-charging", false, cleanUp);
+}
+
+function cleanUp() {
+  battery.onchargingchange = function () {
+    battery.onchargingchange = null;
+    finish();
+  };
+  battery.onlevelchange = null;
+  log("Resetting power status to charging");
+  runEmulatorCmd("power status charging");
+}
+
+verifyInitialState();
diff --git a/dom/battery/test/mochitest.ini b/dom/battery/test/mochitest.ini
index 242a02a8677f..92334129fa7c 100644
--- a/dom/battery/test/mochitest.ini
+++ b/dom/battery/test/mochitest.ini
@@ -1,2 +1,8 @@
 [test_battery_basics.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
+[test_battery_charging.html]
+skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
+[test_battery_discharging.html]
+skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
+[test_deprecated_battery_basics.html]
+skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
diff --git a/dom/battery/test/test_battery_basics.html b/dom/battery/test/test_battery_basics.html
index 14b334481e6a..825d2affeb93 100644
--- a/dom/battery/test/test_battery_basics.html
+++ b/dom/battery/test/test_battery_basics.html
@@ -12,20 +12,23 @@
 
 
 
diff --git a/dom/battery/test/test_battery_charging.html b/dom/battery/test/test_battery_charging.html new file mode 100644 index 000000000000..f95d4252c623 --- /dev/null +++ b/dom/battery/test/test_battery_charging.html @@ -0,0 +1,33 @@ + + + + Test for Battery API + + + + +

+ +
+
+
+ + diff --git a/dom/battery/test/test_battery_discharging.html b/dom/battery/test/test_battery_discharging.html new file mode 100644 index 000000000000..cff4ced67ae5 --- /dev/null +++ b/dom/battery/test/test_battery_discharging.html @@ -0,0 +1,33 @@ + + + + Test for Battery API + + + + +

+ +
+
+
+ + diff --git a/dom/battery/test/test_deprecated_battery_basics.html b/dom/battery/test/test_deprecated_battery_basics.html new file mode 100644 index 000000000000..a75267c7d43b --- /dev/null +++ b/dom/battery/test/test_deprecated_battery_basics.html @@ -0,0 +1,32 @@ + + + + Test for Battery API + + + + +

+ +
+
+
+ + diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl index e3177895afc5..d581e9f8971f 100644 --- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -125,14 +125,15 @@ interface NavigatorGeolocation { Navigator implements NavigatorGeolocation; // http://www.w3.org/TR/battery-status/#navigatorbattery-interface -[NoInterfaceObject] -interface NavigatorBattery { - // XXXbz Per spec this should be non-nullable, but we return null in - // torn-down windows. See bug 884925. - [Throws, Pref="dom.battery.enabled"] - readonly attribute BatteryManager? battery; +partial interface Navigator { + [Throws, Pref="dom.battery.enabled"] + Promise getBattery(); + // Deprecated. Use getBattery() instead. + // XXXbz Per spec this should be non-nullable, but we return null in + // torn-down windows. See bug 884925. + [Throws, Pref="dom.battery.enabled", BinaryName="deprecatedBattery"] + readonly attribute BatteryManager? battery; }; -Navigator implements NavigatorBattery; // https://wiki.mozilla.org/WebAPI/DataStore [NoInterfaceObject, diff --git a/toolkit/modules/Battery.jsm b/toolkit/modules/Battery.jsm index 486a4f70d670..2b0f9abcb72e 100644 --- a/toolkit/modules/Battery.jsm +++ b/toolkit/modules/Battery.jsm @@ -5,12 +5,12 @@ "use strict"; -/** This module wraps around navigator.battery (https://developer.mozilla.org/en-US/docs/Web/API/Navigator.battery). +/** This module wraps around navigator.getBattery (https://developer.mozilla.org/en-US/docs/Web/API/Navigator.getBattery). * and provides a framework for spoofing battery values in test code. * To spoof the battery values, set `Debugging.fake = true` after exporting this with a BackstagePass, - * after which you can spoof a property yb setting the relevant property of the Battery object. + * after which you can spoof a property yb setting the relevant property of the BatteryManager object. */ -this.EXPORTED_SYMBOLS = ["Battery"]; +this.EXPORTED_SYMBOLS = ["GetBattery", "Battery"]; const Ci = Components.interfaces; const Cc = Components.classes; @@ -40,6 +40,17 @@ this.Debugging = { fake: false } +this.GetBattery = function () { + return new Services.appShell.hiddenDOMWindow.Promise(function (resolve, reject) { + // Return fake values if spoofing is enabled, otherwise fetch the real values from the BatteryManager API + if (Debugging.fake) { + resolve(gFakeBattery); + return; + } + Services.appShell.hiddenDOMWindow.navigator.getBattery().then(resolve, reject); + }); +}; + this.Battery = {}; for (let k of ["charging", "chargingTime", "dischargingTime", "level"]) { @@ -54,9 +65,9 @@ for (let k of ["charging", "chargingTime", "dischargingTime", "level"]) { }, set: function(fakeSetting) { if (!Debugging.fake) { - throw new Error("Tried to set fake battery value when battery spoofing was disabled"); + throw new Error("Tried to set fake battery value when battery spoofing was disabled"); } gFakeBattery[prop] = fakeSetting; } }) -} \ No newline at end of file +} diff --git a/toolkit/modules/tests/browser/browser_Battery.js b/toolkit/modules/tests/browser/browser_Battery.js index d9aa0883655e..9a4c4f8fbae1 100644 --- a/toolkit/modules/tests/browser/browser_Battery.js +++ b/toolkit/modules/tests/browser/browser_Battery.js @@ -6,8 +6,11 @@ let imported = Components.utils.import("resource://gre/modules/Battery.jsm", thi Cu.import("resource://gre/modules/Services.jsm", this); function test() { + waitForExplicitFinish(); + is(imported.Debugging.fake, false, "Battery spoofing is initially false") + // begin deprecated battery API testing for (let k of ["charging", "chargingTime", "dischargingTime", "level"]) { Assert.throws(() => Battery[k] = 10, "Setting battery " + k + "preference without spoofing enabled should throw"); ok(Battery[k] == Services.appShell.hiddenDOMWindow.navigator.battery[k], "Battery "+ k + " is correctly set"); @@ -27,4 +30,36 @@ function test() { ok(!Battery.charging, "Test for charging setter"); is(Battery.dischargingTime, 50, "Test for dischargingTime setter"); is(Battery.level, 0.7, "Test for level setter"); -} \ No newline at end of file + + imported.Debugging.fake = false; + // end deprecated battery API testing + + GetBattery().then(function (battery) { + for (let k of ["charging", "chargingTime", "dischargingTime", "level"]) { + let backup = battery[k]; + battery[k] = "__magic__"; + is(battery[k], backup, "Setting battery " + k + "preference without spoofing enabled should fail"); + } + + imported.Debugging.fake = true; + + // reload again to get the fake one + GetBattery().then(function (battery) { + battery.charging = true; + battery.chargingTime = 100; + battery.level = 0.5; + ok(battery.charging, "Test for charging setter"); + is(battery.chargingTime, 100, "Test for chargingTime setter"); + is(battery.level, 0.5, "Test for level setter"); + + battery.charging = false; + battery.dischargingTime = 50; + battery.level = 0.7; + ok(!battery.charging, "Test for charging setter"); + is(battery.dischargingTime, 50, "Test for dischargingTime setter"); + is(battery.level, 0.7, "Test for level setter"); + + finish(); + }); + }); +} From 29e369c3f1c25383eabe049dc2db372738bbbc86 Mon Sep 17 00:00:00 2001 From: Antonio de Luna Lopez Date: Mon, 10 Aug 2015 12:06:00 -0700 Subject: [PATCH 039/208] Bug 1134609 -Make Fetch Request constructor less destructive to input on error r=bkelly --- dom/fetch/InternalRequest.h | 2 +- dom/fetch/Request.cpp | 27 ++++++++++++++++------- dom/fetch/Request.h | 3 +++ dom/tests/mochitest/fetch/test_request.js | 12 ++++++++++ 4 files changed, 35 insertions(+), 9 deletions(-) diff --git a/dom/fetch/InternalRequest.h b/dom/fetch/InternalRequest.h index e871d827db10..c50af67c851a 100644 --- a/dom/fetch/InternalRequest.h +++ b/dom/fetch/InternalRequest.h @@ -319,7 +319,7 @@ class InternalRequest final SetBody(nsIInputStream* aStream) { // A request's body may not be reset once set. - MOZ_ASSERT(!mBodyStream); + MOZ_ASSERT_IF(aStream, !mBodyStream); mBodyStream = aStream; } diff --git a/dom/fetch/Request.cpp b/dom/fetch/Request.cpp index 0d64ac747be4..dac0778bf8c3 100644 --- a/dom/fetch/Request.cpp +++ b/dom/fetch/Request.cpp @@ -163,8 +163,8 @@ Request::Constructor(const GlobalObject& aGlobal, const RequestOrUSVString& aInput, const RequestInit& aInit, ErrorResult& aRv) { + nsCOMPtr temporaryBody; nsRefPtr request; - bool inputRequestHasBody = false; nsCOMPtr global = do_QueryInterface(aGlobal.GetAsSupports()); @@ -173,13 +173,11 @@ Request::Constructor(const GlobalObject& aGlobal, nsCOMPtr body; inputReq->GetBody(getter_AddRefs(body)); if (body) { - inputRequestHasBody = true; if (inputReq->BodyUsed()) { aRv.ThrowTypeError(MSG_FETCH_BODY_CONSUMED_ERROR); return nullptr; - } else { - inputReq->SetBodyUsed(); } + temporaryBody = body; } request = inputReq->GetInternalRequest(); @@ -327,7 +325,7 @@ Request::Constructor(const GlobalObject& aGlobal, return nullptr; } - if (aInit.mBody.WasPassed() || inputRequestHasBody) { + if (aInit.mBody.WasPassed() || temporaryBody) { // HEAD and GET are not allowed to have a body. nsAutoCString method; request->GetMethod(method); @@ -347,8 +345,8 @@ Request::Constructor(const GlobalObject& aGlobal, if (NS_WARN_IF(aRv.Failed())) { return nullptr; } - request->ClearCreatedByFetchEvent(); - request->SetBody(stream); + + temporaryBody = stream; if (!contentType.IsVoid() && !requestHeaders->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) { @@ -356,13 +354,26 @@ Request::Constructor(const GlobalObject& aGlobal, contentType, aRv); } - if (aRv.Failed()) { + if (NS_WARN_IF(aRv.Failed())) { return nullptr; } + + request->ClearCreatedByFetchEvent(); + request->SetBody(temporaryBody); } nsRefPtr domRequest = new Request(global, request); domRequest->SetMimeType(); + + if (aInput.IsRequest()) { + nsRefPtr inputReq = &aInput.GetAsRequest(); + nsCOMPtr body; + inputReq->GetBody(getter_AddRefs(body)); + if (body) { + inputReq->SetBody(nullptr); + inputReq->SetBodyUsed(); + } + } return domRequest.forget(); } diff --git a/dom/fetch/Request.h b/dom/fetch/Request.h index 98bf3c303d93..da926545e064 100644 --- a/dom/fetch/Request.h +++ b/dom/fetch/Request.h @@ -105,6 +105,9 @@ class Request final : public nsISupports void GetBody(nsIInputStream** aStream) { return mRequest->GetBody(aStream); } + void + SetBody(nsIInputStream* aStream) { return mRequest->SetBody(aStream); } + static already_AddRefed Constructor(const GlobalObject& aGlobal, const RequestOrUSVString& aInput, const RequestInit& aInit, ErrorResult& rv); diff --git a/dom/tests/mochitest/fetch/test_request.js b/dom/tests/mochitest/fetch/test_request.js index 3c74a0c4bb9a..c2b3fffcc3c5 100644 --- a/dom/tests/mochitest/fetch/test_request.js +++ b/dom/tests/mochitest/fetch/test_request.js @@ -456,6 +456,17 @@ function testBug1154268() { }); } +function testRequestConsumedByFailedConstructor(){ + var r1 = new Request('http://example.com', { method: 'POST', body: 'hello world' }); + try{ + var r2 = new Request(r1, { method: 'GET' }); + ok(false, 'GET Request copied from POST Request with body should fail.'); + } catch(e) { + ok(true, 'GET Request copied from POST Request with body should fail.'); + } + ok(!r1.bodyUsed, 'Initial request should not be consumed by failed Request constructor'); +} + function runTest() { testDefaultCtor(); testSimpleUrlParse(); @@ -465,6 +476,7 @@ function runTest() { testHeaderGuard(); testModeCorsPreflightEnumValue(); testBug1154268(); + testRequestConsumedByFailedConstructor(); return Promise.resolve() .then(testBodyCreation) From a60e26026562ec1e23efb277088c19d020ecafb9 Mon Sep 17 00:00:00 2001 From: Glenn Randers-Pehrson Date: Thu, 20 Aug 2015 14:17:10 -0700 Subject: [PATCH 040/208] Bug 1187569 - PNGs getting stuck in a pixelated state. r=seth --- image/decoders/nsPNGDecoder.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/image/decoders/nsPNGDecoder.cpp b/image/decoders/nsPNGDecoder.cpp index dd75ce503112..038d4f06a689 100644 --- a/image/decoders/nsPNGDecoder.cpp +++ b/image/decoders/nsPNGDecoder.cpp @@ -693,7 +693,7 @@ nsPNGDecoder::row_callback(png_structp png_ptr, png_bytep new_row, return; } - if (row_num >= (png_uint_32) decoder->mFrameRect.height) { + if (row_num >= static_cast(decoder->mFrameRect.height)) { return; } @@ -772,11 +772,14 @@ nsPNGDecoder::row_callback(png_structp png_ptr, png_bytep new_row, png_longjmp(decoder->mPNG, 1); } - if (decoder->mNumFrames <= 1) { - // Only do incremental image display for the first frame - // XXXbholley - this check should be handled in the superclass - nsIntRect r(0, row_num, width, 1); - decoder->PostInvalidation(r); + if (!decoder->interlacebuf) { + // Do line-by-line partial invalidations for non-interlaced images + decoder->PostInvalidation(IntRect(0, row_num, width, 1)); + } else if (row_num == + static_cast(decoder->mFrameRect.height - 1)) { + // Do only one full image invalidation for each pass (Bug 1187569) + decoder->PostInvalidation(IntRect(0, 0, width, + decoder->mFrameRect.height)); } } } From 793d968dd300d6ed7ff78a580f0666b04c24093b Mon Sep 17 00:00:00 2001 From: Aidin Gharibnavaz Date: Thu, 20 Aug 2015 14:18:20 -0700 Subject: [PATCH 041/208] Bug 1190466 - tools/rb/find-leakers.pl re-written in Python r=mccr8 --- tools/rb/find-leakers.pl | 62 ------------------------ tools/rb/find_leakers.py | 100 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 62 deletions(-) delete mode 100755 tools/rb/find-leakers.pl create mode 100755 tools/rb/find_leakers.py diff --git a/tools/rb/find-leakers.pl b/tools/rb/find-leakers.pl deleted file mode 100755 index 69463edd7699..000000000000 --- a/tools/rb/find-leakers.pl +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/perl -w -# -# 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/. - -use strict; - -my %allocs; -my %classes; -my %counter; - -LINE: while (<>) { - next LINE if (! /^ 0x01AFD3B8 1 AddRef 1 - - $allocs{$obj} = ++$counter{$class}; # the order of allocation - $classes{$obj} = $class; - } - elsif ($op eq 'Release' && $cnt == 0) { - # Example: 0x01AFD3B8 1 Release 0 - - delete($allocs{$obj}); - delete($classes{$obj}); - } - elsif ($op eq 'Ctor') { - # Example: 0x08880BD0 8 Ctor (20) - - $allocs{$obj} = ++$counter{$class}; - $classes{$obj} = $class; - } - elsif ($op eq 'Dtor') { - # Example: 0x08880BD0 8 Dtor (20) - - delete($allocs{$obj}); - delete($classes{$obj}); - } -} - - -sub sort_by_value { - my %x = @_; - sub _by_value($) { my %x = @_; $x{$a} cmp $x{$b}; } - sort _by_value keys(%x); -} - - -foreach my $key (&sort_by_value(%allocs)) { - # Example: 0x03F1D818 (2078) @ - print "$key (", $allocs{$key}, ") @ ", $classes{$key}, "\n"; -} diff --git a/tools/rb/find_leakers.py b/tools/rb/find_leakers.py new file mode 100755 index 000000000000..3076be844678 --- /dev/null +++ b/tools/rb/find_leakers.py @@ -0,0 +1,100 @@ +#!/usr/bin/python +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# This script processes a `refcount' log, and finds out if any object leaked. +# It simply goes through the log, finds `AddRef' or `Ctor' lines, and then +# sees if they `Release' or `Dtor'. If not, it reports them as leaks. +# Please see README file in the same directory. + + +import sys + +def print_output(allocation, obj_to_class): + '''Formats and prints output.''' + items = [] + for obj, count, in allocation.iteritems(): + # Adding items to a list, so we can sort them. + items.append((obj, count)) + # Sorting by count. + items.sort(key=lambda item: item[1]) + + for obj, count, in items: + print "{obj} ({count}) @ {class_name}".format(obj=obj, + count=count, + class_name=obj_to_class[obj]) + +def process_log(log_lines): + '''Process through the log lines, and print out the result. + + @param log_lines: List of strings. + ''' + allocation = {} + class_count = {} + obj_to_class = {} + + for log_line in log_lines: + if not log_line.startswith('<'): + continue + + (class_name, + obj, + ignore, + operation, + count,) = log_line.strip('\r\n').split(' ') + + # for AddRef/Release `count' is the refcount, + # for Ctor/Dtor it's the size. + + if ((operation == 'AddRef' and count == '1') or + operation == 'Ctor'): + # Examples: + # 0x01AFD3B8 1 AddRef 1 + # 0x08880BD0 8 Ctor (20) + class_count[class_name] = class_count.setdefault(class_name, 0) + 1 + allocation[obj] = class_count[class_name] + obj_to_class[obj] = class_name + + elif ((operation == 'Release' and count == '0') or + operation == 'Dtor'): + # Examples: + # 0x01AFD3B8 1 Release 0 + # 0x08880BD0 8 Dtor (20) + if obj not in allocation: + print "An object was released that wasn't allocated!", + print obj, "@", class_name + else: + allocation.pop(obj) + obj_to_class.pop(obj) + + # Printing out the result. + print_output(allocation, obj_to_class) + + +def print_usage(): + print + print "Usage: find-leakers.py [log-file]" + print + print "If `log-file' provided, it will read that as the input log." + print "Else, it will read the stdin as the input log." + print + +def main(): + '''Main method of the script.''' + if len(sys.argv) == 1: + # Reading log from stdin. + process_log(sys.stdin.readlines()) + elif len(sys.argv) == 2: + # Reading log from file. + with open(sys.argv[1], 'r') as log_file: + log_lines = log_file.readlines() + process_log(log_lines) + else: + print 'ERROR: Invalid number of arguments' + print_usage() + +if __name__ == '__main__': + main() + From 42a0be4de75f1fbf63698a89d17248a5fa91521e Mon Sep 17 00:00:00 2001 From: Hiroyuki Ikezoe Date: Thu, 20 Aug 2015 14:18:57 -0700 Subject: [PATCH 042/208] Bug 1191178 - Part 0: Fix unified build in dom/base. Add missing headers and sorting them. r=smaug --- dom/base/nsHostObjectProtocolHandler.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/dom/base/nsHostObjectProtocolHandler.cpp b/dom/base/nsHostObjectProtocolHandler.cpp index 5bf823cbb573..85316b5e6966 100644 --- a/dom/base/nsHostObjectProtocolHandler.cpp +++ b/dom/base/nsHostObjectProtocolHandler.cpp @@ -5,17 +5,19 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsHostObjectProtocolHandler.h" -#include "nsHostObjectURI.h" -#include "nsError.h" -#include "nsClassHashtable.h" -#include "nsNetUtil.h" -#include "nsIPrincipal.h" + #include "DOMMediaStream.h" -#include "mozilla/dom/MediaSource.h" -#include "nsIMemoryReporter.h" #include "mozilla/dom/File.h" -#include "mozilla/Preferences.h" +#include "mozilla/dom/MediaSource.h" #include "mozilla/LoadInfo.h" +#include "mozilla/Preferences.h" +#include "nsClassHashtable.h" +#include "nsError.h" +#include "nsHostObjectURI.h" +#include "nsIMemoryReporter.h" +#include "nsIPrincipal.h" +#include "nsIUUIDGenerator.h" +#include "nsNetUtil.h" using mozilla::dom::BlobImpl; using mozilla::ErrorResult; From e6abed8432076f844b1c77e67bda1973550e5cc2 Mon Sep 17 00:00:00 2001 From: Hiroyuki Ikezoe Date: Thu, 20 Aug 2015 14:19:53 -0700 Subject: [PATCH 043/208] Bug 1191178 - Part 0.1: GetSriLog() is needed to avoid unified build failure. r=francois --- dom/base/nsStyleLinkElement.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dom/base/nsStyleLinkElement.cpp b/dom/base/nsStyleLinkElement.cpp index c7a175c021d2..04734cc4ffeb 100644 --- a/dom/base/nsStyleLinkElement.cpp +++ b/dom/base/nsStyleLinkElement.cpp @@ -31,6 +31,16 @@ #include "nsStyleUtil.h" #include "nsQueryObject.h" +static PRLogModuleInfo* +GetSriLog() +{ + static PRLogModuleInfo *gSriPRLog; + if (!gSriPRLog) { + gSriPRLog = PR_NewLogModule("SRI"); + } + return gSriPRLog; +} + using namespace mozilla; using namespace mozilla::dom; From e5ed66b6fcbf4d128bbcf12228551b43ab3fb0ab Mon Sep 17 00:00:00 2001 From: Hiroyuki Ikezoe Date: Thu, 20 Aug 2015 14:20:06 -0700 Subject: [PATCH 044/208] Bug 1191178 - Part 0.2: Include nsBaseHashTable in nsScriptNameSpaceManager.h explicitly to avoid unified build errors. r=njn --- dom/base/nsScriptNameSpaceManager.h | 1 + 1 file changed, 1 insertion(+) diff --git a/dom/base/nsScriptNameSpaceManager.h b/dom/base/nsScriptNameSpaceManager.h index 84e10b9bb355..c9d5e7711be4 100644 --- a/dom/base/nsScriptNameSpaceManager.h +++ b/dom/base/nsScriptNameSpaceManager.h @@ -22,6 +22,7 @@ #define nsScriptNameSpaceManager_h__ #include "mozilla/MemoryReporting.h" +#include "nsBaseHashtable.h" #include "nsIMemoryReporter.h" #include "nsIScriptNameSpaceManager.h" #include "nsString.h" From 2b1db6042136677556c9366869cfe76770d195f7 Mon Sep 17 00:00:00 2001 From: Hiroyuki Ikezoe Date: Thu, 20 Aug 2015 14:20:33 -0700 Subject: [PATCH 045/208] Bug 1191178 - Part 1: Add a function to check frame timing preference value. r=smaug --- dom/base/nsContentUtils.cpp | 11 +++++++++++ dom/base/nsContentUtils.h | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index a357e13247b0..80f93e74d346 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -254,6 +254,7 @@ bool nsContentUtils::sInitialized = false; bool nsContentUtils::sIsFullScreenApiEnabled = false; bool nsContentUtils::sTrustedFullScreenOnly = true; bool nsContentUtils::sIsCutCopyAllowed = true; +bool nsContentUtils::sIsFrameTimingPrefEnabled = false; bool nsContentUtils::sIsPerformanceTimingEnabled = false; bool nsContentUtils::sIsResourceTimingEnabled = false; bool nsContentUtils::sIsUserTimingLoggingEnabled = false; @@ -536,6 +537,9 @@ nsContentUtils::Init() Preferences::AddBoolVarCache(&sIsUserTimingLoggingEnabled, "dom.performance.enable_user_timing_logging", false); + Preferences::AddBoolVarCache(&sIsFrameTimingPrefEnabled, + "dom.enable_frame_timing", true); + Preferences::AddBoolVarCache(&sIsExperimentalAutocompleteEnabled, "dom.forms.autocomplete.experimental", false); @@ -6776,6 +6780,13 @@ nsContentUtils::IsCutCopyAllowed() IsCallerChrome(); } +/* static */ +bool +nsContentUtils::IsFrameTimingEnabled() +{ + return sIsFrameTimingPrefEnabled; +} + /* static */ bool nsContentUtils::HaveEqualPrincipals(nsIDocument* aDoc1, nsIDocument* aDoc2) diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 19f64898aa26..6f8d6f5ca385 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -1977,6 +1977,11 @@ class nsContentUtils return sSendPerformanceTimingNotifications; } + /* + * Returns true if the frame timing APIs are enabled. + */ + static bool IsFrameTimingEnabled(); + /* * Returns true if URL setters should percent encode the Hash/Ref segment * and getters should return the percent decoded value of the segment @@ -2574,6 +2579,7 @@ class nsContentUtils static bool sIsPerformanceTimingEnabled; static bool sIsResourceTimingEnabled; static bool sIsUserTimingLoggingEnabled; + static bool sIsFrameTimingPrefEnabled; static bool sIsExperimentalAutocompleteEnabled; static bool sEncodeDecodeURLHash; static bool sGettersDecodeURLHash; From f840446ba4c4aacc2cd460556203cd23fda951a7 Mon Sep 17 00:00:00 2001 From: Hiroyuki Ikezoe Date: Thu, 20 Aug 2015 14:20:47 -0700 Subject: [PATCH 046/208] Bug 1191178 - Part 2: Add PerformanceRenderTiming and PerformanceCompositeTiming. r=smaug --- dom/base/PerformanceCompositeTiming.cpp | 30 ++++++++++++ dom/base/PerformanceCompositeTiming.h | 44 +++++++++++++++++ dom/base/PerformanceRenderTiming.cpp | 32 ++++++++++++ dom/base/PerformanceRenderTiming.h | 51 ++++++++++++++++++++ dom/base/moz.build | 4 ++ dom/webidl/PerformanceCompositeTiming.webidl | 19 ++++++++ dom/webidl/PerformanceRenderTiming.webidl | 19 ++++++++ dom/webidl/moz.build | 2 + 8 files changed, 201 insertions(+) create mode 100644 dom/base/PerformanceCompositeTiming.cpp create mode 100644 dom/base/PerformanceCompositeTiming.h create mode 100644 dom/base/PerformanceRenderTiming.cpp create mode 100644 dom/base/PerformanceRenderTiming.h create mode 100644 dom/webidl/PerformanceCompositeTiming.webidl create mode 100644 dom/webidl/PerformanceRenderTiming.webidl diff --git a/dom/base/PerformanceCompositeTiming.cpp b/dom/base/PerformanceCompositeTiming.cpp new file mode 100644 index 000000000000..48362ce2bd60 --- /dev/null +++ b/dom/base/PerformanceCompositeTiming.cpp @@ -0,0 +1,30 @@ +/* -*- 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/. */ + +#include "PerformanceCompositeTiming.h" +#include "mozilla/dom/PerformanceCompositeTimingBinding.h" + +using namespace mozilla::dom; + +PerformanceCompositeTiming::PerformanceCompositeTiming(nsISupports* aParent, + const nsAString& aName, + const DOMHighResTimeStamp& aStartTime, + uint32_t aSourceFrameNumber) +: PerformanceEntry(aParent, aName, NS_LITERAL_STRING("composite")) +, mStartTime(aStartTime) +, mSourceFrameNumber(aSourceFrameNumber) +{ + MOZ_ASSERT(aParent, "Parent performance object should be provided"); +} + +PerformanceCompositeTiming::~PerformanceCompositeTiming() +{ +} + +JSObject* +PerformanceCompositeTiming::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return PerformanceCompositeTimingBinding::Wrap(aCx, this, aGivenProto); +} diff --git a/dom/base/PerformanceCompositeTiming.h b/dom/base/PerformanceCompositeTiming.h new file mode 100644 index 000000000000..deee1598ad46 --- /dev/null +++ b/dom/base/PerformanceCompositeTiming.h @@ -0,0 +1,44 @@ +/* -*- 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_performancecompositetiming_h___ +#define mozilla_dom_performancecompositetiming_h___ + +#include "mozilla/dom/PerformanceEntry.h" + +namespace mozilla { +namespace dom { + +// http://www.w3.org/TR/frame-timing/#performancecompositetiming +class PerformanceCompositeTiming final : public PerformanceEntry +{ +public: + PerformanceCompositeTiming(nsISupports* aParent, + const nsAString& aName, + const DOMHighResTimeStamp& aStartTime, + uint32_t aSourceFrameNumber); + + virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + + virtual DOMHighResTimeStamp StartTime() const override + { + return mStartTime; + } + + uint32_t SourceFrameNumber() const + { + return mSourceFrameNumber; + } + +protected: + virtual ~PerformanceCompositeTiming(); + DOMHighResTimeStamp mStartTime; + uint32_t mSourceFrameNumber; +}; + +} // namespace dom +} // namespace mozilla + +#endif /* mozilla_dom_performancecompositetiming_h___ */ diff --git a/dom/base/PerformanceRenderTiming.cpp b/dom/base/PerformanceRenderTiming.cpp new file mode 100644 index 000000000000..c4f04f1dda93 --- /dev/null +++ b/dom/base/PerformanceRenderTiming.cpp @@ -0,0 +1,32 @@ +/* -*- 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/. */ + +#include "PerformanceRenderTiming.h" +#include "mozilla/dom/PerformanceRenderTimingBinding.h" + +using namespace mozilla::dom; + +PerformanceRenderTiming::PerformanceRenderTiming(nsISupports* aParent, + const nsAString& aName, + const DOMHighResTimeStamp& aStartTime, + const DOMHighResTimeStamp& aDuration, + uint32_t aSourceFrameNumber) +: PerformanceEntry(aParent, aName, NS_LITERAL_STRING("render")) +, mStartTime(aStartTime) +, mDuration(aDuration) +, mSourceFrameNumber(aSourceFrameNumber) +{ + MOZ_ASSERT(aParent, "Parent performance object should be provided"); +} + +PerformanceRenderTiming::~PerformanceRenderTiming() +{ +} + +JSObject* +PerformanceRenderTiming::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return PerformanceRenderTimingBinding::Wrap(aCx, this, aGivenProto); +} diff --git a/dom/base/PerformanceRenderTiming.h b/dom/base/PerformanceRenderTiming.h new file mode 100644 index 000000000000..63eeb106d931 --- /dev/null +++ b/dom/base/PerformanceRenderTiming.h @@ -0,0 +1,51 @@ +/* -*- 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_performancerendertiming_h___ +#define mozilla_dom_performancerendertiming_h___ + +#include "mozilla/dom/PerformanceEntry.h" + +namespace mozilla { +namespace dom { + +// http://www.w3.org/TR/frame-timing/#performancerendertiming +class PerformanceRenderTiming final : public PerformanceEntry +{ +public: + PerformanceRenderTiming(nsISupports* aParent, + const nsAString& aName, + const DOMHighResTimeStamp& aStartTime, + const DOMHighResTimeStamp& aDuration, + uint32_t aSourceFrameNumber); + + virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + + virtual DOMHighResTimeStamp StartTime() const override + { + return mStartTime; + } + + virtual DOMHighResTimeStamp Duration() const override + { + return mDuration; + } + + uint32_t SourceFrameNumber() const + { + return mSourceFrameNumber; + } + +protected: + virtual ~PerformanceRenderTiming(); + DOMHighResTimeStamp mStartTime; + DOMHighResTimeStamp mDuration; + uint32_t mSourceFrameNumber; +}; + +} // namespace dom +} // namespace mozilla + +#endif /* mozilla_dom_performancerendertiming_h___ */ diff --git a/dom/base/moz.build b/dom/base/moz.build index 406a640c89ea..fc4bae3054eb 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -186,11 +186,13 @@ EXPORTS.mozilla.dom += [ 'NodeInfo.h', 'NodeInfoInlines.h', 'NodeIterator.h', + 'PerformanceCompositeTiming.h', 'PerformanceEntry.h', 'PerformanceMark.h', 'PerformanceMeasure.h', 'PerformanceObserver.h', 'PerformanceObserverEntryList.h', + 'PerformanceRenderTiming.h', 'PerformanceResourceTiming.h', 'ProcessGlobal.h', 'ResponsiveImageSelector.h', @@ -327,11 +329,13 @@ UNIFIED_SOURCES += [ 'nsXMLContentSerializer.cpp', 'nsXMLHttpRequest.cpp', 'nsXMLNameSpaceMap.cpp', + 'PerformanceCompositeTiming.cpp', 'PerformanceEntry.cpp', 'PerformanceMark.cpp', 'PerformanceMeasure.cpp', 'PerformanceObserver.cpp', 'PerformanceObserverEntryList.cpp', + 'PerformanceRenderTiming.cpp', 'PerformanceResourceTiming.cpp', 'PostMessageEvent.cpp', 'ProcessGlobal.cpp', diff --git a/dom/webidl/PerformanceCompositeTiming.webidl b/dom/webidl/PerformanceCompositeTiming.webidl new file mode 100644 index 000000000000..c7ccf10e4903 --- /dev/null +++ b/dom/webidl/PerformanceCompositeTiming.webidl @@ -0,0 +1,19 @@ +/* -*- Mode: IDL; 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/. + * + * The origin of this IDL file is + * http://www.w3.org/TR/frame-timing/#performancecompositetiming + * + * Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved. W3C + * liability, trademark and document use rules apply. + */ + +[Pref="dom.enable_frame_timing"] +interface PerformanceCompositeTiming : PerformanceEntry +{ + readonly attribute unsigned long sourceFrameNumber; + + jsonifier; +}; diff --git a/dom/webidl/PerformanceRenderTiming.webidl b/dom/webidl/PerformanceRenderTiming.webidl new file mode 100644 index 000000000000..4ea4ebdd559b --- /dev/null +++ b/dom/webidl/PerformanceRenderTiming.webidl @@ -0,0 +1,19 @@ +/* -*- Mode: IDL; 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/. + * + * The origin of this IDL file is + * http://www.w3.org/TR/frame-timing/#performancerendertiming + * + * Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved. W3C + * liability, trademark and document use rules apply. + */ + +[Pref="dom.enable_frame_timing"] +interface PerformanceRenderTiming : PerformanceEntry +{ + readonly attribute unsigned long sourceFrameNumber; + + jsonifier; +}; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index ebc780f40713..495557770e1c 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -349,12 +349,14 @@ WEBIDL_FILES = [ 'PannerNode.webidl', 'ParentNode.webidl', 'Performance.webidl', + 'PerformanceCompositeTiming.webidl', 'PerformanceEntry.webidl', 'PerformanceMark.webidl', 'PerformanceMeasure.webidl', 'PerformanceNavigation.webidl', 'PerformanceObserver.webidl', 'PerformanceObserverEntryList.webidl', + 'PerformanceRenderTiming.webidl', 'PerformanceResourceTiming.webidl', 'PerformanceTiming.webidl', 'PeriodicWave.webidl', From 362941e9ef0cf6bd9d9ecaee6ac27b11d92ed9d3 Mon Sep 17 00:00:00 2001 From: dimi Date: Wed, 19 Aug 2015 14:46:53 +0800 Subject: [PATCH 047/208] Bug 1191647 - Listen to clear-origin-data in ServiceWorkerManager.cpp. r=bkelly --- dom/workers/ServiceWorkerManager.cpp | 63 +++++++++++----------------- dom/workers/ServiceWorkerManager.h | 2 +- 2 files changed, 25 insertions(+), 40 deletions(-) diff --git a/dom/workers/ServiceWorkerManager.cpp b/dom/workers/ServiceWorkerManager.cpp index 3511a7101ac7..3140a3ae9c92 100644 --- a/dom/workers/ServiceWorkerManager.cpp +++ b/dom/workers/ServiceWorkerManager.cpp @@ -7,7 +7,6 @@ #include "ServiceWorkerManager.h" #include "mozIApplication.h" -#include "mozIApplicationClearPrivateDataParams.h" #include "nsIAppsService.h" #include "nsIDOMEventTarget.h" #include "nsIDocument.h" @@ -83,7 +82,7 @@ BEGIN_WORKERS_NAMESPACE #define PURGE_DOMAIN_DATA "browser:purge-domain-data" #define PURGE_SESSION_HISTORY "browser:purge-session-history" -#define WEBAPPS_CLEAR_DATA "webapps-clear-data" +#define CLEAR_ORIGIN_DATA "clear-origin-data" static_assert(nsIHttpChannelInternal::CORS_MODE_SAME_ORIGIN == static_cast(RequestMode::Same_origin), "RequestMode enumeration value should match Necko CORS mode value."); @@ -431,7 +430,7 @@ ServiceWorkerManager::Init() MOZ_ASSERT(NS_SUCCEEDED(rv)); rv = obs->AddObserver(this, PURGE_DOMAIN_DATA, false /* ownsWeak */); MOZ_ASSERT(NS_SUCCEEDED(rv)); - rv = obs->AddObserver(this, WEBAPPS_CLEAR_DATA, false /* ownsWeak */); + rv = obs->AddObserver(this, CLEAR_ORIGIN_DATA, false /* ownsWeak */); MOZ_ASSERT(NS_SUCCEEDED(rv)); } } @@ -4663,46 +4662,36 @@ UnregisterIfMatchesHostPerPrincipal(const nsACString& aKey, } PLDHashOperator -UnregisterIfMatchesClearPrivateDataParams(const nsACString& aScope, - ServiceWorkerRegistrationInfo* aReg, - void* aPtr) +UnregisterIfMatchesClearOriginParams(const nsACString& aScope, + ServiceWorkerRegistrationInfo* aReg, + void* aPtr) { UnregisterIfMatchesUserData* data = static_cast(aPtr); + MOZ_ASSERT(data); if (data->mUserData) { - mozIApplicationClearPrivateDataParams *params = - static_cast(data->mUserData); + OriginAttributes* params = static_cast(data->mUserData); MOZ_ASSERT(params); + MOZ_ASSERT(aReg); MOZ_ASSERT(aReg->mPrincipal); - uint32_t appId; - nsresult rv = params->GetAppId(&appId); - if (NS_WARN_IF(NS_FAILED(rv))) { - return PL_DHASH_NEXT; - } - - bool browserOnly; - rv = params->GetBrowserOnly(&browserOnly); - if (NS_WARN_IF(NS_FAILED(rv))) { - return PL_DHASH_NEXT; - } - bool equals = false; - if (browserOnly) { + if (params->mInBrowser) { // When we do a system wide "clear cookies and stored data" on B2G we get - // the "webapps-clear-data" notification with the System app appID and + // the "clear-origin-data" notification with the System app appID and // the browserOnly flag set to true. // Web sites registering a service worker on B2G have a principal with the // following information: web site origin + System app appId + inBrowser=1 // So we need to check if the service worker registration info contains // the System app appID and the enabled inBrowser flag and in that case // remove it from the registry. - equals = (appId == aReg->mPrincipal->GetAppId()) && - aReg->mPrincipal->GetIsInBrowserElement(); + OriginAttributes attrs = + mozilla::BasePrincipal::Cast(aReg->mPrincipal)->OriginAttributesRef(); + equals = attrs == *params; } else { - // If we get the "webapps-clear-data" notification because of an app + // If we get the "clear-origin-data" notification because of an app // uninstallation, we need to check the full principal to get the match // in the service workers registry. If we find a match, we unregister the // worker. @@ -4713,7 +4702,7 @@ UnregisterIfMatchesClearPrivateDataParams(const nsACString& aScope, } nsCOMPtr app; - appsService->GetAppByLocalId(appId, getter_AddRefs(app)); + appsService->GetAppByLocalId(params->mAppId, getter_AddRefs(app)); if (NS_WARN_IF(!app)) { return PL_DHASH_NEXT; } @@ -4737,7 +4726,7 @@ UnregisterIfMatchesClearPrivateDataParams(const nsACString& aScope, } PLDHashOperator -UnregisterIfMatchesClearPrivateDataParams(const nsACString& aKey, +UnregisterIfMatchesClearOriginParams(const nsACString& aKey, ServiceWorkerManager::RegistrationDataPerPrincipal* aData, void* aUserData) { @@ -4745,7 +4734,7 @@ UnregisterIfMatchesClearPrivateDataParams(const nsACString& aKey, // We can use EnumerateRead because ForceUnregister (and Unregister) are async. // Otherwise doing some R/W operations on an hashtable during an EnumerateRead // will crash. - aData->mInfos.EnumerateRead(UnregisterIfMatchesClearPrivateDataParams, + aData->mInfos.EnumerateRead(UnregisterIfMatchesClearOriginParams, &data); return PL_DHASH_NEXT; } @@ -4963,14 +4952,13 @@ UpdateEachRegistration(const nsACString& aKey, } void -ServiceWorkerManager::RemoveAllRegistrations( - mozIApplicationClearPrivateDataParams* aParams) +ServiceWorkerManager::RemoveAllRegistrations(OriginAttributes* aParams) { AssertIsOnMainThread(); MOZ_ASSERT(aParams); - mRegistrationInfos.EnumerateRead(UnregisterIfMatchesClearPrivateDataParams, + mRegistrationInfos.EnumerateRead(UnregisterIfMatchesClearOriginParams, aParams); } @@ -5011,15 +4999,12 @@ ServiceWorkerManager::Observe(nsISupports* aSubject, return NS_OK; } - if (strcmp(aTopic, WEBAPPS_CLEAR_DATA) == 0) { + if (strcmp(aTopic, CLEAR_ORIGIN_DATA) == 0) { MOZ_ASSERT(XRE_IsParentProcess()); - nsCOMPtr params = - do_QueryInterface(aSubject); - if (NS_WARN_IF(!params)) { - return NS_OK; - } + OriginAttributes attrs; + MOZ_ALWAYS_TRUE(attrs.Init(nsAutoString(aData))); - RemoveAllRegistrations(params); + RemoveAllRegistrations(&attrs); return NS_OK; } @@ -5033,7 +5018,7 @@ ServiceWorkerManager::Observe(nsISupports* aSubject, if (XRE_IsParentProcess()) { obs->RemoveObserver(this, PURGE_SESSION_HISTORY); obs->RemoveObserver(this, PURGE_DOMAIN_DATA); - obs->RemoveObserver(this, WEBAPPS_CLEAR_DATA); + obs->RemoveObserver(this, CLEAR_ORIGIN_DATA); } } diff --git a/dom/workers/ServiceWorkerManager.h b/dom/workers/ServiceWorkerManager.h index a9538389f062..bf36771012b7 100644 --- a/dom/workers/ServiceWorkerManager.h +++ b/dom/workers/ServiceWorkerManager.h @@ -552,7 +552,7 @@ class ServiceWorkerManager final // Removes all service worker registrations that matches the given // mozIApplicationClearPrivateDataParams. void - RemoveAllRegistrations(mozIApplicationClearPrivateDataParams* aParams); + RemoveAllRegistrations(OriginAttributes* aParams); nsRefPtr mActor; From cfa2bb635dc33ce456c32dcb0eaef5b271f34d4d Mon Sep 17 00:00:00 2001 From: Cykesiopka Date: Thu, 20 Aug 2015 14:33:29 -0700 Subject: [PATCH 048/208] Bug 1195615 - Log a web console warning when a HPKP header is ignored due to a non-built in root cert. r=keeler --- dom/locales/en-US/chrome/security/security.properties | 3 ++- netwerk/protocol/http/nsHttpChannel.cpp | 3 +++ security/manager/ssl/nsISiteSecurityService.idl | 3 ++- security/manager/ssl/nsSiteSecurityService.cpp | 5 ++++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/dom/locales/en-US/chrome/security/security.properties b/dom/locales/en-US/chrome/security/security.properties index ca57a70f22b2..be519e338b92 100644 --- a/dom/locales/en-US/chrome/security/security.properties +++ b/dom/locales/en-US/chrome/security/security.properties @@ -27,7 +27,7 @@ STSMultipleIncludeSubdomains=Strict-Transport-Security: The site specified a hea STSInvalidIncludeSubdomains=Strict-Transport-Security: The site specified a header that included an invalid 'includeSubDomains' directive. STSCouldNotSaveState=Strict-Transport-Security: An error occurred noting the site as a Strict-Transport-Security host. -# LOCALIZATION NOTE: Do not translate "Public-Key-Pins", "HPKP", "max-age" or "includeSubDomains" +# LOCALIZATION NOTE: Do not translate "Public-Key-Pins", "HPKP", "max-age", "report-uri" or "includeSubDomains" PKPUnknownError=Public-Key-Pins: An unknown error occurred processing the header specified by the site. PKPUntrustworthyConnection=Public-Key-Pins: The connection to the site is untrustworthy, so the specified header was ignored. PKPCouldNotParseHeader=Public-Key-Pins: The site specified a header that could not be parsed successfully. @@ -41,6 +41,7 @@ PKPMultipleReportURIs=Public-Key-Pins: The site specified a header that included PKPPinsetDoesNotMatch=Public-Key-Pins: The site specified a header that did not include a matching pin. PKPNoBackupPin=Public-Key-Pins: The site specified a header that did not include a backup pin. PKPCouldNotSaveState=Public-Key-Pins: An error occurred noting the site as a Public-Key-Pins host. +PKPRootNotBuiltIn=Public-Key-Pins: The certificate used by the site was not issued by a certificate in the default root certificate store. To prevent accidental breakage, the specified header was ignored. # LOCALIZATION NOTE: Do not translate "SHA-1" SHA1Sig=This site makes use of a SHA-1 Certificate; it's recommended you use certificates with signature algorithms that use hash functions stronger than SHA-1. diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index 8e2bbb23dc63..81d612840dfd 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -1224,6 +1224,9 @@ GetPKPConsoleErrorTag(uint32_t failureResult, nsAString& consoleErrorTag) case nsISiteSecurityService::ERROR_COULD_NOT_SAVE_STATE: consoleErrorTag = NS_LITERAL_STRING("PKPCouldNotSaveState"); break; + case nsISiteSecurityService::ERROR_ROOT_NOT_BUILT_IN: + consoleErrorTag = NS_LITERAL_STRING("PKPRootNotBuiltIn"); + break; default: consoleErrorTag = NS_LITERAL_STRING("PKPUnknownError"); break; diff --git a/security/manager/ssl/nsISiteSecurityService.idl b/security/manager/ssl/nsISiteSecurityService.idl index a90fd8199bf0..8f3df1ac9de5 100644 --- a/security/manager/ssl/nsISiteSecurityService.idl +++ b/security/manager/ssl/nsISiteSecurityService.idl @@ -23,7 +23,7 @@ namespace mozilla [ref] native nsCStringTArrayRef(nsTArray); [ref] native mozillaPkixTime(mozilla::pkix::Time); -[scriptable, uuid(e6cac961-9f03-4cc3-ad00-a829ae7304dc)] +[scriptable, uuid(275127f8-dbd7-4681-afbf-6df0c6587a01)] interface nsISiteSecurityService : nsISupports { const uint32_t HEADER_HSTS = 0; @@ -44,6 +44,7 @@ interface nsISiteSecurityService : nsISupports const uint32_t ERROR_PINSET_DOES_NOT_MATCH_CHAIN = 11; const uint32_t ERROR_NO_BACKUP_PIN = 12; const uint32_t ERROR_COULD_NOT_SAVE_STATE = 13; + const uint32_t ERROR_ROOT_NOT_BUILT_IN = 14; /** * Parses a given HTTP header and records the results internally. diff --git a/security/manager/ssl/nsSiteSecurityService.cpp b/security/manager/ssl/nsSiteSecurityService.cpp index 49a1f517db11..407cb2677900 100644 --- a/security/manager/ssl/nsSiteSecurityService.cpp +++ b/security/manager/ssl/nsSiteSecurityService.cpp @@ -718,7 +718,10 @@ nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI, } if (!isBuiltIn && !mProcessPKPHeadersFromNonBuiltInRoots) { - return NS_OK; + if (aFailureResult) { + *aFailureResult = nsISiteSecurityService::ERROR_ROOT_NOT_BUILT_IN; + } + return NS_ERROR_FAILURE; } // if maxAge == 0 we must delete all state, for now no hole-punching From 0fa02aee9e3499eaf7e5c7e6e3cf45764c892ecb Mon Sep 17 00:00:00 2001 From: Cykesiopka Date: Thu, 20 Aug 2015 14:33:40 -0700 Subject: [PATCH 049/208] Bug 1195615 - Add web console test. r=past --- .../browser_webconsole_hpkp_invalid-headers.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/browser/devtools/webconsole/test/browser_webconsole_hpkp_invalid-headers.js b/browser/devtools/webconsole/test/browser_webconsole_hpkp_invalid-headers.js index 4535e4aaf708..8eb6993d5704 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_hpkp_invalid-headers.js +++ b/browser/devtools/webconsole/test/browser_webconsole_hpkp_invalid-headers.js @@ -18,9 +18,6 @@ let test = asyncTest(function* () { registerCleanupFunction(() => { Services.prefs.clearUserPref(NON_BUILTIN_ROOT_PREF); }); - // The root used for mochitests is not built-in, so set the relevant pref to - // true to force all pinning error messages to appear. - Services.prefs.setBoolPref(NON_BUILTIN_ROOT_PREF, true); yield loadTab(TEST_URI); @@ -75,12 +72,26 @@ let test = asyncTest(function* () { "multiple 'report-uri' directives." }, hud); + // The root used for mochitests is not built-in, so set the relevant pref to + // true to have the PKP implementation return more specific errors. + Services.prefs.setBoolPref(NON_BUILTIN_ROOT_PREF, true); + yield* checkForMessage({ url: SJS_URL + "?pinsetDoesNotMatch", name: "Non-matching pinset error displayed successfully", text: "Public-Key-Pins: The site specified a header that did not include " + "a matching pin." }, hud); + + Services.prefs.setBoolPref(NON_BUILTIN_ROOT_PREF, false); + + yield* checkForMessage({ + url: SJS_URL + "?pinsetDoesNotMatch", + name: "Non-built-in root error displayed successfully", + text: "Public-Key-Pins: The certificate used by the site was not issued " + + "by a certificate in the default root certificate store. To " + + "prevent accidental breakage, the specified header was ignored." + }, hud); }); function* checkForMessage(curTest, hud) { From eab8a11ada45bf225f57eef6b7775c2388da61c2 Mon Sep 17 00:00:00 2001 From: Hiroyuki Ikezoe Date: Thu, 20 Aug 2015 14:33:54 -0700 Subject: [PATCH 050/208] Bug 1195700 - Disconnect performance observer before being destroyed to avoid crash. r=baku --- dom/base/PerformanceObserver.cpp | 11 ++++++++++- dom/base/PerformanceObserver.h | 1 + dom/base/test/performance_observer.html | 1 + dom/base/test/test_performance_observer.js | 7 +++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/dom/base/PerformanceObserver.cpp b/dom/base/PerformanceObserver.cpp index 21d7741b1bbc..f3f9017f74c8 100644 --- a/dom/base/PerformanceObserver.cpp +++ b/dom/base/PerformanceObserver.cpp @@ -38,6 +38,7 @@ PerformanceObserver::PerformanceObserver(nsPIDOMWindow* aOwner, PerformanceObserverCallback& aCb) : mOwner(aOwner) , mCallback(&aCb) + , mConnected(false) { MOZ_ASSERT(mOwner); mPerformance = aOwner->GetPerformance(); @@ -46,6 +47,7 @@ PerformanceObserver::PerformanceObserver(nsPIDOMWindow* aOwner, PerformanceObserver::PerformanceObserver(WorkerPrivate* aWorkerPrivate, PerformanceObserverCallback& aCb) : mCallback(&aCb) + , mConnected(false) { MOZ_ASSERT(aWorkerPrivate); mPerformance = aWorkerPrivate->GlobalScope()->GetPerformance(); @@ -53,6 +55,8 @@ PerformanceObserver::PerformanceObserver(WorkerPrivate* aWorkerPrivate, PerformanceObserver::~PerformanceObserver() { + Disconnect(); + MOZ_ASSERT(!mConnected); } // static @@ -145,10 +149,15 @@ PerformanceObserver::Observe(const PerformanceObserverInit& aOptions, mEntryTypes = validEntryTypes; mPerformance->AddObserver(this); + mConnected = true; } void PerformanceObserver::Disconnect() { - mPerformance->RemoveObserver(this); + if (mConnected) { + MOZ_ASSERT(mPerformance); + mPerformance->RemoveObserver(this); + mConnected = false; + } } diff --git a/dom/base/PerformanceObserver.h b/dom/base/PerformanceObserver.h index 0a7fcd60330f..85de6ea02d53 100644 --- a/dom/base/PerformanceObserver.h +++ b/dom/base/PerformanceObserver.h @@ -68,6 +68,7 @@ class PerformanceObserver final : public nsISupports, nsRefPtr mCallback; nsRefPtr mPerformance; nsTArray mEntryTypes; + bool mConnected; }; } // namespace dom diff --git a/dom/base/test/performance_observer.html b/dom/base/test/performance_observer.html index d194c17e42df..b24479d8c924 100644 --- a/dom/base/test/performance_observer.html +++ b/dom/base/test/performance_observer.html @@ -48,6 +48,7 @@ observedEntryList = list; }); observer.observe({entryTypes: ['resource']}); + t.add_cleanup(() => observer.disconnect()); assert_equals(observedEntries.length, 0); diff --git a/dom/base/test/test_performance_observer.js b/dom/base/test/test_performance_observer.js index 5eb43c10ceec..cef0f33cd178 100644 --- a/dom/base/test/test_performance_observer.js +++ b/dom/base/test/test_performance_observer.js @@ -44,6 +44,7 @@ test(t => { list.getEntries().forEach(entry => observedEntries.push(entry)); }); observer.observe({entryTypes: ['mark', 'measure']}); + t.add_cleanup(() => observer.disconnect()); assert_equals(observedEntries.length, 0, "User timing entries should never be observed."); @@ -107,6 +108,7 @@ test(t => { observedEntryList = list; }); observer.observe({entryTypes: ['mark']}); + t.add_cleanup(() => observer.disconnect()); performance.mark("test"); assert_array_equals(observedEntryList.getEntries({"entryType": "mark"}), @@ -150,6 +152,7 @@ test(t => { observedEntryList = list; }); observer.observe({entryTypes: ['mark', 'measure']}); + t.add_cleanup(() => observer.disconnect()); performance.mark("test"); assert_array_equals(observedEntryList.getEntriesByType("mark"), @@ -169,6 +172,7 @@ test(t => { observedEntryList = list; }); observer.observe({entryTypes: ['mark', 'measure']}); + t.add_cleanup(() => observer.disconnect()); performance.mark("test"); assert_array_equals(observedEntryList.getEntriesByName("test"), @@ -190,6 +194,7 @@ test(t => { observer.observe({entryTypes: ['mark', 'measure']}); observer.observe({entryTypes: ['mark', 'measure']}); + t.add_cleanup(() => observer.disconnect()); performance.mark("test-start"); performance.mark("test-end"); @@ -210,6 +215,7 @@ test(t => { observer.observe({entryTypes: ['mark', 'measure']}); observer.observe({entryTypes: ['mark']}); + t.add_cleanup(() => observer.disconnect()); performance.mark("test-start"); performance.mark("test-end"); @@ -230,6 +236,7 @@ test(t => { observer.observe({entryTypes: ['mark']}); observer.observe({entryTypes: ['measure']}); + t.add_cleanup(() => observer.disconnect()); performance.mark("test-start"); performance.mark("test-end"); From b396856cab95eeb60171ac69152254c23d6ec071 Mon Sep 17 00:00:00 2001 From: Milan Sreckovic Date: Thu, 20 Aug 2015 14:34:11 -0700 Subject: [PATCH 051/208] Bug 1195844: When checking for old DisplayLink versions, look for a few other DLLs. r=jrmuizel --- gfx/thebes/gfxWindowsPlatform.cpp | 36 ++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 2a25068c6f17..e645035984e8 100755 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -1668,19 +1668,29 @@ bool CouldD3D11DeviceWork() return true; } - if (GetModuleHandleW(L"dlumd32.dll") && GetModuleHandleW(L"igd10umd32.dll")) { - nsString displayLinkModuleVersionString; - gfxWindowsPlatform::GetDLLVersion(L"dlumd32.dll", displayLinkModuleVersionString); - uint64_t displayLinkModuleVersion; - if (!ParseDriverVersion(displayLinkModuleVersionString, &displayLinkModuleVersion)) { - gfxCriticalError() << "DisplayLink: could not parse version"; - gANGLESupportsD3D11 = false; - return false; - } - if (displayLinkModuleVersion <= V(8,6,1,36484)) { - gfxCriticalError(CriticalLog::DefaultOptions(false)) << "DisplayLink: too old version"; - gANGLESupportsD3D11 = false; - return false; + if (GetModuleHandleW(L"igd10umd32.dll")) { + const wchar_t* checkModules[] = {L"dlumd32.dll", + L"dlumd11.dll", + L"dlumd10.dll"}; + for (int i=0; i Date: Thu, 20 Aug 2015 14:34:22 -0700 Subject: [PATCH 052/208] Bug 1196157 - Marks left by performance marks should print the domain of the application and not the complete URL. r=baku --- dom/workers/Performance.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dom/workers/Performance.cpp b/dom/workers/Performance.cpp index 25bc92ed2029..9590469b249e 100644 --- a/dom/workers/Performance.cpp +++ b/dom/workers/Performance.cpp @@ -68,8 +68,13 @@ void Performance::InsertUserEntry(PerformanceEntry* aEntry) { if (mWorkerPrivate->PerformanceLoggingEnabled()) { - PerformanceBase::LogEntry(aEntry, - NS_ConvertUTF16toUTF8(mWorkerPrivate->ScriptURL())); + nsAutoCString uri; + nsCOMPtr scriptURI = mWorkerPrivate->GetResolvedScriptURI(); + if (!scriptURI || NS_FAILED(scriptURI->GetHost(uri))) { + // If we have no URI, just put in "none". + uri.AssignLiteral("none"); + } + PerformanceBase::LogEntry(aEntry, uri); } PerformanceBase::InsertUserEntry(aEntry); } From f6e482adc35eb31b7be60a891bfe6ababf224776 Mon Sep 17 00:00:00 2001 From: Milan Sreckovic Date: Wed, 19 Aug 2015 13:30:57 -0400 Subject: [PATCH 053/208] Bug 1196355: WriteAppNote should use function parameter. r=benwa --- gfx/src/gfxCrashReporterUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/src/gfxCrashReporterUtils.cpp b/gfx/src/gfxCrashReporterUtils.cpp index 79f013861888..69f9cf5074bc 100644 --- a/gfx/src/gfxCrashReporterUtils.cpp +++ b/gfx/src/gfxCrashReporterUtils.cpp @@ -98,7 +98,7 @@ ScopedGfxFeatureReporter::WriteAppNote(char statusChar) nsAutoCString featureString; featureString.AppendPrintf("%s%c ", mFeature, - mStatusChar); + statusChar); if (!gFeaturesAlreadyReported->Contains(featureString)) { gFeaturesAlreadyReported->AppendElement(featureString); From af8ff47bc574d25ea618bf6d30345d59289c7b49 Mon Sep 17 00:00:00 2001 From: David Major Date: Thu, 20 Aug 2015 14:34:57 -0700 Subject: [PATCH 054/208] Bug 1196370 - Remove the clang assembly workaround from bug 1028613. r=ehsan --- xpcom/reflect/xptcall/md/win32/xptcinvoke.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/xpcom/reflect/xptcall/md/win32/xptcinvoke.cpp b/xpcom/reflect/xptcall/md/win32/xptcinvoke.cpp index a4019abd88cd..3d292eb38e8b 100644 --- a/xpcom/reflect/xptcall/md/win32/xptcinvoke.cpp +++ b/xpcom/reflect/xptcall/md/win32/xptcinvoke.cpp @@ -69,14 +69,6 @@ NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex, mov eax,methodIndex call dword ptr[edx+eax*4] // stdcall, i.e. callee cleans up stack. mov esp,ebp -#ifdef __clang__ - // clang-cl doesn't emit the pop and ret instructions because it doesn't realize - // that the call instruction sets a return value in eax. See - // https://bugzilla.mozilla.org/show_bug.cgi?id=1028613 and - // http://llvm.org/bugs/show_bug.cgi?id=17201. - pop ebp - ret -#endif } } #pragma warning(default : 4035) // restore default From dee95e099fc68e58110d0687605e7d79f5577503 Mon Sep 17 00:00:00 2001 From: Ben Hearsum Date: Thu, 20 Aug 2015 17:50:51 -0400 Subject: [PATCH 055/208] bug 1116409: switch update server to sha2 cert; update in-tree pinning. r=rstrong,snorp,mfinkle,dkeeler --- b2g/app/b2g.js | 2 +- browser/app/profile/firefox.js | 2 +- mobile/android/app/mobile.js | 2 +- modules/libpref/init/all.js | 10 +++++----- security/manager/tools/PreloadedHPKPins.json | 4 +++- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index 47e5f0c8fe96..8c23d4cd1255 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -605,7 +605,7 @@ pref("app.update.incompatible.mode", 0); pref("app.update.staging.enabled", true); pref("app.update.service.enabled", true); -pref("app.update.url", "https://aus4.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%PRODUCT_DEVICE%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml"); +pref("app.update.url", "https://aus5.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%PRODUCT_DEVICE%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml"); pref("app.update.channel", "@MOZ_UPDATE_CHANNEL@"); // Interval at which update manifest is fetched. In units of seconds. diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 6e1ac4d19ad9..9bf0bcc1dea8 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -142,7 +142,7 @@ pref("app.update.badge", false); pref("app.update.staging.enabled", true); // Update service URL: -pref("app.update.url", "https://aus4.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml"); +pref("app.update.url", "https://aus5.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml"); // app.update.url.manual is in branding section // app.update.url.details is in branding section diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js index bff3ba99cb77..18256e37aa58 100644 --- a/mobile/android/app/mobile.js +++ b/mobile/android/app/mobile.js @@ -525,7 +525,7 @@ pref("app.update.timerMinimumDelay", 30); // seconds // used by update service to decide whether or not to // automatically download an update pref("app.update.autodownload", "wifi"); -pref("app.update.url.android", "https://aus4.mozilla.org/update/4/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%MOZ_VERSION%/update.xml"); +pref("app.update.url.android", "https://aus5.mozilla.org/update/4/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%MOZ_VERSION%/update.xml"); #ifdef MOZ_UPDATER /* prefs used specifically for updating the app */ diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 3eaa77bdd8b9..798932d913dc 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4967,7 +4967,7 @@ pref("browser.search.official", true); //pref("media.gmp-manager.url.override", ""); // Update service URL for GMP install/updates: -pref("media.gmp-manager.url", "https://aus4.mozilla.org/update/3/GMP/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml"); +pref("media.gmp-manager.url", "https://aus5.mozilla.org/update/3/GMP/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml"); // When |media.gmp-manager.cert.requireBuiltIn| is true or not specified the // final certificate and all certificates the connection is redirected to before @@ -4992,10 +4992,10 @@ pref("media.gmp-manager.cert.requireBuiltIn", true); // IMPORTANT! app.update.certs.* prefs should also be updated if these // are updated. pref("media.gmp-manager.cert.checkAttributes", true); -pref("media.gmp-manager.certs.1.issuerName", "CN=DigiCert Secure Server CA,O=DigiCert Inc,C=US"); -pref("media.gmp-manager.certs.1.commonName", "aus4.mozilla.org"); -pref("media.gmp-manager.certs.2.issuerName", "CN=Thawte SSL CA,O=\"Thawte, Inc.\",C=US"); -pref("media.gmp-manager.certs.2.commonName", "aus4.mozilla.org"); +pref("media.gmp-manager.certs.1.issuerName", "CN=DigiCert SHA2 Secure Server CA,O=DigiCert Inc,C=US"); +pref("media.gmp-manager.certs.1.commonName", "aus5.mozilla.org"); +pref("media.gmp-manager.certs.2.issuerName", "CN=thawte SSL CA - G2,O=thawte, Inc.,C=US"); +pref("media.gmp-manager.certs.2.commonName", "aus5.mozilla.org"); #endif // Whether or not to perform reader mode article parsing on page load. diff --git a/security/manager/tools/PreloadedHPKPins.json b/security/manager/tools/PreloadedHPKPins.json index b05ae57814d7..50d24fa19919 100644 --- a/security/manager/tools/PreloadedHPKPins.json +++ b/security/manager/tools/PreloadedHPKPins.json @@ -227,7 +227,9 @@ // twitterCDN. More specific rules take precedence because we search for // exact domain name first. { "name": "twitter.com", "include_subdomains": true, - "pins": "twitterCDN", "test_mode": false } + "pins": "twitterCDN", "test_mode": false }, + { "name": "aus5.mozilla.org", "include_subdomains": true, + "pins": "mozilla", "test_mode": true, "id": 7 } ], "extra_certificates": [] From 49d9d1063eb337685a8287877fd3d48e4e61aab2 Mon Sep 17 00:00:00 2001 From: David Burns Date: Thu, 20 Aug 2015 23:21:21 +0100 Subject: [PATCH 056/208] Bug 1196920: Add specificationLevel capability to Marionette; r=jgriffin --- .../marionette/client/marionette/tests/unit/test_capabilities.py | 1 + testing/marionette/driver.js | 1 + 2 files changed, 2 insertions(+) diff --git a/testing/marionette/client/marionette/tests/unit/test_capabilities.py b/testing/marionette/client/marionette/tests/unit/test_capabilities.py index baa74c0f3a4f..ddc6b4ccb4ca 100644 --- a/testing/marionette/client/marionette/tests/unit/test_capabilities.py +++ b/testing/marionette/client/marionette/tests/unit/test_capabilities.py @@ -18,6 +18,7 @@ def test_mandates_capabilities(self): self.assertIn("browserVersion", self.caps) self.assertIn("platformName", self.caps) self.assertIn("platformVersion", self.caps) + self.assertIn("specificationLevel", self.caps) self.assertEqual(self.caps["browserName"], self.appinfo["name"]) self.assertEqual(self.caps["browserVersion"], self.appinfo["version"]) diff --git a/testing/marionette/driver.js b/testing/marionette/driver.js index f29bdd301fac..9f9159fe62b2 100644 --- a/testing/marionette/driver.js +++ b/testing/marionette/driver.js @@ -141,6 +141,7 @@ this.GeckoDriver = function(appName, device, emulator) { "browserVersion": Services.appinfo.version, "platformName": Services.appinfo.OS.toUpperCase(), "platformVersion": Services.appinfo.platformVersion, + "specificationLevel": "1", // Supported features "raisesAccessibilityExceptions": false, From cecdeae2785a2791726d900deea248533b22b555 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Thu, 20 Aug 2015 16:15:47 -0700 Subject: [PATCH 057/208] Backed out changeset c6f579ae99a6 (bug 1050749) for battery-interface-idlharness.html bustage --- dom/base/Navigator.cpp | 34 +------ dom/base/Navigator.h | 4 +- dom/battery/BatteryManager.cpp | 53 +---------- dom/battery/BatteryManager.h | 10 +- dom/battery/test/marionette/manifest.ini | 6 -- .../test/marionette/test_battery_level.js | 25 +++-- .../test_battery_status_charging.js | 17 ++-- .../test_battery_status_discharging.js | 17 ++-- .../marionette/test_battery_status_full.js | 15 ++- .../test_battery_status_not_charging.js | 15 ++- .../marionette/test_battery_status_unknown.js | 15 ++- .../test_deprecated_battery_level.js | 68 -------------- ...test_deprecated_battery_status_charging.js | 85 ----------------- ...t_deprecated_battery_status_discharging.js | 93 ------------------- .../test_deprecated_battery_status_full.js | 87 ----------------- ..._deprecated_battery_status_not_charging.js | 93 ------------------- .../test_deprecated_battery_unknown.js | 93 ------------------- dom/battery/test/mochitest.ini | 6 -- dom/battery/test/test_battery_basics.html | 23 ++--- dom/battery/test/test_battery_charging.html | 33 ------- .../test/test_battery_discharging.html | 33 ------- .../test/test_deprecated_battery_basics.html | 32 ------- dom/webidl/Navigator.webidl | 15 ++- toolkit/modules/Battery.jsm | 21 +---- .../modules/tests/browser/browser_Battery.js | 37 +------- 25 files changed, 78 insertions(+), 852 deletions(-) delete mode 100644 dom/battery/test/marionette/test_deprecated_battery_level.js delete mode 100644 dom/battery/test/marionette/test_deprecated_battery_status_charging.js delete mode 100644 dom/battery/test/marionette/test_deprecated_battery_status_discharging.js delete mode 100644 dom/battery/test/marionette/test_deprecated_battery_status_full.js delete mode 100644 dom/battery/test/marionette/test_deprecated_battery_status_not_charging.js delete mode 100644 dom/battery/test/marionette/test_deprecated_battery_unknown.js delete mode 100644 dom/battery/test/test_battery_charging.html delete mode 100644 dom/battery/test/test_battery_discharging.html delete mode 100644 dom/battery/test/test_deprecated_battery_basics.html diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index 7687784f5edd..a11988d58126 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -185,7 +185,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotification) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryPromise) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCellBroadcast) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager) @@ -253,8 +252,6 @@ Navigator::Invalidate() mBatteryManager = nullptr; } - mBatteryPromise = nullptr; - #ifdef MOZ_B2G_FM if (mFMRadio) { mFMRadio->Shutdown(); @@ -1458,37 +1455,8 @@ Navigator::GetMozFMRadio(ErrorResult& aRv) // Navigator::nsINavigatorBattery //***************************************************************************** -Promise* -Navigator::GetBattery(ErrorResult& aRv) -{ - if (mBatteryPromise) { - return mBatteryPromise; - } - - if (!mWindow || !mWindow->GetDocShell()) { - aRv.Throw(NS_ERROR_UNEXPECTED); - return nullptr; - } - - nsCOMPtr go = do_QueryInterface(mWindow); - nsRefPtr batteryPromise = Promise::Create(go, aRv); - if (NS_WARN_IF(aRv.Failed())) { - return nullptr; - } - mBatteryPromise = batteryPromise; - - if (!mBatteryManager) { - mBatteryManager = new battery::BatteryManager(mWindow); - mBatteryManager->Init(); - } - - mBatteryPromise->MaybeResolve(mBatteryManager); - - return mBatteryPromise; -} - battery::BatteryManager* -Navigator::GetDeprecatedBattery(ErrorResult& aRv) +Navigator::GetBattery(ErrorResult& aRv) { if (!mBatteryManager) { if (!mWindow) { diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index cd1114a1a832..b32c40d97d5d 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -160,8 +160,7 @@ class Navigator final : public nsIDOMNavigator Permissions* GetPermissions(ErrorResult& aRv); // The XPCOM GetDoNotTrack is ok Geolocation* GetGeolocation(ErrorResult& aRv); - Promise* GetBattery(ErrorResult& aRv); - battery::BatteryManager* GetDeprecatedBattery(ErrorResult& aRv); + battery::BatteryManager* GetBattery(ErrorResult& aRv); static already_AddRefed GetDataStores(nsPIDOMWindow* aWindow, const nsAString& aName, @@ -372,7 +371,6 @@ class Navigator final : public nsIDOMNavigator nsRefPtr mGeolocation; nsRefPtr mNotification; nsRefPtr mBatteryManager; - nsRefPtr mBatteryPromise; #ifdef MOZ_B2G_FM nsRefPtr mFMRadio; #endif diff --git a/dom/battery/BatteryManager.cpp b/dom/battery/BatteryManager.cpp index f72736f16476..bc9928c23207 100644 --- a/dom/battery/BatteryManager.cpp +++ b/dom/battery/BatteryManager.cpp @@ -10,7 +10,6 @@ #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/Hal.h" #include "mozilla/dom/BatteryManagerBinding.h" -#include "mozilla/Preferences.h" #include "nsIDOMClassInfo.h" /** @@ -57,37 +56,10 @@ BatteryManager::WrapObject(JSContext* aCx, JS::Handle aGivenProto) return BatteryManagerBinding::Wrap(aCx, this, aGivenProto); } -bool -BatteryManager::Charging() const -{ - MOZ_ASSERT(NS_IsMainThread()); - // For testing, unable to report the battery status information - if (Preferences::GetBool("dom.battery.test.default", false)) { - return true; - } - if (Preferences::GetBool("dom.battery.test.charging", false)) { - return true; - } - if (Preferences::GetBool("dom.battery.test.discharging", false)) { - return false; - } - - return mCharging; -} - double BatteryManager::DischargingTime() const { - MOZ_ASSERT(NS_IsMainThread()); - // For testing, unable to report the battery status information - if (Preferences::GetBool("dom.battery.test.default", false)) { - return std::numeric_limits::infinity(); - } - if (Preferences::GetBool("dom.battery.test.discharging", false)) { - return 42.0; - } - - if (Charging() || mRemainingTime == kUnknownRemainingTime) { + if (mCharging || mRemainingTime == kUnknownRemainingTime) { return std::numeric_limits::infinity(); } @@ -97,34 +69,13 @@ BatteryManager::DischargingTime() const double BatteryManager::ChargingTime() const { - MOZ_ASSERT(NS_IsMainThread()); - // For testing, unable to report the battery status information - if (Preferences::GetBool("dom.battery.test.default", false)) { - return 0.0; - } - if (Preferences::GetBool("dom.battery.test.charging", false)) { - return 42.0; - } - - if (!Charging() || mRemainingTime == kUnknownRemainingTime) { + if (!mCharging || mRemainingTime == kUnknownRemainingTime) { return std::numeric_limits::infinity(); } return mRemainingTime; } -double -BatteryManager::Level() const -{ - MOZ_ASSERT(NS_IsMainThread()); - // For testing, unable to report the battery status information - if (Preferences::GetBool("dom.battery.test.default")) { - return 1.0; - } - - return mLevel; -} - void BatteryManager::UpdateFromBatteryInfo(const hal::BatteryInformation& aBatteryInfo) { diff --git a/dom/battery/BatteryManager.h b/dom/battery/BatteryManager.h index 2660d642da04..0ef526ce0a70 100644 --- a/dom/battery/BatteryManager.h +++ b/dom/battery/BatteryManager.h @@ -46,13 +46,19 @@ class BatteryManager : public DOMEventTargetHelper virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; - bool Charging() const; + bool Charging() const + { + return mCharging; + } double ChargingTime() const; double DischargingTime() const; - double Level() const; + double Level() const + { + return mLevel; + } IMPL_EVENT_HANDLER(chargingchange) IMPL_EVENT_HANDLER(chargingtimechange) diff --git a/dom/battery/test/marionette/manifest.ini b/dom/battery/test/marionette/manifest.ini index 87ce1a3a5577..b74ec64e768d 100644 --- a/dom/battery/test/marionette/manifest.ini +++ b/dom/battery/test/marionette/manifest.ini @@ -9,9 +9,3 @@ qemu = true [test_battery_status_full.js] [test_battery_status_not_charging.js] [test_battery_status_unknown.js] -[test_deprecated_battery_level.js] -[test_deprecated_battery_status_charging.js] -[test_deprecated_battery_status_discharging.js] -[test_deprecated_battery_status_full.js] -[test_deprecated_battery_status_not_charging.js] -[test_deprecated_battery_status_unknown.js] diff --git a/dom/battery/test/marionette/test_battery_level.js b/dom/battery/test/marionette/test_battery_level.js index 74b1ec70a74c..b344a26e6171 100644 --- a/dom/battery/test/marionette/test_battery_level.js +++ b/dom/battery/test/marionette/test_battery_level.js @@ -3,18 +3,15 @@ MARIONETTE_TIMEOUT = 10000; -let battery = null; +let battery = window.navigator.battery; function verifyInitialState() { - window.navigator.getBattery().then(function (b) { - battery = b; - ok(battery, "battery"); - is(battery.level, 0.5, "battery.level"); - runEmulatorCmd("power display", function (result) { - is(result.pop(), "OK", "power display successful"); - ok(result.indexOf("capacity: 50") !== -1, "power capacity"); - setUp(); - }); + ok(battery, "battery"); + is(battery.level, 0.5, "battery.level"); + runEmulatorCmd("power display", function (result) { + is(result.pop(), "OK", "power display successful"); + ok(result.indexOf("capacity: 50") !== -1, "power capacity"); + setUp(); }); } @@ -32,10 +29,10 @@ function changeCapacity(capacity, changeExpected, nextFunction) { log("Changing power capacity to " + capacity); if (changeExpected) { battery.onlevelchange = function (event) { - battery.onlevelchange = unexpectedEvent; - is(event.type, "levelchange", "event.type"); - is(battery.level, capacity / 100, "battery.level"); - nextFunction(); + battery.onlevelchange = unexpectedEvent; + is(event.type, "levelchange", "event.type"); + is(battery.level, capacity / 100, "battery.level"); + nextFunction(); }; runEmulatorCmd("power capacity " + capacity); } diff --git a/dom/battery/test/marionette/test_battery_status_charging.js b/dom/battery/test/marionette/test_battery_status_charging.js index 714f73d10ec6..2d7469d9f340 100644 --- a/dom/battery/test/marionette/test_battery_status_charging.js +++ b/dom/battery/test/marionette/test_battery_status_charging.js @@ -3,20 +3,17 @@ MARIONETTE_TIMEOUT = 10000; -let battery = null; +let battery = window.navigator.battery; let fromStatus = "charging"; let fromCharging = true; function verifyInitialState() { - window.navigator.getBattery().then(function (b) { - battery = b; - ok(battery, "battery"); - ok(battery.charging, "battery.charging"); - runEmulatorCmd("power display", function (result) { - is(result.pop(), "OK", "power display successful"); - ok(result.indexOf("status: Charging") !== -1, "power status charging"); - setUp(); - }); + ok(battery, "battery"); + ok(battery.charging, "battery.charging"); + runEmulatorCmd("power display", function (result) { + is(result.pop(), "OK", "power display successful"); + ok(result.indexOf("status: Charging") !== -1, "power status charging"); + setUp(); }); } diff --git a/dom/battery/test/marionette/test_battery_status_discharging.js b/dom/battery/test/marionette/test_battery_status_discharging.js index 972c034927c9..b6a45f2b8467 100644 --- a/dom/battery/test/marionette/test_battery_status_discharging.js +++ b/dom/battery/test/marionette/test_battery_status_discharging.js @@ -3,20 +3,17 @@ MARIONETTE_TIMEOUT = 10000; -let battery = null; +let battery = window.navigator.battery; let fromStatus = "discharging"; let fromCharging = false; function verifyInitialState() { - window.navigator.getBattery().then(function (b) { - battery = b; - ok(battery, "battery"); - ok(battery.charging, "battery.charging"); - runEmulatorCmd("power display", function (result) { - is(result.pop(), "OK", "power display successful"); - ok(result.indexOf("status: Charging") !== -1, "power status charging"); - setUp(); - }); + ok(battery, "battery"); + ok(battery.charging, "battery.charging"); + runEmulatorCmd("power display", function (result) { + is(result.pop(), "OK", "power display successful"); + ok(result.indexOf("status: Charging") !== -1, "power status charging"); + setUp(); }); } diff --git a/dom/battery/test/marionette/test_battery_status_full.js b/dom/battery/test/marionette/test_battery_status_full.js index a636a6eaca9a..80d0fa1129f5 100644 --- a/dom/battery/test/marionette/test_battery_status_full.js +++ b/dom/battery/test/marionette/test_battery_status_full.js @@ -8,15 +8,12 @@ let fromStatus = "full"; let fromCharging = true; function verifyInitialState() { - window.navigator.getBattery().then(function (b) { - battery = b; - ok(battery, "battery"); - ok(battery.charging, "battery.charging"); - runEmulatorCmd("power display", function (result) { - is(result.pop(), "OK", "power display successful"); - ok(result.indexOf("status: Charging") !== -1, "power status charging"); - setUp(); - }); + ok(battery, "battery"); + ok(battery.charging, "battery.charging"); + runEmulatorCmd("power display", function (result) { + is(result.pop(), "OK", "power display successful"); + ok(result.indexOf("status: Charging") !== -1, "power status charging"); + setUp(); }); } diff --git a/dom/battery/test/marionette/test_battery_status_not_charging.js b/dom/battery/test/marionette/test_battery_status_not_charging.js index 9b7b38eeb72c..113017f76e41 100644 --- a/dom/battery/test/marionette/test_battery_status_not_charging.js +++ b/dom/battery/test/marionette/test_battery_status_not_charging.js @@ -8,15 +8,12 @@ let fromStatus = "not-charging"; let fromCharging = false; function verifyInitialState() { - window.navigator.getBattery().then(function (b) { - battery = b; - ok(battery, "battery"); - ok(battery.charging, "battery.charging"); - runEmulatorCmd("power display", function (result) { - is(result.pop(), "OK", "power display successful"); - ok(result.indexOf("status: Charging") !== -1, "power status charging"); - setUp(); - }); + ok(battery, "battery"); + ok(battery.charging, "battery.charging"); + runEmulatorCmd("power display", function (result) { + is(result.pop(), "OK", "power display successful"); + ok(result.indexOf("status: Charging") !== -1, "power status charging"); + setUp(); }); } diff --git a/dom/battery/test/marionette/test_battery_status_unknown.js b/dom/battery/test/marionette/test_battery_status_unknown.js index a86581e38176..42a315a04cb1 100644 --- a/dom/battery/test/marionette/test_battery_status_unknown.js +++ b/dom/battery/test/marionette/test_battery_status_unknown.js @@ -8,15 +8,12 @@ let fromStatus = "unknown"; let fromCharging = false; function verifyInitialState() { - window.navigator.getBattery().then(function (b) { - battery = b; - ok(battery, "battery"); - ok(battery.charging, "battery.charging"); - runEmulatorCmd("power display", function (result) { - is(result.pop(), "OK", "power display successful"); - ok(result.indexOf("status: Charging") !== -1, "power status charging"); - setUp(); - }); + ok(battery, "battery"); + ok(battery.charging, "battery.charging"); + runEmulatorCmd("power display", function (result) { + is(result.pop(), "OK", "power display successful"); + ok(result.indexOf("status: Charging") !== -1, "power status charging"); + setUp(); }); } diff --git a/dom/battery/test/marionette/test_deprecated_battery_level.js b/dom/battery/test/marionette/test_deprecated_battery_level.js deleted file mode 100644 index b344a26e6171..000000000000 --- a/dom/battery/test/marionette/test_deprecated_battery_level.js +++ /dev/null @@ -1,68 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 10000; - -let battery = window.navigator.battery; - -function verifyInitialState() { - ok(battery, "battery"); - is(battery.level, 0.5, "battery.level"); - runEmulatorCmd("power display", function (result) { - is(result.pop(), "OK", "power display successful"); - ok(result.indexOf("capacity: 50") !== -1, "power capacity"); - setUp(); - }); -} - -function unexpectedEvent(event) { - ok(false, "Unexpected " + event.type + " event"); -} - -function setUp() { - battery.onchargingchange = unexpectedEvent; - battery.onlevelchange = unexpectedEvent; - levelUp(); -} - -function changeCapacity(capacity, changeExpected, nextFunction) { - log("Changing power capacity to " + capacity); - if (changeExpected) { - battery.onlevelchange = function (event) { - battery.onlevelchange = unexpectedEvent; - is(event.type, "levelchange", "event.type"); - is(battery.level, capacity / 100, "battery.level"); - nextFunction(); - }; - runEmulatorCmd("power capacity " + capacity); - } - else { - runEmulatorCmd("power capacity " + capacity, function () { - is(battery.level, capacity / 100, "battery.level"); - nextFunction(); - }); - } -} - -function levelUp() { - changeCapacity("90", true, levelDown); -} - -function levelDown() { - changeCapacity("10", true, levelSame); -} - -function levelSame() { - changeCapacity("10", false, cleanUp); -} - -function cleanUp() { - battery.onchargingchange = null; - battery.onlevelchange = function () { - battery.onlevelchange = null; - finish(); - }; - runEmulatorCmd("power capacity 50"); -} - -verifyInitialState(); diff --git a/dom/battery/test/marionette/test_deprecated_battery_status_charging.js b/dom/battery/test/marionette/test_deprecated_battery_status_charging.js deleted file mode 100644 index 2d7469d9f340..000000000000 --- a/dom/battery/test/marionette/test_deprecated_battery_status_charging.js +++ /dev/null @@ -1,85 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 10000; - -let battery = window.navigator.battery; -let fromStatus = "charging"; -let fromCharging = true; - -function verifyInitialState() { - ok(battery, "battery"); - ok(battery.charging, "battery.charging"); - runEmulatorCmd("power display", function (result) { - is(result.pop(), "OK", "power display successful"); - ok(result.indexOf("status: Charging") !== -1, "power status charging"); - setUp(); - }); -} - -function unexpectedEvent(event) { - ok(false, "Unexpected " + event.type + " event"); -} - -function setUp() { - battery.onchargingchange = unexpectedEvent; - battery.onlevelchange = unexpectedEvent; - toDischarging(); -} - -function resetStatus(charging, nextFunction) { - log("Resetting power status to " + fromStatus); - if (charging !== fromCharging) { - battery.onchargingchange = function () { - battery.onchargingchange = unexpectedEvent; - nextFunction(); - }; - runEmulatorCmd("power status " + fromStatus); - } - else { - runEmulatorCmd("power status " + fromStatus, nextFunction); - } -} - -function changeStatus(toStatus, toCharging, nextFunction) { - log("Changing power status to " + toStatus); - if (fromCharging !== toCharging) { - battery.onchargingchange = function (event) { - battery.onchargingchange = unexpectedEvent; - is(event.type, "chargingchange", "event type"); - is(battery.charging, toCharging, "battery.charging"); - resetStatus(toCharging, nextFunction); - }; - runEmulatorCmd("power status " + toStatus); - } - else { - runEmulatorCmd("power status " + toStatus, function () { - is(battery.charging, toCharging, "battery.charging"); - resetStatus(toCharging, nextFunction); - }); - } -} - -function toDischarging() { - changeStatus("discharging", false, toFull); -} - -function toFull() { - changeStatus("full", true, toNotCharging); -} - -function toNotCharging() { - changeStatus("not-charging", false, toUnknown); -} - -function toUnknown() { - changeStatus("unknown", false, cleanUp); -} - -function cleanUp() { - battery.onchargingchange = null; - battery.onlevelchange = null; - finish(); -} - -verifyInitialState(); diff --git a/dom/battery/test/marionette/test_deprecated_battery_status_discharging.js b/dom/battery/test/marionette/test_deprecated_battery_status_discharging.js deleted file mode 100644 index b6a45f2b8467..000000000000 --- a/dom/battery/test/marionette/test_deprecated_battery_status_discharging.js +++ /dev/null @@ -1,93 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 10000; - -let battery = window.navigator.battery; -let fromStatus = "discharging"; -let fromCharging = false; - -function verifyInitialState() { - ok(battery, "battery"); - ok(battery.charging, "battery.charging"); - runEmulatorCmd("power display", function (result) { - is(result.pop(), "OK", "power display successful"); - ok(result.indexOf("status: Charging") !== -1, "power status charging"); - setUp(); - }); -} - -function unexpectedEvent(event) { - ok(false, "Unexpected " + event.type + " event"); -} - -function setUp() { - battery.onchargingchange = function () { - battery.onchargingchange = unexpectedEvent; - toCharging(); - }; - battery.onlevelchange = unexpectedEvent; - log("Changing power status to " + fromStatus); - runEmulatorCmd("power status " + fromStatus); -} - -function resetStatus(charging, nextFunction) { - log("Resetting power status to " + fromStatus); - if (charging !== fromCharging) { - battery.onchargingchange = function () { - battery.onchargingchange = unexpectedEvent; - nextFunction(); - }; - runEmulatorCmd("power status " + fromStatus); - } - else { - runEmulatorCmd("power status " + fromStatus, nextFunction); - } -} - -function changeStatus(toStatus, toCharging, nextFunction) { - log("Changing power status to " + toStatus); - if (fromCharging !== toCharging) { - battery.onchargingchange = function (event) { - battery.onchargingchange = unexpectedEvent; - is(event.type, "chargingchange", "event type"); - is(battery.charging, toCharging, "battery.charging"); - resetStatus(toCharging, nextFunction); - }; - runEmulatorCmd("power status " + toStatus); - } - else { - runEmulatorCmd("power status " + toStatus, function () { - is(battery.charging, toCharging, "battery.charging"); - resetStatus(toCharging, nextFunction); - }); - } -} - -function toCharging() { - changeStatus("charging", true, toFull); -} - -function toFull() { - changeStatus("full", true, toNotCharging); -} - -function toNotCharging() { - changeStatus("not-charging", false, toUnknown); -} - -function toUnknown() { - changeStatus("unknown", false, cleanUp); -} - -function cleanUp() { - battery.onchargingchange = function () { - battery.onchargingchange = null; - finish(); - }; - battery.onlevelchange = null; - log("Resetting power status to charging"); - runEmulatorCmd("power status charging"); -} - -verifyInitialState(); diff --git a/dom/battery/test/marionette/test_deprecated_battery_status_full.js b/dom/battery/test/marionette/test_deprecated_battery_status_full.js deleted file mode 100644 index 80d0fa1129f5..000000000000 --- a/dom/battery/test/marionette/test_deprecated_battery_status_full.js +++ /dev/null @@ -1,87 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 10000; - -let battery = window.navigator.battery; -let fromStatus = "full"; -let fromCharging = true; - -function verifyInitialState() { - ok(battery, "battery"); - ok(battery.charging, "battery.charging"); - runEmulatorCmd("power display", function (result) { - is(result.pop(), "OK", "power display successful"); - ok(result.indexOf("status: Charging") !== -1, "power status charging"); - setUp(); - }); -} - -function unexpectedEvent(event) { - ok(false, "Unexpected " + event.type + " event"); -} - -function setUp() { - battery.onchargingchange = unexpectedEvent; - battery.onlevelchange = unexpectedEvent; - log("Changing power status to " + fromStatus); - runEmulatorCmd("power status " + fromStatus, toCharging); -} - -function resetStatus(charging, nextFunction) { - log("Resetting power status to " + fromStatus); - if (charging !== fromCharging) { - battery.onchargingchange = function () { - battery.onchargingchange = unexpectedEvent; - nextFunction(); - }; - runEmulatorCmd("power status " + fromStatus); - } - else { - runEmulatorCmd("power status " + fromStatus, nextFunction); - } -} - -function changeStatus(toStatus, toCharging, nextFunction) { - log("Changing power status to " + toStatus); - if (fromCharging !== toCharging) { - battery.onchargingchange = function (event) { - battery.onchargingchange = unexpectedEvent; - is(event.type, "chargingchange", "event type"); - is(battery.charging, toCharging, "battery.charging"); - resetStatus(toCharging, nextFunction); - }; - runEmulatorCmd("power status " + toStatus); - } - else { - runEmulatorCmd("power status " + toStatus, function () { - is(battery.charging, toCharging, "battery.charging"); - resetStatus(toCharging, nextFunction); - }); - } -} - -function toCharging() { - changeStatus("charging", true, toDischarging); -} - -function toDischarging() { - changeStatus("discharging", false, toNotCharging); -} - -function toNotCharging() { - changeStatus("not-charging", false, toUnknown); -} - -function toUnknown() { - changeStatus("unknown", false, cleanUp); -} - -function cleanUp() { - battery.onchargingchange = null; - battery.onlevelchange = null; - log("Resetting power status to charging"); - runEmulatorCmd("power status charging", finish); -} - -verifyInitialState(); diff --git a/dom/battery/test/marionette/test_deprecated_battery_status_not_charging.js b/dom/battery/test/marionette/test_deprecated_battery_status_not_charging.js deleted file mode 100644 index 113017f76e41..000000000000 --- a/dom/battery/test/marionette/test_deprecated_battery_status_not_charging.js +++ /dev/null @@ -1,93 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 10000; - -let battery = window.navigator.battery; -let fromStatus = "not-charging"; -let fromCharging = false; - -function verifyInitialState() { - ok(battery, "battery"); - ok(battery.charging, "battery.charging"); - runEmulatorCmd("power display", function (result) { - is(result.pop(), "OK", "power display successful"); - ok(result.indexOf("status: Charging") !== -1, "power status charging"); - setUp(); - }); -} - -function unexpectedEvent(event) { - ok(false, "Unexpected " + event.type + " event"); -} - -function setUp() { - battery.onchargingchange = function () { - battery.onchargingchange = unexpectedEvent; - toCharging(); - }; - battery.onlevelchange = unexpectedEvent; - log("Changing power status to " + fromStatus); - runEmulatorCmd("power status " + fromStatus); -} - -function resetStatus(charging, nextFunction) { - log("Resetting power status to " + fromStatus); - if (charging !== fromCharging) { - battery.onchargingchange = function () { - battery.onchargingchange = unexpectedEvent; - nextFunction(); - }; - runEmulatorCmd("power status " + fromStatus); - } - else { - runEmulatorCmd("power status " + fromStatus, nextFunction); - } -} - -function changeStatus(toStatus, toCharging, nextFunction) { - log("Changing power status to " + toStatus); - if (fromCharging !== toCharging) { - battery.onchargingchange = function (event) { - battery.onchargingchange = unexpectedEvent; - is(event.type, "chargingchange", "event type"); - is(battery.charging, toCharging, "battery.charging"); - resetStatus(toCharging, nextFunction); - }; - runEmulatorCmd("power status " + toStatus); - } - else { - runEmulatorCmd("power status " + toStatus, function () { - is(battery.charging, toCharging, "battery.charging"); - resetStatus(toCharging, nextFunction); - }); - } -} - -function toCharging() { - changeStatus("charging", true, toDischarging); -} - -function toDischarging() { - changeStatus("discharging", false, toFull); -} - -function toFull() { - changeStatus("full", true, toUnknown); -} - -function toUnknown() { - changeStatus("unknown", false, cleanUp); -} - -function cleanUp() { - battery.onchargingchange = function () { - battery.onchargingchange = null; - finish(); - }; - battery.onlevelchange = null; - log("Resetting power status to charging"); - runEmulatorCmd("power status charging"); -} - -verifyInitialState(); diff --git a/dom/battery/test/marionette/test_deprecated_battery_unknown.js b/dom/battery/test/marionette/test_deprecated_battery_unknown.js deleted file mode 100644 index 42a315a04cb1..000000000000 --- a/dom/battery/test/marionette/test_deprecated_battery_unknown.js +++ /dev/null @@ -1,93 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 10000; - -let battery = window.navigator.battery; -let fromStatus = "unknown"; -let fromCharging = false; - -function verifyInitialState() { - ok(battery, "battery"); - ok(battery.charging, "battery.charging"); - runEmulatorCmd("power display", function (result) { - is(result.pop(), "OK", "power display successful"); - ok(result.indexOf("status: Charging") !== -1, "power status charging"); - setUp(); - }); -} - -function unexpectedEvent(event) { - ok(false, "Unexpected " + event.type + " event"); -} - -function setUp() { - battery.onchargingchange = function () { - battery.onchargingchange = unexpectedEvent; - toCharging(); - }; - battery.onlevelchange = unexpectedEvent; - log("Changing power status to " + fromStatus); - runEmulatorCmd("power status " + fromStatus); -} - -function resetStatus(charging, nextFunction) { - log("Resetting power status to " + fromStatus); - if (charging !== fromCharging) { - battery.onchargingchange = function () { - battery.onchargingchange = unexpectedEvent; - nextFunction(); - }; - runEmulatorCmd("power status " + fromStatus); - } - else { - runEmulatorCmd("power status " + fromStatus, nextFunction); - } -} - -function changeStatus(toStatus, toCharging, nextFunction) { - log("Changing power status to " + toStatus); - if (fromCharging !== toCharging) { - battery.onchargingchange = function (event) { - battery.onchargingchange = unexpectedEvent; - is(event.type, "chargingchange", "event type"); - is(battery.charging, toCharging, "battery.charging"); - resetStatus(toCharging, nextFunction); - }; - runEmulatorCmd("power status " + toStatus); - } - else { - runEmulatorCmd("power status " + toStatus, function () { - is(battery.charging, toCharging, "battery.charging"); - resetStatus(toCharging, nextFunction); - }); - } -} - -function toCharging() { - changeStatus("charging", true, toDischarging); -} - -function toDischarging() { - changeStatus("discharging", false, toFull); -} - -function toFull() { - changeStatus("full", true, toNotCharging); -} - -function toNotCharging() { - changeStatus("not-charging", false, cleanUp); -} - -function cleanUp() { - battery.onchargingchange = function () { - battery.onchargingchange = null; - finish(); - }; - battery.onlevelchange = null; - log("Resetting power status to charging"); - runEmulatorCmd("power status charging"); -} - -verifyInitialState(); diff --git a/dom/battery/test/mochitest.ini b/dom/battery/test/mochitest.ini index 92334129fa7c..242a02a8677f 100644 --- a/dom/battery/test/mochitest.ini +++ b/dom/battery/test/mochitest.ini @@ -1,8 +1,2 @@ [test_battery_basics.html] skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) -[test_battery_charging.html] -skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) -[test_battery_discharging.html] -skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) -[test_deprecated_battery_basics.html] -skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) diff --git a/dom/battery/test/test_battery_basics.html b/dom/battery/test/test_battery_basics.html index 825d2affeb93..14b334481e6a 100644 --- a/dom/battery/test/test_battery_basics.html +++ b/dom/battery/test/test_battery_basics.html @@ -12,23 +12,20 @@
 
 
diff --git a/dom/battery/test/test_battery_charging.html b/dom/battery/test/test_battery_charging.html deleted file mode 100644 index f95d4252c623..000000000000 --- a/dom/battery/test/test_battery_charging.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - Test for Battery API - - - - -

- -
-
-
- - diff --git a/dom/battery/test/test_battery_discharging.html b/dom/battery/test/test_battery_discharging.html deleted file mode 100644 index cff4ced67ae5..000000000000 --- a/dom/battery/test/test_battery_discharging.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - Test for Battery API - - - - -

- -
-
-
- - diff --git a/dom/battery/test/test_deprecated_battery_basics.html b/dom/battery/test/test_deprecated_battery_basics.html deleted file mode 100644 index a75267c7d43b..000000000000 --- a/dom/battery/test/test_deprecated_battery_basics.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - Test for Battery API - - - - -

- -
-
-
- - diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl index d581e9f8971f..e3177895afc5 100644 --- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -125,15 +125,14 @@ interface NavigatorGeolocation { Navigator implements NavigatorGeolocation; // http://www.w3.org/TR/battery-status/#navigatorbattery-interface -partial interface Navigator { - [Throws, Pref="dom.battery.enabled"] - Promise getBattery(); - // Deprecated. Use getBattery() instead. - // XXXbz Per spec this should be non-nullable, but we return null in - // torn-down windows. See bug 884925. - [Throws, Pref="dom.battery.enabled", BinaryName="deprecatedBattery"] - readonly attribute BatteryManager? battery; +[NoInterfaceObject] +interface NavigatorBattery { + // XXXbz Per spec this should be non-nullable, but we return null in + // torn-down windows. See bug 884925. + [Throws, Pref="dom.battery.enabled"] + readonly attribute BatteryManager? battery; }; +Navigator implements NavigatorBattery; // https://wiki.mozilla.org/WebAPI/DataStore [NoInterfaceObject, diff --git a/toolkit/modules/Battery.jsm b/toolkit/modules/Battery.jsm index 2b0f9abcb72e..486a4f70d670 100644 --- a/toolkit/modules/Battery.jsm +++ b/toolkit/modules/Battery.jsm @@ -5,12 +5,12 @@ "use strict"; -/** This module wraps around navigator.getBattery (https://developer.mozilla.org/en-US/docs/Web/API/Navigator.getBattery). +/** This module wraps around navigator.battery (https://developer.mozilla.org/en-US/docs/Web/API/Navigator.battery). * and provides a framework for spoofing battery values in test code. * To spoof the battery values, set `Debugging.fake = true` after exporting this with a BackstagePass, - * after which you can spoof a property yb setting the relevant property of the BatteryManager object. + * after which you can spoof a property yb setting the relevant property of the Battery object. */ -this.EXPORTED_SYMBOLS = ["GetBattery", "Battery"]; +this.EXPORTED_SYMBOLS = ["Battery"]; const Ci = Components.interfaces; const Cc = Components.classes; @@ -40,17 +40,6 @@ this.Debugging = { fake: false } -this.GetBattery = function () { - return new Services.appShell.hiddenDOMWindow.Promise(function (resolve, reject) { - // Return fake values if spoofing is enabled, otherwise fetch the real values from the BatteryManager API - if (Debugging.fake) { - resolve(gFakeBattery); - return; - } - Services.appShell.hiddenDOMWindow.navigator.getBattery().then(resolve, reject); - }); -}; - this.Battery = {}; for (let k of ["charging", "chargingTime", "dischargingTime", "level"]) { @@ -65,9 +54,9 @@ for (let k of ["charging", "chargingTime", "dischargingTime", "level"]) { }, set: function(fakeSetting) { if (!Debugging.fake) { - throw new Error("Tried to set fake battery value when battery spoofing was disabled"); + throw new Error("Tried to set fake battery value when battery spoofing was disabled"); } gFakeBattery[prop] = fakeSetting; } }) -} +} \ No newline at end of file diff --git a/toolkit/modules/tests/browser/browser_Battery.js b/toolkit/modules/tests/browser/browser_Battery.js index 9a4c4f8fbae1..d9aa0883655e 100644 --- a/toolkit/modules/tests/browser/browser_Battery.js +++ b/toolkit/modules/tests/browser/browser_Battery.js @@ -6,11 +6,8 @@ let imported = Components.utils.import("resource://gre/modules/Battery.jsm", thi Cu.import("resource://gre/modules/Services.jsm", this); function test() { - waitForExplicitFinish(); - is(imported.Debugging.fake, false, "Battery spoofing is initially false") - // begin deprecated battery API testing for (let k of ["charging", "chargingTime", "dischargingTime", "level"]) { Assert.throws(() => Battery[k] = 10, "Setting battery " + k + "preference without spoofing enabled should throw"); ok(Battery[k] == Services.appShell.hiddenDOMWindow.navigator.battery[k], "Battery "+ k + " is correctly set"); @@ -30,36 +27,4 @@ function test() { ok(!Battery.charging, "Test for charging setter"); is(Battery.dischargingTime, 50, "Test for dischargingTime setter"); is(Battery.level, 0.7, "Test for level setter"); - - imported.Debugging.fake = false; - // end deprecated battery API testing - - GetBattery().then(function (battery) { - for (let k of ["charging", "chargingTime", "dischargingTime", "level"]) { - let backup = battery[k]; - battery[k] = "__magic__"; - is(battery[k], backup, "Setting battery " + k + "preference without spoofing enabled should fail"); - } - - imported.Debugging.fake = true; - - // reload again to get the fake one - GetBattery().then(function (battery) { - battery.charging = true; - battery.chargingTime = 100; - battery.level = 0.5; - ok(battery.charging, "Test for charging setter"); - is(battery.chargingTime, 100, "Test for chargingTime setter"); - is(battery.level, 0.5, "Test for level setter"); - - battery.charging = false; - battery.dischargingTime = 50; - battery.level = 0.7; - ok(!battery.charging, "Test for charging setter"); - is(battery.dischargingTime, 50, "Test for dischargingTime setter"); - is(battery.level, 0.7, "Test for level setter"); - - finish(); - }); - }); -} +} \ No newline at end of file From 8af20dde134fc2e3b93a451c961277b9e55f4cbc Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Fri, 21 Aug 2015 09:17:18 +1000 Subject: [PATCH 058/208] Bug 1189655 - Define MOZ_HAVE_CXX11_CONSTEXPR on VS2015 or later. r=Waldo --- dom/html/HTMLTrackElement.cpp | 2 +- mfbt/Attributes.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dom/html/HTMLTrackElement.cpp b/dom/html/HTMLTrackElement.cpp index bd375fb5eef4..abdda2fa8c2f 100644 --- a/dom/html/HTMLTrackElement.cpp +++ b/dom/html/HTMLTrackElement.cpp @@ -70,7 +70,7 @@ static MOZ_CONSTEXPR nsAttrValue::EnumTable kKindTable[] = { }; // The default value for kKindTable is "subtitles" -static MOZ_CONSTEXPR const char* kKindTableDefaultString = kKindTable->tag; +static MOZ_CONSTEXPR const char* kKindTableDefaultString = kKindTable[0].tag; /** HTMLTrackElement */ HTMLTrackElement::HTMLTrackElement(already_AddRefed& aNodeInfo) diff --git a/mfbt/Attributes.h b/mfbt/Attributes.h index aa31d1729106..252346519a02 100644 --- a/mfbt/Attributes.h +++ b/mfbt/Attributes.h @@ -53,6 +53,7 @@ # define MOZ_HAVE_NEVER_INLINE __declspec(noinline) # define MOZ_HAVE_NORETURN __declspec(noreturn) # if _MSC_VER >= 1900 +# define MOZ_HAVE_CXX11_CONSTEXPR # define MOZ_HAVE_EXPLICIT_CONVERSION # endif # ifdef __clang__ From b70991305b6e0723abb5decac292b9fabafbc9d4 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Fri, 21 Aug 2015 09:17:18 +1000 Subject: [PATCH 059/208] Bug 1180574 - Retry once if we open a window in fullscreen mode in fullscree-api-race test. r=smaug --- dom/html/test/test_fullscreen-api-race.html | 61 ++++++++++----------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/dom/html/test/test_fullscreen-api-race.html b/dom/html/test/test_fullscreen-api-race.html index 6140b971f0ef..49d47f4ed68e 100644 --- a/dom/html/test/test_fullscreen-api-race.html +++ b/dom/html/test/test_fullscreen-api-race.html @@ -72,46 +72,21 @@ } ]; -const DISABLE_LIST = [ - // Bug 1180574 - { openWinFunc: "openNewWindow", - actionFunc: "navigate", - platform: "Linux i686" } -]; - function* testGenerator() { for (var openWinFunc of OPEN_WINDOW_FUNCS) { for (var actionFunc of ACTION_FUNCS) { - var skipTest = false; - for (var disabledItem of DISABLE_LIST) { - if (openWinFunc.name == disabledItem.openWinFunc && - actionFunc.name == disabledItem.actionFunc && - navigator.platform == disabledItem.platform) { - skipTest = true; - break; - } - } - if (!skipTest) { - info(`Testing ${openWinFunc.name}, ${actionFunc.name}`); - yield { openWinFunc: openWinFunc, actionFunc: actionFunc }; - } + info(`Testing ${openWinFunc.name}, ${actionFunc.name}`); + yield { openWinFunc: openWinFunc, actionFunc: actionFunc }; } } } -var tests = testGenerator(); - -function next() { - var test = tests.next().value; - if (!test) { - SimpleTest.finish(); - return; - } +function runTest(test) { var win = test.openWinFunc(); - new Promise(resolve => { + return new Promise(resolve => { SimpleTest.waitForFocus(resolve, win, true); }).then(() => { - return new Promise(resolve => { + return new Promise((resolve, reject) => { var retried = false; function listener(evt) { if (!retried && evt.type == "mozfullscreenerror") { @@ -129,6 +104,12 @@ ok(win.fullScreen, "The window should be in fullscreen"); test.actionFunc(win).then(resolve); } + if (win.fullScreen) { + todo(false, "Should not open in fullscreen mode"); + win.close(); + reject(); + return; + } info("About to enter fullscreen"); win.addEventListener("mozfullscreenchange", listener); win.addEventListener("mozfullscreenerror", listener); @@ -136,10 +117,28 @@ }); }).then(() => { ok(win.closed, "The window should have been closed"); - SimpleTest.waitForFocus(next); }); } +var tests = testGenerator(); + +function next() { + var test = tests.next().value; + if (test) { + runTest(test).catch(() => { + return new Promise(resolve => { + SimpleTest.waitForFocus(resolve); + }).then(() => runTest(test)); + }).catch(() => { + ok(false, "Fail to run test " + + `${test.openWinFunc.name}, ${test.actionFunc.name}`); + }).then(() => SimpleTest.waitForFocus(next)); + } else { + SimpleTest.finish(); + return; + } +} + From 669e16ec73bf9e2a5f7e4645e3a69ecd2d9ae46c Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Thu, 20 Aug 2015 16:19:39 -0700 Subject: [PATCH 060/208] Backed out changeset f51c32dbea00 (bug 875573) for test_can_play_type_mpeg.html orange --- dom/media/DecoderTraits.cpp | 3 +-- dom/media/fmp4/MP4Decoder.cpp | 2 +- dom/media/test/test_can_play_type_mpeg.html | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/dom/media/DecoderTraits.cpp b/dom/media/DecoderTraits.cpp index e7af7c56b2df..8700fe3e16b2 100644 --- a/dom/media/DecoderTraits.cpp +++ b/dom/media/DecoderTraits.cpp @@ -226,7 +226,6 @@ static const char* const gOmxTypes[] = { "audio/3gpp", "audio/flac", "video/mp4", - "video/x-m4v", "video/3gpp", "video/3gpp2", "video/quicktime", @@ -333,7 +332,7 @@ IsAndroidMediaType(const nsACString& aType) } static const char* supportedTypes[] = { - "audio/mpeg", "audio/mp4", "video/mp4", "video/x-m4v", nullptr + "audio/mpeg", "audio/mp4", "video/mp4", nullptr }; return CodecListContains(supportedTypes, aType); } diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index 6baaa093526b..11ccdaeb063e 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -148,7 +148,7 @@ MP4Decoder::CanHandleMediaType(const nsACString& aType, } #endif - if ((!aType.EqualsASCII("video/mp4") && !aType.EqualsASCII("video/x-m4v")) || + if (!aType.EqualsASCII("video/mp4") || !MP4Decoder::CanCreateH264Decoder()) { return false; } diff --git a/dom/media/test/test_can_play_type_mpeg.html b/dom/media/test/test_can_play_type_mpeg.html index 8b822644fc9d..bb03d7ab948c 100644 --- a/dom/media/test/test_can_play_type_mpeg.html +++ b/dom/media/test/test_can_play_type_mpeg.html @@ -26,13 +26,11 @@ } check("video/mp4", "maybe"); - check("video/x-m4v", "maybe"); check("audio/mp4", "maybe"); check("audio/x-m4a", "maybe"); // Not the MIME type that other browsers respond to, so we won't either. check("audio/m4a", ""); - check("video/m4v", ""); // Only Safari responds affirmatively to "audio/aac", // so we'll let x-m4a cover aac support. check("audio/aac", ""); From 81ebc42663165fa0d5abbfb7669b2db69e2ffb7f Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Tue, 18 Aug 2015 11:48:38 +1200 Subject: [PATCH 061/208] bug 1196111 don't keep AudioContext alive from AudioBuffer r=baku AudioBuffers are often generated from OfflineAudioContext to be used in other contexts, when the OfflineAudioContext is no longer required. --- dom/media/webaudio/AudioBuffer.cpp | 4 +--- dom/media/webaudio/AudioBuffer.h | 7 ++++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/dom/media/webaudio/AudioBuffer.cpp b/dom/media/webaudio/AudioBuffer.cpp index 069b8ae9f9cf..04cd63094e58 100644 --- a/dom/media/webaudio/AudioBuffer.cpp +++ b/dom/media/webaudio/AudioBuffer.cpp @@ -20,14 +20,12 @@ namespace dom { NS_IMPL_CYCLE_COLLECTION_CLASS(AudioBuffer) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioBuffer) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext) NS_IMPL_CYCLE_COLLECTION_UNLINK(mJSChannels) NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER tmp->ClearJSChannels(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AudioBuffer) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END @@ -43,7 +41,7 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AudioBuffer, Release) AudioBuffer::AudioBuffer(AudioContext* aContext, uint32_t aNumberOfChannels, uint32_t aLength, float aSampleRate) - : mContext(aContext), + : mOwnerWindow(do_GetWeakReference(aContext->GetOwner())), mLength(aLength), mSampleRate(aSampleRate) { diff --git a/dom/media/webaudio/AudioBuffer.h b/dom/media/webaudio/AudioBuffer.h index 92a52149ef75..478c4c1fc1e2 100644 --- a/dom/media/webaudio/AudioBuffer.h +++ b/dom/media/webaudio/AudioBuffer.h @@ -43,9 +43,10 @@ class AudioBuffer final : public nsWrapperCache NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AudioBuffer) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AudioBuffer) - AudioContext* GetParentObject() const + nsPIDOMWindow* GetParentObject() const { - return mContext; + nsCOMPtr parentObject = do_QueryReferent(mOwnerWindow); + return parentObject; } virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; @@ -104,7 +105,7 @@ class AudioBuffer final : public nsWrapperCache bool RestoreJSChannelData(JSContext* aJSContext); void ClearJSChannels(); - nsRefPtr mContext; + nsWeakPtr mOwnerWindow; // Float32Arrays nsAutoTArray, 2> mJSChannels; From 7c409e44f8d3b1c7ee2e8a68a33fac11fc406703 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Thu, 20 Aug 2015 09:52:56 +1200 Subject: [PATCH 062/208] bug 1196632 pass ownership of runnables to NS_DispatchToMainThread r=jesup The already_AddRefed&& overload saves some ref-counting and provides an assertion if called too late in shutdown. --- dom/media/MediaStreamGraph.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dom/media/MediaStreamGraph.cpp b/dom/media/MediaStreamGraph.cpp index 4a9de4b79840..5466ba970abb 100644 --- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -1716,7 +1716,7 @@ MediaStreamGraphImpl::RunInStableState(bool aSourceIsMSG) mLifecycleState = LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN; LIFECYCLE_LOG("Sending MediaStreamGraphShutDownRunnable %p", this); nsCOMPtr event = new MediaStreamGraphShutDownRunnable(this ); - NS_DispatchToMainThread(event); + NS_DispatchToMainThread(event.forget()); LIFECYCLE_LOG("Disconnecting MediaStreamGraph %p", this); MediaStreamGraphImpl* graph; @@ -1787,7 +1787,7 @@ MediaStreamGraphImpl::RunInStableState(bool aSourceIsMSG) // we have outstanding DOM objects that may need it. mLifecycleState = LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN; nsCOMPtr event = new MediaStreamGraphShutDownRunnable(this); - NS_DispatchToMainThread(event); + NS_DispatchToMainThread(event.forget()); } mDetectedNotRunning = mLifecycleState > LIFECYCLE_RUNNING; @@ -1846,7 +1846,7 @@ MediaStreamGraphImpl::EnsureStableStateEventPosted() return; mPostedRunInStableStateEvent = true; nsCOMPtr event = new MediaStreamGraphStableStateRunnable(this, true); - NS_DispatchToMainThread(event); + NS_DispatchToMainThread(event.forget()); } void @@ -2411,7 +2411,7 @@ MediaStream::AddMainThreadListener(MainThreadMediaStreamListener* aListener) }; nsRefPtr runnable = new NotifyRunnable(this); - if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable)))) { + if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable.forget())))) { return; } @@ -3218,11 +3218,11 @@ MediaStreamGraph::NotifyWhenGraphStarted(AudioNodeStream* aStream) if (graphImpl->CurrentDriver()->AsAudioCallbackDriver()) { nsCOMPtr event = new dom::StateChangeTask( mStream->AsAudioNodeStream(), nullptr, AudioContextState::Running); - NS_DispatchToMainThread(event); + NS_DispatchToMainThread(event.forget()); } else { nsCOMPtr event = new GraphStartedRunnable( mStream->AsAudioNodeStream(), mStream->Graph()); - NS_DispatchToMainThread(event); + NS_DispatchToMainThread(event.forget()); } } virtual void RunDuringShutdown() @@ -3342,7 +3342,7 @@ MediaStreamGraphImpl::AudioContextOperationCompleted(MediaStream* aStream, nsCOMPtr event = new dom::StateChangeTask( aStream->AsAudioNodeStream(), aPromise, state); - NS_DispatchToMainThread(event); + NS_DispatchToMainThread(event.forget()); } void From d7162850e8fadbfdd322fce3c52f969b38064c38 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Thu, 20 Aug 2015 17:57:42 -0700 Subject: [PATCH 063/208] Bug 1196308 - Delete Software Compositor Scheduler. r=sotaro --- gfx/layers/ipc/CompositorParent.cpp | 223 ++++++++-------------------- gfx/layers/ipc/CompositorParent.h | 99 +++++------- 2 files changed, 96 insertions(+), 226 deletions(-) diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 578ad6a8ca34..eb7b7bc99000 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -224,81 +224,14 @@ static void SetThreadPriority() hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR); } -CompositorScheduler::CompositorScheduler(CompositorParent* aCompositorParent) - : mCompositorParent(aCompositorParent) - , mCurrentCompositeTask(nullptr) -{ -} - -CompositorScheduler::~CompositorScheduler() -{ - MOZ_ASSERT(!mCompositorParent); -} - -void -CompositorScheduler::CancelCurrentCompositeTask() -{ - if (mCurrentCompositeTask) { - mCurrentCompositeTask->Cancel(); - mCurrentCompositeTask = nullptr; - } -} - -void -CompositorScheduler::ScheduleTask(CancelableTask* aTask, int aTime) -{ - MOZ_ASSERT(CompositorParent::CompositorLoop()); - MOZ_ASSERT(aTime >= 0); - CompositorParent::CompositorLoop()->PostDelayedTask(FROM_HERE, aTask, aTime); -} - -void -CompositorScheduler::ResumeComposition() -{ - mLastCompose = TimeStamp::Now(); - ComposeToTarget(nullptr); -} - -void -CompositorScheduler::ForceComposeToTarget(gfx::DrawTarget* aTarget, const IntRect* aRect) -{ - mLastCompose = TimeStamp::Now(); - ComposeToTarget(aTarget, aRect); -} - -void -CompositorScheduler::ComposeToTarget(gfx::DrawTarget* aTarget, const IntRect* aRect) -{ - MOZ_ASSERT(CompositorParent::IsInCompositorThread()); - MOZ_ASSERT(mCompositorParent); - mCompositorParent->CompositeToTarget(aTarget, aRect); -} - -void -CompositorScheduler::Destroy() -{ - MOZ_ASSERT(CompositorParent::IsInCompositorThread()); - CancelCurrentCompositeTask(); - mCompositorParent = nullptr; -} - -CompositorSoftwareTimerScheduler::CompositorSoftwareTimerScheduler(CompositorParent* aCompositorParent) - : CompositorScheduler(aCompositorParent) -{ -} - -CompositorSoftwareTimerScheduler::~CompositorSoftwareTimerScheduler() -{ - MOZ_ASSERT(!mCurrentCompositeTask); -} - -// Used when layout.frame_rate is -1. Needs to be kept in sync with -// DEFAULT_FRAME_RATE in nsRefreshDriver.cpp. -static const int32_t kDefaultFrameRate = 60; - +#ifdef COMPOSITOR_PERFORMANCE_WARNING static int32_t CalculateCompositionFrameRate() { + // Used when layout.frame_rate is -1. Needs to be kept in sync with + // DEFAULT_FRAME_RATE in nsRefreshDriver.cpp. + // TODO: This should actually return the vsync rate. + const int32_t defaultFrameRate = 60; int32_t compositionFrameRatePref = gfxPrefs::LayersCompositionFrameRate(); if (compositionFrameRatePref < 0) { // Use the same frame rate for composition as for layout. @@ -306,68 +239,13 @@ CalculateCompositionFrameRate() if (layoutFrameRatePref < 0) { // TODO: The main thread frame scheduling code consults the actual // monitor refresh rate in this case. We should do the same. - return kDefaultFrameRate; + return defaultFrameRate; } return layoutFrameRatePref; } return compositionFrameRatePref; } - -void -CompositorSoftwareTimerScheduler::ScheduleComposition() -{ - if (mCurrentCompositeTask) { - return; - } - - bool initialComposition = mLastCompose.IsNull(); - TimeDuration delta; - if (!initialComposition) { - delta = TimeStamp::Now() - mLastCompose; - } - - int32_t rate = CalculateCompositionFrameRate(); - - // If rate == 0 (ASAP mode), minFrameDelta must be 0 so there's no delay. - TimeDuration minFrameDelta = TimeDuration::FromMilliseconds( - rate == 0 ? 0.0 : std::max(0.0, 1000.0 / rate)); - - mCurrentCompositeTask = NewRunnableMethod(this, - &CompositorSoftwareTimerScheduler::CallComposite); - - if (!initialComposition && delta < minFrameDelta) { - TimeDuration delay = minFrameDelta - delta; -#ifdef COMPOSITOR_PERFORMANCE_WARNING - mExpectedComposeStartTime = TimeStamp::Now() + delay; -#endif - ScheduleTask(mCurrentCompositeTask, delay.ToMilliseconds()); - } else { -#ifdef COMPOSITOR_PERFORMANCE_WARNING - mExpectedComposeStartTime = TimeStamp::Now(); #endif - ScheduleTask(mCurrentCompositeTask, 0); - } -} - -bool -CompositorSoftwareTimerScheduler::NeedsComposite() -{ - return mCurrentCompositeTask ? true : false; -} - -void -CompositorSoftwareTimerScheduler::CallComposite() -{ - Composite(TimeStamp::Now()); -} - -void -CompositorSoftwareTimerScheduler::Composite(TimeStamp aTimestamp) -{ - mCurrentCompositeTask = nullptr; - mLastCompose = aTimestamp; - ComposeToTarget(nullptr); -} CompositorVsyncScheduler::Observer::Observer(CompositorVsyncScheduler* aOwner) : mMutex("CompositorVsyncScheduler.Observer.Mutex") @@ -398,11 +276,12 @@ CompositorVsyncScheduler::Observer::Destroy() } CompositorVsyncScheduler::CompositorVsyncScheduler(CompositorParent* aCompositorParent, nsIWidget* aWidget) - : CompositorScheduler(aCompositorParent) + : mCompositorParent(aCompositorParent) + , mLastCompose(TimeStamp::Now()) + , mCurrentCompositeTask(nullptr) , mNeedsComposite(false) , mIsObservingVsync(false) , mVsyncNotificationsSkipped(0) - , mCompositorParent(aCompositorParent) , mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor") , mSetNeedsCompositeMonitor("SetNeedsCompositeMonitor") , mSetNeedsCompositeTask(nullptr) @@ -414,6 +293,11 @@ CompositorVsyncScheduler::CompositorVsyncScheduler(CompositorParent* aCompositor #ifdef MOZ_WIDGET_GONK GeckoTouchDispatcher::GetInstance()->SetCompositorVsyncScheduler(this); #endif + + // mAsapScheduling is set on the main thread during init, + // but is only accessed after on the compositor thread. + mAsapScheduling = gfxPrefs::LayersCompositionFrameRate() == 0 || + gfxPlatform::IsInLayoutAsapMode(); } CompositorVsyncScheduler::~CompositorVsyncScheduler() @@ -433,13 +317,32 @@ CompositorVsyncScheduler::Destroy() mVsyncObserver->Destroy(); mVsyncObserver = nullptr; CancelCurrentSetNeedsCompositeTask(); - CompositorScheduler::Destroy(); + CancelCurrentCompositeTask(); +} + +void +CompositorVsyncScheduler::PostCompositeTask(TimeStamp aCompositeTimestamp) +{ + // can be called from the compositor or vsync thread + MonitorAutoLock lock(mCurrentCompositeTaskMonitor); + if (mCurrentCompositeTask == nullptr) { + mCurrentCompositeTask = NewRunnableMethod(this, + &CompositorVsyncScheduler::Composite, + aCompositeTimestamp); + ScheduleTask(mCurrentCompositeTask, 0); + } } void CompositorVsyncScheduler::ScheduleComposition() { - SetNeedsComposite(true); + MOZ_ASSERT(CompositorParent::IsInCompositorThread()); + if (mAsapScheduling) { + // Used only for performance testing purposes + PostCompositeTask(TimeStamp::Now()); + } else { + SetNeedsComposite(true); + } } void @@ -488,14 +391,7 @@ CompositorVsyncScheduler::NotifyVsync(TimeStamp aVsyncTimestamp) // Called from the vsync dispatch thread MOZ_ASSERT(!CompositorParent::IsInCompositorThread()); MOZ_ASSERT(!NS_IsMainThread()); - - MonitorAutoLock lock(mCurrentCompositeTaskMonitor); - if (mCurrentCompositeTask == nullptr) { - mCurrentCompositeTask = NewRunnableMethod(this, - &CompositorVsyncScheduler::Composite, - aVsyncTimestamp); - ScheduleTask(mCurrentCompositeTask, 0); - } + PostCompositeTask(aVsyncTimestamp); return true; } @@ -504,7 +400,10 @@ CompositorVsyncScheduler::CancelCurrentCompositeTask() { MOZ_ASSERT(CompositorParent::IsInCompositorThread() || NS_IsMainThread()); MonitorAutoLock lock(mCurrentCompositeTaskMonitor); - CompositorScheduler::CancelCurrentCompositeTask(); + if (mCurrentCompositeTask) { + mCurrentCompositeTask->Cancel(); + mCurrentCompositeTask = nullptr; + } } void @@ -518,7 +417,7 @@ CompositorVsyncScheduler::Composite(TimeStamp aVsyncTimestamp) DispatchTouchEvents(aVsyncTimestamp); - if (mNeedsComposite) { + if (mNeedsComposite || mAsapScheduling) { mNeedsComposite = false; mLastCompose = aVsyncTimestamp; ComposeToTarget(nullptr); @@ -549,7 +448,8 @@ void CompositorVsyncScheduler::ForceComposeToTarget(gfx::DrawTarget* aTarget, const IntRect* aRect) { OnForceComposeToTarget(); - CompositorScheduler::ForceComposeToTarget(aTarget, aRect); + mLastCompose = TimeStamp::Now(); + ComposeToTarget(aTarget, aRect); } bool @@ -613,22 +513,27 @@ MessageLoop* CompositorParent::CompositorLoop() return CompositorThread() ? CompositorThread()->message_loop() : nullptr; } -static bool -IsInCompositorAsapMode() +void +CompositorVsyncScheduler::ScheduleTask(CancelableTask* aTask, int aTime) +{ + MOZ_ASSERT(CompositorParent::CompositorLoop()); + MOZ_ASSERT(aTime >= 0); + CompositorParent::CompositorLoop()->PostDelayedTask(FROM_HERE, aTask, aTime); +} + +void +CompositorVsyncScheduler::ResumeComposition() { - // Returns true if the compositor is allowed to be in ASAP mode - // and layout is not in ASAP mode - return gfxPrefs::LayersCompositionFrameRate() == 0 && - !gfxPlatform::IsInLayoutAsapMode(); + mLastCompose = TimeStamp::Now(); + ComposeToTarget(nullptr); } -static bool -UseVsyncComposition() +void +CompositorVsyncScheduler::ComposeToTarget(gfx::DrawTarget* aTarget, const IntRect* aRect) { - return gfxPrefs::VsyncAlignedCompositor() - && gfxPrefs::HardwareVsyncEnabled() - && !IsInCompositorAsapMode() - && !gfxPlatform::IsInLayoutAsapMode(); + MOZ_ASSERT(CompositorParent::IsInCompositorThread()); + MOZ_ASSERT(mCompositorParent); + mCompositorParent->CompositeToTarget(aTarget, aRect); } CompositorParent::CompositorParent(nsIWidget* aWidget, @@ -675,12 +580,8 @@ CompositorParent::CompositorParent(nsIWidget* aWidget, mApzcTreeManager = new APZCTreeManager(); } - if (UseVsyncComposition()) { - gfxDebugOnce() << "Enabling vsync compositor"; - mCompositorScheduler = new CompositorVsyncScheduler(this, aWidget); - } else { - mCompositorScheduler = new CompositorSoftwareTimerScheduler(this); - } + gfxDebugOnce() << "Enabling vsync compositor"; + mCompositorScheduler = new CompositorVsyncScheduler(this, aWidget); LayerScope::SetPixelScale(mWidget->GetDefaultScale().scale); } diff --git a/gfx/layers/ipc/CompositorParent.h b/gfx/layers/ipc/CompositorParent.h index 5e67d6138996..95a05d264f79 100644 --- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -88,21 +88,31 @@ class CompositorThreadHolder final friend class CompositorParent; }; -class CompositorScheduler +/** + * Manages the vsync (de)registration and tracking on behalf of the + * compositor when it need to paint. + * Turns vsync notifications into scheduled composites. + **/ +class CompositorVsyncScheduler { + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorVsyncScheduler) + public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorScheduler) - explicit CompositorScheduler(CompositorParent* aCompositorParent); + explicit CompositorVsyncScheduler(CompositorParent* aCompositorParent, nsIWidget* aWidget); + bool NotifyVsync(TimeStamp aVsyncTimestamp); + void SetNeedsComposite(bool aSchedule); + void OnForceComposeToTarget(); - virtual void ScheduleComposition() = 0; - virtual void CancelCurrentCompositeTask(); - virtual bool NeedsComposite() = 0; - virtual void Composite(TimeStamp aTimestamp) = 0; - virtual void ScheduleTask(CancelableTask*, int); - virtual void ResumeComposition(); - virtual void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect); - virtual void ComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr); - virtual void Destroy(); + void ScheduleTask(CancelableTask*, int); + void ResumeComposition(); + void ComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr); + void PostCompositeTask(TimeStamp aCompositeTimestamp); + void Destroy(); + void ScheduleComposition(); + void CancelCurrentCompositeTask(); + bool NeedsComposite(); + void Composite(TimeStamp aVsyncTimestamp); + void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect); const TimeStamp& GetLastComposeTime() { @@ -115,56 +125,7 @@ class CompositorScheduler return mExpectedComposeStartTime; } #endif - -protected: - virtual ~CompositorScheduler(); - - CompositorParent* mCompositorParent; - TimeStamp mLastCompose; - CancelableTask* mCurrentCompositeTask; - -#ifdef COMPOSITOR_PERFORMANCE_WARNING - TimeStamp mExpectedComposeStartTime; -#endif -}; - -class CompositorSoftwareTimerScheduler final : public CompositorScheduler -{ -public: - explicit CompositorSoftwareTimerScheduler(CompositorParent* aCompositorParent); - - // from CompositorScheduler - virtual void ScheduleComposition() override; - virtual bool NeedsComposite() override; - virtual void Composite(TimeStamp aTimestamp) override; - - void CallComposite(); -private: - virtual ~CompositorSoftwareTimerScheduler(); -}; - -/** - * Manages the vsync (de)registration and tracking on behalf of the - * compositor when it need to paint. - * Turns vsync notifications into scheduled composites. - **/ - -class CompositorVsyncScheduler final : public CompositorScheduler -{ -public: - explicit CompositorVsyncScheduler(CompositorParent* aCompositorParent, nsIWidget* aWidget); - bool NotifyVsync(TimeStamp aVsyncTimestamp); - void SetNeedsComposite(bool aSchedule); - void OnForceComposeToTarget(); - - // from CompositorScheduler - virtual void ScheduleComposition() override; - virtual void CancelCurrentCompositeTask() override; - virtual bool NeedsComposite() override; - virtual void Composite(TimeStamp aVsyncTimestamp) override; - virtual void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect) override; - virtual void Destroy() override; - + private: virtual ~CompositorVsyncScheduler(); @@ -188,10 +149,18 @@ class CompositorVsyncScheduler final : public CompositorScheduler CompositorVsyncScheduler* mOwner; }; + CompositorParent* mCompositorParent; + TimeStamp mLastCompose; + CancelableTask* mCurrentCompositeTask; + +#ifdef COMPOSITOR_PERFORMANCE_WARNING + TimeStamp mExpectedComposeStartTime; +#endif + + bool mAsapScheduling; bool mNeedsComposite; bool mIsObservingVsync; int32_t mVsyncNotificationsSkipped; - CompositorParent* mCompositorParent; nsRefPtr mCompositorVsyncDispatcher; nsRefPtr mVsyncObserver; @@ -216,7 +185,7 @@ class CompositorParent final : public PCompositorParent, public ShadowLayersManager { NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorParent) - friend class CompositorScheduler; + friend class CompositorVsyncScheduler; public: explicit CompositorParent(nsIWidget* aWidget, @@ -498,7 +467,7 @@ class CompositorParent final : public PCompositorParent, nsRefPtr mApzcTreeManager; nsRefPtr mCompositorThreadHolder; - nsRefPtr mCompositorScheduler; + nsRefPtr mCompositorScheduler; DISALLOW_EVIL_CONSTRUCTORS(CompositorParent); }; From ecd54e1a02fa80924c05d64942da2b3ffa164110 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 20 Aug 2015 17:02:18 -0700 Subject: [PATCH 064/208] Bug 1194560 (follow-up) - Only build rapl on Linux if the arch is x86 or x86-64. r=glandium. --- tools/power/moz.build | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/power/moz.build b/tools/power/moz.build index 91df713e3f82..5a61ab7582d1 100644 --- a/tools/power/moz.build +++ b/tools/power/moz.build @@ -4,8 +4,16 @@ # 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/. -if (CONFIG['OS_ARCH'] == 'Darwin' and CONFIG['CPU_ARCH'] == 'x86_64') or \ - (CONFIG['OS_ARCH'] == 'Linux' and CONFIG['OS_TARGET'] != 'Android'): +do_rapl = False + +if CONFIG['OS_ARCH'] == 'Darwin' and CONFIG['CPU_ARCH'] == 'x86_64': + do_rapl = True + +if CONFIG['OS_ARCH'] == 'Linux' and CONFIG['OS_TARGET'] != 'Android' and \ + CONFIG['CPU_ARCH'] in ('x86', 'x86_64'): + do_rapl = True + +if do_rapl: SimplePrograms([ 'rapl', ]) From 26462028c9193991f31cd0b7d2ddcf84da81747c Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Fri, 21 Aug 2015 13:34:21 +1200 Subject: [PATCH 065/208] Bug 1197022 - [EME] Disable dormant mode for EME videos on all channels. r=kentuckyfriedtakahe --- dom/media/MediaDecoder.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp index 793db26a7c60..7cd854182f57 100644 --- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -159,9 +159,8 @@ bool MediaDecoder::IsHeuristicDormantSupported() const { return -#if defined(MOZ_EME) && defined(RELEASE_BUILD) - // We disallow dormant for encrypted media on Beta and Release until - // bug 1181864 is fixed. +#if defined(MOZ_EME) + // We disallow dormant for encrypted media until bug 1181864 is fixed. mInfo && !mInfo->IsEncrypted() && #endif From 04c3fcc835e8d61395723a7834c7d7d750f2e2dd Mon Sep 17 00:00:00 2001 From: Ting-Yu Lin Date: Wed, 19 Aug 2015 15:54:10 +0800 Subject: [PATCH 066/208] Bug 1195672 - Add |nsAutoCString nsIFrame::ListTag()| for debugging. f=mtseng, r=roc This make it easier to print a frame tag name in one debug log line. --- layout/generic/nsIFrame.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 8f34fab12bcb..65d84ea1594f 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -34,6 +34,7 @@ #include "nsITheme.h" #include "nsLayoutUtils.h" #include "nsQueryFrame.h" +#include "nsStringGlue.h" #include "nsStyleContext.h" #include "nsStyleStruct.h" @@ -3225,6 +3226,11 @@ NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::ParagraphDepthProperty())) fputs(t.get(), out); } void ListTag(nsACString& aTo) const; + nsAutoCString ListTag() const { + nsAutoCString tag; + ListTag(tag); + return tag; + } static void ListTag(nsACString& aTo, const nsIFrame* aFrame); void ListGeneric(nsACString& aTo, const char* aPrefix = "", uint32_t aFlags = 0) const; enum { From f7035f5a4d26d367efcd9ce8da4520f85eec028c Mon Sep 17 00:00:00 2001 From: Ting-Yu Lin Date: Wed, 19 Aug 2015 15:54:10 +0800 Subject: [PATCH 067/208] Bug 1195672 - Make focus changing by long tap behaves like by single tap. f=mtseng, r=roc We want the focus changing behavior by long tap as close as to the one by single tap. The only functional change is that we always clear old focus and re-focus the window if a focusable frame cannot be found. This behavior is the same as the single tap implemented in EventStateManager::PostHandleEvent(). Besides, ChangeFocus now returns the new focusable frame instead of bool which provides more information. --- layout/base/AccessibleCaretManager.cpp | 52 +++++++++++--------------- layout/base/AccessibleCaretManager.h | 5 ++- 2 files changed, 26 insertions(+), 31 deletions(-) diff --git a/layout/base/AccessibleCaretManager.cpp b/layout/base/AccessibleCaretManager.cpp index c522fb2a233d..22dd7e686b4c 100644 --- a/layout/base/AccessibleCaretManager.cpp +++ b/layout/base/AccessibleCaretManager.cpp @@ -502,46 +502,38 @@ AccessibleCaretManager::GetCaretMode() const return CaretMode::Selection; } -bool +nsIFrame* AccessibleCaretManager::ChangeFocus(nsIFrame* aFrame) const { - nsIFrame* currFrame = aFrame; - nsIContent* newFocusContent = nullptr; - while (currFrame) { - int32_t tabIndexUnused = 0; - if (currFrame->IsFocusable(&tabIndexUnused, true)) { - newFocusContent = currFrame->GetContent(); - nsCOMPtr domElement(do_QueryInterface(newFocusContent)); - if (domElement) - break; + // This implementation is similar to EventStateManager::PostHandleEvent(). + // Look for the nearest enclosing focusable frame. + nsIFrame* focusableFrame = aFrame; + while (focusableFrame) { + if (focusableFrame->IsFocusable(nullptr, true)) { + break; } - currFrame = currFrame->GetParent(); + focusableFrame = focusableFrame->GetParent(); } - // If target frame is focusable, we should move focus to it. If target frame - // isn't focusable, and our previous focused content is editable, we should - // clear focus. + // If a focusable frame is found, move focus to it. Otherwise, clear the old + // focus then re-focus the window. nsFocusManager* fm = nsFocusManager::GetFocusManager(); - if (newFocusContent && currFrame) { - nsCOMPtr domElement(do_QueryInterface(newFocusContent)); - fm->SetFocus(domElement, 0); + MOZ_ASSERT(fm); + + if (focusableFrame) { + nsIContent* focusableContent = focusableFrame->GetContent(); + MOZ_ASSERT(focusableContent, "Focusable frame must have content!"); + nsCOMPtr focusableElement = do_QueryInterface(focusableContent); + fm->SetFocus(focusableElement, nsIFocusManager::FLAG_BYMOUSE); } else { - nsIContent* focusedContent = GetFocusedContent(); - if (focusedContent) { - // Clear focus if content was editable element, or contentEditable. - nsGenericHTMLElement* focusedGeneric = - nsGenericHTMLElement::FromContent(focusedContent); - if (focusedContent->GetTextEditorRootContent() || - (focusedGeneric && focusedGeneric->IsContentEditable())) { - nsIDOMWindow* win = mPresShell->GetDocument()->GetWindow(); - if (win) { - fm->ClearFocus(win); - } - } + nsIDOMWindow* win = mPresShell->GetDocument()->GetWindow(); + if (win) { + fm->ClearFocus(win); + fm->SetFocusedWindow(win); } } - return (newFocusContent && currFrame); + return focusableFrame; } nsresult diff --git a/layout/base/AccessibleCaretManager.h b/layout/base/AccessibleCaretManager.h index 4cae49fa8b18..55c661a86c27 100644 --- a/layout/base/AccessibleCaretManager.h +++ b/layout/base/AccessibleCaretManager.h @@ -115,7 +115,10 @@ class AccessibleCaretManager void UpdateCaretsForSelectionMode(); void UpdateCaretsForTilt(); - bool ChangeFocus(nsIFrame* aFrame) const; + // Change focus to the nearest enclosing focusable frame of aFrame. + // @return focusable frame if there is any; nullptr otherwise. + nsIFrame* ChangeFocus(nsIFrame* aFrame) const; + nsresult SelectWord(nsIFrame* aFrame, const nsPoint& aPoint) const; void SetSelectionDragState(bool aState) const; void SetSelectionDirection(nsDirection aDir) const; From b5c03060aa4f1a90dc917eca9f2690eca0ebbc5b Mon Sep 17 00:00:00 2001 From: Ting-Yu Lin Date: Wed, 19 Aug 2015 15:54:10 +0800 Subject: [PATCH 068/208] Bug 1195672 - Move the check that frame is selectable into SelectWord. f=mtseng, r=roc There's a bug that when a frame is focusable but not selectable, we won't focus on it because we call IsSelectable() before ChangeFocus(). By moving the check into SelectWord(), we'll have a chance to focus on it. This resolves a issue that when long press to select a word on a new opened app, the selection highlight is gray instead of blue. --- layout/base/AccessibleCaretManager.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/layout/base/AccessibleCaretManager.cpp b/layout/base/AccessibleCaretManager.cpp index 22dd7e686b4c..f02e4e272bc9 100644 --- a/layout/base/AccessibleCaretManager.cpp +++ b/layout/base/AccessibleCaretManager.cpp @@ -335,11 +335,6 @@ AccessibleCaretManager::SelectWordOrShortcut(const nsPoint& aPoint) return NS_ERROR_FAILURE; } - bool selectable; - ptFrame->IsSelectable(&selectable, nullptr); - if (!selectable) { - return NS_ERROR_FAILURE; - } nsPoint ptInFrame = aPoint; nsLayoutUtils::TransformPoint(rootFrame, ptFrame, ptInFrame); @@ -539,6 +534,12 @@ AccessibleCaretManager::ChangeFocus(nsIFrame* aFrame) const nsresult AccessibleCaretManager::SelectWord(nsIFrame* aFrame, const nsPoint& aPoint) const { + bool selectable; + aFrame->IsSelectable(&selectable, nullptr); + if (!selectable) { + return NS_ERROR_FAILURE; + } + SetSelectionDragState(true); nsFrame* frame = static_cast(aFrame); nsresult rs = frame->SelectByTypeAtPoint(mPresShell->GetPresContext(), aPoint, From 02f1642d0721cdd7da9c3dc8e6b224e1f99459ab Mon Sep 17 00:00:00 2001 From: Ting-Yu Lin Date: Wed, 19 Aug 2015 15:54:10 +0800 Subject: [PATCH 069/208] Bug 1195672 - Revise the logic of long tap on empty content. f=mtseng, r=roc The only logic change is that we now call UpdateCaret() before dispatching CaretStateChangedEvent. This resolves a bug that the text selection dialog flashes when long tapping on an empty content. --- layout/base/AccessibleCaretManager.cpp | 40 +++++++++++++++----------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/layout/base/AccessibleCaretManager.cpp b/layout/base/AccessibleCaretManager.cpp index f02e4e272bc9..94c4a83af462 100644 --- a/layout/base/AccessibleCaretManager.cpp +++ b/layout/base/AccessibleCaretManager.cpp @@ -328,28 +328,38 @@ AccessibleCaretManager::SelectWordOrShortcut(const nsPoint& aPoint) return NS_ERROR_NOT_AVAILABLE; } - // Find content offsets for mouse down point + // Find the frame under point. nsIFrame* ptFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, aPoint, nsLayoutUtils::IGNORE_PAINT_SUPPRESSION | nsLayoutUtils::IGNORE_CROSS_DOC); if (!ptFrame) { return NS_ERROR_FAILURE; } + nsIFrame* focusedFrame = ChangeFocus(ptFrame); - nsPoint ptInFrame = aPoint; - nsLayoutUtils::TransformPoint(rootFrame, ptFrame, ptInFrame); +#ifdef DEBUG_FRAME_DUMP + AC_LOG("%s: Found %s under (%d, %d)", __FUNCTION__, ptFrame->ListTag().get(), + aPoint.x, aPoint.y); + AC_LOG("%s: Focused on %s", __FUNCTION__, + focusedFrame ? focusedFrame->ListTag().get() : "no frame"); +#endif - nsIContent* editingHost = ptFrame->GetContent()->GetEditingHost(); - if (ChangeFocus(ptFrame) && - (editingHost && !nsContentUtils::HasNonEmptyTextContent( - editingHost, nsContentUtils::eRecurseIntoChildren))) { - // Content is empty. No need to select word. - AC_LOG("%s, Cannot select word bacause content is empty", __FUNCTION__); - DispatchCaretStateChangedEvent(CaretChangedReason::Longpressonemptycontent); + // Firstly check long press on an empty editable content. + Element* newFocusEditingHost = ptFrame->GetContent()->GetEditingHost(); + if (focusedFrame && newFocusEditingHost && + !nsContentUtils::HasNonEmptyTextContent( + newFocusEditingHost, nsContentUtils::eRecurseIntoChildren)) { + // We need to update carets to get correct information before dispatching + // CaretStateChangedEvent. UpdateCarets(); + DispatchCaretStateChangedEvent(CaretChangedReason::Longpressonemptycontent); return NS_OK; } + // Then try select a word under point. + nsPoint ptInFrame = aPoint; + nsLayoutUtils::TransformPoint(rootFrame, ptFrame, ptInFrame); + nsresult rv = SelectWord(ptFrame, ptInFrame); UpdateCarets(); return rv; @@ -545,12 +555,6 @@ AccessibleCaretManager::SelectWord(nsIFrame* aFrame, const nsPoint& aPoint) cons nsresult rs = frame->SelectByTypeAtPoint(mPresShell->GetPresContext(), aPoint, eSelectWord, eSelectWord, 0); -#ifdef DEBUG_FRAME_DUMP - nsCString frameTag; - frame->ListTag(frameTag); - AC_LOG("Frame=%s, ptInFrame=(%d, %d)", frameTag.get(), aPoint.x, aPoint.y); -#endif - SetSelectionDragState(false); ClearMaintainedSelection(); @@ -950,6 +954,10 @@ AccessibleCaretManager::DispatchCaretStateChangedEvent(CaretChangedReason aReaso event->SetTrusted(true); event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true; + + AC_LOG("%s: reason %d, collapsed %d, caretVisible %d", __FUNCTION__, + init.mReason, init.mCollapsed, init.mCaretVisible); + (new AsyncEventDispatcher(doc, event))->RunDOMEventWhenSafe(); } From 36d7fd8674ba6bcec84dcb4f6740f5663f658d0b Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Thu, 20 Aug 2015 16:50:08 +1000 Subject: [PATCH 070/208] Bug 1196398: [mp4] Do not allocate memory spanning across ftyp and moov atom. r=kentuckyfriedtakahe A typical non-fragmented mp4 would have the ftyp atom located at the beginning of the mp4 and the moov at the end. We would to calculate the location of the metadata by spanning the byte range of the two atoms. As such, we would typically allocate an amount of memory equivalent to the size of the mp4. Instead we now reconstruct the metadata to only have the ftyp and moov atoms contiguously. --- dom/media/fmp4/MP4Demuxer.cpp | 12 ++--- media/libstagefright/binding/MP4Metadata.cpp | 9 ++-- media/libstagefright/binding/MoofParser.cpp | 52 +++++++++++++++---- .../binding/include/mp4_demuxer/MP4Metadata.h | 2 +- .../binding/include/mp4_demuxer/MoofParser.h | 3 ++ 5 files changed, 53 insertions(+), 25 deletions(-) diff --git a/dom/media/fmp4/MP4Demuxer.cpp b/dom/media/fmp4/MP4Demuxer.cpp index a21ff213941f..0a95ac56c86e 100644 --- a/dom/media/fmp4/MP4Demuxer.cpp +++ b/dom/media/fmp4/MP4Demuxer.cpp @@ -79,22 +79,16 @@ MP4Demuxer::Init() AutoPinned stream(mStream); // Check that we have enough data to read the metadata. - MediaByteRange br = mp4_demuxer::MP4Metadata::MetadataRange(stream); - if (br.IsNull()) { + if (!mp4_demuxer::MP4Metadata::HasCompleteMetadata(stream)) { return InitPromise::CreateAndReject(DemuxerFailureReason::WAITING_FOR_DATA, __func__); } - if (!mInitData->SetLength(br.Length(), fallible)) { + mInitData = mp4_demuxer::MP4Metadata::Metadata(stream); + if (!mInitData) { // OOM return InitPromise::CreateAndReject(DemuxerFailureReason::DEMUXER_ERROR, __func__); } - size_t size; - mStream->ReadAt(br.mStart, mInitData->Elements(), br.Length(), &size); - if (size != size_t(br.Length())) { - return InitPromise::CreateAndReject(DemuxerFailureReason::DEMUXER_ERROR, __func__); - } - nsRefPtr bufferstream = new mp4_demuxer::BufferStream(mInitData); diff --git a/media/libstagefright/binding/MP4Metadata.cpp b/media/libstagefright/binding/MP4Metadata.cpp index 5effe9f44998..dfa488c3d0ac 100644 --- a/media/libstagefright/binding/MP4Metadata.cpp +++ b/media/libstagefright/binding/MP4Metadata.cpp @@ -287,17 +287,14 @@ MP4Metadata::HasCompleteMetadata(Stream* aSource) return parser->HasMetadata(); } -/*static*/ mozilla::MediaByteRange -MP4Metadata::MetadataRange(Stream* aSource) +/*static*/ already_AddRefed +MP4Metadata::Metadata(Stream* aSource) { // The MoofParser requires a monitor, but we don't need one here. mozilla::Monitor monitor("MP4Metadata::HasCompleteMetadata"); mozilla::MonitorAutoLock mon(monitor); auto parser = mozilla::MakeUnique(aSource, 0, false, &monitor); - if (parser->HasMetadata()) { - return parser->mInitRange; - } - return mozilla::MediaByteRange(); + return parser->Metadata(); } } // namespace mp4_demuxer diff --git a/media/libstagefright/binding/MoofParser.cpp b/media/libstagefright/binding/MoofParser.cpp index 7bb7d090de03..61a1ec2c720e 100644 --- a/media/libstagefright/binding/MoofParser.cpp +++ b/media/libstagefright/binding/MoofParser.cpp @@ -148,8 +148,9 @@ MoofParser::BlockingReadNextMoof() return false; } -bool -MoofParser::HasMetadata() +void +MoofParser::ScanForMetadata(mozilla::MediaByteRange& aFtyp, + mozilla::MediaByteRange& aMoov) { int64_t length = std::numeric_limits::max(); mSource->Length(&length); @@ -157,24 +158,57 @@ MoofParser::HasMetadata() byteRanges.AppendElement(MediaByteRange(0, length)); nsRefPtr stream = new BlockingStream(mSource); - MediaByteRange ftyp; - MediaByteRange moov; BoxContext context(stream, byteRanges); for (Box box(&context, mOffset); box.IsAvailable(); box = box.Next()) { if (box.IsType("ftyp")) { - ftyp = box.Range(); + aFtyp = box.Range(); continue; } if (box.IsType("moov")) { - moov = box.Range(); + aMoov = box.Range(); break; } } + mInitRange = aFtyp.Extents(aMoov); +} + +bool +MoofParser::HasMetadata() +{ + MediaByteRange ftyp; + MediaByteRange moov; + ScanForMetadata(ftyp, moov); + return !!ftyp.Length() && !!moov.Length(); +} + +already_AddRefed +MoofParser::Metadata() +{ + MediaByteRange ftyp; + MediaByteRange moov; + ScanForMetadata(ftyp, moov); if (!ftyp.Length() || !moov.Length()) { - return false; + return nullptr; } - mInitRange = ftyp.Extents(moov); - return true; + nsRefPtr metadata = new MediaByteBuffer(); + if (!metadata->SetLength(ftyp.Length() + moov.Length(), fallible)) { + // OOM + return nullptr; + } + + nsRefPtr stream = new BlockingStream(mSource); + size_t read; + bool rv = + stream->ReadAt(ftyp.mStart, metadata->Elements(), ftyp.Length(), &read); + if (!rv || read != ftyp.Length()) { + return nullptr; + } + rv = + stream->ReadAt(moov.mStart, metadata->Elements() + ftyp.Length(), moov.Length(), &read); + if (!rv || read != moov.Length()) { + return nullptr; + } + return metadata.forget(); } Interval diff --git a/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h b/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h index de9273c2725d..28a79bcec755 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h +++ b/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h @@ -30,7 +30,7 @@ class MP4Metadata ~MP4Metadata(); static bool HasCompleteMetadata(Stream* aSource); - static mozilla::MediaByteRange MetadataRange(Stream* aSource); + static already_AddRefed Metadata(Stream* aSource); uint32_t GetNumberTracks(mozilla::TrackInfo::TrackType aType) const; mozilla::UniquePtr GetTrackInfo(mozilla::TrackInfo::TrackType aType, size_t aTrackNumber) const; diff --git a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h index 86daead28cd4..742e1a72b11b 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h +++ b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h @@ -228,6 +228,7 @@ class MoofParser bool BlockingReadNextMoof(); bool HasMetadata(); + already_AddRefed Metadata(); MediaByteRange FirstCompleteMediaSegment(); MediaByteRange FirstCompleteMediaHeader(); @@ -244,6 +245,8 @@ class MoofParser Monitor* mMonitor; nsTArray& Moofs() { mMonitor->AssertCurrentThreadOwns(); return mMoofs; } private: + void ScanForMetadata(mozilla::MediaByteRange& aFtyp, + mozilla::MediaByteRange& aMoov); nsTArray mMoofs; nsTArray mMediaRanges; bool mIsAudio; From a736eaca23b0a9532cc343f2bc7b5c3757d836ff Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Fri, 21 Aug 2015 14:45:30 +1000 Subject: [PATCH 071/208] Revert "Bug 1196398: [mp4] Do not allocate memory spanning across ftyp and moov atom. r=kentuckyfriedtakahe" This reverts commit 73156610be5f --- dom/media/fmp4/MP4Demuxer.cpp | 12 +++-- media/libstagefright/binding/MP4Metadata.cpp | 9 ++-- media/libstagefright/binding/MoofParser.cpp | 52 ++++--------------- .../binding/include/mp4_demuxer/MP4Metadata.h | 2 +- .../binding/include/mp4_demuxer/MoofParser.h | 3 -- 5 files changed, 25 insertions(+), 53 deletions(-) diff --git a/dom/media/fmp4/MP4Demuxer.cpp b/dom/media/fmp4/MP4Demuxer.cpp index 0a95ac56c86e..a21ff213941f 100644 --- a/dom/media/fmp4/MP4Demuxer.cpp +++ b/dom/media/fmp4/MP4Demuxer.cpp @@ -79,16 +79,22 @@ MP4Demuxer::Init() AutoPinned stream(mStream); // Check that we have enough data to read the metadata. - if (!mp4_demuxer::MP4Metadata::HasCompleteMetadata(stream)) { + MediaByteRange br = mp4_demuxer::MP4Metadata::MetadataRange(stream); + if (br.IsNull()) { return InitPromise::CreateAndReject(DemuxerFailureReason::WAITING_FOR_DATA, __func__); } - mInitData = mp4_demuxer::MP4Metadata::Metadata(stream); - if (!mInitData) { + if (!mInitData->SetLength(br.Length(), fallible)) { // OOM return InitPromise::CreateAndReject(DemuxerFailureReason::DEMUXER_ERROR, __func__); } + size_t size; + mStream->ReadAt(br.mStart, mInitData->Elements(), br.Length(), &size); + if (size != size_t(br.Length())) { + return InitPromise::CreateAndReject(DemuxerFailureReason::DEMUXER_ERROR, __func__); + } + nsRefPtr bufferstream = new mp4_demuxer::BufferStream(mInitData); diff --git a/media/libstagefright/binding/MP4Metadata.cpp b/media/libstagefright/binding/MP4Metadata.cpp index dfa488c3d0ac..5effe9f44998 100644 --- a/media/libstagefright/binding/MP4Metadata.cpp +++ b/media/libstagefright/binding/MP4Metadata.cpp @@ -287,14 +287,17 @@ MP4Metadata::HasCompleteMetadata(Stream* aSource) return parser->HasMetadata(); } -/*static*/ already_AddRefed -MP4Metadata::Metadata(Stream* aSource) +/*static*/ mozilla::MediaByteRange +MP4Metadata::MetadataRange(Stream* aSource) { // The MoofParser requires a monitor, but we don't need one here. mozilla::Monitor monitor("MP4Metadata::HasCompleteMetadata"); mozilla::MonitorAutoLock mon(monitor); auto parser = mozilla::MakeUnique(aSource, 0, false, &monitor); - return parser->Metadata(); + if (parser->HasMetadata()) { + return parser->mInitRange; + } + return mozilla::MediaByteRange(); } } // namespace mp4_demuxer diff --git a/media/libstagefright/binding/MoofParser.cpp b/media/libstagefright/binding/MoofParser.cpp index 61a1ec2c720e..7bb7d090de03 100644 --- a/media/libstagefright/binding/MoofParser.cpp +++ b/media/libstagefright/binding/MoofParser.cpp @@ -148,9 +148,8 @@ MoofParser::BlockingReadNextMoof() return false; } -void -MoofParser::ScanForMetadata(mozilla::MediaByteRange& aFtyp, - mozilla::MediaByteRange& aMoov) +bool +MoofParser::HasMetadata() { int64_t length = std::numeric_limits::max(); mSource->Length(&length); @@ -158,57 +157,24 @@ MoofParser::ScanForMetadata(mozilla::MediaByteRange& aFtyp, byteRanges.AppendElement(MediaByteRange(0, length)); nsRefPtr stream = new BlockingStream(mSource); + MediaByteRange ftyp; + MediaByteRange moov; BoxContext context(stream, byteRanges); for (Box box(&context, mOffset); box.IsAvailable(); box = box.Next()) { if (box.IsType("ftyp")) { - aFtyp = box.Range(); + ftyp = box.Range(); continue; } if (box.IsType("moov")) { - aMoov = box.Range(); + moov = box.Range(); break; } } - mInitRange = aFtyp.Extents(aMoov); -} - -bool -MoofParser::HasMetadata() -{ - MediaByteRange ftyp; - MediaByteRange moov; - ScanForMetadata(ftyp, moov); - return !!ftyp.Length() && !!moov.Length(); -} - -already_AddRefed -MoofParser::Metadata() -{ - MediaByteRange ftyp; - MediaByteRange moov; - ScanForMetadata(ftyp, moov); if (!ftyp.Length() || !moov.Length()) { - return nullptr; - } - nsRefPtr metadata = new MediaByteBuffer(); - if (!metadata->SetLength(ftyp.Length() + moov.Length(), fallible)) { - // OOM - return nullptr; + return false; } - - nsRefPtr stream = new BlockingStream(mSource); - size_t read; - bool rv = - stream->ReadAt(ftyp.mStart, metadata->Elements(), ftyp.Length(), &read); - if (!rv || read != ftyp.Length()) { - return nullptr; - } - rv = - stream->ReadAt(moov.mStart, metadata->Elements() + ftyp.Length(), moov.Length(), &read); - if (!rv || read != moov.Length()) { - return nullptr; - } - return metadata.forget(); + mInitRange = ftyp.Extents(moov); + return true; } Interval diff --git a/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h b/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h index 28a79bcec755..de9273c2725d 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h +++ b/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h @@ -30,7 +30,7 @@ class MP4Metadata ~MP4Metadata(); static bool HasCompleteMetadata(Stream* aSource); - static already_AddRefed Metadata(Stream* aSource); + static mozilla::MediaByteRange MetadataRange(Stream* aSource); uint32_t GetNumberTracks(mozilla::TrackInfo::TrackType aType) const; mozilla::UniquePtr GetTrackInfo(mozilla::TrackInfo::TrackType aType, size_t aTrackNumber) const; diff --git a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h index 742e1a72b11b..86daead28cd4 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h +++ b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h @@ -228,7 +228,6 @@ class MoofParser bool BlockingReadNextMoof(); bool HasMetadata(); - already_AddRefed Metadata(); MediaByteRange FirstCompleteMediaSegment(); MediaByteRange FirstCompleteMediaHeader(); @@ -245,8 +244,6 @@ class MoofParser Monitor* mMonitor; nsTArray& Moofs() { mMonitor->AssertCurrentThreadOwns(); return mMoofs; } private: - void ScanForMetadata(mozilla::MediaByteRange& aFtyp, - mozilla::MediaByteRange& aMoov); nsTArray mMoofs; nsTArray mMediaRanges; bool mIsAudio; From 554d774760d8461d03fff6c85553ee859f4e58ef Mon Sep 17 00:00:00 2001 From: Nikhil Marathe Date: Thu, 20 Aug 2015 13:56:37 -0700 Subject: [PATCH 072/208] Bug 1181037 - Use entry settings object's base URL. r=ehsan The second test, which checks for NetworkError is incorrect. [[Update]] step 12 states: "If response is a network error or response's status is not in the range 200 to 299, then: 1. Reject p with a TypeError." which specifically converts the NetworkError (due to 404) to a TypeError. Also fixes controller-on-reload.https.html Update web-platform-tests expected data --- dom/workers/ServiceWorkerContainer.cpp | 37 +++++++++++++++---- .../controller-on-reload.https.html.ini | 5 --- ...ch-event-async-respond-with.https.html.ini | 1 + .../registration-iframe.https.html.ini | 11 ------ .../registration-iframe.https.html | 2 +- 5 files changed, 31 insertions(+), 25 deletions(-) delete mode 100644 testing/web-platform/mozilla/meta/service-workers/service-worker/controller-on-reload.https.html.ini delete mode 100644 testing/web-platform/mozilla/meta/service-workers/service-worker/registration-iframe.https.html.ini diff --git a/dom/workers/ServiceWorkerContainer.cpp b/dom/workers/ServiceWorkerContainer.cpp index ee3faddb8077..11081d84bdf9 100644 --- a/dom/workers/ServiceWorkerContainer.cpp +++ b/dom/workers/ServiceWorkerContainer.cpp @@ -113,13 +113,32 @@ ServiceWorkerContainer::Register(const nsAString& aScriptURL, return nullptr; } - nsCOMPtr window = GetOwner(); - MOZ_ASSERT(window); + nsCOMPtr baseURI; + + nsIDocument* doc = GetEntryDocument(); + if (doc) { + baseURI = doc->GetBaseURI(); + } else { + // XXXnsm. One of our devtools browser test calls register() from a content + // script where there is no valid entry document. Use the window to resolve + // the uri in that case. + nsCOMPtr window = GetOwner(); + nsCOMPtr outerWindow; + if (window && (outerWindow = window->GetOuterWindow()) && + outerWindow->GetServiceWorkersTestingEnabled()) { + baseURI = window->GetDocBaseURI(); + } + } + + + if (!baseURI) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return nullptr; + } nsresult rv; nsCOMPtr scriptURI; - rv = NS_NewURI(getter_AddRefs(scriptURI), aScriptURL, nullptr, - window->GetDocBaseURI()); + rv = NS_NewURI(getter_AddRefs(scriptURI), aScriptURL, nullptr, baseURI); if (NS_WARN_IF(NS_FAILED(rv))) { aRv.ThrowTypeError(MSG_INVALID_URL, &aScriptURL); return nullptr; @@ -143,17 +162,19 @@ ServiceWorkerContainer::Register(const nsAString& aScriptURL, } else { // Step 5. Parse against entry settings object's base URL. rv = NS_NewURI(getter_AddRefs(scopeURI), aOptions.mScope.Value(), - nullptr, window->GetDocBaseURI()); + nullptr, baseURI); if (NS_WARN_IF(NS_FAILED(rv))) { nsAutoCString spec; - if (window->GetDocBaseURI()) { - window->GetDocBaseURI()->GetSpec(spec); - } + baseURI->GetSpec(spec); aRv.ThrowTypeError(MSG_INVALID_SCOPE, &aOptions.mScope.Value(), &spec); return nullptr; } } + // The spec says that the "client" passed to Register() must be the global + // where the ServiceWorkerContainer was retrieved from. + nsCOMPtr window = GetOwner(); + MOZ_ASSERT(window); aRv = swm->Register(window, scopeURI, scriptURI, getter_AddRefs(promise)); if (aRv.Failed()) { return nullptr; diff --git a/testing/web-platform/mozilla/meta/service-workers/service-worker/controller-on-reload.https.html.ini b/testing/web-platform/mozilla/meta/service-workers/service-worker/controller-on-reload.https.html.ini deleted file mode 100644 index b9a5b66c2327..000000000000 --- a/testing/web-platform/mozilla/meta/service-workers/service-worker/controller-on-reload.https.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[controller-on-reload.https.html] - type: testharness - [controller is set upon reload after registration] - expected: FAIL - diff --git a/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-event-async-respond-with.https.html.ini b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-event-async-respond-with.https.html.ini index dcee8d7d5967..1755750ac752 100644 --- a/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-event-async-respond-with.https.html.ini +++ b/testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-event-async-respond-with.https.html.ini @@ -3,3 +3,4 @@ expected: OK [Calling respondWith asynchronously throws an exception] expected: FAIL + diff --git a/testing/web-platform/mozilla/meta/service-workers/service-worker/registration-iframe.https.html.ini b/testing/web-platform/mozilla/meta/service-workers/service-worker/registration-iframe.https.html.ini deleted file mode 100644 index 4145809bdfdf..000000000000 --- a/testing/web-platform/mozilla/meta/service-workers/service-worker/registration-iframe.https.html.ini +++ /dev/null @@ -1,11 +0,0 @@ -[registration-iframe.https.html] - type: testharness - [Subframe's container's register method should use calling frame's document's url as a base url for parsing its script url and scope url - normal case] - expected: FAIL - - [Subframe's container's register method should use calling frame's document's url as a base url for parsing its script url and scope url - error case] - expected: FAIL - - [A scope url should start with the given script url] - expected: FAIL - diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/registration-iframe.https.html b/testing/web-platform/mozilla/tests/service-workers/service-worker/registration-iframe.https.html index fe4f30d95a21..fb60afe84975 100644 --- a/testing/web-platform/mozilla/tests/service-workers/service-worker/registration-iframe.https.html +++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/registration-iframe.https.html @@ -68,7 +68,7 @@ assert_unreached('register() should reject'); }, function(e) { - assert_equals(e.name, 'NetworkError'); + assert_equals(e.name, 'TypeError'); frame.remove(); return service_worker_unregister_and_done(t, scope); }) From ac929025fa0b1316147da9508625995630947bf8 Mon Sep 17 00:00:00 2001 From: Nikhil Marathe Date: Wed, 19 Aug 2015 08:55:01 -0700 Subject: [PATCH 073/208] Bug 1181039 - ServiceWorkerRegistration must be compared by scope. r=bkelly The spec for getRegistration() and getRegistrations() states: "Resolve promise with a ServiceWorkerRegistration object, setting its service worker client to service worker client, which represents registration." indicating a new ServiceWorkerRegistration is created per call. The existing Blink test depends on Blink's implementation detail which caches the registration. --- .../service-worker/getregistration.https.html.ini | 8 -------- .../service-worker/getregistration.https.html | 4 ++-- 2 files changed, 2 insertions(+), 10 deletions(-) delete mode 100644 testing/web-platform/mozilla/meta/service-workers/service-worker/getregistration.https.html.ini diff --git a/testing/web-platform/mozilla/meta/service-workers/service-worker/getregistration.https.html.ini b/testing/web-platform/mozilla/meta/service-workers/service-worker/getregistration.https.html.ini deleted file mode 100644 index 02c26b03cfd7..000000000000 --- a/testing/web-platform/mozilla/meta/service-workers/service-worker/getregistration.https.html.ini +++ /dev/null @@ -1,8 +0,0 @@ -[getregistration.https.html] - type: testharness - [Register then getRegistration] - expected: FAIL - - [Register then getRegistration with a URL having a fragment] - expected: FAIL - diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/getregistration.https.html b/testing/web-platform/mozilla/tests/service-workers/service-worker/getregistration.https.html index 84fcee791aba..3abf8210906e 100644 --- a/testing/web-platform/mozilla/tests/service-workers/service-worker/getregistration.https.html +++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/getregistration.https.html @@ -24,7 +24,7 @@ return navigator.serviceWorker.getRegistration(scope); }) .then(function(value) { - assert_equals(value, registration, + assert_equals(value.scope, registration.scope, 'getRegistration should resolve with registration'); service_worker_unregister_and_done(t, scope); }) @@ -42,7 +42,7 @@ return navigator.serviceWorker.getRegistration(documentURL); }) .then(function(value) { - assert_equals(value, registration, + assert_equals(value.scope, registration.scope, 'getRegistration should resolve with registration'); service_worker_unregister_and_done(t, scope); }) From 4c3074bb422ae79a307f7ac83508b0fc0037b707 Mon Sep 17 00:00:00 2001 From: Nikhil Marathe Date: Tue, 18 Aug 2015 16:28:04 -0700 Subject: [PATCH 074/208] Bug 1181056 - waitUntil() should throw if called when event is not dispatching. r=smaug --- dom/webidl/ExtendableEvent.webidl | 1 + dom/workers/ServiceWorkerEvents.cpp | 7 ++++++- dom/workers/ServiceWorkerEvents.h | 2 +- .../extendable-event-async-waituntil.https.html.ini | 5 ----- 4 files changed, 8 insertions(+), 7 deletions(-) delete mode 100644 testing/web-platform/mozilla/meta/service-workers/service-worker/extendable-event-async-waituntil.https.html.ini diff --git a/dom/webidl/ExtendableEvent.webidl b/dom/webidl/ExtendableEvent.webidl index 47a192ba6ff8..01dc545efd4e 100644 --- a/dom/webidl/ExtendableEvent.webidl +++ b/dom/webidl/ExtendableEvent.webidl @@ -11,6 +11,7 @@ Exposed=ServiceWorker] interface ExtendableEvent : Event { // https://github.com/slightlyoff/ServiceWorker/issues/261 + [Throws] void waitUntil(Promise p); }; diff --git a/dom/workers/ServiceWorkerEvents.cpp b/dom/workers/ServiceWorkerEvents.cpp index 75203a49f5bc..21321a59cc5d 100644 --- a/dom/workers/ServiceWorkerEvents.cpp +++ b/dom/workers/ServiceWorkerEvents.cpp @@ -395,10 +395,15 @@ ExtendableEvent::ExtendableEvent(EventTarget* aOwner) } void -ExtendableEvent::WaitUntil(Promise& aPromise) +ExtendableEvent::WaitUntil(Promise& aPromise, ErrorResult& aRv) { MOZ_ASSERT(!NS_IsMainThread()); + if (EventPhase() == nsIDOMEvent::NONE) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return; + } + // Only first caller counts. if (EventPhase() == AT_TARGET && !mPromise) { mPromise = &aPromise; diff --git a/dom/workers/ServiceWorkerEvents.h b/dom/workers/ServiceWorkerEvents.h index a9ca3c8534fd..0ffd9ef67e25 100644 --- a/dom/workers/ServiceWorkerEvents.h +++ b/dom/workers/ServiceWorkerEvents.h @@ -141,7 +141,7 @@ class ExtendableEvent : public Event } void - WaitUntil(Promise& aPromise); + WaitUntil(Promise& aPromise, ErrorResult& aRv); already_AddRefed GetPromise() const diff --git a/testing/web-platform/mozilla/meta/service-workers/service-worker/extendable-event-async-waituntil.https.html.ini b/testing/web-platform/mozilla/meta/service-workers/service-worker/extendable-event-async-waituntil.https.html.ini deleted file mode 100644 index 52a17fc60b18..000000000000 --- a/testing/web-platform/mozilla/meta/service-workers/service-worker/extendable-event-async-waituntil.https.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[extendable-event-async-waituntil.https.html] - type: testharness - [Calling waitUntil asynchronously throws an exception] - expected: FAIL - From e8e63b3d2cd81dcfabc1c4d527a6c3f92e33fb4a Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Wed, 19 Aug 2015 15:55:34 +0900 Subject: [PATCH 075/208] Bug 1120793 - Remove obsolete _Throw wrapping. r=froydnj --- configure.in | 67 ++++++------------------- memory/mozalloc/moz.build | 9 +--- memory/mozalloc/msvc_throw_wrapper.cpp | 26 ---------- memory/mozalloc/msvc_throw_wrapper.h | 18 ------- memory/mozalloc/staticruntime/moz.build | 8 +-- memory/mozalloc/throw_msvc.h | 2 - 6 files changed, 17 insertions(+), 113 deletions(-) delete mode 100644 memory/mozalloc/msvc_throw_wrapper.cpp delete mode 100644 memory/mozalloc/msvc_throw_wrapper.h diff --git a/configure.in b/configure.in index 6d33504ae788..29b4f42836a4 100644 --- a/configure.in +++ b/configure.in @@ -663,66 +663,30 @@ See https://developer.mozilla.org/en/Windows_Build_Prerequisites.]) unset _MSVC_VER_FILTER - AC_CACHE_CHECK(for std::_Throw, ac_cv_have_std__Throw, + AC_CACHE_CHECK(for overridable _RAISE, + ac_cv_have__RAISE, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS _SAVE_CXXFLAGS="$CXXFLAGS" CXXFLAGS="${CXXFLAGS} -D_HAS_EXCEPTIONS=0" - AC_TRY_COMPILE([#include ], - [std::_Throw(std::exception()); return 0;], - ac_cv_have_std__Throw="yes", - ac_cv_have_std__Throw="no") + AC_TRY_COMPILE([#include + #undef _RAISE + #define _RAISE(x) externallyDefinedFunction((x).what()) + #include + ], + [std::vector v; return v.at(1);], + ac_cv_have__RAISE="no", + ac_cv_have__RAISE="yes") CXXFLAGS="$_SAVE_CXXFLAGS" AC_LANG_RESTORE ]) - - if test "$ac_cv_have_std__Throw" = "yes"; then - AC_CACHE_CHECK(for |class __declspec(dllimport) exception| bug, - ac_cv_have_dllimport_exception_bug, - [ - AC_LANG_SAVE - AC_LANG_CPLUSPLUS - _SAVE_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="${CXXFLAGS} -D_HAS_EXCEPTIONS=0" - AC_TRY_LINK([#include ], - [std::vector v; return v.at(1);], - ac_cv_have_dllimport_exception_bug="no", - ac_cv_have_dllimport_exception_bug="yes") - CXXFLAGS="$_SAVE_CXXFLAGS" - AC_LANG_RESTORE - ]) - if test "$ac_cv_have_dllimport_exception_bug" = "no"; then - WRAP_STL_INCLUDES=1 - MOZ_MSVC_STL_WRAP_Throw=1 - AC_DEFINE(MOZ_MSVC_STL_WRAP_Throw) - fi + if test "$ac_cv_have__RAISE" = "yes"; then + WRAP_STL_INCLUDES=1 + MOZ_MSVC_STL_WRAP_RAISE=1 + AC_DEFINE(MOZ_MSVC_STL_WRAP_RAISE) else - AC_CACHE_CHECK(for overridable _RAISE, - ac_cv_have__RAISE, - [ - AC_LANG_SAVE - AC_LANG_CPLUSPLUS - _SAVE_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="${CXXFLAGS} -D_HAS_EXCEPTIONS=0" - AC_TRY_COMPILE([#include - #undef _RAISE - #define _RAISE(x) externallyDefinedFunction((x).what()) - #include - ], - [std::vector v; return v.at(1);], - ac_cv_have__RAISE="no", - ac_cv_have__RAISE="yes") - CXXFLAGS="$_SAVE_CXXFLAGS" - AC_LANG_RESTORE - ]) - if test "$ac_cv_have__RAISE" = "yes"; then - WRAP_STL_INCLUDES=1 - MOZ_MSVC_STL_WRAP_RAISE=1 - AC_DEFINE(MOZ_MSVC_STL_WRAP_RAISE) - else - AC_MSG_ERROR([Gecko exception wrapping doesn't understand your your MSVC/SDK. Please file a bug describing this error and your build configuration.]) - fi + AC_MSG_ERROR([Gecko exception wrapping doesn't understand your your MSVC/SDK. Please file a bug describing this error and your build configuration.]) fi if test "$WRAP_STL_INCLUDES" = "1"; then @@ -839,7 +803,6 @@ AC_SUBST(INTEL_CXX) AC_SUBST(STL_FLAGS) AC_SUBST(WRAP_STL_INCLUDES) -AC_SUBST(MOZ_MSVC_STL_WRAP_Throw) AC_SUBST(MOZ_MSVC_STL_WRAP_RAISE) dnl ======================================================== diff --git a/memory/mozalloc/moz.build b/memory/mozalloc/moz.build index 443a7f0efe9c..6bfe4bd139ca 100644 --- a/memory/mozalloc/moz.build +++ b/memory/mozalloc/moz.build @@ -11,25 +11,18 @@ EXPORTS.mozilla += [ 'mozalloc_oom.h', ] -if CONFIG['MOZ_MSVC_STL_WRAP_RAISE'] or CONFIG['MOZ_MSVC_STL_WRAP_Throw']: - build_msvc_wrappers = 1 -else: - build_msvc_wrappers = 0 - if CONFIG['WRAP_STL_INCLUDES']: if CONFIG['GNU_CXX']: EXPORTS.mozilla += ['throw_gcc.h'] elif CONFIG['_MSC_VER']: DEFINES['_HAS_EXCEPTIONS'] = 0 - if build_msvc_wrappers: + if CONFIG['MOZ_MSVC_STL_WRAP_RAISE']: EXPORTS.mozilla += [ 'msvc_raise_wrappers.h', - 'msvc_throw_wrapper.h', 'throw_msvc.h', ] SOURCES += [ 'msvc_raise_wrappers.cpp', - 'msvc_throw_wrapper.cpp', ] UNIFIED_SOURCES += [ diff --git a/memory/mozalloc/msvc_throw_wrapper.cpp b/memory/mozalloc/msvc_throw_wrapper.cpp deleted file mode 100644 index e93fd8a50ce6..000000000000 --- a/memory/mozalloc/msvc_throw_wrapper.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: sw=4 ts=4 et : - */ -/* 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/. */ - -#include - -#include "mozilla/mozalloc_abort.h" - -namespace std { - -// NB: user code is not supposed to touch the std:: namespace. We're -// doing this after careful review because we want to define our own -// exception throwing semantics. Don't try this at home! - -__declspec(dllexport) void mozilla_Throw(const exception& e); - -void -mozilla_Throw(const exception& e) -{ - mozalloc_abort(e.what()); -} - -} // namespace std diff --git a/memory/mozalloc/msvc_throw_wrapper.h b/memory/mozalloc/msvc_throw_wrapper.h deleted file mode 100644 index 3bdfba40381a..000000000000 --- a/memory/mozalloc/msvc_throw_wrapper.h +++ /dev/null @@ -1,18 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: sw=4 ts=4 et : - */ -/* 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_msvc_throw_wrapper_h -#define mozilla_msvc_throw_wrapper_h - -// Define our own _Throw because the Win2k CRT doesn't export it. -# ifdef _EXCEPTION_ -# error "Unable to wrap _Throw(); CRT _Throw() already declared" -# endif -# define _Throw mozilla_Throw -# include - -#endif // ifndef mozilla_msvc_throw_wrapper_h diff --git a/memory/mozalloc/staticruntime/moz.build b/memory/mozalloc/staticruntime/moz.build index 56de6a066c0b..f29a9f8f5fea 100644 --- a/memory/mozalloc/staticruntime/moz.build +++ b/memory/mozalloc/staticruntime/moz.build @@ -6,17 +6,11 @@ NO_VISIBILITY_FLAGS = True -if CONFIG['MOZ_MSVC_STL_WRAP_RAISE'] or CONFIG['MOZ_MSVC_STL_WRAP_Throw']: - build_msvc_wrappers = 1 -else: - build_msvc_wrappers = 0 - if CONFIG['WRAP_STL_INCLUDES']: DEFINES['_HAS_EXCEPTIONS'] = 0 - if build_msvc_wrappers: + if CONFIG['MOZ_MSVC_STL_WRAP_RAISE']: SOURCES += [ '../msvc_raise_wrappers.cpp', - '../msvc_throw_wrapper.cpp', ] UNIFIED_SOURCES += [ diff --git a/memory/mozalloc/throw_msvc.h b/memory/mozalloc/throw_msvc.h index 3169e75f3fa6..e6ebf46dc4c0 100644 --- a/memory/mozalloc/throw_msvc.h +++ b/memory/mozalloc/throw_msvc.h @@ -10,8 +10,6 @@ #if defined(MOZ_MSVC_STL_WRAP_RAISE) # include "msvc_raise_wrappers.h" -#elif defined(MOZ_MSVC_STL_WRAP_Throw) -# include "msvc_throw_wrapper.h" #else # error "Unknown STL wrapper tactic" #endif From 85dd8f9242c883ea863f69ebaaec00607877904d Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Thu, 20 Aug 2015 11:51:56 +0900 Subject: [PATCH 076/208] Bug 1196608 - Link liblgpllibs against mozglue. r=mshal --- config/external/lgpllibs/moz.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/external/lgpllibs/moz.build b/config/external/lgpllibs/moz.build index 9812b79c36e2..27df35dbf831 100644 --- a/config/external/lgpllibs/moz.build +++ b/config/external/lgpllibs/moz.build @@ -10,7 +10,7 @@ # # Any library added here should also be reflected in the about:license page. -SharedLibrary('lgpllibs') +GeckoSharedLibrary('lgpllibs', linkage=None) SHARED_LIBRARY_NAME = 'lgpllibs' if CONFIG['MOZ_LIBAV_FFT']: From 1bcf07b24e5213c43170666dcdd21e76cbab7d1c Mon Sep 17 00:00:00 2001 From: Bas Schouten Date: Thu, 20 Aug 2015 20:03:44 +0000 Subject: [PATCH 077/208] Bug 1189891: Only include STL wrapper requirements on the first include. r=glandium --- config/msvc-stl-wrapper.template.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/msvc-stl-wrapper.template.h b/config/msvc-stl-wrapper.template.h index 0a01a6dd1b5f..c42da266ed0d 100644 --- a/config/msvc-stl-wrapper.template.h +++ b/config/msvc-stl-wrapper.template.h @@ -8,6 +8,9 @@ #ifndef mozilla_${HEADER}_h #define mozilla_${HEADER}_h +#ifndef MOZ_HAVE_INCLUDED_ALLOC +#define MOZ_HAVE_INCLUDED_ALLOC + #if _HAS_EXCEPTIONS # error "STL code can only be used with -fno-exceptions" #endif @@ -32,6 +35,7 @@ #else # error "STL code can only be used with infallible ::operator new()" #endif +#endif /* MOZ_HAVE_INCLUDED_ALLOC */ #ifdef _DEBUG // From From 92ebac6a80d5e5fbcec4f2548b4f47b7f9b0c0a3 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 21 Aug 2015 08:29:06 +0900 Subject: [PATCH 078/208] Bug 1189891 - Avoid including from pkix/Input.h. r=bsmith --- security/pkix/include/pkix/Input.h | 8 ++++---- security/pkix/test/lib/pkixtestutil.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/security/pkix/include/pkix/Input.h b/security/pkix/include/pkix/Input.h index 8ff9bb09243a..4b7232c42ac6 100644 --- a/security/pkix/include/pkix/Input.h +++ b/security/pkix/include/pkix/Input.h @@ -25,7 +25,7 @@ #ifndef mozilla_pkix_Input_h #define mozilla_pkix_Input_h -#include +#include #include "pkix/Result.h" #include "stdint.h" @@ -133,7 +133,7 @@ inline bool InputsAreEqual(const Input& a, const Input& b) { return a.GetLength() == b.GetLength() && - !std::memcmp(a.UnsafeGetData(), b.UnsafeGetData(), a.GetLength()); + !std::equal(a.UnsafeGetData(), a.UnsafeGetData() + a.GetLength(), b.UnsafeGetData()); } // An Reader is a cursor/iterator through the contents of an Input, designed to @@ -205,7 +205,7 @@ class Reader final if (static_cast(end - input) != N) { return false; } - if (memcmp(input, toMatch, N)) { + if (std::equal(input, end, toMatch)) { return false; } input = end; @@ -221,7 +221,7 @@ class Reader final if (toMatch.GetLength() != remaining) { return false; } - if (std::memcmp(input, toMatch.UnsafeGetData(), remaining)) { + if (std::equal(input, end, toMatch.UnsafeGetData())) { return false; } input = end; diff --git a/security/pkix/test/lib/pkixtestutil.h b/security/pkix/test/lib/pkixtestutil.h index 896ab5eb9bfa..5a445cc17758 100644 --- a/security/pkix/test/lib/pkixtestutil.h +++ b/security/pkix/test/lib/pkixtestutil.h @@ -28,6 +28,7 @@ #include #include // Some Mozilla-supported compilers lack #include +#include #include "pkix/pkixtypes.h" #include "../../lib/ScopedPtr.h" From cfae941ef11241f4206289ac2556cb9c800d4655 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Thu, 20 Aug 2015 16:50:08 +1000 Subject: [PATCH 079/208] Bug 1196398: [mp4] Do not allocate memory spanning across ftyp and moov atom. r=kentuckyfriedtakahe A typical non-fragmented mp4 would have the ftyp atom located at the beginning of the mp4 and the moov at the end. We would to calculate the location of the metadata by spanning the byte range of the two atoms. As such, we would typically allocate an amount of memory equivalent to the size of the mp4. Instead we now reconstruct the metadata to only have the ftyp and moov atoms contiguously. --- dom/media/fmp4/MP4Demuxer.cpp | 12 ++--- media/libstagefright/binding/MP4Metadata.cpp | 9 ++-- media/libstagefright/binding/MoofParser.cpp | 52 +++++++++++++++---- .../binding/include/mp4_demuxer/MP4Metadata.h | 2 +- .../binding/include/mp4_demuxer/MoofParser.h | 3 ++ 5 files changed, 53 insertions(+), 25 deletions(-) diff --git a/dom/media/fmp4/MP4Demuxer.cpp b/dom/media/fmp4/MP4Demuxer.cpp index a21ff213941f..0a95ac56c86e 100644 --- a/dom/media/fmp4/MP4Demuxer.cpp +++ b/dom/media/fmp4/MP4Demuxer.cpp @@ -79,22 +79,16 @@ MP4Demuxer::Init() AutoPinned stream(mStream); // Check that we have enough data to read the metadata. - MediaByteRange br = mp4_demuxer::MP4Metadata::MetadataRange(stream); - if (br.IsNull()) { + if (!mp4_demuxer::MP4Metadata::HasCompleteMetadata(stream)) { return InitPromise::CreateAndReject(DemuxerFailureReason::WAITING_FOR_DATA, __func__); } - if (!mInitData->SetLength(br.Length(), fallible)) { + mInitData = mp4_demuxer::MP4Metadata::Metadata(stream); + if (!mInitData) { // OOM return InitPromise::CreateAndReject(DemuxerFailureReason::DEMUXER_ERROR, __func__); } - size_t size; - mStream->ReadAt(br.mStart, mInitData->Elements(), br.Length(), &size); - if (size != size_t(br.Length())) { - return InitPromise::CreateAndReject(DemuxerFailureReason::DEMUXER_ERROR, __func__); - } - nsRefPtr bufferstream = new mp4_demuxer::BufferStream(mInitData); diff --git a/media/libstagefright/binding/MP4Metadata.cpp b/media/libstagefright/binding/MP4Metadata.cpp index 5effe9f44998..6782b34e9428 100644 --- a/media/libstagefright/binding/MP4Metadata.cpp +++ b/media/libstagefright/binding/MP4Metadata.cpp @@ -287,17 +287,14 @@ MP4Metadata::HasCompleteMetadata(Stream* aSource) return parser->HasMetadata(); } -/*static*/ mozilla::MediaByteRange -MP4Metadata::MetadataRange(Stream* aSource) +/*static*/ already_AddRefed +MP4Metadata::Metadata(Stream* aSource) { // The MoofParser requires a monitor, but we don't need one here. mozilla::Monitor monitor("MP4Metadata::HasCompleteMetadata"); mozilla::MonitorAutoLock mon(monitor); auto parser = mozilla::MakeUnique(aSource, 0, false, &monitor); - if (parser->HasMetadata()) { - return parser->mInitRange; - } - return mozilla::MediaByteRange(); + return parser->Metadata(); } } // namespace mp4_demuxer diff --git a/media/libstagefright/binding/MoofParser.cpp b/media/libstagefright/binding/MoofParser.cpp index 7bb7d090de03..79fa3ff7741a 100644 --- a/media/libstagefright/binding/MoofParser.cpp +++ b/media/libstagefright/binding/MoofParser.cpp @@ -148,8 +148,9 @@ MoofParser::BlockingReadNextMoof() return false; } -bool -MoofParser::HasMetadata() +void +MoofParser::ScanForMetadata(mozilla::MediaByteRange& aFtyp, + mozilla::MediaByteRange& aMoov) { int64_t length = std::numeric_limits::max(); mSource->Length(&length); @@ -157,24 +158,57 @@ MoofParser::HasMetadata() byteRanges.AppendElement(MediaByteRange(0, length)); nsRefPtr stream = new BlockingStream(mSource); - MediaByteRange ftyp; - MediaByteRange moov; BoxContext context(stream, byteRanges); for (Box box(&context, mOffset); box.IsAvailable(); box = box.Next()) { if (box.IsType("ftyp")) { - ftyp = box.Range(); + aFtyp = box.Range(); continue; } if (box.IsType("moov")) { - moov = box.Range(); + aMoov = box.Range(); break; } } + mInitRange = aFtyp.Extents(aMoov); +} + +bool +MoofParser::HasMetadata() +{ + MediaByteRange ftyp; + MediaByteRange moov; + ScanForMetadata(ftyp, moov); + return !!ftyp.Length() && !!moov.Length(); +} + +already_AddRefed +MoofParser::Metadata() +{ + MediaByteRange ftyp; + MediaByteRange moov; + ScanForMetadata(ftyp, moov); if (!ftyp.Length() || !moov.Length()) { - return false; + return nullptr; } - mInitRange = ftyp.Extents(moov); - return true; + nsRefPtr metadata = new MediaByteBuffer(); + if (!metadata->SetLength(ftyp.Length() + moov.Length(), fallible)) { + // OOM + return nullptr; + } + + nsRefPtr stream = new BlockingStream(mSource); + size_t read; + bool rv = + stream->ReadAt(ftyp.mStart, metadata->Elements(), ftyp.Length(), &read); + if (!rv || read != ftyp.Length()) { + return nullptr; + } + rv = + stream->ReadAt(moov.mStart, metadata->Elements() + ftyp.Length(), moov.Length(), &read); + if (!rv || read != moov.Length()) { + return nullptr; + } + return metadata.forget(); } Interval diff --git a/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h b/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h index de9273c2725d..45def45af7a0 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h +++ b/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h @@ -30,7 +30,7 @@ class MP4Metadata ~MP4Metadata(); static bool HasCompleteMetadata(Stream* aSource); - static mozilla::MediaByteRange MetadataRange(Stream* aSource); + static already_AddRefed Metadata(Stream* aSource); uint32_t GetNumberTracks(mozilla::TrackInfo::TrackType aType) const; mozilla::UniquePtr GetTrackInfo(mozilla::TrackInfo::TrackType aType, size_t aTrackNumber) const; diff --git a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h index 86daead28cd4..4b1740b1e234 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h +++ b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h @@ -228,6 +228,7 @@ class MoofParser bool BlockingReadNextMoof(); bool HasMetadata(); + already_AddRefed Metadata(); MediaByteRange FirstCompleteMediaSegment(); MediaByteRange FirstCompleteMediaHeader(); @@ -244,6 +245,8 @@ class MoofParser Monitor* mMonitor; nsTArray& Moofs() { mMonitor->AssertCurrentThreadOwns(); return mMoofs; } private: + void ScanForMetadata(mozilla::MediaByteRange& aFtyp, + mozilla::MediaByteRange& aMoov); nsTArray mMoofs; nsTArray mMediaRanges; bool mIsAudio; From 159c0f0912ae88facde718f0e5b779e64cb3f8c4 Mon Sep 17 00:00:00 2001 From: Hannes Verschore Date: Fri, 21 Aug 2015 07:56:41 +0200 Subject: [PATCH 080/208] Bug 1169214: IonMonkey - Part 1: Create Ion shared stub helpers, r=jandem --- js/src/jit/BaselineIC.cpp | 18 +++++----- js/src/jit/SharedIC.cpp | 28 ++++++++++++--- js/src/jit/arm/SharedICHelpers-arm.h | 42 +++++++++++++++++----- js/src/jit/arm/Trampoline-arm.cpp | 6 ++-- js/src/jit/mips32/SharedICHelpers-mips32.h | 42 +++++++++++++++++----- js/src/jit/mips32/Trampoline-mips32.cpp | 6 ++-- js/src/jit/none/SharedICHelpers-none.h | 14 +++++--- js/src/jit/x64/SharedICHelpers-x64.h | 42 +++++++++++++++++----- js/src/jit/x64/Trampoline-x64.cpp | 6 ++-- js/src/jit/x86/SharedICHelpers-x86.h | 42 +++++++++++++++++----- js/src/jit/x86/Trampoline-x86.cpp | 6 ++-- 11 files changed, 186 insertions(+), 66 deletions(-) diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index ae9ad0652d65..3b5ef9751d59 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -3293,7 +3293,7 @@ ICGetElemNativeCompiler::emitCallScripted(MacroAssembler& masm, Register objR // Push argc, callee, and descriptor. { Register callScratch = regs.takeAny(); - EmitCreateStubFrameDescriptor(masm, callScratch); + EmitBaselineCreateStubFrameDescriptor(masm, callScratch); masm.Push(Imm32(0)); // ActualArgc is 0 masm.Push(callee); masm.Push(callScratch); @@ -7215,7 +7215,7 @@ ICGetProp_CallScripted::Compiler::generateStubCode(MacroAssembler& masm) // Note that we use Push, not push, so that callJit will align the stack // properly on ARM. masm.Push(R0); - EmitCreateStubFrameDescriptor(masm, scratch); + EmitBaselineCreateStubFrameDescriptor(masm, scratch); masm.Push(Imm32(0)); // ActualArgc is 0 masm.Push(callee); masm.Push(scratch); @@ -8747,7 +8747,7 @@ ICSetProp_CallScripted::Compiler::generateStubCode(MacroAssembler& masm) // Stack: [ ..., R0, R1, ..STUBFRAME-HEADER.., padding? ] masm.PushValue(Address(BaselineFrameReg, STUB_FRAME_SIZE)); masm.Push(R0); - EmitCreateStubFrameDescriptor(masm, scratch); + EmitBaselineCreateStubFrameDescriptor(masm, scratch); masm.Push(Imm32(1)); // ActualArgc is 1 masm.Push(callee); masm.Push(scratch); @@ -10171,7 +10171,7 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm) masm.popValue(val); callee = masm.extractObject(val, ExtractTemp0); - EmitCreateStubFrameDescriptor(masm, scratch); + EmitBaselineCreateStubFrameDescriptor(masm, scratch); // Note that we use Push, not push, so that callJit will align the stack // properly on ARM. @@ -10474,7 +10474,7 @@ ICCall_Native::Compiler::generateStubCode(MacroAssembler& masm) masm.push(argcReg); Register scratch = regs.takeAny(); - EmitCreateStubFrameDescriptor(masm, scratch); + EmitBaselineCreateStubFrameDescriptor(masm, scratch); masm.push(scratch); masm.push(ICTailCallReg); masm.enterFakeExitFrame(NativeExitFrameLayout::Token()); @@ -10572,7 +10572,7 @@ ICCall_ClassHook::Compiler::generateStubCode(MacroAssembler& masm) // Construct a native exit frame. masm.push(argcReg); - EmitCreateStubFrameDescriptor(masm, scratch); + EmitBaselineCreateStubFrameDescriptor(masm, scratch); masm.push(scratch); masm.push(ICTailCallReg); masm.enterFakeExitFrame(NativeExitFrameLayout::Token()); @@ -10659,7 +10659,7 @@ ICCall_ScriptedApplyArray::Compiler::generateStubCode(MacroAssembler& masm) // All pushes after this use Push instead of push to make sure ARM can align // stack properly for call. Register scratch = regs.takeAny(); - EmitCreateStubFrameDescriptor(masm, scratch); + EmitBaselineCreateStubFrameDescriptor(masm, scratch); // Reload argc from length of array. masm.extractObject(arrayVal, argcReg); @@ -10760,7 +10760,7 @@ ICCall_ScriptedApplyArguments::Compiler::generateStubCode(MacroAssembler& masm) // All pushes after this use Push instead of push to make sure ARM can align // stack properly for call. Register scratch = regs.takeAny(); - EmitCreateStubFrameDescriptor(masm, scratch); + EmitBaselineCreateStubFrameDescriptor(masm, scratch); masm.loadPtr(Address(BaselineFrameReg, 0), argcReg); masm.loadPtr(Address(argcReg, BaselineFrame::offsetOfNumActualArgs()), argcReg); @@ -10893,7 +10893,7 @@ ICCall_ScriptedFunCall::Compiler::generateStubCode(MacroAssembler& masm) callee = masm.extractObject(val, ExtractTemp0); Register scratch = regs.takeAny(); - EmitCreateStubFrameDescriptor(masm, scratch); + EmitBaselineCreateStubFrameDescriptor(masm, scratch); // Note that we use Push, not push, so that callJit will align the stack // properly on ARM. diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index 5539e92f3269..a3f3a85ec1a3 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -746,7 +746,12 @@ ICStubCompiler::tailCallVM(const VMFunction& fun, MacroAssembler& masm) MOZ_ASSERT(fun.expectTailCall == TailCall); uint32_t argSize = fun.explicitStackSlots() * sizeof(void*); - EmitTailCallVM(code, masm, argSize); + if (engine_ == Engine::Baseline) { + EmitBaselineTailCallVM(code, masm, argSize); + } else { + uint32_t stackSize = argSize + fun.extraValuesToPop * sizeof(Value); + EmitIonTailCallVM(code, masm, stackSize); + } return true; } @@ -760,7 +765,10 @@ ICStubCompiler::callVM(const VMFunction& fun, MacroAssembler& masm) return false; MOZ_ASSERT(fun.expectTailCall == NonTailCall); - EmitCallVM(code, masm); + if (engine_ == Engine::Baseline) + EmitBaselineCallVM(code, masm); + else + EmitIonCallVM(code, fun.explicitStackSlots(), masm); return true; } @@ -778,7 +786,10 @@ ICStubCompiler::callTypeUpdateIC(MacroAssembler& masm, uint32_t objectOffset) void ICStubCompiler::enterStubFrame(MacroAssembler& masm, Register scratch) { - EmitEnterStubFrame(masm, scratch); + if (engine_ == Engine::Baseline) + EmitBaselineEnterStubFrame(masm, scratch); + else + EmitIonEnterStubFrame(masm, scratch); MOZ_ASSERT(!inStubFrame_); inStubFrame_ = true; @@ -793,12 +804,21 @@ ICStubCompiler::leaveStubFrame(MacroAssembler& masm, bool calledIntoIon) { MOZ_ASSERT(entersStubFrame_ && inStubFrame_); inStubFrame_ = false; - EmitLeaveStubFrame(masm, calledIntoIon); + + if (engine_ == Engine::Baseline) + EmitBaselineLeaveStubFrame(masm, calledIntoIon); + else + EmitIonLeaveStubFrame(masm); } void ICStubCompiler::pushFramePtr(MacroAssembler& masm, Register scratch) { + if (engine_ == Engine::IonMonkey) { + masm.push(Imm32(0)); + return; + } + if (inStubFrame_) { masm.loadPtr(Address(BaselineFrameReg, 0), scratch); masm.pushBaselineFramePtr(scratch, scratch); diff --git a/js/src/jit/arm/SharedICHelpers-arm.h b/js/src/jit/arm/SharedICHelpers-arm.h index 9f1419a01054..8e9a9cda842a 100644 --- a/js/src/jit/arm/SharedICHelpers-arm.h +++ b/js/src/jit/arm/SharedICHelpers-arm.h @@ -79,7 +79,7 @@ EmitChangeICReturnAddress(MacroAssembler& masm, Register reg) } inline void -EmitTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t argSize) +EmitBaselineTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t argSize) { // We assume during this that R0 and R1 have been pushed, and that R2 is // unused. @@ -106,7 +106,13 @@ EmitTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t argSize) } inline void -EmitCreateStubFrameDescriptor(MacroAssembler& masm, Register reg) +EmitIonTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t stackSize) +{ + MOZ_CRASH("Not implemented yet."); +} + +inline void +EmitBaselineCreateStubFrameDescriptor(MacroAssembler& masm, Register reg) { // Compute stub frame size. We have to add two pointers: the stub reg and // previous frame pointer pushed by EmitEnterStubFrame. @@ -118,19 +124,25 @@ EmitCreateStubFrameDescriptor(MacroAssembler& masm, Register reg) } inline void -EmitCallVM(JitCode* target, MacroAssembler& masm) +EmitBaselineCallVM(JitCode* target, MacroAssembler& masm) { - EmitCreateStubFrameDescriptor(masm, r0); + EmitBaselineCreateStubFrameDescriptor(masm, r0); masm.push(r0); masm.call(target); } +inline void +EmitIonCallVM(JitCode* target, size_t stackSlots, MacroAssembler& masm) +{ + MOZ_CRASH("Not implemented yet."); +} + // Size of vales pushed by EmitEnterStubFrame. static const uint32_t STUB_FRAME_SIZE = 4 * sizeof(void*); static const uint32_t STUB_FRAME_SAVED_STUB_OFFSET = sizeof(void*); inline void -EmitEnterStubFrame(MacroAssembler& masm, Register scratch) +EmitBaselineEnterStubFrame(MacroAssembler& masm, Register scratch) { MOZ_ASSERT(scratch != ICTailCallReg); @@ -159,7 +171,13 @@ EmitEnterStubFrame(MacroAssembler& masm, Register scratch) } inline void -EmitLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false) +EmitIonEnterStubFrame(MacroAssembler& masm, Register scratch) +{ + MOZ_CRASH("Not implemented yet."); +} + +inline void +EmitBaselineLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false) { // Ion frames do not save and restore the frame pointer. If we called into // Ion, we have to restore the stack pointer from the frame descriptor. If @@ -183,6 +201,12 @@ EmitLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false) masm.pop(ScratchRegister); } +inline void +EmitIonLeaveStubFrame(MacroAssembler& masm) +{ + MOZ_CRASH("Not implemented yet."); +} + inline void EmitStowICValues(MacroAssembler& masm, int values) { @@ -262,7 +286,7 @@ EmitCallTypeUpdateIC(MacroAssembler& masm, JitCode* code, uint32_t objectOffset) masm.j(Assembler::Equal, &success); // If the IC failed, then call the update fallback function. - EmitEnterStubFrame(masm, R1.scratchReg()); + EmitBaselineEnterStubFrame(masm, R1.scratchReg()); masm.loadValue(Address(BaselineStackReg, STUB_FRAME_SIZE + objectOffset), R1); @@ -274,8 +298,8 @@ EmitCallTypeUpdateIC(MacroAssembler& masm, JitCode* code, uint32_t objectOffset) masm.loadPtr(Address(BaselineFrameReg, 0), R0.scratchReg()); masm.pushBaselineFramePtr(R0.scratchReg(), R0.scratchReg()); - EmitCallVM(code, masm); - EmitLeaveStubFrame(masm); + EmitBaselineCallVM(code, masm); + EmitBaselineLeaveStubFrame(masm); // Success at end. masm.bind(&success); diff --git a/js/src/jit/arm/Trampoline-arm.cpp b/js/src/jit/arm/Trampoline-arm.cpp index 9baeb12259b4..7eca4cdaee5e 100644 --- a/js/src/jit/arm/Trampoline-arm.cpp +++ b/js/src/jit/arm/Trampoline-arm.cpp @@ -980,7 +980,7 @@ JitRuntime::generateDebugTrapHandler(JSContext* cx) // stub frame has a nullptr ICStub pointer, since this pointer is marked // during GC. masm.movePtr(ImmPtr(nullptr), ICStubReg); - EmitEnterStubFrame(masm, scratch2); + EmitBaselineEnterStubFrame(masm, scratch2); JitCode* code = cx->runtime()->jitRuntime()->getVMWrapper(HandleDebugTrapInfo); if (!code) @@ -988,9 +988,9 @@ JitRuntime::generateDebugTrapHandler(JSContext* cx) masm.push(lr); masm.push(scratch1); - EmitCallVM(code, masm); + EmitBaselineCallVM(code, masm); - EmitLeaveStubFrame(masm); + EmitBaselineLeaveStubFrame(masm); // If the stub returns |true|, we have to perform a forced return (return // from the JS frame). If the stub returns |false|, just return from the diff --git a/js/src/jit/mips32/SharedICHelpers-mips32.h b/js/src/jit/mips32/SharedICHelpers-mips32.h index e0269ad7e3d6..68a398a67911 100644 --- a/js/src/jit/mips32/SharedICHelpers-mips32.h +++ b/js/src/jit/mips32/SharedICHelpers-mips32.h @@ -78,7 +78,7 @@ EmitChangeICReturnAddress(MacroAssembler& masm, Register reg) } inline void -EmitTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t argSize) +EmitBaselineTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t argSize) { // We assume during this that R0 and R1 have been pushed, and that R2 is // unused. @@ -107,7 +107,13 @@ EmitTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t argSize) } inline void -EmitCreateStubFrameDescriptor(MacroAssembler& masm, Register reg) +EmitIonTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t stackSize) +{ + MOZ_CRASH("Not implemented yet."); +} + +inline void +EmitBaselineCreateStubFrameDescriptor(MacroAssembler& masm, Register reg) { // Compute stub frame size. We have to add two pointers: the stub reg and // previous frame pointer pushed by EmitEnterStubFrame. @@ -119,13 +125,19 @@ EmitCreateStubFrameDescriptor(MacroAssembler& masm, Register reg) } inline void -EmitCallVM(JitCode* target, MacroAssembler& masm) +EmitBaselineCallVM(JitCode* target, MacroAssembler& masm) { - EmitCreateStubFrameDescriptor(masm, t6); + EmitBaselineCreateStubFrameDescriptor(masm, t6); masm.push(t6); masm.call(target); } +inline void +EmitIonCallVM(JitCode* target, size_t stackSlots, MacroAssembler& masm) +{ + MOZ_CRASH("Not implemented yet."); +} + struct BaselineStubFrame { uintptr_t savedFrame; uintptr_t savedStub; @@ -137,7 +149,7 @@ static const uint32_t STUB_FRAME_SIZE = sizeof(BaselineStubFrame); static const uint32_t STUB_FRAME_SAVED_STUB_OFFSET = offsetof(BaselineStubFrame, savedStub); inline void -EmitEnterStubFrame(MacroAssembler& masm, Register scratch) +mitBaselineEnterStubFrame(MacroAssembler& masm, Register scratch) { MOZ_ASSERT(scratch != ICTailCallReg); @@ -170,7 +182,13 @@ EmitEnterStubFrame(MacroAssembler& masm, Register scratch) } inline void -EmitLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false) +EmitIonEnterStubFrame(MacroAssembler& masm, Register scratch) +{ + MOZ_CRASH("Not implemented yet."); +} + +inline void +EmitBaselineLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false) { // Ion frames do not save and restore the frame pointer. If we called // into Ion, we have to restore the stack pointer from the frame descriptor. @@ -198,6 +216,12 @@ EmitLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false) masm.addPtr(Imm32(STUB_FRAME_SIZE), StackPointer); } +inline void +EmitIonLeaveStubFrame(MacroAssembler& masm) +{ + MOZ_CRASH("Not implemented yet."); +} + inline void EmitStowICValues(MacroAssembler& masm, int values) { @@ -274,7 +298,7 @@ EmitCallTypeUpdateIC(MacroAssembler& masm, JitCode* code, uint32_t objectOffset) masm.ma_b(R1.scratchReg(), Imm32(1), &success, Assembler::Equal, ShortJump); // If the IC failed, then call the update fallback function. - EmitEnterStubFrame(masm, R1.scratchReg()); + EmitBaselineEnterStubFrame(masm, R1.scratchReg()); masm.loadValue(Address(BaselineStackReg, STUB_FRAME_SIZE + objectOffset), R1); @@ -286,8 +310,8 @@ EmitCallTypeUpdateIC(MacroAssembler& masm, JitCode* code, uint32_t objectOffset) masm.loadPtr(Address(BaselineFrameReg, 0), R0.scratchReg()); masm.pushBaselineFramePtr(R0.scratchReg(), R0.scratchReg()); - EmitCallVM(code, masm); - EmitLeaveStubFrame(masm); + EmitBaselineCallVM(code, masm); + EmitBaselineLeaveStubFrame(masm); // Success at end. masm.bind(&success); diff --git a/js/src/jit/mips32/Trampoline-mips32.cpp b/js/src/jit/mips32/Trampoline-mips32.cpp index e899a2b3babf..d57865c0a08d 100644 --- a/js/src/jit/mips32/Trampoline-mips32.cpp +++ b/js/src/jit/mips32/Trampoline-mips32.cpp @@ -948,7 +948,7 @@ JitRuntime::generateDebugTrapHandler(JSContext* cx) // the stub frame has a nullptr ICStub pointer, since this pointer is // marked during GC. masm.movePtr(ImmPtr(nullptr), ICStubReg); - EmitEnterStubFrame(masm, scratch2); + EmitBaselineEnterStubFrame(masm, scratch2); JitCode* code = cx->runtime()->jitRuntime()->getVMWrapper(HandleDebugTrapInfo); if (!code) @@ -958,9 +958,9 @@ JitRuntime::generateDebugTrapHandler(JSContext* cx) masm.storePtr(ra, Address(StackPointer, sizeof(uintptr_t))); masm.storePtr(scratch1, Address(StackPointer, 0)); - EmitCallVM(code, masm); + EmitBaselineCallVM(code, masm); - EmitLeaveStubFrame(masm); + EmitBaselineLeaveStubFrame(masm); // If the stub returns |true|, we have to perform a forced return // (return from the JS frame). If the stub returns |false|, just return diff --git a/js/src/jit/none/SharedICHelpers-none.h b/js/src/jit/none/SharedICHelpers-none.h index a35d6e0196bd..1cb33aaad097 100644 --- a/js/src/jit/none/SharedICHelpers-none.h +++ b/js/src/jit/none/SharedICHelpers-none.h @@ -20,11 +20,15 @@ inline void EmitCallIC(CodeOffsetLabel*, MacroAssembler&) { MOZ_CRASH(); } inline void EmitEnterTypeMonitorIC(MacroAssembler&, size_t v = 0) { MOZ_CRASH(); } inline void EmitReturnFromIC(MacroAssembler&) { MOZ_CRASH(); } inline void EmitChangeICReturnAddress(MacroAssembler&, Register) { MOZ_CRASH(); } -inline void EmitTailCallVM(JitCode*, MacroAssembler&, uint32_t) { MOZ_CRASH(); } -inline void EmitCreateStubFrameDescriptor(MacroAssembler&, Register) { MOZ_CRASH(); } -inline void EmitCallVM(JitCode*, MacroAssembler&) { MOZ_CRASH(); } -inline void EmitEnterStubFrame(MacroAssembler&, Register) { MOZ_CRASH(); } -inline void EmitLeaveStubFrame(MacroAssembler&, bool v = false) { MOZ_CRASH(); } +inline void EmitBaselineTailCallVM(JitCode*, MacroAssembler&, uint32_t) { MOZ_CRASH(); } +inline void EmitIonTailCallVM(JitCode*, MacroAssembler&, uint32_t) { MOZ_CRASH(); } +inline void EmitBaselineCreateStubFrameDescriptor(MacroAssembler&, Register) { MOZ_CRASH(); } +inline void EmitBaselineCallVM(JitCode*, MacroAssembler&) { MOZ_CRASH(); } +inline void EmitIonCallVM(JitCode*, size_t, MacroAssembler&) { MOZ_CRASH(); } +inline void EmitBaselineEnterStubFrame(MacroAssembler&, Register) { MOZ_CRASH(); } +inline void EmitIonEnterStubFrame(MacroAssembler&, Register) { MOZ_CRASH(); } +inline void EmitBaselineLeaveStubFrame(MacroAssembler&, bool v = false) { MOZ_CRASH(); } +inline void EmitIonLeaveStubFrame(MacroAssembler&) { MOZ_CRASH(); } inline void EmitStowICValues(MacroAssembler&, int) { MOZ_CRASH(); } inline void EmitUnstowICValues(MacroAssembler&, int, bool v = false) { MOZ_CRASH(); } inline void EmitCallTypeUpdateIC(MacroAssembler&, JitCode*, uint32_t) { MOZ_CRASH(); } diff --git a/js/src/jit/x64/SharedICHelpers-x64.h b/js/src/jit/x64/SharedICHelpers-x64.h index f00d2569914d..11203017cb8c 100644 --- a/js/src/jit/x64/SharedICHelpers-x64.h +++ b/js/src/jit/x64/SharedICHelpers-x64.h @@ -70,7 +70,7 @@ EmitChangeICReturnAddress(MacroAssembler& masm, Register reg) } inline void -EmitTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t argSize) +EmitBaselineTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t argSize) { // We an assume during this that R0 and R1 have been pushed. masm.movq(BaselineFrameReg, ScratchReg); @@ -90,7 +90,13 @@ EmitTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t argSize) } inline void -EmitCreateStubFrameDescriptor(MacroAssembler& masm, Register reg) +EmitIonTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t stackSize) +{ + MOZ_CRASH("Not implemented yet."); +} + +inline void +EmitBaselineCreateStubFrameDescriptor(MacroAssembler& masm, Register reg) { // Compute stub frame size. We have to add two pointers: the stub reg and previous // frame pointer pushed by EmitEnterStubFrame. @@ -102,19 +108,25 @@ EmitCreateStubFrameDescriptor(MacroAssembler& masm, Register reg) } inline void -EmitCallVM(JitCode* target, MacroAssembler& masm) +EmitBaselineCallVM(JitCode* target, MacroAssembler& masm) { - EmitCreateStubFrameDescriptor(masm, ScratchReg); + EmitBaselineCreateStubFrameDescriptor(masm, ScratchReg); masm.push(ScratchReg); masm.call(target); } +inline void +EmitIonCallVM(JitCode* target, size_t stackSlots, MacroAssembler& masm) +{ + MOZ_CRASH("Not implemented yet."); +} + // Size of vales pushed by EmitEnterStubFrame. static const uint32_t STUB_FRAME_SIZE = 4 * sizeof(void*); static const uint32_t STUB_FRAME_SAVED_STUB_OFFSET = sizeof(void*); inline void -EmitEnterStubFrame(MacroAssembler& masm, Register) +EmitBaselineEnterStubFrame(MacroAssembler& masm, Register) { EmitRestoreTailCallReg(masm); @@ -140,7 +152,13 @@ EmitEnterStubFrame(MacroAssembler& masm, Register) } inline void -EmitLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false) +EmitIonEnterStubFrame(MacroAssembler& masm, Register scratch) +{ + MOZ_CRASH("Not implemented yet."); +} + +inline void +EmitBaselineLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false) { // Ion frames do not save and restore the frame pointer. If we called // into Ion, we have to restore the stack pointer from the frame descriptor. @@ -165,6 +183,12 @@ EmitLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false) masm.storePtr(ICTailCallReg, Address(BaselineStackReg, 0)); } +inline void +EmitIonLeaveStubFrame(MacroAssembler& masm) +{ + MOZ_CRASH("Not implemented yet."); +} + inline void EmitStowICValues(MacroAssembler& masm, int values) { @@ -242,7 +266,7 @@ EmitCallTypeUpdateIC(MacroAssembler& masm, JitCode* code, uint32_t objectOffset) masm.j(Assembler::Equal, &success); // If the IC failed, then call the update fallback function. - EmitEnterStubFrame(masm, R1.scratchReg()); + EmitBaselineEnterStubFrame(masm, R1.scratchReg()); masm.loadValue(Address(BaselineStackReg, STUB_FRAME_SIZE + objectOffset), R1); @@ -254,8 +278,8 @@ EmitCallTypeUpdateIC(MacroAssembler& masm, JitCode* code, uint32_t objectOffset) masm.loadPtr(Address(BaselineFrameReg, 0), R0.scratchReg()); masm.pushBaselineFramePtr(R0.scratchReg(), R0.scratchReg()); - EmitCallVM(code, masm); - EmitLeaveStubFrame(masm); + EmitBaselineCallVM(code, masm); + EmitBaselineLeaveStubFrame(masm); // Success at end. masm.bind(&success); diff --git a/js/src/jit/x64/Trampoline-x64.cpp b/js/src/jit/x64/Trampoline-x64.cpp index 48afad42d99d..9a7893045016 100644 --- a/js/src/jit/x64/Trampoline-x64.cpp +++ b/js/src/jit/x64/Trampoline-x64.cpp @@ -872,7 +872,7 @@ JitRuntime::generateDebugTrapHandler(JSContext* cx) // the stub frame has a nullptr ICStub pointer, since this pointer is marked // during GC. masm.movePtr(ImmPtr(nullptr), ICStubReg); - EmitEnterStubFrame(masm, scratch3); + EmitBaselineEnterStubFrame(masm, scratch3); JitCode* code = cx->runtime()->jitRuntime()->getVMWrapper(HandleDebugTrapInfo); if (!code) @@ -880,9 +880,9 @@ JitRuntime::generateDebugTrapHandler(JSContext* cx) masm.push(scratch1); masm.push(scratch2); - EmitCallVM(code, masm); + EmitBaselineCallVM(code, masm); - EmitLeaveStubFrame(masm); + EmitBaselineLeaveStubFrame(masm); // If the stub returns |true|, we have to perform a forced return // (return from the JS frame). If the stub returns |false|, just return diff --git a/js/src/jit/x86/SharedICHelpers-x86.h b/js/src/jit/x86/SharedICHelpers-x86.h index d8d6135e92a8..1be795ad493b 100644 --- a/js/src/jit/x86/SharedICHelpers-x86.h +++ b/js/src/jit/x86/SharedICHelpers-x86.h @@ -71,7 +71,7 @@ EmitChangeICReturnAddress(MacroAssembler& masm, Register reg) } inline void -EmitTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t argSize) +EmitBaselineTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t argSize) { // We assume during this that R0 and R1 have been pushed. @@ -93,7 +93,13 @@ EmitTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t argSize) } inline void -EmitCreateStubFrameDescriptor(MacroAssembler& masm, Register reg) +EmitIonTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t stackSize) +{ + MOZ_CRASH("Not implemented yet."); +} + +inline void +EmitBaselineCreateStubFrameDescriptor(MacroAssembler& masm, Register reg) { // Compute stub frame size. We have to add two pointers: the stub reg and previous // frame pointer pushed by EmitEnterStubFrame. @@ -105,19 +111,25 @@ EmitCreateStubFrameDescriptor(MacroAssembler& masm, Register reg) } inline void -EmitCallVM(JitCode* target, MacroAssembler& masm) +EmitBaselineCallVM(JitCode* target, MacroAssembler& masm) { - EmitCreateStubFrameDescriptor(masm, eax); + EmitBaselineCreateStubFrameDescriptor(masm, eax); masm.push(eax); masm.call(target); } +inline void +EmitIonCallVM(JitCode* target, size_t stackSlots, MacroAssembler& masm) +{ + MOZ_CRASH("Not implemented yet."); +} + // Size of vales pushed by EmitEnterStubFrame. static const uint32_t STUB_FRAME_SIZE = 4 * sizeof(void*); static const uint32_t STUB_FRAME_SAVED_STUB_OFFSET = sizeof(void*); inline void -EmitEnterStubFrame(MacroAssembler& masm, Register scratch) +EmitBaselineEnterStubFrame(MacroAssembler& masm, Register scratch) { MOZ_ASSERT(scratch != ICTailCallReg); @@ -145,7 +157,13 @@ EmitEnterStubFrame(MacroAssembler& masm, Register scratch) } inline void -EmitLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false) +EmitIonEnterStubFrame(MacroAssembler& masm, Register scratch) +{ + MOZ_CRASH("Not implemented yet."); +} + +inline void +EmitBaselineLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false) { // Ion frames do not save and restore the frame pointer. If we called // into Ion, we have to restore the stack pointer from the frame descriptor. @@ -171,6 +189,12 @@ EmitLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false) masm.storePtr(ICTailCallReg, Address(BaselineStackReg, 0)); } +inline void +EmitIonLeaveStubFrame(MacroAssembler& masm) +{ + MOZ_CRASH("Not implemented yet."); +} + inline void EmitStowICValues(MacroAssembler& masm, int values) { @@ -248,7 +272,7 @@ EmitCallTypeUpdateIC(MacroAssembler& masm, JitCode* code, uint32_t objectOffset) masm.j(Assembler::Equal, &success); // If the IC failed, then call the update fallback function. - EmitEnterStubFrame(masm, R1.scratchReg()); + EmitBaselineEnterStubFrame(masm, R1.scratchReg()); masm.loadValue(Address(BaselineStackReg, STUB_FRAME_SIZE + objectOffset), R1); @@ -260,8 +284,8 @@ EmitCallTypeUpdateIC(MacroAssembler& masm, JitCode* code, uint32_t objectOffset) masm.loadPtr(Address(BaselineFrameReg, 0), R0.scratchReg()); masm.pushBaselineFramePtr(R0.scratchReg(), R0.scratchReg()); - EmitCallVM(code, masm); - EmitLeaveStubFrame(masm); + EmitBaselineCallVM(code, masm); + EmitBaselineLeaveStubFrame(masm); // Success at end. masm.bind(&success); diff --git a/js/src/jit/x86/Trampoline-x86.cpp b/js/src/jit/x86/Trampoline-x86.cpp index 7194759ef59a..f5f87edd10c8 100644 --- a/js/src/jit/x86/Trampoline-x86.cpp +++ b/js/src/jit/x86/Trampoline-x86.cpp @@ -900,7 +900,7 @@ JitRuntime::generateDebugTrapHandler(JSContext* cx) // the stub frame has a nullptr ICStub pointer, since this pointer is // marked during GC. masm.movePtr(ImmPtr(nullptr), ICStubReg); - EmitEnterStubFrame(masm, scratch3); + EmitBaselineEnterStubFrame(masm, scratch3); JitCode* code = cx->runtime()->jitRuntime()->getVMWrapper(HandleDebugTrapInfo); if (!code) @@ -908,9 +908,9 @@ JitRuntime::generateDebugTrapHandler(JSContext* cx) masm.push(scratch1); masm.push(scratch2); - EmitCallVM(code, masm); + EmitBaselineCallVM(code, masm); - EmitLeaveStubFrame(masm); + EmitBaselineLeaveStubFrame(masm); // If the stub returns |true|, we have to perform a forced return // (return from the JS frame). If the stub returns |false|, just return From 0590e85c2e1cc212e2e80035b9db57040e8f5df8 Mon Sep 17 00:00:00 2001 From: Hannes Verschore Date: Fri, 21 Aug 2015 07:56:43 +0200 Subject: [PATCH 081/208] Bug 1169214: IonMonkey - Part 2: Add the x86 shared stub helpers, r=jandem --- js/src/jit/x86/SharedICHelpers-x86.h | 30 ++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/js/src/jit/x86/SharedICHelpers-x86.h b/js/src/jit/x86/SharedICHelpers-x86.h index 1be795ad493b..8ad8a22b315d 100644 --- a/js/src/jit/x86/SharedICHelpers-x86.h +++ b/js/src/jit/x86/SharedICHelpers-x86.h @@ -95,7 +95,15 @@ EmitBaselineTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t argSize) inline void EmitIonTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t stackSize) { - MOZ_CRASH("Not implemented yet."); + masm.movl(Operand(esp, stackSize), eax); + masm.shrl(Imm32(FRAMESIZE_SHIFT), eax); + masm.addl(Imm32(stackSize + JitStubFrameLayout::Size() - sizeof(intptr_t)), eax); + + masm.makeFrameDescriptor(eax, JitFrame_IonJS); + masm.push(eax); + masm.push(ICTailCallReg); + + masm.jmp(target); } inline void @@ -121,7 +129,16 @@ EmitBaselineCallVM(JitCode* target, MacroAssembler& masm) inline void EmitIonCallVM(JitCode* target, size_t stackSlots, MacroAssembler& masm) { - MOZ_CRASH("Not implemented yet."); + uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonStub); + masm.Push(Imm32(descriptor)); + masm.call(target); + + // Remove rest of the frame left on the stack. We remove the return address + // which is implicitly poped when returning. + size_t framePop = sizeof(ExitFrameLayout) - sizeof(void*); + + // Pop arguments from framePushed. + masm.implicitPop(stackSlots * sizeof(void*) + framePop); } // Size of vales pushed by EmitEnterStubFrame. @@ -159,7 +176,11 @@ EmitBaselineEnterStubFrame(MacroAssembler& masm, Register scratch) inline void EmitIonEnterStubFrame(MacroAssembler& masm, Register scratch) { - MOZ_CRASH("Not implemented yet."); + MOZ_ASSERT(scratch != ICTailCallReg); + + masm.pop(ICTailCallReg); + masm.push(ICTailCallReg); + masm.push(ICStubReg); } inline void @@ -192,7 +213,8 @@ EmitBaselineLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false) inline void EmitIonLeaveStubFrame(MacroAssembler& masm) { - MOZ_CRASH("Not implemented yet."); + masm.pop(ICStubReg); + masm.pop(ICTailCallReg); } inline void From 56d381d09e8ed64316f36f22b192aac9f34df107 Mon Sep 17 00:00:00 2001 From: Hannes Verschore Date: Fri, 21 Aug 2015 07:56:44 +0200 Subject: [PATCH 082/208] Bug 1169214: IonMonkey - Part 3: Add the x64 shared stub helpers, r=jandem --- js/src/jit/x64/SharedICHelpers-x64.h | 30 +++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/js/src/jit/x64/SharedICHelpers-x64.h b/js/src/jit/x64/SharedICHelpers-x64.h index 11203017cb8c..82760eaa03ea 100644 --- a/js/src/jit/x64/SharedICHelpers-x64.h +++ b/js/src/jit/x64/SharedICHelpers-x64.h @@ -92,7 +92,15 @@ EmitBaselineTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t argSize) inline void EmitIonTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t stackSize) { - MOZ_CRASH("Not implemented yet."); + masm.movq(Operand(esp, stackSize), ScratchReg); + masm.shrq(Imm32(FRAMESIZE_SHIFT), ScratchReg); + masm.addq(Imm32(stackSize + JitStubFrameLayout::Size() - sizeof(intptr_t)), ScratchReg); + + // Push frame descriptor and perform the tail call. + masm.makeFrameDescriptor(ScratchReg, JitFrame_IonJS); + masm.push(ScratchReg); + masm.push(ICTailCallReg); + masm.jmp(target); } inline void @@ -118,7 +126,16 @@ EmitBaselineCallVM(JitCode* target, MacroAssembler& masm) inline void EmitIonCallVM(JitCode* target, size_t stackSlots, MacroAssembler& masm) { - MOZ_CRASH("Not implemented yet."); + uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonStub); + masm.Push(Imm32(descriptor)); + masm.call(target); + + // Remove rest of the frame left on the stack. We remove the return address + // which is implicitly poped when returning. + size_t framePop = sizeof(ExitFrameLayout) - sizeof(void*); + + // Pop arguments from framePushed. + masm.implicitPop(stackSlots * sizeof(void*) + framePop); } // Size of vales pushed by EmitEnterStubFrame. @@ -152,9 +169,11 @@ EmitBaselineEnterStubFrame(MacroAssembler& masm, Register) } inline void -EmitIonEnterStubFrame(MacroAssembler& masm, Register scratch) +EmitIonEnterStubFrame(MacroAssembler& masm, Register) { - MOZ_CRASH("Not implemented yet."); + masm.pop(ICTailCallReg); + masm.push(ICTailCallReg); + masm.push(ICStubReg); } inline void @@ -186,7 +205,8 @@ EmitBaselineLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false) inline void EmitIonLeaveStubFrame(MacroAssembler& masm) { - MOZ_CRASH("Not implemented yet."); + masm.pop(ICStubReg); + masm.pop(ICTailCallReg); } inline void From eb86ebff8d00e300e89bc442f1e037bc0ee50d1c Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 21 Aug 2015 15:05:32 +0900 Subject: [PATCH 083/208] Backout changesets af1b36497559 and 1d52ab626597 (bug 1189891) for pkix bustage --- config/msvc-stl-wrapper.template.h | 4 ---- security/pkix/include/pkix/Input.h | 8 ++++---- security/pkix/test/lib/pkixtestutil.h | 1 - 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/config/msvc-stl-wrapper.template.h b/config/msvc-stl-wrapper.template.h index c42da266ed0d..0a01a6dd1b5f 100644 --- a/config/msvc-stl-wrapper.template.h +++ b/config/msvc-stl-wrapper.template.h @@ -8,9 +8,6 @@ #ifndef mozilla_${HEADER}_h #define mozilla_${HEADER}_h -#ifndef MOZ_HAVE_INCLUDED_ALLOC -#define MOZ_HAVE_INCLUDED_ALLOC - #if _HAS_EXCEPTIONS # error "STL code can only be used with -fno-exceptions" #endif @@ -35,7 +32,6 @@ #else # error "STL code can only be used with infallible ::operator new()" #endif -#endif /* MOZ_HAVE_INCLUDED_ALLOC */ #ifdef _DEBUG // From diff --git a/security/pkix/include/pkix/Input.h b/security/pkix/include/pkix/Input.h index 4b7232c42ac6..8ff9bb09243a 100644 --- a/security/pkix/include/pkix/Input.h +++ b/security/pkix/include/pkix/Input.h @@ -25,7 +25,7 @@ #ifndef mozilla_pkix_Input_h #define mozilla_pkix_Input_h -#include +#include #include "pkix/Result.h" #include "stdint.h" @@ -133,7 +133,7 @@ inline bool InputsAreEqual(const Input& a, const Input& b) { return a.GetLength() == b.GetLength() && - !std::equal(a.UnsafeGetData(), a.UnsafeGetData() + a.GetLength(), b.UnsafeGetData()); + !std::memcmp(a.UnsafeGetData(), b.UnsafeGetData(), a.GetLength()); } // An Reader is a cursor/iterator through the contents of an Input, designed to @@ -205,7 +205,7 @@ class Reader final if (static_cast(end - input) != N) { return false; } - if (std::equal(input, end, toMatch)) { + if (memcmp(input, toMatch, N)) { return false; } input = end; @@ -221,7 +221,7 @@ class Reader final if (toMatch.GetLength() != remaining) { return false; } - if (std::equal(input, end, toMatch.UnsafeGetData())) { + if (std::memcmp(input, toMatch.UnsafeGetData(), remaining)) { return false; } input = end; diff --git a/security/pkix/test/lib/pkixtestutil.h b/security/pkix/test/lib/pkixtestutil.h index 5a445cc17758..896ab5eb9bfa 100644 --- a/security/pkix/test/lib/pkixtestutil.h +++ b/security/pkix/test/lib/pkixtestutil.h @@ -28,7 +28,6 @@ #include #include // Some Mozilla-supported compilers lack #include -#include #include "pkix/pkixtypes.h" #include "../../lib/ScopedPtr.h" From a5fc3d57fcea403529ef0c7a997ca4062814d5cd Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 19 Aug 2015 15:20:09 +1000 Subject: [PATCH 084/208] Bug 1195073: [MSE/webm] P1. Detect individual webm clusters. r=kinetik WebMContainerParser was incorrectly reporting webm blocks rather than clusters, causing the webm demuxer to later fail to parse the remaining data. --- dom/media/mediasource/ContainerParser.cpp | 93 ++++++++++++++++------- 1 file changed, 64 insertions(+), 29 deletions(-) diff --git a/dom/media/mediasource/ContainerParser.cpp b/dom/media/mediasource/ContainerParser.cpp index 395246b1a9a5..1ac3a7c287ae 100644 --- a/dom/media/mediasource/ContainerParser.cpp +++ b/dom/media/mediasource/ContainerParser.cpp @@ -177,16 +177,6 @@ class WebMContainerParser : public ContainerParser { (*aData)[3] == 0x6b) { return true; } - // 0xa3 // SimpleBlock - if (aData->Length() >= 1 && - (*aData)[0] == 0xa3) { - return true; - } - // 0xa1 // Block - if (aData->Length() >= 1 && - (*aData)[0] == 0xa1) { - return true; - } return false; } @@ -195,6 +185,17 @@ class WebMContainerParser : public ContainerParser { { bool initSegment = IsInitSegmentPresent(aData); if (initSegment) { + if (mLastMapping) { + // The last data contained a complete cluster but we can only detect it + // now that a new one is starting. + // We use mOffset as end position to ensure that any blocks not reported + // by WebMBufferParser are properly skipped. + mCompleteMediaSegmentRange = MediaByteRange(mLastMapping.ref().mSyncOffset, + mOffset); + mLastMapping.reset(); + MSE_DEBUG(WebMContainerParser, "New cluster found at start, ending previous one"); + return false; + } mOffset = 0; mParser = WebMBufferedParser(0); mOverlappedMapping.Clear(); @@ -242,38 +243,71 @@ class WebMContainerParser : public ContainerParser { return false; } + if (mLastMapping && + mLastMapping.ref().mSyncOffset != mapping[0].mSyncOffset) { + // The last data contained a complete cluster but we can only detect it + // now that a new one is starting. + // We use the start of the next cluster as end position to ensure that any + // blocks not reported by WebMBufferParser is properly skipped. + mCompleteMediaSegmentRange = MediaByteRange(mLastMapping.ref().mSyncOffset, + mapping[0].mSyncOffset); + mOverlappedMapping.AppendElements(mapping); + mLastMapping.reset(); + MSE_DEBUG(WebMContainerParser, "New cluster found at start, ending previous one"); + return false; + } + + // Calculate media range for first media segment. + + // Check if we have a cluster finishing in the current data. uint32_t endIdx = mapping.Length() - 1; + bool foundNewCluster = false; + while (mapping[0].mSyncOffset != mapping[endIdx].mSyncOffset) { + endIdx -= 1; + foundNewCluster = true; + } - // Calculate media range for first media segment - uint32_t segmentEndIdx = endIdx; - while (mapping[0].mSyncOffset != mapping[segmentEndIdx].mSyncOffset) { - segmentEndIdx -= 1; + int32_t completeIdx = endIdx; + while (completeIdx >= 0 && mOffset < mapping[completeIdx].mEndOffset) { + MSE_DEBUG(WebMContainerParser, "block is incomplete, missing: %lld", + mapping[completeIdx].mEndOffset - mOffset); + completeIdx -= 1; } - if (segmentEndIdx > 0 && mOffset >= mapping[segmentEndIdx].mEndOffset) { - mCompleteMediaHeaderRange = MediaByteRange(mParser.mInitEndOffset, + + // Save parsed blocks for which we do not have all data yet. + mOverlappedMapping.AppendElements(mapping.Elements() + completeIdx + 1, + mapping.Length() - completeIdx - 1); + + if (completeIdx < 0) { + mLastMapping.reset(); + return false; + } + + if (mCompleteMediaHeaderRange.IsNull()) { + mCompleteMediaHeaderRange = MediaByteRange(mapping[0].mSyncOffset, mapping[0].mEndOffset); - mCompleteMediaSegmentRange = MediaByteRange(mParser.mInitEndOffset, - mapping[segmentEndIdx].mEndOffset); } + mLastMapping = Some(mapping[completeIdx]); - // Exclude frames that we don't have enough data to cover the end of. - while (mOffset < mapping[endIdx].mEndOffset && endIdx > 0) { - endIdx -= 1; + if (foundNewCluster && mOffset >= mapping[endIdx].mEndOffset) { + // We now have all information required to delimit a complete cluster. + mCompleteMediaSegmentRange = MediaByteRange(mapping[endIdx].mSyncOffset, + mapping[endIdx].mEndOffset); } - if (endIdx == 0) { + if (!completeIdx) { return false; } - uint64_t frameDuration = mapping[endIdx].mTimecode - mapping[endIdx - 1].mTimecode; + uint64_t frameDuration = + mapping[completeIdx].mTimecode - mapping[completeIdx - 1].mTimecode; aStart = mapping[0].mTimecode / NS_PER_USEC; - aEnd = (mapping[endIdx].mTimecode + frameDuration) / NS_PER_USEC; - - MSE_DEBUG(WebMContainerParser, "[%lld, %lld] [fso=%lld, leo=%lld, l=%u endIdx=%u]", - aStart, aEnd, mapping[0].mSyncOffset, mapping[endIdx].mEndOffset, mapping.Length(), endIdx); + aEnd = (mapping[completeIdx].mTimecode + frameDuration) / NS_PER_USEC; - mapping.RemoveElementsAt(0, endIdx + 1); - mOverlappedMapping.AppendElements(mapping); + MSE_DEBUG(WebMContainerParser, "[%lld, %lld] [fso=%lld, leo=%lld, l=%u processedIdx=%u fs=%lld]", + aStart, aEnd, mapping[0].mSyncOffset, + mapping[completeIdx].mEndOffset, mapping.Length(), completeIdx, + mCompleteMediaSegmentRange.mEnd); return true; } @@ -288,6 +322,7 @@ class WebMContainerParser : public ContainerParser { WebMBufferedParser mParser; nsTArray mOverlappedMapping; int64_t mOffset; + Maybe mLastMapping; }; #ifdef MOZ_FMP4 From 510e8b79e9eec39d091c042ca025956212224561 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 19 Aug 2015 15:22:31 +1000 Subject: [PATCH 085/208] Bug 1195073: [webm] P2. Add WebMBufferedState::GetLastBlockOffset method. r=kinetik MSE may input partial media segment, which could cause the WebMDemuxer and libnestegg to error upon encountering an incomplete block which can't be recovered from. this will allow to limit read to known complete blocks. --- dom/media/webm/WebMBufferedParser.cpp | 23 +++++++++++++++++++++++ dom/media/webm/WebMBufferedParser.h | 14 ++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/dom/media/webm/WebMBufferedParser.cpp b/dom/media/webm/WebMBufferedParser.cpp index 8b80aa46d779..0900b64ec272 100644 --- a/dom/media/webm/WebMBufferedParser.cpp +++ b/dom/media/webm/WebMBufferedParser.cpp @@ -344,6 +344,22 @@ void WebMBufferedState::NotifyDataArrived(const unsigned char* aBuffer, uint32_t i += 1; } } + + mLastEndOffset = std::max(aOffset + aLength, mLastEndOffset); + + ReentrantMonitorAutoEnter mon(mReentrantMonitor); + + if (mTimeMapping.IsEmpty()) { + return; + } + int32_t endIdx = mTimeMapping.Length() - 1; + while (endIdx >= 0 && mLastEndOffset < mTimeMapping[endIdx].mEndOffset) { + endIdx -= 1; + } + if (endIdx < 0) { + return; + } + mLastBlockOffset = mTimeMapping[endIdx].mEndOffset; } void WebMBufferedState::Reset() { @@ -398,6 +414,13 @@ int64_t WebMBufferedState::GetInitEndOffset() return mRangeParsers[0].mInitEndOffset; } +int64_t WebMBufferedState::GetLastBlockOffset() +{ + ReentrantMonitorAutoEnter mon(mReentrantMonitor); + + return mLastBlockOffset; +} + bool WebMBufferedState::GetStartTime(uint64_t *aTime) { ReentrantMonitorAutoEnter mon(mReentrantMonitor); diff --git a/dom/media/webm/WebMBufferedParser.h b/dom/media/webm/WebMBufferedParser.h index 89efd0826ce0..549982d5a71c 100644 --- a/dom/media/webm/WebMBufferedParser.h +++ b/dom/media/webm/WebMBufferedParser.h @@ -225,7 +225,11 @@ class WebMBufferedState final NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebMBufferedState) public: - WebMBufferedState() : mReentrantMonitor("WebMBufferedState") { + WebMBufferedState() + : mReentrantMonitor("WebMBufferedState") + , mLastBlockOffset(-1) + , mLastEndOffset(-1) + { MOZ_COUNT_CTOR(WebMBufferedState); } @@ -242,6 +246,8 @@ class WebMBufferedState final // Returns end offset of init segment or -1 if none found. int64_t GetInitEndOffset(); + // Returns the end offset of the last complete block or -1 if none found. + int64_t GetLastBlockOffset(); // Returns start time bool GetStartTime(uint64_t *aTime); @@ -255,12 +261,16 @@ class WebMBufferedState final MOZ_COUNT_DTOR(WebMBufferedState); } - // Synchronizes access to the mTimeMapping array. + // Synchronizes access to the mTimeMapping array and mLastBlockOffset. ReentrantMonitor mReentrantMonitor; // Sorted (by offset) map of data offsets to timecodes. Populated // on the main thread as data is received and parsed by WebMBufferedParsers. nsTArray mTimeMapping; + // The last complete block parsed. -1 if not set. + int64_t mLastBlockOffset; + // The last seen data end offset. -1 if not set. + int64_t mLastEndOffset; // Sorted (by offset) live parser instances. Main thread only. nsTArray mRangeParsers; From 2cfff6027356c2d26c51b775fde00bba9598c9cc Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 19 Aug 2015 15:24:12 +1000 Subject: [PATCH 086/208] Bug 1195073: [webm] P3. Initialize members. r=kinetik --- dom/media/webm/WebMDemuxer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp index 02f57c04abfe..78f9af8a7ab0 100644 --- a/dom/media/webm/WebMDemuxer.cpp +++ b/dom/media/webm/WebMDemuxer.cpp @@ -122,6 +122,7 @@ WebMDemuxer::WebMDemuxer(MediaResource* aResource) , mVideoTrack(0) , mAudioTrack(0) , mSeekPreroll(0) + , mLastAudioFrameTime(0) , mLastVideoFrameTime(0) , mAudioCodec(-1) , mVideoCodec(-1) @@ -689,6 +690,10 @@ WebMDemuxer::SeekInternal(const media::TimeUnit& aTarget) } WEBM_DEBUG("got offset from buffered state: %" PRIu64 "", offset); } + + mLastAudioFrameTime = 0; + mLastVideoFrameTime = 0; + return NS_OK; } From abc1f51fbb7a4784a2547a1aba8a783563d38fb5 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 19 Aug 2015 15:27:18 +1000 Subject: [PATCH 087/208] Bug 1195073: [MSE/webm] P4. Limit nestegg reads to the last block's boundaries. r=kinetik This prevent entering into an unrecoverable error state when parsing incomplete data as often seen with MSE. --- dom/media/mediasource/SourceBufferResource.h | 5 +++ dom/media/webm/WebMDemuxer.cpp | 35 +++++++++++--------- dom/media/webm/WebMDemuxer.h | 18 ++++++++++ 3 files changed, 43 insertions(+), 15 deletions(-) diff --git a/dom/media/mediasource/SourceBufferResource.h b/dom/media/mediasource/SourceBufferResource.h index 19a4e89883eb..0a47fcbdc106 100644 --- a/dom/media/mediasource/SourceBufferResource.h +++ b/dom/media/mediasource/SourceBufferResource.h @@ -100,6 +100,11 @@ class SourceBufferResource final : public MediaResource return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); } + virtual bool IsExpectingMoreData() override + { + return false; + } + // Used by SourceBuffer. void AppendData(MediaByteBuffer* aData); void Ended(); diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp index 78f9af8a7ab0..0f88a388036f 100644 --- a/dom/media/webm/WebMDemuxer.cpp +++ b/dom/media/webm/WebMDemuxer.cpp @@ -35,40 +35,39 @@ extern PRLogModuleInfo* gNesteggLog; // Functions for reading and seeking using WebMDemuxer required for // nestegg_io. The 'user data' passed to these functions is the -// demuxer's MediaResourceIndex +// demuxer. static int webmdemux_read(void* aBuffer, size_t aLength, void* aUserData) { MOZ_ASSERT(aUserData); - MediaResourceIndex* resource = - reinterpret_cast(aUserData); - int64_t length = resource->GetLength(); MOZ_ASSERT(aLength < UINT32_MAX); + WebMDemuxer* demuxer = reinterpret_cast(aUserData); + int64_t length = demuxer->GetEndDataOffset(); uint32_t count = aLength; - if (length >= 0 && count + resource->Tell() > length) { - count = uint32_t(length - resource->Tell()); + int64_t position = demuxer->GetResource()->Tell(); + if (length >= 0 && count + position > length) { + count = length - position; } uint32_t bytes = 0; - nsresult rv = resource->Read(static_cast(aBuffer), count, &bytes); - bool eof = !bytes; + nsresult rv = + demuxer->GetResource()->Read(static_cast(aBuffer), count, &bytes); + bool eof = bytes < aLength; return NS_FAILED(rv) ? -1 : eof ? 0 : 1; } static int webmdemux_seek(int64_t aOffset, int aWhence, void* aUserData) { MOZ_ASSERT(aUserData); - MediaResourceIndex* resource = - reinterpret_cast(aUserData); - nsresult rv = resource->Seek(aWhence, aOffset); + WebMDemuxer* demuxer = reinterpret_cast(aUserData); + nsresult rv = demuxer->GetResource()->Seek(aWhence, aOffset); return NS_SUCCEEDED(rv) ? 0 : -1; } static int64_t webmdemux_tell(void* aUserData) { MOZ_ASSERT(aUserData); - MediaResourceIndex* resource = - reinterpret_cast(aUserData); - return resource->Tell(); + WebMDemuxer* demuxer = reinterpret_cast(aUserData); + return demuxer->GetResource()->Tell(); } static void webmdemux_log(nestegg* aContext, @@ -129,6 +128,8 @@ WebMDemuxer::WebMDemuxer(MediaResource* aResource) , mHasVideo(false) , mHasAudio(false) , mNeedReIndex(true) + , mLastWebMBlockOffset(-1) + , mIsExpectingMoreData(true) { if (!gNesteggLog) { gNesteggLog = PR_NewLogModule("Nestegg"); @@ -253,7 +254,7 @@ WebMDemuxer::ReadMetadata() io.read = webmdemux_read; io.seek = webmdemux_seek; io.tell = webmdemux_tell; - io.userdata = &mResource; + io.userdata = this; int64_t maxOffset = mBufferedState->GetInitEndOffset(); if (maxOffset == -1) { maxOffset = mResource.GetLength(); @@ -429,6 +430,8 @@ WebMDemuxer::EnsureUpToDateIndex() if (!mInitData && mBufferedState->GetInitEndOffset() != -1) { mInitData = mResource.MediaReadAt(0, mBufferedState->GetInitEndOffset()); } + mLastWebMBlockOffset = mBufferedState->GetLastBlockOffset(); + mIsExpectingMoreData = mResource.GetResource()->IsExpectingMoreData(); mNeedReIndex = false; } @@ -455,6 +458,8 @@ WebMDemuxer::GetCrypto() bool WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSamples) { + EnsureUpToDateIndex(); + nsRefPtr holder(NextPacket(aType)); if (!holder) { diff --git a/dom/media/webm/WebMDemuxer.h b/dom/media/webm/WebMDemuxer.h index 834df8b865fa..91de7e156d13 100644 --- a/dom/media/webm/WebMDemuxer.h +++ b/dom/media/webm/WebMDemuxer.h @@ -85,6 +85,18 @@ class WebMDemuxer : public MediaDataDemuxer // Pushes a packet to the front of the video packet queue. virtual void PushVideoPacket(NesteggPacketHolder* aItem); + // Public accessor for nestegg callbacks + MediaResourceIndex* GetResource() + { + return &mResource; + } + + int64_t GetEndDataOffset() + { + return mLastWebMBlockOffset < 0 || mIsExpectingMoreData + ? mResource.GetLength() : mLastWebMBlockOffset; + } + private: friend class WebMTrackDemuxer; @@ -152,6 +164,12 @@ class WebMDemuxer : public MediaDataDemuxer bool mHasVideo; bool mHasAudio; bool mNeedReIndex; + + // The last complete block parsed by the WebMBufferedState. -1 if not set. + // We cache those values rather than retrieving them for performance reasons + // as nestegg only performs 1-byte read at a time. + int64_t mLastWebMBlockOffset; + bool mIsExpectingMoreData; }; class WebMTrackDemuxer : public MediaTrackDemuxer From 7201eefe07b0907bbf480bdea1cf565dad58b02a Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 19 Aug 2015 15:31:30 +1000 Subject: [PATCH 088/208] Bug 1195073: [MSE] P5. Detect out of order appends and recreate demuxer. r=gerald The webm demuxer will only handle data where frames's a monotonically increasing. --- dom/media/mediasource/TrackBuffersManager.cpp | 82 ++++++++++++++++++- dom/media/mediasource/TrackBuffersManager.h | 5 ++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp index b902dc7fdf89..4f8272dfafdb 100644 --- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -97,6 +97,7 @@ TrackBuffersManager::TrackBuffersManager(dom::SourceBufferAttributes* aAttribute , mAppendState(AppendState::WAITING_FOR_SEGMENT) , mBufferFull(false) , mFirstInitializationSegmentReceived(false) + , mNewSegmentStarted(false) , mActiveTrack(false) , mType(aType) , mParser(ContainerParser::CreateForMIMEType(aType)) @@ -655,10 +656,12 @@ TrackBuffersManager::SegmentParserLoop() // This is a new initialization segment. Obsolete the old one. RecreateParser(false); } + mNewSegmentStarted = true; continue; } if (mParser->IsMediaSegmentPresent(mInputBuffer)) { SetAppendState(AppendState::PARSING_MEDIA_SEGMENT); + mNewSegmentStarted = true; continue; } // We have neither an init segment nor a media segment, this is either @@ -669,7 +672,7 @@ TrackBuffersManager::SegmentParserLoop() } int64_t start, end; - mParser->ParseStartAndEndTimestamps(mInputBuffer, start, end); + bool newData = mParser->ParseStartAndEndTimestamps(mInputBuffer, start, end); mProcessedInput += mInputBuffer->Length(); // 5. If the append state equals PARSING_INIT_SEGMENT, then run the @@ -696,6 +699,22 @@ TrackBuffersManager::SegmentParserLoop() NeedMoreData(); return; } + + // We can't feed some demuxers (WebMDemuxer) with data that do not have + // monotonizally increasing timestamps. So we check if we have a + // discontinuity from the previous segment parsed. + // If so, recreate a new demuxer to ensure that the demuxer is only fed + // monotonically increasing data. + if (newData) { + if (mNewSegmentStarted && mLastParsedEndTime.isSome() && + start < mLastParsedEndTime.ref().ToMicroseconds()) { + ResetDemuxingState(); + return; + } + mNewSegmentStarted = false; + mLastParsedEndTime = Some(TimeUnit::FromMicroseconds(end)); + } + // 3. If the input buffer contains one or more complete coded frames, then run the coded frame processing algorithm. nsRefPtr self = this; mProcessingRequest.Begin(CodedFrameProcessing() @@ -756,6 +775,7 @@ TrackBuffersManager::ShutdownDemuxers() mAudioTracks.mDemuxer = nullptr; } mInputDemuxer = nullptr; + mLastParsedEndTime.reset(); } void @@ -780,6 +800,58 @@ TrackBuffersManager::CreateDemuxerforMIMEType() return; } +// We reset the demuxer by creating a new one and initializing it. +void +TrackBuffersManager::ResetDemuxingState() +{ + MOZ_ASSERT(mParser && mParser->HasInitData()); + RecreateParser(true); + mCurrentInputBuffer = new SourceBufferResource(mType); + // The demuxer isn't initialized yet ; we don't want to notify it + // that data has been appended yet ; so we simply append the init segment + // to the resource. + mCurrentInputBuffer->AppendData(mParser->InitData()); + CreateDemuxerforMIMEType(); + if (!mInputDemuxer) { + RejectAppend(NS_ERROR_FAILURE, __func__); + return; + } + mDemuxerInitRequest.Begin(mInputDemuxer->Init() + ->Then(GetTaskQueue(), __func__, + this, + &TrackBuffersManager::OnDemuxerResetDone, + &TrackBuffersManager::OnDemuxerInitFailed)); +} + +void +TrackBuffersManager::OnDemuxerResetDone(nsresult) +{ + MOZ_ASSERT(OnTaskQueue()); + MSE_DEBUG("mAbort:%d", static_cast(mAbort)); + mDemuxerInitRequest.Complete(); + if (mAbort) { + RejectAppend(NS_ERROR_ABORT, __func__); + return; + } + + // Recreate track demuxers. + uint32_t numVideos = mInputDemuxer->GetNumberTracks(TrackInfo::kVideoTrack); + if (numVideos) { + // We currently only handle the first video track. + mVideoTracks.mDemuxer = mInputDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0); + MOZ_ASSERT(mVideoTracks.mDemuxer); + } + + uint32_t numAudios = mInputDemuxer->GetNumberTracks(TrackInfo::kAudioTrack); + if (numAudios) { + // We currently only handle the first audio track. + mAudioTracks.mDemuxer = mInputDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0); + MOZ_ASSERT(mAudioTracks.mDemuxer); + } + + SegmentParserLoop(); +} + void TrackBuffersManager::AppendDataToCurrentInputBuffer(MediaByteBuffer* aData) { @@ -1056,6 +1128,14 @@ TrackBuffersManager::CodedFrameProcessing() // The mediaRange is offset by the init segment position previously added. uint32_t length = mediaRange.mEnd - (mProcessedInput - mInputBuffer->Length()); + if (!length) { + // We've completed our earlier media segment and no new data is to be + // processed. This happens with some containers that can't detect that a + // media segment is ending until a new one starts. + nsRefPtr p = mProcessingPromise.Ensure(__func__); + CompleteCodedFrameProcessing(); + return p; + } nsRefPtr segment = new MediaByteBuffer; if (!segment->AppendElements(mInputBuffer->Elements(), length, fallible)) { return CodedFrameProcessingPromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY, __func__); diff --git a/dom/media/mediasource/TrackBuffersManager.h b/dom/media/mediasource/TrackBuffersManager.h index dfa5c67d549c..6187507142e5 100644 --- a/dom/media/mediasource/TrackBuffersManager.h +++ b/dom/media/mediasource/TrackBuffersManager.h @@ -113,6 +113,7 @@ class TrackBuffersManager : public SourceBufferContentManager { void InitializationSegmentReceived(); void ShutdownDemuxers(); void CreateDemuxerforMIMEType(); + void ResetDemuxingState(); void NeedMoreData(); void RejectAppend(nsresult aRejectValue, const char* aName); // Will return a promise that will be resolved once all frames of the current @@ -151,6 +152,8 @@ class TrackBuffersManager : public SourceBufferContentManager { // TODO: Unused for now. Atomic mBufferFull; bool mFirstInitializationSegmentReceived; + // Set to true once a new segment is started. + bool mNewSegmentStarted; bool mActiveTrack; Maybe mGroupStartTimestamp; media::TimeUnit mGroupEndTimestamp; @@ -171,9 +174,11 @@ class TrackBuffersManager : public SourceBufferContentManager { nsRefPtr mInputDemuxer; // Length already processed in current media segment. uint32_t mProcessedInput; + Maybe mLastParsedEndTime; void OnDemuxerInitDone(nsresult); void OnDemuxerInitFailed(DemuxerFailureReason aFailure); + void OnDemuxerResetDone(nsresult); MozPromiseRequestHolder mDemuxerInitRequest; bool mEncrypted; From dabcd79dc0bf797bba6ee89ddfc88e336fb9f5f2 Mon Sep 17 00:00:00 2001 From: Chris Peterson Date: Sat, 1 Aug 2015 11:59:40 -0700 Subject: [PATCH 089/208] Bug 1190148 - Fix warnings in toolkit/crashreporter/client and mark as FAIL_ON_WARNINGS. r=ted --- toolkit/crashreporter/client/crashreporter_gtk_common.cpp | 8 +++----- toolkit/crashreporter/client/crashreporter_osx.mm | 2 +- toolkit/crashreporter/client/moz.build | 2 ++ 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/toolkit/crashreporter/client/crashreporter_gtk_common.cpp b/toolkit/crashreporter/client/crashreporter_gtk_common.cpp index d68fc255f338..395a339bfd34 100644 --- a/toolkit/crashreporter/client/crashreporter_gtk_common.cpp +++ b/toolkit/crashreporter/client/crashreporter_gtk_common.cpp @@ -409,17 +409,15 @@ bool UIMoveFile(const string& file, const string& newfile) } if (pID == 0) { char* const args[4] = { - "mv", + const_cast("mv"), strdup(file.c_str()), strdup(newfile.c_str()), 0 }; if (args[1] && args[2]) execve("/bin/mv", args, 0); - if (args[1]) - free(args[1]); - if (args[2]) - free(args[2]); + free(args[1]); + free(args[2]); exit(-1); } int status; diff --git a/toolkit/crashreporter/client/crashreporter_osx.mm b/toolkit/crashreporter/client/crashreporter_osx.mm index 2d329ac2f4d7..0768d6da31ae 100644 --- a/toolkit/crashreporter/client/crashreporter_osx.mm +++ b/toolkit/crashreporter/client/crashreporter_osx.mm @@ -279,7 +279,7 @@ -(IBAction)viewReportClicked:(id)sender modalDelegate:nil didEndSelector:nil contextInfo:nil]; } -- (IBAction)viewReportOkClicked:(id)sender; +- (IBAction)viewReportOkClicked:(id)sender { [mViewReportWindow orderOut:nil]; [NSApp endSheet:mViewReportWindow]; diff --git a/toolkit/crashreporter/client/moz.build b/toolkit/crashreporter/client/moz.build index 14cc0ffad4cf..6536e8f583ba 100644 --- a/toolkit/crashreporter/client/moz.build +++ b/toolkit/crashreporter/client/moz.build @@ -73,3 +73,5 @@ RCINCLUDE = 'crashreporter.rc' DISABLE_STL_WRAPPING = True include('/toolkit/crashreporter/crashreporter.mozbuild') + +FAIL_ON_WARNINGS = True From e5f57b61935afec59e160a01b20ec2477878c724 Mon Sep 17 00:00:00 2001 From: Chris Peterson Date: Tue, 18 Aug 2015 00:13:49 -0700 Subject: [PATCH 090/208] Bug 1195186 - Build media/pocketsphinx in unified mode. r=kdavis --- media/pocketsphinx/moz.build | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/media/pocketsphinx/moz.build b/media/pocketsphinx/moz.build index 3888baaecd5b..94173802a75c 100644 --- a/media/pocketsphinx/moz.build +++ b/media/pocketsphinx/moz.build @@ -12,9 +12,8 @@ EXPORTS.pocketsphinx += [ 'pocketsphinx.h', ] -SOURCES += [ +UNIFIED_SOURCES += [ 'src/acmod.c', - 'src/allphone_search.c', 'src/bin_mdef.c', 'src/blkarray_list.c', 'src/dict.c', @@ -29,7 +28,6 @@ SOURCES += [ 'src/ms_gauden.c', 'src/ms_mgau.c', 'src/ms_senone.c', - 'src/ngram_search.c', 'src/ngram_search_fwdflat.c', 'src/ngram_search_fwdtree.c', 'src/phone_loop_search.c', @@ -38,12 +36,17 @@ SOURCES += [ 'src/ps_lattice.c', 'src/ps_mllr.c', 'src/ptm_mgau.c', - 'src/s2_semi_mgau.c', - 'src/state_align_search.c', 'src/tmat.c', 'src/vector.c', ] +SOURCES += [ + 'src/allphone_search.c', + 'src/ngram_search.c', + 'src/s2_semi_mgau.c', + 'src/state_align_search.c', +] + # Suppress warnings in third-party code. if CONFIG['GNU_CC']: CFLAGS += [ From d86514df2d4bff0ef413c500ae97305a3abd8f15 Mon Sep 17 00:00:00 2001 From: Bas Schouten Date: Thu, 20 Aug 2015 20:03:44 +0000 Subject: [PATCH 091/208] Bug 1189891: Only include STL wrapper requirements on the first include. r=glandium --- config/msvc-stl-wrapper.template.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/msvc-stl-wrapper.template.h b/config/msvc-stl-wrapper.template.h index 0a01a6dd1b5f..c42da266ed0d 100644 --- a/config/msvc-stl-wrapper.template.h +++ b/config/msvc-stl-wrapper.template.h @@ -8,6 +8,9 @@ #ifndef mozilla_${HEADER}_h #define mozilla_${HEADER}_h +#ifndef MOZ_HAVE_INCLUDED_ALLOC +#define MOZ_HAVE_INCLUDED_ALLOC + #if _HAS_EXCEPTIONS # error "STL code can only be used with -fno-exceptions" #endif @@ -32,6 +35,7 @@ #else # error "STL code can only be used with infallible ::operator new()" #endif +#endif /* MOZ_HAVE_INCLUDED_ALLOC */ #ifdef _DEBUG // From From ab3baee71dcc197cb2ef12a0fb6cd688aea5b8fe Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 21 Aug 2015 08:29:06 +0900 Subject: [PATCH 092/208] Bug 1189891 - Avoid including from pkix/Input.h. r=bsmith --- security/pkix/include/pkix/Input.h | 8 ++++---- security/pkix/test/lib/pkixtestutil.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/security/pkix/include/pkix/Input.h b/security/pkix/include/pkix/Input.h index 8ff9bb09243a..e09526fb490a 100644 --- a/security/pkix/include/pkix/Input.h +++ b/security/pkix/include/pkix/Input.h @@ -25,7 +25,7 @@ #ifndef mozilla_pkix_Input_h #define mozilla_pkix_Input_h -#include +#include #include "pkix/Result.h" #include "stdint.h" @@ -133,7 +133,7 @@ inline bool InputsAreEqual(const Input& a, const Input& b) { return a.GetLength() == b.GetLength() && - !std::memcmp(a.UnsafeGetData(), b.UnsafeGetData(), a.GetLength()); + std::equal(a.UnsafeGetData(), a.UnsafeGetData() + a.GetLength(), b.UnsafeGetData()); } // An Reader is a cursor/iterator through the contents of an Input, designed to @@ -205,7 +205,7 @@ class Reader final if (static_cast(end - input) != N) { return false; } - if (memcmp(input, toMatch, N)) { + if (!std::equal(input, end, toMatch)) { return false; } input = end; @@ -221,7 +221,7 @@ class Reader final if (toMatch.GetLength() != remaining) { return false; } - if (std::memcmp(input, toMatch.UnsafeGetData(), remaining)) { + if (!std::equal(input, end, toMatch.UnsafeGetData())) { return false; } input = end; diff --git a/security/pkix/test/lib/pkixtestutil.h b/security/pkix/test/lib/pkixtestutil.h index 896ab5eb9bfa..5a445cc17758 100644 --- a/security/pkix/test/lib/pkixtestutil.h +++ b/security/pkix/test/lib/pkixtestutil.h @@ -28,6 +28,7 @@ #include #include // Some Mozilla-supported compilers lack #include +#include #include "pkix/pkixtypes.h" #include "../../lib/ScopedPtr.h" From d0a15887613b9e94c4f1ec841141bd799e7e702a Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Fri, 21 Aug 2015 16:38:55 +1000 Subject: [PATCH 093/208] Bug 1195073: [MSE] P6. Fix B2G build. a=bustage --- dom/media/mediasource/ContainerParser.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/dom/media/mediasource/ContainerParser.cpp b/dom/media/mediasource/ContainerParser.cpp index 1ac3a7c287ae..8bf331f8c4d6 100644 --- a/dom/media/mediasource/ContainerParser.cpp +++ b/dom/media/mediasource/ContainerParser.cpp @@ -11,6 +11,7 @@ #include "mozilla/ErrorResult.h" #include "mp4_demuxer/MoofParser.h" #include "mozilla/Logging.h" +#include "mozilla/Maybe.h" #include "MediaData.h" #ifdef MOZ_FMP4 #include "MP4Stream.h" From e5a5e9bc081bbdacdd8d68c74b1bd2ed2253f1d4 Mon Sep 17 00:00:00 2001 From: Edwin Flores Date: Fri, 21 Aug 2015 17:24:18 +1000 Subject: [PATCH 094/208] Bug 1197051 - Don't try to decode ahead while seeking - r=jya --- dom/media/MediaDecoderStateMachine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index f6d7fa47b0ea..1c5ad3094639 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -1720,7 +1720,7 @@ MediaDecoderStateMachine::RequestVideoData() bool skipToNextKeyFrame = mSentFirstFrameLoadedEvent && NeedToSkipToNextKeyframe(); int64_t currentTime = mState == DECODER_STATE_SEEKING ? 0 : GetMediaTime(); - bool forceDecodeAhead = mSentFirstFrameLoadedEvent && + bool forceDecodeAhead = mSentFirstFrameLoadedEvent && !IsSeeking() && static_cast(VideoQueue().GetSize()) <= SCARCE_VIDEO_QUEUE_SIZE; SAMPLE_LOG("Queueing video task - queued=%i, decoder-queued=%o, skip=%i, time=%lld", From 44940300be8561e1401191b00a8513ec6432dae0 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Fri, 21 Aug 2015 17:53:30 +1000 Subject: [PATCH 095/208] Bug 1195073: [MSE] P7. Disable invalid webm test. a=test-only --- .../meta/media-source/mediasource-sourcebuffer-mode.html.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/testing/web-platform/meta/media-source/mediasource-sourcebuffer-mode.html.ini b/testing/web-platform/meta/media-source/mediasource-sourcebuffer-mode.html.ini index 4572fc8cbd4e..94893e18ae4d 100644 --- a/testing/web-platform/meta/media-source/mediasource-sourcebuffer-mode.html.ini +++ b/testing/web-platform/meta/media-source/mediasource-sourcebuffer-mode.html.ini @@ -1,6 +1,10 @@ [mediasource-sourcebuffer-mode.html] type: testharness prefs: [media.mediasource.enabled:true] + [Test setting SourceBuffer.mode and SourceBuffer.timestampOffset while parsing media segment.] + expected: + if os == "linux": FAIL + if (os == "win") and (version == "5.1.2600"): FAIL [Test setting SourceBuffer.mode triggers parent MediaSource 'ended' to 'open' transition.] expected: if os == "linux": FAIL From 6c7fed1c3252a7a8038ce4ea5177b39977aa8352 Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Fri, 21 Aug 2015 10:46:05 +0200 Subject: [PATCH 096/208] Backed out 5 changesets 507a508aea7, 16669eed518d, 6f6fc1a91d07, 1e983ccb61cc, c5afa29ea85a (bug 1195073) for M2 and W5 on OSX and Linux and R(R2, Ru2) bustage on Linux. r=backout Backed out changeset 507a508aea70 (bug 1195073) Backed out changeset 16669eed518d (bug 1195073) Backed out changeset 6f6fc1a91d07 (bug 1195073) Backed out changeset 1e983ccb61cc (bug 1195073) Backed out changeset c5afa29ea85a (bug 1195073) --- dom/media/mediasource/ContainerParser.cpp | 93 ++++++------------- dom/media/mediasource/SourceBufferResource.h | 5 - dom/media/mediasource/TrackBuffersManager.cpp | 82 +--------------- dom/media/mediasource/TrackBuffersManager.h | 5 - dom/media/webm/WebMBufferedParser.cpp | 23 ----- dom/media/webm/WebMBufferedParser.h | 14 +-- dom/media/webm/WebMDemuxer.cpp | 40 +++----- dom/media/webm/WebMDemuxer.h | 18 ---- 8 files changed, 47 insertions(+), 233 deletions(-) diff --git a/dom/media/mediasource/ContainerParser.cpp b/dom/media/mediasource/ContainerParser.cpp index 8bf331f8c4d6..5fa35a0c7e9f 100644 --- a/dom/media/mediasource/ContainerParser.cpp +++ b/dom/media/mediasource/ContainerParser.cpp @@ -178,6 +178,16 @@ class WebMContainerParser : public ContainerParser { (*aData)[3] == 0x6b) { return true; } + // 0xa3 // SimpleBlock + if (aData->Length() >= 1 && + (*aData)[0] == 0xa3) { + return true; + } + // 0xa1 // Block + if (aData->Length() >= 1 && + (*aData)[0] == 0xa1) { + return true; + } return false; } @@ -186,17 +196,6 @@ class WebMContainerParser : public ContainerParser { { bool initSegment = IsInitSegmentPresent(aData); if (initSegment) { - if (mLastMapping) { - // The last data contained a complete cluster but we can only detect it - // now that a new one is starting. - // We use mOffset as end position to ensure that any blocks not reported - // by WebMBufferParser are properly skipped. - mCompleteMediaSegmentRange = MediaByteRange(mLastMapping.ref().mSyncOffset, - mOffset); - mLastMapping.reset(); - MSE_DEBUG(WebMContainerParser, "New cluster found at start, ending previous one"); - return false; - } mOffset = 0; mParser = WebMBufferedParser(0); mOverlappedMapping.Clear(); @@ -244,71 +243,38 @@ class WebMContainerParser : public ContainerParser { return false; } - if (mLastMapping && - mLastMapping.ref().mSyncOffset != mapping[0].mSyncOffset) { - // The last data contained a complete cluster but we can only detect it - // now that a new one is starting. - // We use the start of the next cluster as end position to ensure that any - // blocks not reported by WebMBufferParser is properly skipped. - mCompleteMediaSegmentRange = MediaByteRange(mLastMapping.ref().mSyncOffset, - mapping[0].mSyncOffset); - mOverlappedMapping.AppendElements(mapping); - mLastMapping.reset(); - MSE_DEBUG(WebMContainerParser, "New cluster found at start, ending previous one"); - return false; - } - - // Calculate media range for first media segment. - - // Check if we have a cluster finishing in the current data. uint32_t endIdx = mapping.Length() - 1; - bool foundNewCluster = false; - while (mapping[0].mSyncOffset != mapping[endIdx].mSyncOffset) { - endIdx -= 1; - foundNewCluster = true; - } - int32_t completeIdx = endIdx; - while (completeIdx >= 0 && mOffset < mapping[completeIdx].mEndOffset) { - MSE_DEBUG(WebMContainerParser, "block is incomplete, missing: %lld", - mapping[completeIdx].mEndOffset - mOffset); - completeIdx -= 1; + // Calculate media range for first media segment + uint32_t segmentEndIdx = endIdx; + while (mapping[0].mSyncOffset != mapping[segmentEndIdx].mSyncOffset) { + segmentEndIdx -= 1; } - - // Save parsed blocks for which we do not have all data yet. - mOverlappedMapping.AppendElements(mapping.Elements() + completeIdx + 1, - mapping.Length() - completeIdx - 1); - - if (completeIdx < 0) { - mLastMapping.reset(); - return false; - } - - if (mCompleteMediaHeaderRange.IsNull()) { - mCompleteMediaHeaderRange = MediaByteRange(mapping[0].mSyncOffset, + if (segmentEndIdx > 0 && mOffset >= mapping[segmentEndIdx].mEndOffset) { + mCompleteMediaHeaderRange = MediaByteRange(mParser.mInitEndOffset, mapping[0].mEndOffset); + mCompleteMediaSegmentRange = MediaByteRange(mParser.mInitEndOffset, + mapping[segmentEndIdx].mEndOffset); } - mLastMapping = Some(mapping[completeIdx]); - if (foundNewCluster && mOffset >= mapping[endIdx].mEndOffset) { - // We now have all information required to delimit a complete cluster. - mCompleteMediaSegmentRange = MediaByteRange(mapping[endIdx].mSyncOffset, - mapping[endIdx].mEndOffset); + // Exclude frames that we don't have enough data to cover the end of. + while (mOffset < mapping[endIdx].mEndOffset && endIdx > 0) { + endIdx -= 1; } - if (!completeIdx) { + if (endIdx == 0) { return false; } - uint64_t frameDuration = - mapping[completeIdx].mTimecode - mapping[completeIdx - 1].mTimecode; + uint64_t frameDuration = mapping[endIdx].mTimecode - mapping[endIdx - 1].mTimecode; aStart = mapping[0].mTimecode / NS_PER_USEC; - aEnd = (mapping[completeIdx].mTimecode + frameDuration) / NS_PER_USEC; + aEnd = (mapping[endIdx].mTimecode + frameDuration) / NS_PER_USEC; + + MSE_DEBUG(WebMContainerParser, "[%lld, %lld] [fso=%lld, leo=%lld, l=%u endIdx=%u]", + aStart, aEnd, mapping[0].mSyncOffset, mapping[endIdx].mEndOffset, mapping.Length(), endIdx); - MSE_DEBUG(WebMContainerParser, "[%lld, %lld] [fso=%lld, leo=%lld, l=%u processedIdx=%u fs=%lld]", - aStart, aEnd, mapping[0].mSyncOffset, - mapping[completeIdx].mEndOffset, mapping.Length(), completeIdx, - mCompleteMediaSegmentRange.mEnd); + mapping.RemoveElementsAt(0, endIdx + 1); + mOverlappedMapping.AppendElements(mapping); return true; } @@ -323,7 +289,6 @@ class WebMContainerParser : public ContainerParser { WebMBufferedParser mParser; nsTArray mOverlappedMapping; int64_t mOffset; - Maybe mLastMapping; }; #ifdef MOZ_FMP4 diff --git a/dom/media/mediasource/SourceBufferResource.h b/dom/media/mediasource/SourceBufferResource.h index 0a47fcbdc106..19a4e89883eb 100644 --- a/dom/media/mediasource/SourceBufferResource.h +++ b/dom/media/mediasource/SourceBufferResource.h @@ -100,11 +100,6 @@ class SourceBufferResource final : public MediaResource return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); } - virtual bool IsExpectingMoreData() override - { - return false; - } - // Used by SourceBuffer. void AppendData(MediaByteBuffer* aData); void Ended(); diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp index 4f8272dfafdb..b902dc7fdf89 100644 --- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -97,7 +97,6 @@ TrackBuffersManager::TrackBuffersManager(dom::SourceBufferAttributes* aAttribute , mAppendState(AppendState::WAITING_FOR_SEGMENT) , mBufferFull(false) , mFirstInitializationSegmentReceived(false) - , mNewSegmentStarted(false) , mActiveTrack(false) , mType(aType) , mParser(ContainerParser::CreateForMIMEType(aType)) @@ -656,12 +655,10 @@ TrackBuffersManager::SegmentParserLoop() // This is a new initialization segment. Obsolete the old one. RecreateParser(false); } - mNewSegmentStarted = true; continue; } if (mParser->IsMediaSegmentPresent(mInputBuffer)) { SetAppendState(AppendState::PARSING_MEDIA_SEGMENT); - mNewSegmentStarted = true; continue; } // We have neither an init segment nor a media segment, this is either @@ -672,7 +669,7 @@ TrackBuffersManager::SegmentParserLoop() } int64_t start, end; - bool newData = mParser->ParseStartAndEndTimestamps(mInputBuffer, start, end); + mParser->ParseStartAndEndTimestamps(mInputBuffer, start, end); mProcessedInput += mInputBuffer->Length(); // 5. If the append state equals PARSING_INIT_SEGMENT, then run the @@ -699,22 +696,6 @@ TrackBuffersManager::SegmentParserLoop() NeedMoreData(); return; } - - // We can't feed some demuxers (WebMDemuxer) with data that do not have - // monotonizally increasing timestamps. So we check if we have a - // discontinuity from the previous segment parsed. - // If so, recreate a new demuxer to ensure that the demuxer is only fed - // monotonically increasing data. - if (newData) { - if (mNewSegmentStarted && mLastParsedEndTime.isSome() && - start < mLastParsedEndTime.ref().ToMicroseconds()) { - ResetDemuxingState(); - return; - } - mNewSegmentStarted = false; - mLastParsedEndTime = Some(TimeUnit::FromMicroseconds(end)); - } - // 3. If the input buffer contains one or more complete coded frames, then run the coded frame processing algorithm. nsRefPtr self = this; mProcessingRequest.Begin(CodedFrameProcessing() @@ -775,7 +756,6 @@ TrackBuffersManager::ShutdownDemuxers() mAudioTracks.mDemuxer = nullptr; } mInputDemuxer = nullptr; - mLastParsedEndTime.reset(); } void @@ -800,58 +780,6 @@ TrackBuffersManager::CreateDemuxerforMIMEType() return; } -// We reset the demuxer by creating a new one and initializing it. -void -TrackBuffersManager::ResetDemuxingState() -{ - MOZ_ASSERT(mParser && mParser->HasInitData()); - RecreateParser(true); - mCurrentInputBuffer = new SourceBufferResource(mType); - // The demuxer isn't initialized yet ; we don't want to notify it - // that data has been appended yet ; so we simply append the init segment - // to the resource. - mCurrentInputBuffer->AppendData(mParser->InitData()); - CreateDemuxerforMIMEType(); - if (!mInputDemuxer) { - RejectAppend(NS_ERROR_FAILURE, __func__); - return; - } - mDemuxerInitRequest.Begin(mInputDemuxer->Init() - ->Then(GetTaskQueue(), __func__, - this, - &TrackBuffersManager::OnDemuxerResetDone, - &TrackBuffersManager::OnDemuxerInitFailed)); -} - -void -TrackBuffersManager::OnDemuxerResetDone(nsresult) -{ - MOZ_ASSERT(OnTaskQueue()); - MSE_DEBUG("mAbort:%d", static_cast(mAbort)); - mDemuxerInitRequest.Complete(); - if (mAbort) { - RejectAppend(NS_ERROR_ABORT, __func__); - return; - } - - // Recreate track demuxers. - uint32_t numVideos = mInputDemuxer->GetNumberTracks(TrackInfo::kVideoTrack); - if (numVideos) { - // We currently only handle the first video track. - mVideoTracks.mDemuxer = mInputDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0); - MOZ_ASSERT(mVideoTracks.mDemuxer); - } - - uint32_t numAudios = mInputDemuxer->GetNumberTracks(TrackInfo::kAudioTrack); - if (numAudios) { - // We currently only handle the first audio track. - mAudioTracks.mDemuxer = mInputDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0); - MOZ_ASSERT(mAudioTracks.mDemuxer); - } - - SegmentParserLoop(); -} - void TrackBuffersManager::AppendDataToCurrentInputBuffer(MediaByteBuffer* aData) { @@ -1128,14 +1056,6 @@ TrackBuffersManager::CodedFrameProcessing() // The mediaRange is offset by the init segment position previously added. uint32_t length = mediaRange.mEnd - (mProcessedInput - mInputBuffer->Length()); - if (!length) { - // We've completed our earlier media segment and no new data is to be - // processed. This happens with some containers that can't detect that a - // media segment is ending until a new one starts. - nsRefPtr p = mProcessingPromise.Ensure(__func__); - CompleteCodedFrameProcessing(); - return p; - } nsRefPtr segment = new MediaByteBuffer; if (!segment->AppendElements(mInputBuffer->Elements(), length, fallible)) { return CodedFrameProcessingPromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY, __func__); diff --git a/dom/media/mediasource/TrackBuffersManager.h b/dom/media/mediasource/TrackBuffersManager.h index 6187507142e5..dfa5c67d549c 100644 --- a/dom/media/mediasource/TrackBuffersManager.h +++ b/dom/media/mediasource/TrackBuffersManager.h @@ -113,7 +113,6 @@ class TrackBuffersManager : public SourceBufferContentManager { void InitializationSegmentReceived(); void ShutdownDemuxers(); void CreateDemuxerforMIMEType(); - void ResetDemuxingState(); void NeedMoreData(); void RejectAppend(nsresult aRejectValue, const char* aName); // Will return a promise that will be resolved once all frames of the current @@ -152,8 +151,6 @@ class TrackBuffersManager : public SourceBufferContentManager { // TODO: Unused for now. Atomic mBufferFull; bool mFirstInitializationSegmentReceived; - // Set to true once a new segment is started. - bool mNewSegmentStarted; bool mActiveTrack; Maybe mGroupStartTimestamp; media::TimeUnit mGroupEndTimestamp; @@ -174,11 +171,9 @@ class TrackBuffersManager : public SourceBufferContentManager { nsRefPtr mInputDemuxer; // Length already processed in current media segment. uint32_t mProcessedInput; - Maybe mLastParsedEndTime; void OnDemuxerInitDone(nsresult); void OnDemuxerInitFailed(DemuxerFailureReason aFailure); - void OnDemuxerResetDone(nsresult); MozPromiseRequestHolder mDemuxerInitRequest; bool mEncrypted; diff --git a/dom/media/webm/WebMBufferedParser.cpp b/dom/media/webm/WebMBufferedParser.cpp index 0900b64ec272..8b80aa46d779 100644 --- a/dom/media/webm/WebMBufferedParser.cpp +++ b/dom/media/webm/WebMBufferedParser.cpp @@ -344,22 +344,6 @@ void WebMBufferedState::NotifyDataArrived(const unsigned char* aBuffer, uint32_t i += 1; } } - - mLastEndOffset = std::max(aOffset + aLength, mLastEndOffset); - - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - - if (mTimeMapping.IsEmpty()) { - return; - } - int32_t endIdx = mTimeMapping.Length() - 1; - while (endIdx >= 0 && mLastEndOffset < mTimeMapping[endIdx].mEndOffset) { - endIdx -= 1; - } - if (endIdx < 0) { - return; - } - mLastBlockOffset = mTimeMapping[endIdx].mEndOffset; } void WebMBufferedState::Reset() { @@ -414,13 +398,6 @@ int64_t WebMBufferedState::GetInitEndOffset() return mRangeParsers[0].mInitEndOffset; } -int64_t WebMBufferedState::GetLastBlockOffset() -{ - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - - return mLastBlockOffset; -} - bool WebMBufferedState::GetStartTime(uint64_t *aTime) { ReentrantMonitorAutoEnter mon(mReentrantMonitor); diff --git a/dom/media/webm/WebMBufferedParser.h b/dom/media/webm/WebMBufferedParser.h index 549982d5a71c..89efd0826ce0 100644 --- a/dom/media/webm/WebMBufferedParser.h +++ b/dom/media/webm/WebMBufferedParser.h @@ -225,11 +225,7 @@ class WebMBufferedState final NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebMBufferedState) public: - WebMBufferedState() - : mReentrantMonitor("WebMBufferedState") - , mLastBlockOffset(-1) - , mLastEndOffset(-1) - { + WebMBufferedState() : mReentrantMonitor("WebMBufferedState") { MOZ_COUNT_CTOR(WebMBufferedState); } @@ -246,8 +242,6 @@ class WebMBufferedState final // Returns end offset of init segment or -1 if none found. int64_t GetInitEndOffset(); - // Returns the end offset of the last complete block or -1 if none found. - int64_t GetLastBlockOffset(); // Returns start time bool GetStartTime(uint64_t *aTime); @@ -261,16 +255,12 @@ class WebMBufferedState final MOZ_COUNT_DTOR(WebMBufferedState); } - // Synchronizes access to the mTimeMapping array and mLastBlockOffset. + // Synchronizes access to the mTimeMapping array. ReentrantMonitor mReentrantMonitor; // Sorted (by offset) map of data offsets to timecodes. Populated // on the main thread as data is received and parsed by WebMBufferedParsers. nsTArray mTimeMapping; - // The last complete block parsed. -1 if not set. - int64_t mLastBlockOffset; - // The last seen data end offset. -1 if not set. - int64_t mLastEndOffset; // Sorted (by offset) live parser instances. Main thread only. nsTArray mRangeParsers; diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp index 0f88a388036f..02f57c04abfe 100644 --- a/dom/media/webm/WebMDemuxer.cpp +++ b/dom/media/webm/WebMDemuxer.cpp @@ -35,39 +35,40 @@ extern PRLogModuleInfo* gNesteggLog; // Functions for reading and seeking using WebMDemuxer required for // nestegg_io. The 'user data' passed to these functions is the -// demuxer. +// demuxer's MediaResourceIndex static int webmdemux_read(void* aBuffer, size_t aLength, void* aUserData) { MOZ_ASSERT(aUserData); + MediaResourceIndex* resource = + reinterpret_cast(aUserData); + int64_t length = resource->GetLength(); MOZ_ASSERT(aLength < UINT32_MAX); - WebMDemuxer* demuxer = reinterpret_cast(aUserData); - int64_t length = demuxer->GetEndDataOffset(); uint32_t count = aLength; - int64_t position = demuxer->GetResource()->Tell(); - if (length >= 0 && count + position > length) { - count = length - position; + if (length >= 0 && count + resource->Tell() > length) { + count = uint32_t(length - resource->Tell()); } uint32_t bytes = 0; - nsresult rv = - demuxer->GetResource()->Read(static_cast(aBuffer), count, &bytes); - bool eof = bytes < aLength; + nsresult rv = resource->Read(static_cast(aBuffer), count, &bytes); + bool eof = !bytes; return NS_FAILED(rv) ? -1 : eof ? 0 : 1; } static int webmdemux_seek(int64_t aOffset, int aWhence, void* aUserData) { MOZ_ASSERT(aUserData); - WebMDemuxer* demuxer = reinterpret_cast(aUserData); - nsresult rv = demuxer->GetResource()->Seek(aWhence, aOffset); + MediaResourceIndex* resource = + reinterpret_cast(aUserData); + nsresult rv = resource->Seek(aWhence, aOffset); return NS_SUCCEEDED(rv) ? 0 : -1; } static int64_t webmdemux_tell(void* aUserData) { MOZ_ASSERT(aUserData); - WebMDemuxer* demuxer = reinterpret_cast(aUserData); - return demuxer->GetResource()->Tell(); + MediaResourceIndex* resource = + reinterpret_cast(aUserData); + return resource->Tell(); } static void webmdemux_log(nestegg* aContext, @@ -121,15 +122,12 @@ WebMDemuxer::WebMDemuxer(MediaResource* aResource) , mVideoTrack(0) , mAudioTrack(0) , mSeekPreroll(0) - , mLastAudioFrameTime(0) , mLastVideoFrameTime(0) , mAudioCodec(-1) , mVideoCodec(-1) , mHasVideo(false) , mHasAudio(false) , mNeedReIndex(true) - , mLastWebMBlockOffset(-1) - , mIsExpectingMoreData(true) { if (!gNesteggLog) { gNesteggLog = PR_NewLogModule("Nestegg"); @@ -254,7 +252,7 @@ WebMDemuxer::ReadMetadata() io.read = webmdemux_read; io.seek = webmdemux_seek; io.tell = webmdemux_tell; - io.userdata = this; + io.userdata = &mResource; int64_t maxOffset = mBufferedState->GetInitEndOffset(); if (maxOffset == -1) { maxOffset = mResource.GetLength(); @@ -430,8 +428,6 @@ WebMDemuxer::EnsureUpToDateIndex() if (!mInitData && mBufferedState->GetInitEndOffset() != -1) { mInitData = mResource.MediaReadAt(0, mBufferedState->GetInitEndOffset()); } - mLastWebMBlockOffset = mBufferedState->GetLastBlockOffset(); - mIsExpectingMoreData = mResource.GetResource()->IsExpectingMoreData(); mNeedReIndex = false; } @@ -458,8 +454,6 @@ WebMDemuxer::GetCrypto() bool WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSamples) { - EnsureUpToDateIndex(); - nsRefPtr holder(NextPacket(aType)); if (!holder) { @@ -695,10 +689,6 @@ WebMDemuxer::SeekInternal(const media::TimeUnit& aTarget) } WEBM_DEBUG("got offset from buffered state: %" PRIu64 "", offset); } - - mLastAudioFrameTime = 0; - mLastVideoFrameTime = 0; - return NS_OK; } diff --git a/dom/media/webm/WebMDemuxer.h b/dom/media/webm/WebMDemuxer.h index 91de7e156d13..834df8b865fa 100644 --- a/dom/media/webm/WebMDemuxer.h +++ b/dom/media/webm/WebMDemuxer.h @@ -85,18 +85,6 @@ class WebMDemuxer : public MediaDataDemuxer // Pushes a packet to the front of the video packet queue. virtual void PushVideoPacket(NesteggPacketHolder* aItem); - // Public accessor for nestegg callbacks - MediaResourceIndex* GetResource() - { - return &mResource; - } - - int64_t GetEndDataOffset() - { - return mLastWebMBlockOffset < 0 || mIsExpectingMoreData - ? mResource.GetLength() : mLastWebMBlockOffset; - } - private: friend class WebMTrackDemuxer; @@ -164,12 +152,6 @@ class WebMDemuxer : public MediaDataDemuxer bool mHasVideo; bool mHasAudio; bool mNeedReIndex; - - // The last complete block parsed by the WebMBufferedState. -1 if not set. - // We cache those values rather than retrieving them for performance reasons - // as nestegg only performs 1-byte read at a time. - int64_t mLastWebMBlockOffset; - bool mIsExpectingMoreData; }; class WebMTrackDemuxer : public MediaTrackDemuxer From a8e538b32f6cd8c42f76ce4b16928c0a51fb7a70 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Fri, 21 Aug 2015 09:55:43 +0100 Subject: [PATCH 097/208] Bug 1196887 - Compare the writing-mode property, not only whether it is horizontal or vertical, when deciding whether to compute display:inline as inline-block. r=dholbert --- ...7-1-computed-display-inline-block-ref.html | 3 +++ ...96887-1-computed-display-inline-block.html | 5 +++++ layout/reftests/writing-mode/reftest.list | 1 + layout/style/nsStyleContext.cpp | 21 +++++++++++-------- 4 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 layout/reftests/writing-mode/1196887-1-computed-display-inline-block-ref.html create mode 100644 layout/reftests/writing-mode/1196887-1-computed-display-inline-block.html diff --git a/layout/reftests/writing-mode/1196887-1-computed-display-inline-block-ref.html b/layout/reftests/writing-mode/1196887-1-computed-display-inline-block-ref.html new file mode 100644 index 000000000000..502e5a964550 --- /dev/null +++ b/layout/reftests/writing-mode/1196887-1-computed-display-inline-block-ref.html @@ -0,0 +1,3 @@ + +

There should be no red:

+
diff --git a/layout/reftests/writing-mode/1196887-1-computed-display-inline-block.html b/layout/reftests/writing-mode/1196887-1-computed-display-inline-block.html new file mode 100644 index 000000000000..676cd3d22135 --- /dev/null +++ b/layout/reftests/writing-mode/1196887-1-computed-display-inline-block.html @@ -0,0 +1,5 @@ + +

There should be no red:

+
+
+ diff --git a/layout/reftests/writing-mode/reftest.list b/layout/reftests/writing-mode/reftest.list index 2e49fbc02523..071e59b5f1c5 100644 --- a/layout/reftests/writing-mode/reftest.list +++ b/layout/reftests/writing-mode/reftest.list @@ -150,6 +150,7 @@ test-pref(dom.meta-viewport.enabled,true) test-pref(font.size.inflation.emPerLin == 1172774-percent-padding-4.html 1172774-percent-vertical-ref.html == 1174450-intrinsic-sizing.html 1174450-intrinsic-sizing-ref.html == 1175789-underline-overline-1.html 1175789-underline-overline-1-ref.html +== 1196887-1-computed-display-inline-block.html 1196887-1-computed-display-inline-block-ref.html # Suite of tests from Gérard Talbot in bug 1079151 include abspos/reftest.list diff --git a/layout/style/nsStyleContext.cpp b/layout/style/nsStyleContext.cpp index d8969cffcf9e..cbbe83b95317 100644 --- a/layout/style/nsStyleContext.cpp +++ b/layout/style/nsStyleContext.cpp @@ -759,16 +759,19 @@ nsStyleContext::ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup) } } - // Elements with display:inline whose writing-mode is orthogonal to their - // parent's mode will be converted to display:inline-block. + /* + * According to https://drafts.csswg.org/css-writing-modes-3/#block-flow: + * + * If a box has a different block flow direction than its containing block: + * * If the box has a specified display of inline, its display computes + * to inline-block. [CSS21] + * ...etc. + */ if (disp->mDisplay == NS_STYLE_DISPLAY_INLINE && mParent) { - // We don't need the full mozilla::WritingMode value (incorporating dir and - // text-orientation) here, all we care about is vertical vs horizontal. - bool thisHorizontal = - StyleVisibility()->mWritingMode == NS_STYLE_WRITING_MODE_HORIZONTAL_TB; - bool parentHorizontal = mParent->StyleVisibility()->mWritingMode == - NS_STYLE_WRITING_MODE_HORIZONTAL_TB; - if (thisHorizontal != parentHorizontal) { + // We don't need the full mozilla::WritingMode value (incorporating dir + // and text-orientation) here; just the writing-mode property is enough. + if (StyleVisibility()->mWritingMode != + mParent->StyleVisibility()->mWritingMode) { nsStyleDisplay *mutable_display = static_cast(GetUniqueStyleData(eStyleStruct_Display)); mutable_display->mOriginalDisplay = mutable_display->mDisplay = From 501ab3e7bcc412cbe07bac58f9790fb37719f1c8 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Fri, 21 Aug 2015 09:55:52 +0100 Subject: [PATCH 098/208] Bug 1193481 - Prefer "Firefox Emoji" font for emoji characters in GetCommonFallbackFonts on B2G. r=jdaggett --- gfx/thebes/gfxAndroidPlatform.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/gfx/thebes/gfxAndroidPlatform.cpp b/gfx/thebes/gfxAndroidPlatform.cpp index a8df49057031..92d9148e7ee8 100644 --- a/gfx/thebes/gfxAndroidPlatform.cpp +++ b/gfx/thebes/gfxAndroidPlatform.cpp @@ -181,13 +181,30 @@ gfxAndroidPlatform::GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh, { static const char kDroidSansJapanese[] = "Droid Sans Japanese"; static const char kMotoyaLMaru[] = "MotoyaLMaru"; + static const char kNotoColorEmoji[] = "Noto Color Emoji"; +#ifdef MOZ_WIDGET_GONK + static const char kFirefoxEmoji[] = "Firefox Emoji"; +#endif if (aNextCh == 0xfe0fu) { // if char is followed by VS16, try for a color emoji glyph - aFontList.AppendElement("Noto Color Emoji"); +#ifdef MOZ_WIDGET_GONK + aFontList.AppendElement(kFirefoxEmoji); +#endif + aFontList.AppendElement(kNotoColorEmoji); } - if (IS_IN_BMP(aCh)) { + if (!IS_IN_BMP(aCh)) { + uint32_t p = aCh >> 16; + if (p == 1) { // try color emoji font, unless VS15 (text style) present + if (aNextCh != 0xfe0fu && aNextCh != 0xfe0eu) { +#ifdef MOZ_WIDGET_GONK + aFontList.AppendElement(kFirefoxEmoji); +#endif + aFontList.AppendElement(kNotoColorEmoji); + } + } + } else { // try language-specific "Droid Sans *" and "Noto Sans *" fonts for // certain blocks, as most devices probably have these uint8_t block = (aCh >> 8) & 0xff; From 07593c9efcabcbbfe6304f616a20486940679372 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Fri, 21 Aug 2015 09:57:01 +0100 Subject: [PATCH 099/208] Bug 1194763 - Ensure non-cluster-start flag is set properly for a run-initial supplementary-plane combining mark when shaping text. r=jdaggett --- gfx/thebes/gfxFont.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index b3b2726ea90a..d983924dbee0 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -534,9 +534,9 @@ gfxFontShaper::MergeFontFeatures( } void -gfxShapedText::SetupClusterBoundaries(uint32_t aOffset, +gfxShapedText::SetupClusterBoundaries(uint32_t aOffset, const char16_t *aString, - uint32_t aLength) + uint32_t aLength) { CompressedGlyph *glyphs = GetCharacterGlyphs() + aOffset; @@ -547,8 +547,15 @@ gfxShapedText::SetupClusterBoundaries(uint32_t aOffset, // the ClusterIterator won't be able to tell us if the string // _begins_ with a cluster-extender, so we handle that here - if (aLength && IsClusterExtender(*aString)) { - *glyphs = extendCluster; + if (aLength) { + uint32_t ch = *aString; + if (aLength > 1 && NS_IS_HIGH_SURROGATE(ch) && + NS_IS_LOW_SURROGATE(aString[1])) { + ch = SURROGATE_TO_UCS4(ch, aString[1]); + } + if (IsClusterExtender(ch)) { + *glyphs = extendCluster; + } } while (!iter.AtEnd()) { From 4df79513df152f361bb7bdfa74d15f98afc08955 Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Fri, 21 Aug 2015 11:26:39 +0200 Subject: [PATCH 100/208] Backed out changeset aed2e9e74697 (bug 1195073) because it will now pass unexpected due to the previous backout. r=backout --- .../meta/media-source/mediasource-sourcebuffer-mode.html.ini | 4 ---- 1 file changed, 4 deletions(-) diff --git a/testing/web-platform/meta/media-source/mediasource-sourcebuffer-mode.html.ini b/testing/web-platform/meta/media-source/mediasource-sourcebuffer-mode.html.ini index 94893e18ae4d..4572fc8cbd4e 100644 --- a/testing/web-platform/meta/media-source/mediasource-sourcebuffer-mode.html.ini +++ b/testing/web-platform/meta/media-source/mediasource-sourcebuffer-mode.html.ini @@ -1,10 +1,6 @@ [mediasource-sourcebuffer-mode.html] type: testharness prefs: [media.mediasource.enabled:true] - [Test setting SourceBuffer.mode and SourceBuffer.timestampOffset while parsing media segment.] - expected: - if os == "linux": FAIL - if (os == "win") and (version == "5.1.2600"): FAIL [Test setting SourceBuffer.mode triggers parent MediaSource 'ended' to 'open' transition.] expected: if os == "linux": FAIL From 12a236833125ab5fd4d54398edbaa2b775b31ba2 Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Fri, 21 Aug 2015 11:31:59 +0200 Subject: [PATCH 101/208] Backed out changeset 6beb23f39237 (bug 1195073) because other parts of the bug have been backed out. r=backout --- dom/media/mediasource/ContainerParser.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/dom/media/mediasource/ContainerParser.cpp b/dom/media/mediasource/ContainerParser.cpp index 5fa35a0c7e9f..395246b1a9a5 100644 --- a/dom/media/mediasource/ContainerParser.cpp +++ b/dom/media/mediasource/ContainerParser.cpp @@ -11,7 +11,6 @@ #include "mozilla/ErrorResult.h" #include "mp4_demuxer/MoofParser.h" #include "mozilla/Logging.h" -#include "mozilla/Maybe.h" #include "MediaData.h" #ifdef MOZ_FMP4 #include "MP4Stream.h" From f87ecaa27a3ef09a978dc7a6478e6d6e0516250d Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 21 Aug 2015 11:58:06 +0100 Subject: [PATCH 102/208] Bug 1191814 - WebSpeech synthesis API and AudioChannelService, r=eeejay --- .../synth/ipc/PSpeechSynthesisRequest.ipdl | 2 + .../synth/ipc/SpeechSynthesisChild.cpp | 8 +++ .../synth/ipc/SpeechSynthesisChild.h | 2 + .../synth/ipc/SpeechSynthesisParent.cpp | 8 +++ .../synth/ipc/SpeechSynthesisParent.h | 2 + dom/media/webspeech/synth/nsSpeechTask.cpp | 57 ++++++++++++++++++- dom/media/webspeech/synth/nsSpeechTask.h | 11 ++++ 7 files changed, 89 insertions(+), 1 deletion(-) diff --git a/dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl b/dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl index 9a146145bbd7..d244b1708ca5 100644 --- a/dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl +++ b/dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl @@ -23,6 +23,8 @@ async protocol PSpeechSynthesisRequest ForceEnd(); + SetAudioOutputVolume(uint32_t aVolume); + child: __delete__(bool aIsError, float aElapsedTime, uint32_t aCharIndex); diff --git a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp index c6f4e60258ac..04acb3e9e5d5 100644 --- a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp +++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp @@ -191,5 +191,13 @@ SpeechTaskChild::ForceEnd() mActor->SendForceEnd(); } +void +SpeechTaskChild::SetAudioOutputVolume(uint32_t aVolume) +{ + if (mActor) { + mActor->SendSetAudioOutputVolume(aVolume); + } +} + } // namespace dom } // namespace mozilla diff --git a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h index a89cbaa43814..cb0d7d78f848 100644 --- a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h +++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h @@ -92,6 +92,8 @@ class SpeechTaskChild : public nsSpeechTask virtual void ForceEnd() override; + virtual void SetAudioOutputVolume(uint32_t aVolume) override; + private: SpeechSynthesisRequestChild* mActor; }; diff --git a/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.cpp b/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.cpp index e6ef6d654618..6729f3bbf628 100644 --- a/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.cpp +++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.cpp @@ -127,6 +127,14 @@ SpeechSynthesisRequestParent::RecvForceEnd() return true; } +bool +SpeechSynthesisRequestParent::RecvSetAudioOutputVolume(const uint32_t& aVolume) +{ + MOZ_ASSERT(mTask); + mTask->SetAudioOutputVolume(aVolume); + return true; +} + // SpeechTaskParent nsresult diff --git a/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.h b/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.h index 67272583c5d6..95417666f218 100644 --- a/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.h +++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.h @@ -69,6 +69,8 @@ class SpeechSynthesisRequestParent : public PSpeechSynthesisRequestParent virtual bool RecvCancel() override; virtual bool RecvForceEnd() override; + + virtual bool RecvSetAudioOutputVolume(const uint32_t& aVolume) override; }; class SpeechTaskParent : public nsSpeechTask diff --git a/dom/media/webspeech/synth/nsSpeechTask.cpp b/dom/media/webspeech/synth/nsSpeechTask.cpp index efe7c66c0ecb..00bef46f4243 100644 --- a/dom/media/webspeech/synth/nsSpeechTask.cpp +++ b/dom/media/webspeech/synth/nsSpeechTask.cpp @@ -4,10 +4,12 @@ * 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/. */ +#include "AudioChannelAgent.h" +#include "AudioChannelService.h" #include "AudioSegment.h" #include "nsSpeechTask.h" -#include "SpeechSynthesis.h" #include "nsSynthVoiceRegistry.h" +#include "SpeechSynthesis.h" // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to // GetTickCount() and conflicts with nsSpeechTask::GetCurrentTime(). @@ -89,6 +91,7 @@ NS_IMPL_CYCLE_COLLECTION(nsSpeechTask, mSpeechSynthesis, mUtterance, mCallback); NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSpeechTask) NS_INTERFACE_MAP_ENTRY(nsISpeechTask) + NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechTask) NS_INTERFACE_MAP_END @@ -314,6 +317,8 @@ nsSpeechTask::DispatchStart() nsresult nsSpeechTask::DispatchStartInner() { + CreateAudioChannelAgent(); + nsSynthVoiceRegistry::GetInstance()->SetIsSpeaking(true); return DispatchStartImpl(); } @@ -356,6 +361,8 @@ nsSpeechTask::DispatchEnd(float aElapsedTime, uint32_t aCharIndex) nsresult nsSpeechTask::DispatchEndInner(float aElapsedTime, uint32_t aCharIndex) { + DestroyAudioChannelAgent(); + if (!mPreCanceled) { nsSynthVoiceRegistry::GetInstance()->SpeakNext(); } @@ -645,5 +652,53 @@ nsSpeechTask::SetSpeechSynthesis(SpeechSynthesis* aSpeechSynthesis) mSpeechSynthesis = aSpeechSynthesis; } +void +nsSpeechTask::CreateAudioChannelAgent() +{ + if (!mUtterance) { + return; + } + + if (mAudioChannelAgent) { + mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY); + } + + mAudioChannelAgent = new AudioChannelAgent(); + mAudioChannelAgent->InitWithWeakCallback(mUtterance->GetOwner(), + static_cast(AudioChannelService::GetDefaultAudioChannel()), + this); +} + +void +nsSpeechTask::DestroyAudioChannelAgent() +{ + if (mAudioChannelAgent) { + mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY); + mAudioChannelAgent = nullptr; + } +} + +NS_IMETHODIMP +nsSpeechTask::WindowVolumeChanged(float aVolume, bool aMuted) +{ + SetAudioOutputVolume(mVolume * aVolume * aMuted); + return NS_OK; +} + +NS_IMETHODIMP +nsSpeechTask::WindowAudioCaptureChanged() +{ + // This is not supported yet. + return NS_OK; +} + +void +nsSpeechTask::SetAudioOutputVolume(uint32_t aVolume) +{ + if (mStream) { + mStream->SetAudioOutputVolume(this, aVolume); + } +} + } // namespace dom } // namespace mozilla diff --git a/dom/media/webspeech/synth/nsSpeechTask.h b/dom/media/webspeech/synth/nsSpeechTask.h index 70e7929ef6a4..327f2a93032c 100644 --- a/dom/media/webspeech/synth/nsSpeechTask.h +++ b/dom/media/webspeech/synth/nsSpeechTask.h @@ -9,6 +9,7 @@ #include "MediaStreamGraph.h" #include "SpeechSynthesisUtterance.h" +#include "nsIAudioChannelAgent.h" #include "nsISpeechService.h" namespace mozilla { @@ -19,6 +20,7 @@ class SpeechSynthesis; class SynthStreamListener; class nsSpeechTask : public nsISpeechTask + , public nsIAudioChannelAgentCallback { friend class SynthStreamListener; @@ -27,6 +29,7 @@ class nsSpeechTask : public nsISpeechTask NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsSpeechTask, nsISpeechTask) NS_DECL_NSISPEECHTASK + NS_DECL_NSIAUDIOCHANNELAGENTCALLBACK explicit nsSpeechTask(SpeechSynthesisUtterance* aUtterance); nsSpeechTask(float aVolume, const nsAString& aText); @@ -49,6 +52,8 @@ class nsSpeechTask : public nsISpeechTask void SetChosenVoiceURI(const nsAString& aUri); + virtual void SetAudioOutputVolume(uint32_t aVolume); + bool IsPreCanceled() { return mPreCanceled; @@ -102,12 +107,18 @@ class nsSpeechTask : public nsISpeechTask nsresult DispatchEndInner(float aElapsedTime, uint32_t aCharIndex); + void CreateAudioChannelAgent(); + + void DestroyAudioChannelAgent(); + nsRefPtr mStream; nsRefPtr mPort; nsCOMPtr mCallback; + nsCOMPtr mAudioChannelAgent; + uint32_t mChannels; nsRefPtr mSpeechSynthesis; From c677884680db9962370088cbcda0130b66801364 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Fri, 21 Aug 2015 08:52:11 -0400 Subject: [PATCH 103/208] Bug 1196914 - Don't scroll to focused input unless the IME went away and came back. r=rbarker --- mobile/android/base/GeckoAppShell.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index b68c0ba6de29..8e2f69dd5740 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -2391,12 +2391,20 @@ public static boolean isTablet() { return HardwareUtils.isTablet(); } + private static boolean sImeWasEnabledOnLastResize = false; public static void viewSizeChanged() { LayerView v = getLayerView(); - if (v != null && v.isIMEEnabled()) { + if (v == null) { + return; + } + boolean imeIsEnabled = v.isIMEEnabled(); + if (imeIsEnabled && !sImeWasEnabledOnLastResize) { + // The IME just came up after not being up, so let's scroll + // to the focused input. sendEventToGecko(GeckoEvent.createBroadcastEvent( "ScrollTo:FocusedInput", "")); } + sImeWasEnabledOnLastResize = imeIsEnabled; } @WrapForJNI(stubName = "GetCurrentNetworkInformationWrapper") From be7022e7f19b24eadb5f2ea37a2c1544ee55f923 Mon Sep 17 00:00:00 2001 From: Sotaro Ikeda Date: Fri, 21 Aug 2015 06:28:55 -0700 Subject: [PATCH 104/208] Bug 1194442 - Code clean up of AudioManager r=alwu --- dom/system/gonk/AudioManager.cpp | 316 ++++++++++++++++--------------- dom/system/gonk/AudioManager.h | 20 ++ 2 files changed, 183 insertions(+), 153 deletions(-) diff --git a/dom/system/gonk/AudioManager.cpp b/dom/system/gonk/AudioManager.cpp index 6a7552fc329c..314d838e7924 100644 --- a/dom/system/gonk/AudioManager.cpp +++ b/dom/system/gonk/AudioManager.cpp @@ -65,8 +65,6 @@ using namespace mozilla::dom::bluetooth; #define AUDIO_POLICY_SERVICE_NAME "media.audio_policy" #define SETTINGS_SERVICE "@mozilla.org/settingsService;1" -static void BinderDeadCallback(status_t aErr); -static void InternalSetAudioRoutes(SwitchState aState); // Refer AudioService.java from Android static const uint32_t sMaxStreamVolumeTbl[AUDIO_STREAM_CNT] = { 5, // voice call @@ -99,22 +97,14 @@ static const nsAttrValue::EnumTable kAudioOutputProfilesTable[] = { { nullptr } }; -// A bitwise variable for recording what kind of headset is attached. -static int sHeadsetState; -#if defined(MOZ_B2G_BT) || ANDROID_VERSION >= 17 -static bool sBluetoothA2dpEnabled; -#endif static const int kBtSampleRate = 8000; -static bool sSwitchDone = true; -#ifdef MOZ_B2G_BT -static bool sA2dpSwitchDone = true; -#endif typedef MozPromise VolumeInitPromise; namespace mozilla { namespace dom { namespace gonk { + static const VolumeData gVolumeData[VOLUME_TOTAL_NUMBER] = { {"audio.volume.content", VOLUME_MEDIA}, {"audio.volume.notification", VOLUME_NOTIFICATION}, @@ -123,6 +113,20 @@ static const VolumeData gVolumeData[VOLUME_TOTAL_NUMBER] = { {"audio.volume.bt_sco", VOLUME_BLUETOOTH_SCO} }; +class RunnableCallTask : public Task +{ +public: + explicit RunnableCallTask(nsIRunnable* aRunnable) + : mRunnable(aRunnable) {} + + void Run() override + { + mRunnable->Run(); + } +protected: + nsCOMPtr mRunnable; +}; + class AudioProfileData final { public: @@ -156,54 +160,48 @@ class AudioProfileData final bool mActive; }; -class RecoverTask : public nsRunnable +void +AudioManager::HandleAudioFlingerDied() { -public: - RecoverTask() {} - NS_IMETHODIMP Run() { - nsCOMPtr amService = do_GetService(NS_AUDIOMANAGER_CONTRACTID); - NS_ENSURE_TRUE(amService, NS_OK); - AudioManager *am = static_cast(amService.get()); - - uint32_t attempt; - for (attempt = 0; attempt < 50; attempt++) { - if (defaultServiceManager()->checkService(String16(AUDIO_POLICY_SERVICE_NAME)) != 0) { - break; - } - - LOG("AudioPolicyService is dead! attempt=%d", attempt); - usleep(1000 * 200); + uint32_t attempt; + for (attempt = 0; attempt < 50; attempt++) { + if (defaultServiceManager()->checkService(String16(AUDIO_POLICY_SERVICE_NAME)) != 0) { + break; } - MOZ_RELEASE_ASSERT(attempt < 50); + LOG("AudioPolicyService is dead! attempt=%d", attempt); + usleep(1000 * 200); + } - for (uint32_t loop = 0; loop < AUDIO_STREAM_CNT; ++loop) { - AudioSystem::initStreamVolume(static_cast(loop), 0, - sMaxStreamVolumeTbl[loop]); - uint32_t index; - am->GetStreamVolumeIndex(loop, &index); - am->SetStreamVolumeIndex(loop, index); - } + MOZ_RELEASE_ASSERT(attempt < 50); + + for (uint32_t loop = 0; loop < AUDIO_STREAM_CNT; ++loop) { + AudioSystem::initStreamVolume(static_cast(loop), + 0, + sMaxStreamVolumeTbl[loop]); + uint32_t index; + GetStreamVolumeIndex(loop, &index); + SetStreamVolumeIndex(loop, index); + } - if (sHeadsetState & AUDIO_DEVICE_OUT_WIRED_HEADSET) - InternalSetAudioRoutes(SWITCH_STATE_HEADSET); - else if (sHeadsetState & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) - InternalSetAudioRoutes(SWITCH_STATE_HEADPHONE); - else - InternalSetAudioRoutes(SWITCH_STATE_OFF); + if (mHeadsetState & AUDIO_DEVICE_OUT_WIRED_HEADSET) { + UpdateHeadsetConnectionState(SWITCH_STATE_HEADSET); + } else if (mHeadsetState & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) { + UpdateHeadsetConnectionState(SWITCH_STATE_HEADPHONE); + } else { + UpdateHeadsetConnectionState(SWITCH_STATE_OFF); + } - int32_t phoneState = nsIAudioManager::PHONE_STATE_INVALID; - am->GetPhoneState(&phoneState); + int32_t phoneState = nsIAudioManager::PHONE_STATE_INVALID; + GetPhoneState(&phoneState); #if ANDROID_VERSION < 17 - AudioSystem::setPhoneState(phoneState); + AudioSystem::setPhoneState(phoneState); #else - AudioSystem::setPhoneState(static_cast(phoneState)); + AudioSystem::setPhoneState(static_cast(phoneState)); #endif - AudioSystem::get_audio_flinger(); - return NS_OK; - } -}; + AudioSystem::get_audio_flinger(); +} class VolumeInitCallback final : public nsISettingsServiceCallback { @@ -277,89 +275,65 @@ class VolumeInitCallback final : public nsISettingsServiceCallback }; NS_IMPL_ISUPPORTS(VolumeInitCallback, nsISettingsServiceCallback) -} /* namespace gonk */ -} /* namespace dom */ -} /* namespace mozilla */ static void BinderDeadCallback(status_t aErr) { - if (aErr == DEAD_OBJECT) { - NS_DispatchToMainThread(new RecoverTask()); + if (aErr != DEAD_OBJECT) { + return; } + + nsCOMPtr runnable = + NS_NewRunnableFunction([]() { + MOZ_ASSERT(NS_IsMainThread()); + nsRefPtr audioManager = AudioManager::GetInstance(); + NS_ENSURE_TRUE(audioManager.get(), ); + audioManager->HandleAudioFlingerDied(); + }); + + NS_DispatchToMainThread(runnable); } static bool IsDeviceOn(audio_devices_t device) { - if (static_cast< - audio_policy_dev_state_t (*) (audio_devices_t, const char *) - >(AudioSystem::getDeviceConnectionState)) - return AudioSystem::getDeviceConnectionState(device, "") == +#if ANDROID_VERSION >= 15 + return AudioSystem::getDeviceConnectionState(device, "") == AUDIO_POLICY_DEVICE_STATE_AVAILABLE; - +#else return false; -} - -static void ProcessDelayedAudioRoute(SwitchState aState) -{ - if (sSwitchDone) - return; - InternalSetAudioRoutes(aState); - sSwitchDone = true; -} - -#ifdef MOZ_B2G_BT -static void ProcessDelayedA2dpRoute(audio_policy_dev_state_t aState, const nsCString aAddress) -{ - if (sA2dpSwitchDone) - return; - AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, - aState, aAddress.get()); - String8 cmd("bluetooth_enabled=false"); - AudioSystem::setParameters(0, cmd); - cmd.setTo("A2dpSuspended=true"); - AudioSystem::setParameters(0, cmd); - sA2dpSwitchDone = true; -} #endif +} NS_IMPL_ISUPPORTS(AudioManager, nsIAudioManager, nsIObserver) -static void -InternalSetAudioRoutesICS(SwitchState aState) +void +AudioManager::UpdateHeadsetConnectionState(hal::SwitchState aState) { +#if ANDROID_VERSION >= 15 if (aState == SWITCH_STATE_HEADSET) { AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_WIRED_HEADSET, AUDIO_POLICY_DEVICE_STATE_AVAILABLE, ""); - sHeadsetState |= AUDIO_DEVICE_OUT_WIRED_HEADSET; + mHeadsetState |= AUDIO_DEVICE_OUT_WIRED_HEADSET; } else if (aState == SWITCH_STATE_HEADPHONE) { AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_WIRED_HEADPHONE, AUDIO_POLICY_DEVICE_STATE_AVAILABLE, ""); - sHeadsetState |= AUDIO_DEVICE_OUT_WIRED_HEADPHONE; + mHeadsetState |= AUDIO_DEVICE_OUT_WIRED_HEADPHONE; } else if (aState == SWITCH_STATE_OFF) { - if (sHeadsetState & AUDIO_DEVICE_OUT_WIRED_HEADSET) { + if (mHeadsetState & AUDIO_DEVICE_OUT_WIRED_HEADSET) { AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_WIRED_HEADSET, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, ""); } - if (sHeadsetState & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) { + if (mHeadsetState & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) { AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_WIRED_HEADPHONE, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, ""); } - sHeadsetState = 0; + mHeadsetState = 0; } -} -static void -InternalSetAudioRoutes(SwitchState aState) -{ - if (static_cast< - status_t (*)(audio_devices_t, audio_policy_dev_state_t, const char*) - >(AudioSystem::setDeviceConnectionState)) { - InternalSetAudioRoutesICS(aState); - } else { - NS_NOTREACHED("Doesn't support audio routing on GB version"); - } +#else + NS_NOTREACHED("Doesn't support audio routing on GB version"); +#endif } void @@ -399,10 +373,26 @@ AudioManager::HandleBluetoothStatusChanged(nsISupports* aSubject, SwitchProfileData(DEVICE_BLUETOOTH, false); } } else if (!strcmp(aTopic, BLUETOOTH_A2DP_STATUS_CHANGED_ID)) { - if (audioState == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE && sA2dpSwitchDone) { + if (audioState == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE && mA2dpSwitchDone) { + nsRefPtr self = this; + nsCOMPtr runnable = + NS_NewRunnableFunction([self, audioState, aAddress]() { + if (self->mA2dpSwitchDone) { + return; + } + AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, + audioState, + aAddress.get()); + String8 cmd("bluetooth_enabled=false"); + AudioSystem::setParameters(0, cmd); + cmd.setTo("A2dpSuspended=true"); + AudioSystem::setParameters(0, cmd); + self->mA2dpSwitchDone = true; + }); MessageLoop::current()->PostDelayedTask( - FROM_HERE, NewRunnableFunction(&ProcessDelayedA2dpRoute, audioState, aAddress), 1000); - sA2dpSwitchDone = false; + FROM_HERE, new RunnableCallTask(runnable), 1000); + + mA2dpSwitchDone = false; SwitchProfileData(DEVICE_BLUETOOTH, false); } else { AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, @@ -411,7 +401,7 @@ AudioManager::HandleBluetoothStatusChanged(nsISupports* aSubject, AudioSystem::setParameters(0, cmd); cmd.setTo("A2dpSuspended=false"); AudioSystem::setParameters(0, cmd); - sA2dpSwitchDone = true; + mA2dpSwitchDone = true; SwitchProfileData(DEVICE_BLUETOOTH, true); #if ANDROID_VERSION >= 17 if (AudioSystem::getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_NO_BT_A2DP) { @@ -419,7 +409,7 @@ AudioManager::HandleBluetoothStatusChanged(nsISupports* aSubject, } #endif } - sBluetoothA2dpEnabled = audioState == AUDIO_POLICY_DEVICE_STATE_AVAILABLE; + mBluetoothA2dpEnabled = audioState == AUDIO_POLICY_DEVICE_STATE_AVAILABLE; } else if (!strcmp(aTopic, BLUETOOTH_HFP_STATUS_CHANGED_ID)) { AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, audioState, aAddress.get()); @@ -537,46 +527,68 @@ NotifyHeadphonesStatus(SwitchState aState) class HeadphoneSwitchObserver : public SwitchObserver { public: - HeadphoneSwitchObserver(AudioManager* aAudioManager) - : mAudioManager(aAudioManager) { } - void Notify(const SwitchEvent& aEvent) { - NotifyHeadphonesStatus(aEvent.status()); - // When user pulled out the headset, a delay of routing here can avoid the leakage of audio from speaker. - if (aEvent.status() == SWITCH_STATE_OFF && sSwitchDone) { - MessageLoop::current()->PostDelayedTask( - FROM_HERE, NewRunnableFunction(&ProcessDelayedAudioRoute, SWITCH_STATE_OFF), 1000); - mAudioManager->SwitchProfileData(DEVICE_HEADSET, false); - sSwitchDone = false; - } else if (aEvent.status() != SWITCH_STATE_OFF) { - InternalSetAudioRoutes(aEvent.status()); - mAudioManager->SwitchProfileData(DEVICE_HEADSET, true); - sSwitchDone = true; - } - // Handle the coexistence of a2dp / headset device, latest one wins. -#if ANDROID_VERSION >= 17 - int32_t forceUse = 0; - mAudioManager->GetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, &forceUse); - if (aEvent.status() != SWITCH_STATE_OFF && sBluetoothA2dpEnabled) { - mAudioManager->SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NO_BT_A2DP); - } else if (forceUse == AUDIO_POLICY_FORCE_NO_BT_A2DP) { - mAudioManager->SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NONE); - } -#endif + void Notify(const hal::SwitchEvent& aEvent) { + nsRefPtr audioManager = AudioManager::GetInstance(); + MOZ_ASSERT(audioManager); + audioManager->HandleHeadphoneSwitchEvent(aEvent); } -private: - AudioManager* mAudioManager; }; +void +AudioManager::HandleHeadphoneSwitchEvent(const hal::SwitchEvent& aEvent) +{ + NotifyHeadphonesStatus(aEvent.status()); + // When user pulled out the headset, a delay of routing here can avoid the leakage of audio from speaker. + if (aEvent.status() == SWITCH_STATE_OFF && mSwitchDone) { + + nsRefPtr self = this; + nsCOMPtr runnable = + NS_NewRunnableFunction([self]() { + if (self->mSwitchDone) { + return; + } + self->UpdateHeadsetConnectionState(SWITCH_STATE_OFF); + self->mSwitchDone = true; + }); + MessageLoop::current()->PostDelayedTask(FROM_HERE, new RunnableCallTask(runnable), 1000); + + SwitchProfileData(DEVICE_HEADSET, false); + mSwitchDone = false; + } else if (aEvent.status() != SWITCH_STATE_OFF) { + UpdateHeadsetConnectionState(aEvent.status()); + SwitchProfileData(DEVICE_HEADSET, true); + mSwitchDone = true; + } + // Handle the coexistence of a2dp / headset device, latest one wins. +#if ANDROID_VERSION >= 17 + int32_t forceUse = 0; + GetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, &forceUse); + if (aEvent.status() != SWITCH_STATE_OFF && mBluetoothA2dpEnabled) { + SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NO_BT_A2DP); + } else if (forceUse == AUDIO_POLICY_FORCE_NO_BT_A2DP) { + SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NONE); + } +#endif +} + AudioManager::AudioManager() : mPhoneState(PHONE_STATE_CURRENT) - , mObserver(new HeadphoneSwitchObserver(this)) + , mHeadsetState(0) + , mSwitchDone(true) +#if defined(MOZ_B2G_BT) || ANDROID_VERSION >= 17 + , mBluetoothA2dpEnabled(false) +#endif +#ifdef MOZ_B2G_BT + , mA2dpSwitchDone(true) +#endif + , mObserver(new HeadphoneSwitchObserver()) #ifdef MOZ_B2G_RIL , mMuteCallToRIL(false) #endif { RegisterSwitchObserver(SWITCH_HEADPHONES, mObserver); - InternalSetAudioRoutes(GetCurrentSwitchState(SWITCH_HEADPHONES)); + UpdateHeadsetConnectionState(GetCurrentSwitchState(SWITCH_HEADPHONES)); NotifyHeadphonesStatus(GetCurrentSwitchState(SWITCH_HEADPHONES)); for (uint32_t loop = 0; loop < AUDIO_STREAM_CNT; ++loop) { @@ -746,32 +758,26 @@ AudioManager::SetPhoneState(int32_t aState) NS_IMETHODIMP AudioManager::SetForceForUse(int32_t aUsage, int32_t aForce) { - if (static_cast< - status_t (*)(audio_policy_force_use_t, audio_policy_forced_cfg_t) - >(AudioSystem::setForceUse)) { - // Dynamically resolved the ICS signature. - status_t status = AudioSystem::setForceUse( - (audio_policy_force_use_t)aUsage, - (audio_policy_forced_cfg_t)aForce); - return status ? NS_ERROR_FAILURE : NS_OK; - } - +#if ANDROID_VERSION >= 15 + status_t status = AudioSystem::setForceUse( + (audio_policy_force_use_t)aUsage, + (audio_policy_forced_cfg_t)aForce); + return status ? NS_ERROR_FAILURE : NS_OK; +#else NS_NOTREACHED("Doesn't support force routing on GB version"); return NS_ERROR_UNEXPECTED; +#endif } NS_IMETHODIMP AudioManager::GetForceForUse(int32_t aUsage, int32_t* aForce) { - if (static_cast< - audio_policy_forced_cfg_t (*)(audio_policy_force_use_t) - >(AudioSystem::getForceUse)) { - // Dynamically resolved the ICS signature. - *aForce = AudioSystem::getForceUse((audio_policy_force_use_t)aUsage); - return NS_OK; - } - +#if ANDROID_VERSION >= 15 + *aForce = AudioSystem::getForceUse((audio_policy_force_use_t)aUsage); + return NS_OK; +#else NS_NOTREACHED("Doesn't support force routing on GB version"); return NS_ERROR_UNEXPECTED; +#endif } NS_IMETHODIMP @@ -787,7 +793,7 @@ AudioManager::SetFmRadioAudioEnabled(bool aFmRadioAudioEnabled) AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_FM, aFmRadioAudioEnabled ? AUDIO_POLICY_DEVICE_STATE_AVAILABLE : AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, ""); - InternalSetAudioRoutes(GetCurrentSwitchState(SWITCH_HEADPHONES)); + UpdateHeadsetConnectionState(GetCurrentSwitchState(SWITCH_HEADPHONES)); // sync volume with music after powering on fm radio if (aFmRadioAudioEnabled) { uint32_t volIndex = mCurrentStreamVolumeTbl[AUDIO_STREAM_MUSIC]; @@ -1253,3 +1259,7 @@ AudioManager::UpdateVolumeFromProfile(AudioProfileData* aProfileData) aProfileData->mVolumeTable[gVolumeData[idx].mCategory]); } } + +} /* namespace gonk */ +} /* namespace dom */ +} /* namespace mozilla */ diff --git a/dom/system/gonk/AudioManager.h b/dom/system/gonk/AudioManager.h index 0ab3ba8f220d..dd16c49beb1e 100644 --- a/dom/system/gonk/AudioManager.h +++ b/dom/system/gonk/AudioManager.h @@ -16,6 +16,7 @@ #ifndef mozilla_dom_system_b2g_audiomanager_h__ #define mozilla_dom_system_b2g_audiomanager_h__ +#include "mozilla/HalTypes.h" #include "mozilla/Observer.h" #include "nsAutoPtr.h" #include "nsIAudioManager.h" @@ -98,8 +99,25 @@ class AudioManager final : public nsIAudioManager // Validate whether the volume index is within the range nsresult ValidateVolumeIndex(uint32_t aCategory, uint32_t aIndex) const; + // Called when android AudioFlinger in mediaserver is died + void HandleAudioFlingerDied(); + + void HandleHeadphoneSwitchEvent(const hal::SwitchEvent& aEvent); + protected: int32_t mPhoneState; + + // A bitwise variable for recording what kind of headset/headphone is attached. + int32_t mHeadsetState; + + bool mSwitchDone; + +#if defined(MOZ_B2G_BT) || ANDROID_VERSION >= 17 + bool mBluetoothA2dpEnabled; +#endif +#ifdef MOZ_B2G_BT + bool mA2dpSwitchDone; +#endif uint32_t mCurrentStreamVolumeTbl[AUDIO_STREAM_CNT]; nsresult SetStreamVolumeIndex(int32_t aStream, uint32_t aIndex); @@ -156,6 +174,8 @@ class AudioManager final : public nsIAudioManager void InitProfileVolumeSucceeded(); void InitProfileVolumeFailed(const char* aError); + void UpdateHeadsetConnectionState(hal::SwitchState aState); + AudioManager(); ~AudioManager(); }; From de0bf83dce195d29e777d5e55de2f8946a1addb1 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Fri, 21 Aug 2015 09:41:52 -0400 Subject: [PATCH 105/208] Bug 1187903 - Skip various failure-prone EME tests on Windows debug. --- dom/media/test/mochitest.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dom/media/test/mochitest.ini b/dom/media/test/mochitest.ini index dde2ff7e2ffd..7053803d16be 100644 --- a/dom/media/test/mochitest.ini +++ b/dom/media/test/mochitest.ini @@ -623,18 +623,18 @@ skip-if = toolkit == 'android' # bug 1043403 [test_eme_persistent_sessions.html] skip-if = toolkit == 'android' # bug 1043403 [test_eme_playback.html] -skip-if = toolkit == 'android' # bug 1043403 +skip-if = toolkit == 'android' || (os == 'win' && debug) # bug 1043403, bug 1187903 [test_eme_requestKeySystemAccess.html] skip-if = toolkit == 'android' # bug 1043403 [test_eme_stream_capture_blocked_case1.html] tags=msg capturestream -skip-if = toolkit == 'android' || (os == 'win' && !debug) # bug 1043403, bug 1140675 +skip-if = toolkit == 'android' || os == 'win' # bug 1043403, bug 1140675, bug 1187903 [test_eme_stream_capture_blocked_case2.html] tags=msg capturestream -skip-if = toolkit == 'android' || (os == 'win' && !debug) # bug 1043403, bug 1140675 +skip-if = toolkit == 'android' || os == 'win' # bug 1043403, bug 1140675, bug 1187903 [test_eme_stream_capture_blocked_case3.html] tags=msg capturestream -skip-if = toolkit == 'android' || (os == 'win' && !debug) # bug 1043403, bug 1140675 +skip-if = toolkit == 'android' || os == 'win' # bug 1043403, bug 1140675, bug 1187903 [test_empty_resource.html] [test_error_in_video_document.html] skip-if = toolkit == 'android' || (os == 'win' && !debug) || (os == 'mac' && !debug) # bug 608634 From dda71b16a4b6599dc8517ea90e8ae7d59d8f9f3a Mon Sep 17 00:00:00 2001 From: Jamie Nicol Date: Tue, 18 Aug 2015 17:53:56 +0100 Subject: [PATCH 106/208] Bug 1191463 - Handle possible ID3D10Texture2D::Map() failure. r=Bas --- gfx/layers/d3d11/ReadbackManagerD3D11.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gfx/layers/d3d11/ReadbackManagerD3D11.cpp b/gfx/layers/d3d11/ReadbackManagerD3D11.cpp index baa82d2a7bc1..28d7f5146ddc 100644 --- a/gfx/layers/d3d11/ReadbackManagerD3D11.cpp +++ b/gfx/layers/d3d11/ReadbackManagerD3D11.cpp @@ -44,12 +44,13 @@ class ReadbackResultWriterD3D11 final : public nsIRunnable mTask->mReadbackTexture->GetDesc(&desc); D3D10_MAPPED_TEXTURE2D mappedTex; - // We know this map will immediately succeed, as we've already mapped this - // copied data on our task thread. + // Unless there is an error this map should succeed immediately, as we've + // recently mapped (and unmapped) this copied data on our task thread. HRESULT hr = mTask->mReadbackTexture->Map(0, D3D10_MAP_READ, 0, &mappedTex); if (FAILED(hr)) { mTask->mSink->ProcessReadback(nullptr); + return NS_OK; } { From 1c3e83e1fd66ce71093c069929e97dbc5e00dd3c Mon Sep 17 00:00:00 2001 From: Mark Goodwin Date: Fri, 21 Aug 2015 15:14:08 +0100 Subject: [PATCH 107/208] Bug 1153444 - Fix up Key Pinning Telemetry (r=keeler) --- security/certverifier/CertVerifier.cpp | 41 +++++++++++++------ security/certverifier/CertVerifier.h | 21 +++++++++- .../certverifier/NSSCertDBTrustDomain.cpp | 5 ++- security/certverifier/NSSCertDBTrustDomain.h | 2 + .../manager/ssl/PublicKeyPinningService.cpp | 39 ++++++++++++------ .../manager/ssl/PublicKeyPinningService.h | 4 +- .../ssl/RootCertificateTelemetryUtils.cpp | 14 ++----- .../ssl/RootCertificateTelemetryUtils.h | 9 ++++ .../manager/ssl/SSLServerCertVerification.cpp | 14 ++++++- .../manager/ssl/tests/unit/test_pinning.js | 4 +- 10 files changed, 111 insertions(+), 42 deletions(-) diff --git a/security/certverifier/CertVerifier.cpp b/security/certverifier/CertVerifier.cpp index c0263181faf1..3d0470e7cd5a 100644 --- a/security/certverifier/CertVerifier.cpp +++ b/security/certverifier/CertVerifier.cpp @@ -124,7 +124,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage, /*optional out*/ SECOidTag* evOidPolicy, /*optional out*/ OCSPStaplingStatus* ocspStaplingStatus, /*optional out*/ KeySizeStatus* keySizeStatus, - /*optional out*/ SignatureDigestStatus* sigDigestStatus) + /*optional out*/ SignatureDigestStatus* sigDigestStatus, + /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo) { MOZ_LOG(gCertVerifierLog, LogLevel::Debug, ("Top of VerifyCert\n")); @@ -212,7 +213,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage, mCertShortLifetimeInDays, pinningDisabled, MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff, - AcceptAllAlgorithms, nullptr, + AcceptAllAlgorithms, nullptr, nullptr, builtChain); rv = BuildCertChain(trustDomain, certDER, time, EndEntityOrCA::MustBeEndEntity, @@ -262,12 +263,18 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage, for (size_t i=0; i < digestAlgorithmOptionsCount && rv != Success && srv == SECSuccess; i++) { + // Because of the try-strict and fallback approach, we have to clear any + // previously noted telemetry information + if (pinningTelemetryInfo) { + pinningTelemetryInfo->Reset(); + } NSSCertDBTrustDomain trustDomain(trustSSL, evOCSPFetching, mOCSPCache, pinArg, ocspGETConfig, mCertShortLifetimeInDays, mPinningMode, MIN_RSA_BITS, ValidityCheckingMode::CheckForEV, - digestAlgorithmOptions[i], hostname, builtChain); + digestAlgorithmOptions[i], pinningTelemetryInfo, hostname, + builtChain); rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time, KeyUsage::digitalSignature,// (EC)DHE KeyUsage::keyEncipherment, // RSA @@ -315,12 +322,19 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage, for (size_t i=0; iReset(); + } + NSSCertDBTrustDomain trustDomain(trustSSL, defaultOCSPFetching, mOCSPCache, pinArg, ocspGETConfig, mCertShortLifetimeInDays, mPinningMode, keySizeOptions[i], ValidityCheckingMode::CheckingOff, digestAlgorithmOptions[j], + pinningTelemetryInfo, hostname, builtChain); rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time, KeyUsage::digitalSignature,//(EC)DHE @@ -361,7 +375,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage, mCertShortLifetimeInDays, pinningDisabled, MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff, - AcceptAllAlgorithms, nullptr, + AcceptAllAlgorithms, nullptr, nullptr, builtChain); rv = BuildCertChain(trustDomain, certDER, time, EndEntityOrCA::MustBeCA, KeyUsage::keyCertSign, @@ -376,7 +390,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage, mCertShortLifetimeInDays, pinningDisabled, MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff, - AcceptAllAlgorithms, nullptr, + AcceptAllAlgorithms, nullptr, nullptr, builtChain); rv = BuildCertChain(trustDomain, certDER, time, EndEntityOrCA::MustBeEndEntity, @@ -402,7 +416,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage, mCertShortLifetimeInDays, pinningDisabled, MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff, - AcceptAllAlgorithms, nullptr, + AcceptAllAlgorithms, nullptr, nullptr, builtChain); rv = BuildCertChain(trustDomain, certDER, time, EndEntityOrCA::MustBeEndEntity, @@ -425,7 +439,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage, mCertShortLifetimeInDays, pinningDisabled, MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff, - AcceptAllAlgorithms, nullptr, + AcceptAllAlgorithms, nullptr, nullptr, builtChain); rv = BuildCertChain(trustDomain, certDER, time, EndEntityOrCA::MustBeEndEntity, @@ -457,7 +471,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage, pinArg, ocspGETConfig, mCertShortLifetimeInDays, pinningDisabled, MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff, - AcceptAllAlgorithms, nullptr, builtChain); + AcceptAllAlgorithms, nullptr, nullptr, + builtChain); rv = BuildCertChain(sslTrust, certDER, time, endEntityOrCA, keyUsage, eku, CertPolicyId::anyPolicy, stapledOCSPResponse); @@ -467,7 +482,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage, mCertShortLifetimeInDays, pinningDisabled, MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff, - AcceptAllAlgorithms, nullptr, + AcceptAllAlgorithms, nullptr, nullptr, builtChain); rv = BuildCertChain(emailTrust, certDER, time, endEntityOrCA, keyUsage, eku, CertPolicyId::anyPolicy, @@ -481,7 +496,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage, MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff, AcceptAllAlgorithms, - nullptr, builtChain); + nullptr, nullptr, builtChain); rv = BuildCertChain(objectSigningTrust, certDER, time, endEntityOrCA, keyUsage, eku, CertPolicyId::anyPolicy, stapledOCSPResponse); @@ -515,7 +530,8 @@ CertVerifier::VerifySSLServerCert(CERTCertificate* peerCert, /*optional out*/ SECOidTag* evOidPolicy, /*optional out*/ OCSPStaplingStatus* ocspStaplingStatus, /*optional out*/ KeySizeStatus* keySizeStatus, - /*optional out*/ SignatureDigestStatus* sigDigestStatus) + /*optional out*/ SignatureDigestStatus* sigDigestStatus, + /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo) { PR_ASSERT(peerCert); // XXX: PR_ASSERT(pinarg) @@ -540,7 +556,8 @@ CertVerifier::VerifySSLServerCert(CERTCertificate* peerCert, SECStatus rv = VerifyCert(peerCert, certificateUsageSSLServer, time, pinarg, hostname, flags, stapledOCSPResponse, &builtChainTemp, evOidPolicy, ocspStaplingStatus, - keySizeStatus, sigDigestStatus); + keySizeStatus, sigDigestStatus, + pinningTelemetryInfo); if (rv != SECSuccess) { return rv; } diff --git a/security/certverifier/CertVerifier.h b/security/certverifier/CertVerifier.h index f282d01c4af1..dfd3cf81ae59 100644 --- a/security/certverifier/CertVerifier.h +++ b/security/certverifier/CertVerifier.h @@ -7,6 +7,7 @@ #ifndef mozilla_psm__CertVerifier_h #define mozilla_psm__CertVerifier_h +#include "mozilla/Telemetry.h" #include "pkix/pkixtypes.h" #include "OCSPCache.h" #include "ScopedNSSTypes.h" @@ -31,6 +32,20 @@ enum class SignatureDigestStatus { AlreadyBad = 5, }; +class PinningTelemetryInfo +{ +public: + // Should we accumulate pinning telemetry for the result? + bool accumulateResult; + Telemetry::ID certPinningResultHistogram; + int32_t certPinningResultBucket; + // Should we accumulate telemetry for the root? + bool accumulateForRoot; + int32_t rootBucket; + + void Reset() { accumulateForRoot = false; accumulateResult = false; } +}; + class CertVerifier { public: @@ -62,7 +77,8 @@ class CertVerifier /*optional out*/ SECOidTag* evOidPolicy = nullptr, /*optional out*/ OCSPStaplingStatus* ocspStaplingStatus = nullptr, /*optional out*/ KeySizeStatus* keySizeStatus = nullptr, - /*optional out*/ SignatureDigestStatus* sigDigestStatus = nullptr); + /*optional out*/ SignatureDigestStatus* sigDigestStatus = nullptr, + /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo = nullptr); SECStatus VerifySSLServerCert( CERTCertificate* peerCert, @@ -76,7 +92,8 @@ class CertVerifier /*optional out*/ SECOidTag* evOidPolicy = nullptr, /*optional out*/ OCSPStaplingStatus* ocspStaplingStatus = nullptr, /*optional out*/ KeySizeStatus* keySizeStatus = nullptr, - /*optional out*/ SignatureDigestStatus* sigDigestStatus = nullptr); + /*optional out*/ SignatureDigestStatus* sigDigestStatus = nullptr, + /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo = nullptr); enum PinningMode { pinningDisabled = 0, diff --git a/security/certverifier/NSSCertDBTrustDomain.cpp b/security/certverifier/NSSCertDBTrustDomain.cpp index 30508ff84876..1c7807fffc2a 100644 --- a/security/certverifier/NSSCertDBTrustDomain.cpp +++ b/security/certverifier/NSSCertDBTrustDomain.cpp @@ -51,6 +51,7 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(SECTrustType certDBTrustType, unsigned int minRSABits, ValidityCheckingMode validityCheckingMode, SignatureDigestOption signatureDigestOption, + /*optional*/ PinningTelemetryInfo* pinningTelemetryInfo, /*optional*/ const char* hostname, /*optional*/ ScopedCERTCertList* builtChain) : mCertDBTrustType(certDBTrustType) @@ -63,6 +64,7 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(SECTrustType certDBTrustType, , mMinRSABits(minRSABits) , mValidityCheckingMode(validityCheckingMode) , mSignatureDigestOption(signatureDigestOption) + , mPinningTelemetryInfo(pinningTelemetryInfo) , mHostname(hostname) , mBuiltChain(builtChain) , mCertBlocklist(do_GetService(NS_CERTBLOCKLIST_CONTRACTID)) @@ -792,7 +794,8 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time) (mPinningMode == CertVerifier::pinningEnforceTestMode); bool chainHasValidPins; nsresult nsrv = PublicKeyPinningService::ChainHasValidPins( - certList, mHostname, time, enforceTestMode, chainHasValidPins); + certList, mHostname, time, enforceTestMode, chainHasValidPins, + mPinningTelemetryInfo); if (NS_FAILED(nsrv)) { return Result::FATAL_ERROR_LIBRARY_FAILURE; } diff --git a/security/certverifier/NSSCertDBTrustDomain.h b/security/certverifier/NSSCertDBTrustDomain.h index fa7534534cc5..7ab032248d7d 100644 --- a/security/certverifier/NSSCertDBTrustDomain.h +++ b/security/certverifier/NSSCertDBTrustDomain.h @@ -70,6 +70,7 @@ class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain unsigned int minRSABits, ValidityCheckingMode validityCheckingMode, SignatureDigestOption, + /*optional*/ PinningTelemetryInfo* pinningTelemetryInfo = nullptr, /*optional*/ const char* hostname = nullptr, /*optional out*/ ScopedCERTCertList* builtChain = nullptr); @@ -154,6 +155,7 @@ class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain const unsigned int mMinRSABits; ValidityCheckingMode mValidityCheckingMode; SignatureDigestOption mSignatureDigestOption; + PinningTelemetryInfo* mPinningTelemetryInfo; const char* mHostname; // non-owning - only used for pinning checks ScopedCERTCertList* mBuiltChain; // non-owning nsCOMPtr mCertBlocklist; diff --git a/security/manager/ssl/PublicKeyPinningService.cpp b/security/manager/ssl/PublicKeyPinningService.cpp index 262bd4d61ce3..073b3db9db0e 100644 --- a/security/manager/ssl/PublicKeyPinningService.cpp +++ b/security/manager/ssl/PublicKeyPinningService.cpp @@ -271,7 +271,8 @@ FindPinningInformation(const char* hostname, mozilla::pkix::Time time, static nsresult CheckPinsForHostname(const CERTCertList* certList, const char* hostname, bool enforceTestMode, mozilla::pkix::Time time, - /*out*/ bool& chainHasValidPins) + /*out*/ bool& chainHasValidPins, + /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo) { chainHasValidPins = false; if (!certList) { @@ -316,22 +317,32 @@ CheckPinsForHostname(const CERTCertList* certList, const char* hostname, } // We can collect per-host pinning violations for this host because it is // operationally critical to Firefox. - if (staticFingerprints->mId != kUnknownId) { - int32_t bucket = staticFingerprints->mId * 2 + (enforceTestModeResult ? 1 : 0); - histogram = staticFingerprints->mTestMode - ? Telemetry::CERT_PINNING_MOZ_TEST_RESULTS_BY_HOST - : Telemetry::CERT_PINNING_MOZ_RESULTS_BY_HOST; - Telemetry::Accumulate(histogram, bucket); - } else { - Telemetry::Accumulate(histogram, enforceTestModeResult ? 1 : 0); + if (pinningTelemetryInfo) { + if (staticFingerprints->mId != kUnknownId) { + int32_t bucket = staticFingerprints->mId * 2 + + (enforceTestModeResult ? 1 : 0); + histogram = staticFingerprints->mTestMode + ? Telemetry::CERT_PINNING_MOZ_TEST_RESULTS_BY_HOST + : Telemetry::CERT_PINNING_MOZ_RESULTS_BY_HOST; + pinningTelemetryInfo->certPinningResultBucket = bucket; + } else { + pinningTelemetryInfo->certPinningResultBucket = + enforceTestModeResult ? 1 : 0; + } + pinningTelemetryInfo->accumulateResult = true; + pinningTelemetryInfo->certPinningResultHistogram = histogram; } // We only collect per-CA pinning statistics upon failures. CERTCertListNode* rootNode = CERT_LIST_TAIL(certList); // Only log telemetry if the certificate list is non-empty. if (!CERT_LIST_END(rootNode, certList)) { - if (!enforceTestModeResult) { - AccumulateTelemetryForRootCA(Telemetry::CERT_PINNING_FAILURES_BY_CA, rootNode->cert); + if (!enforceTestModeResult && pinningTelemetryInfo) { + int32_t binNumber = RootCABinNumber(&rootNode->cert->derCert); + if (binNumber != ROOT_CERTIFICATE_UNKNOWN ) { + pinningTelemetryInfo->accumulateForRoot = true; + pinningTelemetryInfo->rootBucket = binNumber; + } } } @@ -350,7 +361,8 @@ PublicKeyPinningService::ChainHasValidPins(const CERTCertList* certList, const char* hostname, mozilla::pkix::Time time, bool enforceTestMode, - /*out*/ bool& chainHasValidPins) + /*out*/ bool& chainHasValidPins, + /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo) { chainHasValidPins = false; if (!certList) { @@ -361,7 +373,8 @@ PublicKeyPinningService::ChainHasValidPins(const CERTCertList* certList, } nsAutoCString canonicalizedHostname(CanonicalizeHostname(hostname)); return CheckPinsForHostname(certList, canonicalizedHostname.get(), - enforceTestMode, time, chainHasValidPins); + enforceTestMode, time, chainHasValidPins, + pinningTelemetryInfo); } nsresult diff --git a/security/manager/ssl/PublicKeyPinningService.h b/security/manager/ssl/PublicKeyPinningService.h index bb6021b237fd..9a02ab912056 100644 --- a/security/manager/ssl/PublicKeyPinningService.h +++ b/security/manager/ssl/PublicKeyPinningService.h @@ -6,6 +6,7 @@ #define PublicKeyPinningService_h #include "cert.h" +#include "CertVerifier.h" #include "nsString.h" #include "nsTArray.h" #include "pkix/Time.h" @@ -31,7 +32,8 @@ class PublicKeyPinningService const char* hostname, mozilla::pkix::Time time, bool enforceTestMode, - /*out*/ bool& chainHasValidPins); + /*out*/ bool& chainHasValidPins, + /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo); /** * Returns true if there is any intersection between the certificate list * and the pins specified in the aSHA256key array. Values passed in are diff --git a/security/manager/ssl/RootCertificateTelemetryUtils.cpp b/security/manager/ssl/RootCertificateTelemetryUtils.cpp index 2ca71627dd0a..6070bc89dba3 100644 --- a/security/manager/ssl/RootCertificateTelemetryUtils.cpp +++ b/security/manager/ssl/RootCertificateTelemetryUtils.cpp @@ -11,13 +11,7 @@ #include "ScopedNSSTypes.h" #include "mozilla/ArrayUtils.h" -// Note: New CAs will show up as UNKNOWN_ROOT until -// RootHashes.inc is updated to include them. 0 is reserved by -// genRootCAHashes.js for the unknowns. -#define UNKNOWN_ROOT 0 -#define HASH_FAILURE -1 - -namespace mozilla { namespace psm { +namespace mozilla { namespace psm { PRLogModuleInfo* gPublicKeyPinningTelemetryLog = PR_NewLogModule("PublicKeyPinningTelemetryService"); @@ -54,7 +48,7 @@ RootCABinNumber(const SECItem* cert) // Compute SHA256 hash of the certificate nsresult rv = digest.DigestBuf(SEC_OID_SHA256, cert->data, cert->len); if (NS_WARN_IF(NS_FAILED(rv))) { - return HASH_FAILURE; + return ROOT_CERTIFICATE_HASH_FAILURE; } // Compare against list of stored hashes @@ -76,7 +70,7 @@ RootCABinNumber(const SECItem* cert) } // Didn't match. - return UNKNOWN_ROOT; + return ROOT_CERTIFICATE_UNKNOWN; } @@ -88,7 +82,7 @@ AccumulateTelemetryForRootCA(mozilla::Telemetry::ID probe, { int32_t binId = RootCABinNumber(&cert->derCert); - if (binId != HASH_FAILURE) { + if (binId != ROOT_CERTIFICATE_HASH_FAILURE) { Accumulate(probe, binId); } } diff --git a/security/manager/ssl/RootCertificateTelemetryUtils.h b/security/manager/ssl/RootCertificateTelemetryUtils.h index 7ed3e54f4a60..05dbb4e44612 100644 --- a/security/manager/ssl/RootCertificateTelemetryUtils.h +++ b/security/manager/ssl/RootCertificateTelemetryUtils.h @@ -12,6 +12,15 @@ namespace mozilla { namespace psm { +// Note: New CAs will show up as UNKNOWN_ROOT until +// RootHashes.inc is updated to include them. 0 is reserved by +// genRootCAHashes.js for the unknowns. +#define ROOT_CERTIFICATE_UNKNOWN 0 +#define ROOT_CERTIFICATE_HASH_FAILURE -1 + +int32_t +RootCABinNumber(const SECItem* cert); + void AccumulateTelemetryForRootCA(mozilla::Telemetry::ID probe, const CERTCertificate* cert); diff --git a/security/manager/ssl/SSLServerCertVerification.cpp b/security/manager/ssl/SSLServerCertVerification.cpp index 91728bccc862..d75b9cf70d75 100644 --- a/security/manager/ssl/SSLServerCertVerification.cpp +++ b/security/manager/ssl/SSLServerCertVerification.cpp @@ -1178,13 +1178,15 @@ AuthCertificate(CertVerifier& certVerifier, CertVerifier::OCSP_STAPLING_NEVER_CHECKED; KeySizeStatus keySizeStatus = KeySizeStatus::NeverChecked; SignatureDigestStatus sigDigestStatus = SignatureDigestStatus::NeverChecked; + PinningTelemetryInfo pinningTelemetryInfo; rv = certVerifier.VerifySSLServerCert(cert, stapledOCSPResponse, time, infoObject, infoObject->GetHostNameRaw(), saveIntermediates, 0, &certList, &evOidPolicy, &ocspStaplingStatus, - &keySizeStatus, &sigDigestStatus); + &keySizeStatus, &sigDigestStatus, + &pinningTelemetryInfo); PRErrorCode savedErrorCode; if (rv != SECSuccess) { savedErrorCode = PR_GetError(); @@ -1202,6 +1204,16 @@ AuthCertificate(CertVerifier& certVerifier, static_cast(sigDigestStatus)); } + if (pinningTelemetryInfo.accumulateForRoot) { + Telemetry::Accumulate(Telemetry::CERT_PINNING_FAILURES_BY_CA, + pinningTelemetryInfo.rootBucket); + } + + if (pinningTelemetryInfo.accumulateResult) { + Telemetry::Accumulate(pinningTelemetryInfo.certPinningResultHistogram, + pinningTelemetryInfo.certPinningResultBucket); + } + // We want to remember the CA certs in the temp db, so that the application can find the // complete chain at any time it might need it. // But we keep only those CA certs in the temp db, that we didn't already know. diff --git a/security/manager/ssl/tests/unit/test_pinning.js b/security/manager/ssl/tests/unit/test_pinning.js index 8e32951e4d05..b771be2b0467 100644 --- a/security/manager/ssl/tests/unit/test_pinning.js +++ b/security/manager/ssl/tests/unit/test_pinning.js @@ -214,11 +214,11 @@ function check_pinning_telemetry() { .snapshot(); // Because all of our test domains are pinned to user-specified trust // anchors, effectively only strict mode and enforce test-mode get evaluated - equal(prod_histogram.counts[0], 16, + equal(prod_histogram.counts[0], 4, "Actual and expected prod (non-Mozilla) failure count should match"); equal(prod_histogram.counts[1], 4, "Actual and expected prod (non-Mozilla) success count should match"); - equal(test_histogram.counts[0], 5, + equal(test_histogram.counts[0], 2, "Actual and expected test (non-Mozilla) failure count should match"); equal(test_histogram.counts[1], 0, "Actual and expected test (non-Mozilla) success count should match"); From 0bbfe28f8e791ef1bc1a458ba5547d8bb7d570ed Mon Sep 17 00:00:00 2001 From: Hannes Verschore Date: Fri, 21 Aug 2015 10:14:21 +0200 Subject: [PATCH 108/208] Bug 1175976: IonMonkey - Part1: Move unaryArith from baseline to shared stub, r=jandem --- js/src/jit/BaselineIC.cpp | 137 -------------------------------------- js/src/jit/BaselineIC.h | 88 ------------------------ js/src/jit/SharedIC.cpp | 135 +++++++++++++++++++++++++++++++++++++ js/src/jit/SharedIC.h | 89 +++++++++++++++++++++++++ 4 files changed, 224 insertions(+), 225 deletions(-) diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 3b5ef9751d59..aabdbb8a1939 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -1861,143 +1861,6 @@ ICToNumber_Fallback::Compiler::generateStubCode(MacroAssembler& masm) return tailCallVM(DoToNumberFallbackInfo, masm); } -// -// UnaryArith_Fallback -// - -static bool -DoUnaryArithFallback(JSContext* cx, BaselineFrame* frame, ICUnaryArith_Fallback* stub_, - HandleValue val, MutableHandleValue res) -{ - // This fallback stub may trigger debug mode toggling. - DebugModeOSRVolatileStub stub(frame, stub_); - - RootedScript script(cx, frame->script()); - jsbytecode* pc = stub->icEntry()->pc(script); - JSOp op = JSOp(*pc); - FallbackICSpew(cx, stub, "UnaryArith(%s)", js_CodeName[op]); - - switch (op) { - case JSOP_BITNOT: { - int32_t result; - if (!BitNot(cx, val, &result)) - return false; - res.setInt32(result); - break; - } - case JSOP_NEG: - if (!NegOperation(cx, script, pc, val, res)) - return false; - break; - default: - MOZ_CRASH("Unexpected op"); - } - - // Check if debug mode toggling made the stub invalid. - if (stub.invalid()) - return true; - - if (res.isDouble()) - stub->setSawDoubleResult(); - - if (stub->numOptimizedStubs() >= ICUnaryArith_Fallback::MAX_OPTIMIZED_STUBS) { - // TODO: Discard/replace stubs. - return true; - } - - if (val.isInt32() && res.isInt32()) { - JitSpew(JitSpew_BaselineIC, " Generating %s(Int32 => Int32) stub", js_CodeName[op]); - ICUnaryArith_Int32::Compiler compiler(cx, op); - ICStub* int32Stub = compiler.getStub(compiler.getStubSpace(script)); - if (!int32Stub) - return false; - stub->addNewStub(int32Stub); - return true; - } - - if (val.isNumber() && res.isNumber() && cx->runtime()->jitSupportsFloatingPoint) { - JitSpew(JitSpew_BaselineIC, " Generating %s(Number => Number) stub", js_CodeName[op]); - - // Unlink int32 stubs, the double stub handles both cases and TI specializes for both. - stub->unlinkStubsWithKind(cx, ICStub::UnaryArith_Int32); - - ICUnaryArith_Double::Compiler compiler(cx, op); - ICStub* doubleStub = compiler.getStub(compiler.getStubSpace(script)); - if (!doubleStub) - return false; - stub->addNewStub(doubleStub); - return true; - } - - return true; -} - -typedef bool (*DoUnaryArithFallbackFn)(JSContext*, BaselineFrame*, ICUnaryArith_Fallback*, - HandleValue, MutableHandleValue); -static const VMFunction DoUnaryArithFallbackInfo = - FunctionInfo(DoUnaryArithFallback, TailCall, PopValues(1)); - -bool -ICUnaryArith_Fallback::Compiler::generateStubCode(MacroAssembler& masm) -{ - MOZ_ASSERT(engine_ == Engine::Baseline); - MOZ_ASSERT(R0 == JSReturnOperand); - - // Restore the tail call register. - EmitRestoreTailCallReg(masm); - - // Ensure stack is fully synced for the expression decompiler. - masm.pushValue(R0); - - // Push arguments. - masm.pushValue(R0); - masm.push(ICStubReg); - pushFramePtr(masm, R0.scratchReg()); - - return tailCallVM(DoUnaryArithFallbackInfo, masm); -} - -bool -ICUnaryArith_Double::Compiler::generateStubCode(MacroAssembler& masm) -{ - MOZ_ASSERT(engine_ == Engine::Baseline); - - Label failure; - masm.ensureDouble(R0, FloatReg0, &failure); - - MOZ_ASSERT(op == JSOP_NEG || op == JSOP_BITNOT); - - if (op == JSOP_NEG) { - masm.negateDouble(FloatReg0); - masm.boxDouble(FloatReg0, R0); - } else { - // Truncate the double to an int32. - Register scratchReg = R1.scratchReg(); - - Label doneTruncate; - Label truncateABICall; - masm.branchTruncateDouble(FloatReg0, scratchReg, &truncateABICall); - masm.jump(&doneTruncate); - - masm.bind(&truncateABICall); - masm.setupUnalignedABICall(scratchReg); - masm.passABIArg(FloatReg0, MoveOp::DOUBLE); - masm.callWithABI(BitwiseCast(JS::ToInt32)); - masm.storeCallResult(scratchReg); - - masm.bind(&doneTruncate); - masm.not32(scratchReg); - masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0); - } - - EmitReturnFromIC(masm); - - // Failure case - jump to next stub - masm.bind(&failure); - EmitStubGuardFailure(masm); - return true; -} - // // GetElem_Fallback // diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index 04f7b9e51dbb..e9bd1b7f6bf5 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -1104,94 +1104,6 @@ class ICToNumber_Fallback : public ICFallbackStub }; }; -// UnaryArith -// JSOP_BITNOT -// JSOP_NEG - -class ICUnaryArith_Fallback : public ICFallbackStub -{ - friend class ICStubSpace; - - explicit ICUnaryArith_Fallback(JitCode* stubCode) - : ICFallbackStub(UnaryArith_Fallback, stubCode) - { - extra_ = 0; - } - - public: - static const uint32_t MAX_OPTIMIZED_STUBS = 8; - - bool sawDoubleResult() { - return extra_; - } - void setSawDoubleResult() { - extra_ = 1; - } - - // Compiler for this stub kind. - class Compiler : public ICStubCompiler { - protected: - bool generateStubCode(MacroAssembler& masm); - - public: - explicit Compiler(JSContext* cx) - : ICStubCompiler(cx, ICStub::UnaryArith_Fallback, Engine::Baseline) - {} - - ICStub* getStub(ICStubSpace* space) { - return newStub(space, getStubCode()); - } - }; -}; - -class ICUnaryArith_Int32 : public ICStub -{ - friend class ICStubSpace; - - explicit ICUnaryArith_Int32(JitCode* stubCode) - : ICStub(UnaryArith_Int32, stubCode) - {} - - public: - class Compiler : public ICMultiStubCompiler { - protected: - bool generateStubCode(MacroAssembler& masm); - - public: - Compiler(JSContext* cx, JSOp op) - : ICMultiStubCompiler(cx, ICStub::UnaryArith_Int32, op, Engine::Baseline) - {} - - ICStub* getStub(ICStubSpace* space) { - return newStub(space, getStubCode()); - } - }; -}; - -class ICUnaryArith_Double : public ICStub -{ - friend class ICStubSpace; - - explicit ICUnaryArith_Double(JitCode* stubCode) - : ICStub(UnaryArith_Double, stubCode) - {} - - public: - class Compiler : public ICMultiStubCompiler { - protected: - bool generateStubCode(MacroAssembler& masm); - - public: - Compiler(JSContext* cx, JSOp op) - : ICMultiStubCompiler(cx, ICStub::UnaryArith_Double, op, Engine::Baseline) - {} - - ICStub* getStub(ICStubSpace* space) { - return newStub(space, getStubCode()); - } - }; -}; - // GetElem // JSOP_GETELEM diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index a3f3a85ec1a3..bdd29dd436d2 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -1427,7 +1427,142 @@ ICBinaryArith_DoubleWithInt32::Compiler::generateStubCode(MacroAssembler& masm) return true; } +// +// UnaryArith_Fallback +// + +static bool +DoUnaryArithFallback(JSContext* cx, BaselineFrame* frame, ICUnaryArith_Fallback* stub_, + HandleValue val, MutableHandleValue res) +{ + // This fallback stub may trigger debug mode toggling. + DebugModeOSRVolatileStub stub(frame, stub_); + + RootedScript script(cx, frame->script()); + jsbytecode* pc = stub->icEntry()->pc(script); + JSOp op = JSOp(*pc); + FallbackICSpew(cx, stub, "UnaryArith(%s)", js_CodeName[op]); + + switch (op) { + case JSOP_BITNOT: { + int32_t result; + if (!BitNot(cx, val, &result)) + return false; + res.setInt32(result); + break; + } + case JSOP_NEG: + if (!NegOperation(cx, script, pc, val, res)) + return false; + break; + default: + MOZ_CRASH("Unexpected op"); + } + + // Check if debug mode toggling made the stub invalid. + if (stub.invalid()) + return true; + + if (res.isDouble()) + stub->setSawDoubleResult(); + + if (stub->numOptimizedStubs() >= ICUnaryArith_Fallback::MAX_OPTIMIZED_STUBS) { + // TODO: Discard/replace stubs. + return true; + } + + if (val.isInt32() && res.isInt32()) { + JitSpew(JitSpew_BaselineIC, " Generating %s(Int32 => Int32) stub", js_CodeName[op]); + ICUnaryArith_Int32::Compiler compiler(cx, op); + ICStub* int32Stub = compiler.getStub(compiler.getStubSpace(script)); + if (!int32Stub) + return false; + stub->addNewStub(int32Stub); + return true; + } + if (val.isNumber() && res.isNumber() && cx->runtime()->jitSupportsFloatingPoint) { + JitSpew(JitSpew_BaselineIC, " Generating %s(Number => Number) stub", js_CodeName[op]); + + // Unlink int32 stubs, the double stub handles both cases and TI specializes for both. + stub->unlinkStubsWithKind(cx, ICStub::UnaryArith_Int32); + + ICUnaryArith_Double::Compiler compiler(cx, op); + ICStub* doubleStub = compiler.getStub(compiler.getStubSpace(script)); + if (!doubleStub) + return false; + stub->addNewStub(doubleStub); + return true; + } + + return true; +} + +typedef bool (*DoUnaryArithFallbackFn)(JSContext*, BaselineFrame*, ICUnaryArith_Fallback*, + HandleValue, MutableHandleValue); +static const VMFunction DoUnaryArithFallbackInfo = + FunctionInfo(DoUnaryArithFallback, TailCall, PopValues(1)); + +bool +ICUnaryArith_Fallback::Compiler::generateStubCode(MacroAssembler& masm) +{ + MOZ_ASSERT(engine_ == Engine::Baseline); + MOZ_ASSERT(R0 == JSReturnOperand); + + // Restore the tail call register. + EmitRestoreTailCallReg(masm); + + // Ensure stack is fully synced for the expression decompiler. + masm.pushValue(R0); + + // Push arguments. + masm.pushValue(R0); + masm.push(ICStubReg); + pushFramePtr(masm, R0.scratchReg()); + + return tailCallVM(DoUnaryArithFallbackInfo, masm); +} + +bool +ICUnaryArith_Double::Compiler::generateStubCode(MacroAssembler& masm) +{ + MOZ_ASSERT(engine_ == Engine::Baseline); + + Label failure; + masm.ensureDouble(R0, FloatReg0, &failure); + + MOZ_ASSERT(op == JSOP_NEG || op == JSOP_BITNOT); + + if (op == JSOP_NEG) { + masm.negateDouble(FloatReg0); + masm.boxDouble(FloatReg0, R0); + } else { + // Truncate the double to an int32. + Register scratchReg = R1.scratchReg(); + + Label doneTruncate; + Label truncateABICall; + masm.branchTruncateDouble(FloatReg0, scratchReg, &truncateABICall); + masm.jump(&doneTruncate); + + masm.bind(&truncateABICall); + masm.setupUnalignedABICall(scratchReg); + masm.passABIArg(FloatReg0, MoveOp::DOUBLE); + masm.callWithABI(BitwiseCast(JS::ToInt32)); + masm.storeCallResult(scratchReg); + + masm.bind(&doneTruncate); + masm.not32(scratchReg); + masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0); + } + + EmitReturnFromIC(masm); + + // Failure case - jump to next stub + masm.bind(&failure); + EmitStubGuardFailure(masm); + return true; +} } // namespace jit } // namespace js diff --git a/js/src/jit/SharedIC.h b/js/src/jit/SharedIC.h index d8054dc6943d..50b857ec52df 100644 --- a/js/src/jit/SharedIC.h +++ b/js/src/jit/SharedIC.h @@ -1389,6 +1389,95 @@ class ICBinaryArith_DoubleWithInt32 : public ICStub }; }; +// UnaryArith +// JSOP_BITNOT +// JSOP_NEG + +class ICUnaryArith_Fallback : public ICFallbackStub +{ + friend class ICStubSpace; + + explicit ICUnaryArith_Fallback(JitCode* stubCode) + : ICFallbackStub(UnaryArith_Fallback, stubCode) + { + extra_ = 0; + } + + public: + static const uint32_t MAX_OPTIMIZED_STUBS = 8; + + bool sawDoubleResult() { + return extra_; + } + void setSawDoubleResult() { + extra_ = 1; + } + + // Compiler for this stub kind. + class Compiler : public ICStubCompiler { + protected: + bool generateStubCode(MacroAssembler& masm); + + public: + explicit Compiler(JSContext* cx) + : ICStubCompiler(cx, ICStub::UnaryArith_Fallback, Engine::Baseline) + {} + + ICStub* getStub(ICStubSpace* space) { + return newStub(space, getStubCode()); + } + }; +}; + +class ICUnaryArith_Int32 : public ICStub +{ + friend class ICStubSpace; + + explicit ICUnaryArith_Int32(JitCode* stubCode) + : ICStub(UnaryArith_Int32, stubCode) + {} + + public: + class Compiler : public ICMultiStubCompiler { + protected: + bool generateStubCode(MacroAssembler& masm); + + public: + Compiler(JSContext* cx, JSOp op) + : ICMultiStubCompiler(cx, ICStub::UnaryArith_Int32, op, Engine::Baseline) + {} + + ICStub* getStub(ICStubSpace* space) { + return newStub(space, getStubCode()); + } + }; +}; + +class ICUnaryArith_Double : public ICStub +{ + friend class ICStubSpace; + + explicit ICUnaryArith_Double(JitCode* stubCode) + : ICStub(UnaryArith_Double, stubCode) + {} + + public: + class Compiler : public ICMultiStubCompiler { + protected: + bool generateStubCode(MacroAssembler& masm); + + public: + Compiler(JSContext* cx, JSOp op) + : ICMultiStubCompiler(cx, ICStub::UnaryArith_Double, op, Engine::Baseline) + {} + + ICStub* getStub(ICStubSpace* space) { + return newStub(space, getStubCode()); + } + }; +}; + + } // namespace jit } // namespace js From cdbb41b037b49cd8c8365904bc99819faec00dd1 Mon Sep 17 00:00:00 2001 From: Hannes Verschore Date: Fri, 21 Aug 2015 10:14:24 +0200 Subject: [PATCH 109/208] Bug 1175976: IonMonkey - Part2: Get the UnaryArith stub working in ionmonkey, r=jandem --- js/src/jit/BaselineCompiler.cpp | 2 +- js/src/jit/BaselineIC.cpp | 2 - js/src/jit/BaselineICList.h | 4 -- js/src/jit/CodeGenerator.cpp | 9 ++++ js/src/jit/IonBuilder.cpp | 77 +++++++++++++++++++++++++++------ js/src/jit/IonBuilder.h | 5 ++- js/src/jit/MIR.cpp | 9 ---- js/src/jit/MIR.h | 6 ++- js/src/jit/SharedIC.cpp | 17 +++++--- js/src/jit/SharedIC.h | 12 ++--- js/src/jit/SharedICList.h | 3 ++ 11 files changed, 101 insertions(+), 45 deletions(-) diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 9eeaffb75598..db1e31ddbfdb 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -1628,7 +1628,7 @@ BaselineCompiler::emitUnaryArith() frame.popRegsAndSync(1); // Call IC - ICUnaryArith_Fallback::Compiler stubCompiler(cx); + ICUnaryArith_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::Baseline); if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false; diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index aabdbb8a1939..f20a532ad12b 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -6,7 +6,6 @@ #include "jit/BaselineIC.h" -#include "mozilla/Casting.h" #include "mozilla/DebugOnly.h" #include "mozilla/SizePrintfMacros.h" #include "mozilla/TemplateLib.h" @@ -42,7 +41,6 @@ #include "vm/StringObject-inl.h" #include "vm/UnboxedObject-inl.h" -using mozilla::BitwiseCast; using mozilla::DebugOnly; namespace js { diff --git a/js/src/jit/BaselineICList.h b/js/src/jit/BaselineICList.h index f66d164429c4..76c0cb6d85af 100644 --- a/js/src/jit/BaselineICList.h +++ b/js/src/jit/BaselineICList.h @@ -49,10 +49,6 @@ namespace jit { \ _(ToNumber_Fallback) \ \ - _(UnaryArith_Fallback) \ - _(UnaryArith_Int32) \ - _(UnaryArith_Double) \ - \ _(Call_Fallback) \ _(Call_Scripted) \ _(Call_AnyScripted) \ diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 2fe896777186..a63820f05f39 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -1729,6 +1729,10 @@ CodeGenerator::visitUnarySharedStub(LUnarySharedStub* lir) { JSOp jsop = JSOp(*lir->mir()->resumePoint()->pc()); switch (jsop) { + case JSOP_BITNOT: + case JSOP_NEG: + emitSharedStub(ICStub::Kind::UnaryArith_Fallback, lir); + break; default: MOZ_CRASH("Unsupported jsop in shared stubs."); } @@ -7869,6 +7873,11 @@ CodeGenerator::linkSharedStubs(JSContext* cx) stub = stubCompiler.getStub(&stubSpace_); break; } + case ICStub::Kind::UnaryArith_Fallback: { + ICUnaryArith_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::IonMonkey); + stub = stubCompiler.getStub(&stubSpace_); + break; + } default: MOZ_CRASH("Unsupported shared stub."); } diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index b98daf72ae28..8474f57a7b4a 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -4484,19 +4484,49 @@ IonBuilder::pushConstant(const Value& v) return true; } +bool +IonBuilder::bitnotTrySpecialized(bool* emitted, MDefinition* input) +{ + MOZ_ASSERT(*emitted == false); + + // Try to emit a specialized bitnot instruction based on the input type + // of the operand. + + if (input->mightBeType(MIRType_Object) || input->mightBeType(MIRType_Symbol)) + return true; + + MBitNot* ins = MBitNot::New(alloc(), input); + ins->setSpecialization(MIRType_Int32); + + current->add(ins); + current->push(ins); + + *emitted = true; + return true; +} + bool IonBuilder::jsop_bitnot() { + bool emitted = false; + MDefinition* input = current->pop(); + + if (!forceInlineCaches()) { + if (!bitnotTrySpecialized(&emitted, input) || emitted) + return emitted; + } + + if (!arithTrySharedStub(&emitted, JSOP_BITNOT, nullptr, input) || emitted) + return emitted; + + // Not possible to optimize. Do a slow vm call. MBitNot* ins = MBitNot::New(alloc(), input); current->add(ins); - ins->infer(); - current->push(ins); - if (ins->isEffectful() && !resumeAfter(ins)) - return false; - return true; + MOZ_ASSERT(ins->isEffectful()); + return resumeAfter(ins); } bool IonBuilder::jsop_bitop(JSOp op) @@ -4672,21 +4702,42 @@ IonBuilder::binaryArithTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, } bool -IonBuilder::binaryArithTrySharedStub(bool* emitted, JSOp op, - MDefinition* left, MDefinition* right) +IonBuilder::arithTrySharedStub(bool* emitted, JSOp op, + MDefinition* left, MDefinition* right) { MOZ_ASSERT(*emitted == false); + JSOp actualOp = JSOp(*pc); // Try to emit a shared stub cache. if (js_JitOptions.disableSharedStubs) return true; - // It is not possible for shared stubs to impersonate another op. - if (JSOp(*pc) != op) + // The actual jsop 'jsop_pos' is not supported yet. + if (actualOp == JSOP_POS) return true; - MBinarySharedStub *stub = MBinarySharedStub::New(alloc(), left, right); + MInstruction* stub = nullptr; + switch (actualOp) { + case JSOP_NEG: + case JSOP_BITNOT: + MOZ_ASSERT_IF(op == JSOP_MUL, left->isConstantValue() && + left->constantValue().toInt32() == -1); + MOZ_ASSERT_IF(op != JSOP_MUL, !left); + + stub = MUnarySharedStub::New(alloc(), right); + break; + case JSOP_ADD: + case JSOP_SUB: + case JSOP_MUL: + case JSOP_DIV: + case JSOP_MOD: + stub = MBinarySharedStub::New(alloc(), left, right); + break; + default: + MOZ_CRASH("unsupported arith"); + } + current->add(stub); current->push(stub); @@ -4717,7 +4768,7 @@ IonBuilder::jsop_binary_arith(JSOp op, MDefinition* left, MDefinition* right) return emitted; } - if (!binaryArithTrySharedStub(&emitted, op, left, right) || emitted) + if (!arithTrySharedStub(&emitted, op, left, right) || emitted) return emitted; // Not possible to optimize. Do a slow vm call. @@ -4791,9 +4842,7 @@ IonBuilder::jsop_neg() MDefinition* right = current->pop(); - if (!jsop_binary_arith(JSOP_MUL, negator, right)) - return false; - return true; + return jsop_binary_arith(JSOP_MUL, negator, right); } class AutoAccumulateReturns diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 800425c0d6c2..62d9cf5cb5d6 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -489,7 +489,10 @@ class IonBuilder bool binaryArithTrySpecialized(bool* emitted, JSOp op, MDefinition* left, MDefinition* right); bool binaryArithTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, MDefinition* left, MDefinition* right); - bool binaryArithTrySharedStub(bool* emitted, JSOp op, MDefinition* left, MDefinition* right); + bool arithTrySharedStub(bool* emitted, JSOp op, MDefinition* left, MDefinition* right); + + // jsop_bitnot helpers. + bool bitnotTrySpecialized(bool* emitted, MDefinition* input); // binary data lookup helpers. TypedObjectPrediction typedObjectPrediction(MDefinition* typedObj); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index f16cb85b3570..e74e0bd1747d 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -1998,15 +1998,6 @@ MCall::addArg(size_t argnum, MDefinition* arg) initOperand(argnum + NumNonArgumentOperands, arg); } -void -MBitNot::infer() -{ - if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(0)->mightBeType(MIRType_Symbol)) - specialization_ = MIRType_None; - else - specialization_ = MIRType_Int32; -} - static inline bool IsConstant(MDefinition* def, double v) { diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 55ede231673d..f34a840c38fe 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -5215,6 +5215,7 @@ class MBitNot explicit MBitNot(MDefinition* input) : MUnaryInstruction(input) { + specialization_ = MIRType_None; setResultType(MIRType_Int32); setMovable(); } @@ -5225,7 +5226,10 @@ class MBitNot static MBitNot* NewAsmJS(TempAllocator& alloc, MDefinition* input); MDefinition* foldsTo(TempAllocator& alloc) override; - void infer(); + void setSpecialization(MIRType type) { + specialization_ = type; + setResultType(type); + } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index bdd29dd436d2..2f9f6faa58af 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -5,6 +5,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "jit/SharedIC.h" + +#include "mozilla/Casting.h" #include "mozilla/SizePrintfMacros.h" #include "jslibmath.h" @@ -24,6 +26,8 @@ #include "jit/MacroAssembler-inl.h" #include "vm/Interpreter-inl.h" +using mozilla::BitwiseCast; + namespace js { namespace jit { @@ -1435,10 +1439,12 @@ static bool DoUnaryArithFallback(JSContext* cx, BaselineFrame* frame, ICUnaryArith_Fallback* stub_, HandleValue val, MutableHandleValue res) { + ICStubCompiler::Engine engine = SharedStubEngine(frame); + RootedScript script(cx, SharedStubScript(frame, stub_)); + // This fallback stub may trigger debug mode toggling. - DebugModeOSRVolatileStub stub(frame, stub_); + DebugModeOSRVolatileStub stub(engine, frame, stub_); - RootedScript script(cx, frame->script()); jsbytecode* pc = stub->icEntry()->pc(script); JSOp op = JSOp(*pc); FallbackICSpew(cx, stub, "UnaryArith(%s)", js_CodeName[op]); @@ -1473,7 +1479,7 @@ DoUnaryArithFallback(JSContext* cx, BaselineFrame* frame, ICUnaryArith_Fallback* if (val.isInt32() && res.isInt32()) { JitSpew(JitSpew_BaselineIC, " Generating %s(Int32 => Int32) stub", js_CodeName[op]); - ICUnaryArith_Int32::Compiler compiler(cx, op); + ICUnaryArith_Int32::Compiler compiler(cx, op, engine); ICStub* int32Stub = compiler.getStub(compiler.getStubSpace(script)); if (!int32Stub) return false; @@ -1487,7 +1493,7 @@ DoUnaryArithFallback(JSContext* cx, BaselineFrame* frame, ICUnaryArith_Fallback* // Unlink int32 stubs, the double stub handles both cases and TI specializes for both. stub->unlinkStubsWithKind(cx, ICStub::UnaryArith_Int32); - ICUnaryArith_Double::Compiler compiler(cx, op); + ICUnaryArith_Double::Compiler compiler(cx, op, engine); ICStub* doubleStub = compiler.getStub(compiler.getStubSpace(script)); if (!doubleStub) return false; @@ -1506,7 +1512,6 @@ static const VMFunction DoUnaryArithFallbackInfo = bool ICUnaryArith_Fallback::Compiler::generateStubCode(MacroAssembler& masm) { - MOZ_ASSERT(engine_ == Engine::Baseline); MOZ_ASSERT(R0 == JSReturnOperand); // Restore the tail call register. @@ -1526,8 +1531,6 @@ ICUnaryArith_Fallback::Compiler::generateStubCode(MacroAssembler& masm) bool ICUnaryArith_Double::Compiler::generateStubCode(MacroAssembler& masm) { - MOZ_ASSERT(engine_ == Engine::Baseline); - Label failure; masm.ensureDouble(R0, FloatReg0, &failure); diff --git a/js/src/jit/SharedIC.h b/js/src/jit/SharedIC.h index 50b857ec52df..111b00ab5717 100644 --- a/js/src/jit/SharedIC.h +++ b/js/src/jit/SharedIC.h @@ -1419,8 +1419,8 @@ class ICUnaryArith_Fallback : public ICFallbackStub bool generateStubCode(MacroAssembler& masm); public: - explicit Compiler(JSContext* cx) - : ICStubCompiler(cx, ICStub::UnaryArith_Fallback, Engine::Baseline) + explicit Compiler(JSContext* cx, Engine engine) + : ICStubCompiler(cx, ICStub::UnaryArith_Fallback, engine) {} ICStub* getStub(ICStubSpace* space) { @@ -1443,8 +1443,8 @@ class ICUnaryArith_Int32 : public ICStub bool generateStubCode(MacroAssembler& masm); public: - Compiler(JSContext* cx, JSOp op) - : ICMultiStubCompiler(cx, ICStub::UnaryArith_Int32, op, Engine::Baseline) + Compiler(JSContext* cx, JSOp op, Engine engine) + : ICMultiStubCompiler(cx, ICStub::UnaryArith_Int32, op, engine) {} ICStub* getStub(ICStubSpace* space) { @@ -1467,8 +1467,8 @@ class ICUnaryArith_Double : public ICStub bool generateStubCode(MacroAssembler& masm); public: - Compiler(JSContext* cx, JSOp op) - : ICMultiStubCompiler(cx, ICStub::UnaryArith_Double, op, Engine::Baseline) + Compiler(JSContext* cx, JSOp op, Engine engine) + : ICMultiStubCompiler(cx, ICStub::UnaryArith_Double, op, engine) {} ICStub* getStub(ICStubSpace* space) { diff --git a/js/src/jit/SharedICList.h b/js/src/jit/SharedICList.h index fb69f10fe40b..85e6936ba7f8 100644 --- a/js/src/jit/SharedICList.h +++ b/js/src/jit/SharedICList.h @@ -20,6 +20,9 @@ namespace jit { _(BinaryArith_BooleanWithInt32) \ _(BinaryArith_DoubleWithInt32) \ \ + _(UnaryArith_Fallback) \ + _(UnaryArith_Int32) \ + _(UnaryArith_Double) \ } // namespace jit } // namespace js From 1d0fb9199aaed177cf85c15c8f74156106143c36 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Fri, 21 Aug 2015 10:44:23 -0400 Subject: [PATCH 110/208] Bug 1197176 - Ensure we actually do a composite after resuming the compositor. r=snorp --- mobile/android/base/gfx/GLController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/mobile/android/base/gfx/GLController.java b/mobile/android/base/gfx/GLController.java index 0c8f20264952..518320185331 100644 --- a/mobile/android/base/gfx/GLController.java +++ b/mobile/android/base/gfx/GLController.java @@ -272,6 +272,7 @@ void resumeCompositor(int width, int height) { if (mCompositorCreated) { GeckoAppShell.scheduleResumeComposition(width, height); GeckoAppShell.sendEventToGecko(GeckoEvent.createCompositorResumeEvent()); + mView.requestRender(); } } From 00abd1baadbd72e96c37c525a93d94abdc0f1b4c Mon Sep 17 00:00:00 2001 From: Alastor Wu Date: Wed, 19 Aug 2015 12:43:25 +0800 Subject: [PATCH 111/208] Bug 1187092 - Refactor the suspend process. r=jwwang --- dom/media/MediaResource.cpp | 141 +++++++++++++++++++++++------------- dom/media/MediaResource.h | 52 ++++++++++--- 2 files changed, 133 insertions(+), 60 deletions(-) diff --git a/dom/media/MediaResource.cpp b/dom/media/MediaResource.cpp index 70c7932d6958..2502428137e2 100644 --- a/dom/media/MediaResource.cpp +++ b/dom/media/MediaResource.cpp @@ -69,12 +69,14 @@ ChannelMediaResource::ChannelMediaResource(MediaDecoder* aDecoder, nsIURI* aURI, const nsACString& aContentType) : BaseMediaResource(aDecoder, aChannel, aURI, aContentType), - mOffset(0), mSuspendCount(0), - mReopenOnError(false), mIgnoreClose(false), + mOffset(0), + mReopenOnError(false), + mIgnoreClose(false), mCacheStream(this), mLock("ChannelMediaResource.mLock"), mIgnoreResume(false), - mIsTransportSeekable(true) + mIsTransportSeekable(true), + mSuspendAgent(mChannel) { if (!gMediaResourceLog) { gMediaResourceLog = PR_NewLogModule("MediaResource"); @@ -317,13 +319,7 @@ ChannelMediaResource::OnStartRequest(nsIRequest* aRequest) mReopenOnError = false; mIgnoreClose = false; - if (mSuspendCount > 0) { - // Re-suspend the channel if it needs to be suspended - // No need to call PossiblySuspend here since the channel is - // definitely in the right state for us in OnStartRequest. - mChannel->Suspend(); - mIgnoreResume = false; - } + mSuspendAgent.UpdateSuspendedStatusIfNeeded(); // Fires an initial progress event. owner->DownloadProgressed(); @@ -389,7 +385,7 @@ nsresult ChannelMediaResource::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) { NS_ASSERTION(mChannel.get() == aRequest, "Wrong channel!"); - NS_ASSERTION(mSuspendCount == 0, + NS_ASSERTION(!mSuspendAgent.IsSuspended(), "How can OnStopRequest fire while we're suspended?"); { @@ -439,6 +435,7 @@ ChannelMediaResource::OnChannelRedirect(nsIChannel* aOld, nsIChannel* aNew, uint32_t aFlags) { mChannel = aNew; + mSuspendAgent.NotifyChannelOpened(mChannel); return SetupChannelHeaders(); } @@ -678,7 +675,7 @@ already_AddRefed ChannelMediaResource::CloneData(MediaDecoder* aD // which will recreate the channel. This way, if all of the media data // is already in the cache we don't create an unnecessary HTTP channel // and perform a useless HTTP transaction. - resource->mSuspendCount = 1; + resource->mSuspendAgent.Suspend(); resource->mCacheStream.InitAsClone(&mCacheStream); resource->mChannelStatistics = new MediaChannelStatistics(mChannelStatistics); resource->mChannelStatistics->Stop(); @@ -701,10 +698,7 @@ void ChannelMediaResource::CloseChannel() } if (mChannel) { - if (mSuspendCount > 0) { - // Resume the channel before we cancel it - PossiblyResume(); - } + mSuspendAgent.NotifyChannelClosing(); // The status we use here won't be passed to the decoder, since // we've already revoked the listener. It can however be passed // to nsDocumentViewer::LoadComplete if our channel is the one @@ -790,29 +784,27 @@ void ChannelMediaResource::Suspend(bool aCloseImmediately) return; } - if (mChannel) { - if (aCloseImmediately && mCacheStream.IsTransportSeekable()) { - // Kill off our channel right now, but don't tell anyone about it. - mIgnoreClose = true; - CloseChannel(); - element->DownloadSuspended(); - } else if (mSuspendCount == 0) { + if (mChannel && aCloseImmediately && mCacheStream.IsTransportSeekable()) { + // Kill off our channel right now, but don't tell anyone about it. + mIgnoreClose = true; + CloseChannel(); + element->DownloadSuspended(); + } + + if (mSuspendAgent.Suspend()) { + if (mChannel) { { MutexAutoLock lock(mLock); mChannelStatistics->Stop(); } - PossiblySuspend(); element->DownloadSuspended(); } } - - ++mSuspendCount; } void ChannelMediaResource::Resume() { NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread"); - NS_ASSERTION(mSuspendCount > 0, "Too many resumes!"); MediaDecoderOwner* owner = mDecoder->GetMediaOwner(); if (!owner) { @@ -825,9 +817,7 @@ void ChannelMediaResource::Resume() return; } - NS_ASSERTION(mSuspendCount > 0, "Resume without previous Suspend!"); - --mSuspendCount; - if (mSuspendCount == 0) { + if (mSuspendAgent.Resume()) { if (mChannel) { // Just wake up our existing channel { @@ -837,7 +827,6 @@ void ChannelMediaResource::Resume() // if an error occurs after Resume, assume it's because the server // timed out the connection and we should reopen it. mReopenOnError = true; - PossiblyResume(); element->DownloadResumed(); } else { int64_t totalLength = mCacheStream.GetLength(); @@ -909,6 +898,7 @@ ChannelMediaResource::RecreateChannel() NS_ASSERTION(!GetContentType().IsEmpty(), "When recreating a channel, we should know the Content-Type."); mChannel->SetContentType(GetContentType()); + mSuspendAgent.NotifyChannelOpened(mChannel); // Tell the cache to reset the download status when the channel is reopened. mCacheStream.NotifyChannelRecreated(); @@ -1000,21 +990,19 @@ ChannelMediaResource::CacheClientSeek(int64_t aOffset, bool aResume) CloseChannel(); - if (aResume) { - NS_ASSERTION(mSuspendCount > 0, "Too many resumes!"); - // No need to mess with the channel, since we're making a new one - --mSuspendCount; - } - mOffset = aOffset; // Don't report close of the channel because the channel is not closed for // download ended, but for internal changes in the read position. mIgnoreClose = true; + if (aResume) { + mSuspendAgent.Resume(); + } + // Don't create a new channel if we are still suspended. The channel will // be recreated when we are resumed. - if (mSuspendCount > 0) { + if (mSuspendAgent.IsSuspended()) { return NS_OK; } @@ -1091,7 +1079,7 @@ ChannelMediaResource::IsSuspendedByCache() bool ChannelMediaResource::IsSuspended() { - return mSuspendCount > 0; + return mSuspendAgent.IsSuspended(); } void @@ -1131,29 +1119,80 @@ ChannelMediaResource::GetLength() return mCacheStream.GetLength(); } +// ChannelSuspendAgent + +bool +ChannelSuspendAgent::Suspend() +{ + SuspendInternal(); + return (++mSuspendCount == 1); +} + void -ChannelMediaResource::PossiblySuspend() +ChannelSuspendAgent::SuspendInternal() { - bool isPending = false; - nsresult rv = mChannel->IsPending(&isPending); - if (NS_SUCCEEDED(rv) && isPending) { - mChannel->Suspend(); - mIgnoreResume = false; - } else { - mIgnoreResume = true; + if (mChannel) { + bool isPending = false; + nsresult rv = mChannel->IsPending(&isPending); + if (NS_SUCCEEDED(rv) && isPending && !mIsChannelSuspended) { + mChannel->Suspend(); + mIsChannelSuspended = true; + } } } +bool +ChannelSuspendAgent::Resume() +{ + MOZ_ASSERT(IsSuspended(), "Resume without suspend!"); + --mSuspendCount; + + if (mSuspendCount == 0) { + if (mChannel && mIsChannelSuspended) { + mChannel->Resume(); + mIsChannelSuspended = false; + } + return true; + } + return false; +} + void -ChannelMediaResource::PossiblyResume() +ChannelSuspendAgent::UpdateSuspendedStatusIfNeeded() { - if (!mIgnoreResume) { + if (!mIsChannelSuspended && IsSuspended()) { + SuspendInternal(); + } +} + +void +ChannelSuspendAgent::NotifyChannelOpened(nsIChannel* aChannel) +{ + MOZ_ASSERT(aChannel); + mChannel = aChannel; +} + +void +ChannelSuspendAgent::NotifyChannelClosing() +{ + MOZ_ASSERT(mChannel); + // Before close the channel, it need to be resumed to make sure its internal + // state is correct. Besides, We need to suspend the channel after recreating. + if (mIsChannelSuspended) { mChannel->Resume(); - } else { - mIgnoreResume = false; + mIsChannelSuspended = false; } + mChannel = nullptr; +} + +bool +ChannelSuspendAgent::IsSuspended() +{ + return (mSuspendCount > 0); } +// FileMediaResource + class FileMediaResource : public BaseMediaResource { public: diff --git a/dom/media/MediaResource.h b/dom/media/MediaResource.h index d53f77d54a4e..5222106cde68 100644 --- a/dom/media/MediaResource.h +++ b/dom/media/MediaResource.h @@ -537,6 +537,47 @@ class BaseMediaResource : public MediaResource { bool mLoadInBackground; }; + +/** + * This class is responsible for managing the suspend count and report suspend + * status of channel. + **/ +class ChannelSuspendAgent { +public: + explicit ChannelSuspendAgent(nsIChannel* aChannel) + : mChannel(aChannel), + mSuspendCount(0), + mIsChannelSuspended(false) + {} + + // True when the channel has been suspended or needs to be suspended. + bool IsSuspended(); + + // Return true when the channel is logically suspended, i.e. the suspend + // count goes from 0 to 1. + bool Suspend(); + + // Return true only when the suspend count is equal to zero. + bool Resume(); + + // Call after opening channel, set channel and check whether the channel + // needs to be suspended. + void NotifyChannelOpened(nsIChannel* aChannel); + + // Call before closing channel, reset the channel internal status if needed. + void NotifyChannelClosing(); + + // Check whether we need to suspend the channel. + void UpdateSuspendedStatusIfNeeded(); +private: + // Only suspends channel but not changes the suspend count. + void SuspendInternal(); + + nsIChannel* mChannel; + Atomic mSuspendCount; + bool mIsChannelSuspended; +}; + /** * This is the MediaResource implementation that wraps Necko channels. * Much of its functionality is actually delegated to MediaCache via @@ -707,21 +748,12 @@ class ChannelMediaResource : public BaseMediaResource uint32_t aCount, uint32_t *aWriteCount); - // Suspend the channel only if the channels is currently downloading data. - // If it isn't we set a flag, mIgnoreResume, so that PossiblyResume knows - // whether to acutually resume or not. - void PossiblySuspend(); - - // Resume from a suspend if we actually suspended (See PossiblySuspend). - void PossiblyResume(); - // Main thread access only int64_t mOffset; nsRefPtr mListener; // A data received event for the decoder that has been dispatched but has // not yet been processed. nsRevocableEventPtr > mDataReceivedEvent; - Atomic mSuspendCount; // When this flag is set, if we get a network error we should silently // reopen the stream. bool mReopenOnError; @@ -747,6 +779,8 @@ class ChannelMediaResource : public BaseMediaResource // True if the stream can seek into unbuffered ranged, i.e. if the // connection supports byte range requests. bool mIsTransportSeekable; + + ChannelSuspendAgent mSuspendAgent; }; /** From 45c60142435764a71b6a0e6359e437b1b1dd4cf9 Mon Sep 17 00:00:00 2001 From: Alastor Wu Date: Thu, 26 Mar 2015 16:27:25 +0800 Subject: [PATCH 112/208] Bug 1129882 - Create agent in telephony object. r=szchen, r=htsai --- dom/telephony/Telephony.cpp | 116 ++++++++++++++++++++++++++- dom/telephony/Telephony.h | 22 +++++ dom/telephony/TelephonyCall.cpp | 87 +++++++++++++------- dom/telephony/TelephonyCall.h | 7 ++ dom/telephony/TelephonyCallGroup.cpp | 58 ++++++++++---- dom/telephony/TelephonyCallGroup.h | 8 ++ dom/webidl/Telephony.webidl | 6 ++ 7 files changed, 255 insertions(+), 49 deletions(-) diff --git a/dom/telephony/Telephony.cpp b/dom/telephony/Telephony.cpp index 4ca27cab41d7..75734c97e93c 100644 --- a/dom/telephony/Telephony.cpp +++ b/dom/telephony/Telephony.cpp @@ -7,6 +7,7 @@ #include "Telephony.h" #include "mozilla/Preferences.h" +#include "mozilla/dom/AudioChannelBinding.h" #include "mozilla/dom/CallEvent.h" #include "mozilla/dom/MozMobileConnectionBinding.h" #include "mozilla/dom/Promise.h" @@ -20,6 +21,7 @@ #include "nsServiceManagerUtils.h" #include "nsThreadUtils.h" +#include "AudioChannelAgent.h" #include "CallsList.h" #include "TelephonyCall.h" #include "TelephonyCallGroup.h" @@ -62,8 +64,11 @@ class Telephony::Listener : public nsITelephonyListener }; Telephony::Telephony(nsPIDOMWindow* aOwner) - : DOMEventTargetHelper(aOwner) + : DOMEventTargetHelper(aOwner), + mIsAudioStartPlaying(false), + mAudioAgentNotify(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY) { + MOZ_ASSERT(aOwner); nsCOMPtr global = do_QueryInterface(aOwner); MOZ_ASSERT(global); @@ -518,6 +523,61 @@ Telephony::StopTone(const Optional& aServiceId, ErrorResult& aRv) aRv = mService->StopTone(serviceId); } +void +Telephony::OwnAudioChannel(ErrorResult& aRv) +{ + if (mAudioAgent) { + return; + } + + mAudioAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1"); + MOZ_ASSERT(mAudioAgent); + aRv = mAudioAgent->Init(GetParentObject(), + (int32_t)AudioChannel::Telephony, this); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + aRv = HandleAudioAgentState(); + if (NS_WARN_IF(aRv.Failed())) { + return; + } +} + +nsresult +Telephony::HandleAudioAgentState() +{ + if (!mAudioAgent) { + return NS_OK; + } + + Nullable activeCall; + GetActive(activeCall); + nsresult rv; + // Only stop agent when the call is disconnected. + if ((!mCalls.Length() && !mGroup->CallsArray().Length()) && + mIsAudioStartPlaying) { + mIsAudioStartPlaying = false; + rv = mAudioAgent->NotifyStoppedPlaying(mAudioAgentNotify); + mAudioAgent = nullptr; + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } else if (!activeCall.IsNull() && !mIsAudioStartPlaying) { + mIsAudioStartPlaying = true; + float volume = 1.0; + bool muted = false; + rv = mAudioAgent->NotifyStartedPlaying(mAudioAgentNotify, &volume, &muted); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + rv = WindowVolumeChanged(volume, muted); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + return NS_OK; +} + bool Telephony::GetMuted(ErrorResult& aRv) const { @@ -591,13 +651,62 @@ Telephony::GetReady(ErrorResult& aRv) const return promise.forget(); } +// nsIAudioChannelAgentCallback + +NS_IMETHODIMP +Telephony::WindowVolumeChanged(float aVolume, bool aMuted) +{ + // Check the limitation of the network connection + if (mCalls.Length() > 1 || + (mCalls.Length() == 1 && mGroup->CallsArray().Length())) { + return NS_ERROR_FAILURE; + } + + ErrorResult rv; + nsCOMPtr global = do_QueryInterface(GetOwner()); + nsRefPtr promise = Promise::Create(global, rv); + if (NS_WARN_IF(rv.Failed())) { + return rv.StealNSResult(); + } + + // Check the single call or conference call + bool isSingleCall = mCalls.Length(); + nsCOMPtr callback = new TelephonyCallback(promise); + if (isSingleCall) { + rv = aMuted ? mCalls[0]->Hold(callback) : mCalls[0]->Resume(callback); + } else { + rv = aMuted ? mGroup->Hold(callback) : mGroup->Resume(callback); + } + if (NS_WARN_IF(rv.Failed())) { + return rv.StealNSResult(); + } + + return NS_OK; +} + +NS_IMETHODIMP +Telephony::WindowAudioCaptureChanged() +{ + // Do nothing + return NS_OK; +} + // nsITelephonyListener NS_IMETHODIMP Telephony::CallStateChanged(uint32_t aLength, nsITelephonyCallInfo** aAllInfo) { + nsresult rv; for (uint32_t i = 0; i < aLength; ++i) { - HandleCallInfo(aAllInfo[i]); + rv = HandleCallInfo(aAllInfo[i]); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + + rv = HandleAudioAgentState(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; } return NS_OK; } @@ -605,7 +714,8 @@ Telephony::CallStateChanged(uint32_t aLength, nsITelephonyCallInfo** aAllInfo) NS_IMETHODIMP Telephony::EnumerateCallState(nsITelephonyCallInfo* aInfo) { - return HandleCallInfo(aInfo); + uint32_t currentCallNum = 1; + return CallStateChanged(currentCallNum, &aInfo); } NS_IMETHODIMP diff --git a/dom/telephony/Telephony.h b/dom/telephony/Telephony.h index 0ef8ce27704d..77863fec624a 100644 --- a/dom/telephony/Telephony.h +++ b/dom/telephony/Telephony.h @@ -11,6 +11,7 @@ #include "mozilla/dom/Promise.h" #include "mozilla/dom/telephony/TelephonyCommon.h" +#include "nsIAudioChannelAgent.h" #include "nsITelephonyCallInfo.h" #include "nsITelephonyService.h" @@ -31,6 +32,7 @@ class TelephonyDialCallback; class OwningTelephonyCallOrTelephonyCallGroup; class Telephony final : public DOMEventTargetHelper, + public nsIAudioChannelAgentCallback, private nsITelephonyListener { /** @@ -44,6 +46,8 @@ class Telephony final : public DOMEventTargetHelper, friend class telephony::TelephonyDialCallback; + // The audio agent is needed to communicate with the audio channel service. + nsCOMPtr mAudioAgent; nsCOMPtr mService; nsRefPtr mListener; @@ -54,8 +58,13 @@ class Telephony final : public DOMEventTargetHelper, nsRefPtr mReadyPromise; + bool mIsAudioStartPlaying; + + uint32_t mAudioAgentNotify; + public: NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIAUDIOCHANNELAGENTCALLBACK NS_DECL_NSITELEPHONYLISTENER NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper) NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Telephony, @@ -94,6 +103,15 @@ class Telephony final : public DOMEventTargetHelper, void StopTone(const Optional& aServiceId, ErrorResult& aRv); + // In the audio channel architecture, the system app needs to know the state + // of every audio channel, including the telephony. Therefore, when a + // telephony call is activated , the audio channel service would notify the + // system app about that. And we need a agent to communicate with the audio + // channel service. We would follow the call states to make a correct + // notification. + void + OwnAudioChannel(ErrorResult& aRv); + bool GetMuted(ErrorResult& aRv) const; @@ -213,6 +231,10 @@ class Telephony final : public DOMEventTargetHelper, nsresult HandleCallInfo(nsITelephonyCallInfo* aInfo); + + // Check the call states to decide whether need to send the notificaiton. + nsresult + HandleAudioAgentState(); }; } // namespace dom diff --git a/dom/telephony/TelephonyCall.cpp b/dom/telephony/TelephonyCall.cpp index cfe87cbb6397..d1ab58f7d49f 100644 --- a/dom/telephony/TelephonyCall.cpp +++ b/dom/telephony/TelephonyCall.cpp @@ -324,69 +324,94 @@ TelephonyCall::Hold(ErrorResult& aRv) return nullptr; } + nsCOMPtr callback = new TelephonyCallback(promise); + aRv = Hold(callback); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + return promise.forget(); +} + +already_AddRefed +TelephonyCall::Resume(ErrorResult& aRv) +{ + nsRefPtr promise = CreatePromise(aRv); + if (!promise) { + return nullptr; + } + + nsCOMPtr callback = new TelephonyCallback(promise); + aRv = Resume(callback); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + return promise.forget(); +} + +nsresult +TelephonyCall::Hold(nsITelephonyCallback* aCallback) +{ if (mCallState != nsITelephonyService::CALL_STATE_CONNECTED) { NS_WARNING(nsPrintfCString("Hold non-connected call is rejected!" " (State: %u)", mCallState).get()); - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); - return promise.forget(); + aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError")); + return NS_ERROR_DOM_INVALID_STATE_ERR; } if (mGroup) { NS_WARNING("Hold a call in conference is rejected!"); - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); - return promise.forget(); + aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError")); + return NS_ERROR_DOM_INVALID_STATE_ERR; } if (!mSwitchable) { NS_WARNING("Hold a non-switchable call is rejected!"); - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); - return promise.forget(); + aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError")); + return NS_ERROR_DOM_INVALID_STATE_ERR; } - nsCOMPtr callback = new TelephonyCallback(promise); - aRv = mTelephony->Service()->HoldCall(mServiceId, mCallIndex, callback); - NS_ENSURE_TRUE(!aRv.Failed(), nullptr); + nsresult rv = mTelephony->Service()->HoldCall(mServiceId, mCallIndex, aCallback); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } if (mSecondId) { // No state transition when we switch two numbers within one TelephonyCall // object. Otherwise, the state here will be inconsistent with the backend // RIL and will never be right. - return promise.forget(); + return NS_OK; } - return promise.forget(); + return NS_OK; } -already_AddRefed -TelephonyCall::Resume(ErrorResult& aRv) +nsresult +TelephonyCall::Resume(nsITelephonyCallback* aCallback) { - nsRefPtr promise = CreatePromise(aRv); - if (!promise) { - return nullptr; - } - if (mCallState != nsITelephonyService::CALL_STATE_HELD) { - NS_WARNING(nsPrintfCString("Resume non-held call is rejected!" - " (State: %u)", mCallState).get()); - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); - return promise.forget(); + NS_WARNING("Resume non-held call is rejected!"); + aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError")); + return NS_ERROR_DOM_INVALID_STATE_ERR; } if (mGroup) { NS_WARNING("Resume a call in conference is rejected!"); - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); - return promise.forget(); + aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError")); + return NS_ERROR_DOM_INVALID_STATE_ERR; } if (!mSwitchable) { NS_WARNING("Resume a non-switchable call is rejected!"); - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); - return promise.forget(); + aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError")); + return NS_ERROR_DOM_INVALID_STATE_ERR; } - nsCOMPtr callback = new TelephonyCallback(promise); - aRv = mTelephony->Service()->ResumeCall(mServiceId, mCallIndex, callback); - NS_ENSURE_TRUE(!aRv.Failed(), nullptr); + nsresult rv = mTelephony->Service()->ResumeCall(mServiceId, mCallIndex, aCallback); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } - return promise.forget(); -} + return NS_OK; +} \ No newline at end of file diff --git a/dom/telephony/TelephonyCall.h b/dom/telephony/TelephonyCall.h index dbb53f444bb9..4d4bae031de2 100644 --- a/dom/telephony/TelephonyCall.h +++ b/dom/telephony/TelephonyCall.h @@ -12,6 +12,7 @@ #include "mozilla/dom/TelephonyCallBinding.h" #include "mozilla/dom/TelephonyCallId.h" #include "mozilla/dom/telephony/TelephonyCommon.h" +#include "nsITelephonyService.h" class nsPIDOMWindow; @@ -185,6 +186,12 @@ class TelephonyCall final : public DOMEventTargetHelper ~TelephonyCall(); + nsresult + Hold(nsITelephonyCallback* aCallback); + + nsresult + Resume(nsITelephonyCallback* aCallback); + void ChangeStateInternal(uint16_t aCallState, bool aFireEvents); diff --git a/dom/telephony/TelephonyCallGroup.cpp b/dom/telephony/TelephonyCallGroup.cpp index 541cc134a79b..addfe94cfa48 100644 --- a/dom/telephony/TelephonyCallGroup.cpp +++ b/dom/telephony/TelephonyCallGroup.cpp @@ -347,16 +347,12 @@ TelephonyCallGroup::Hold(ErrorResult& aRv) return nullptr; } - if (mCallState != nsITelephonyService::CALL_STATE_CONNECTED) { - NS_WARNING("Holding a non-connected call is rejected!"); - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); - return promise.forget(); + nsCOMPtr callback = new TelephonyCallback(promise); + aRv = Hold(callback); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; } - nsCOMPtr callback = new TelephonyCallback(promise); - aRv = mTelephony->Service()->HoldConference(mCalls[0]->ServiceId(), - callback); - NS_ENSURE_TRUE(!aRv.Failed(), nullptr); return promise.forget(); } @@ -370,15 +366,47 @@ TelephonyCallGroup::Resume(ErrorResult& aRv) return nullptr; } + nsCOMPtr callback = new TelephonyCallback(promise); + aRv = Resume(callback); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + return promise.forget(); +} + +nsresult +TelephonyCallGroup::Hold(nsITelephonyCallback* aCallback) +{ + if (mCallState != nsITelephonyService::CALL_STATE_CONNECTED) { + NS_WARNING("Holding a non-connected call is rejected!"); + aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError")); + return NS_ERROR_DOM_INVALID_STATE_ERR; + } + + nsresult rv = mTelephony->Service()->HoldConference(mCalls[0]->ServiceId(), + aCallback); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + +nsresult +TelephonyCallGroup::Resume(nsITelephonyCallback* aCallback) +{ if (mCallState != nsITelephonyService::CALL_STATE_HELD) { NS_WARNING("Resuming a non-held call is rejected!"); - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); - return promise.forget(); + aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError")); + return NS_ERROR_DOM_INVALID_STATE_ERR; } - nsCOMPtr callback = new TelephonyCallback(promise); - aRv = mTelephony->Service()->ResumeConference(mCalls[0]->ServiceId(), - callback); - NS_ENSURE_TRUE(!aRv.Failed(), nullptr); - return promise.forget(); + nsresult rv = mTelephony->Service()->ResumeConference(mCalls[0]->ServiceId(), + aCallback); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; } diff --git a/dom/telephony/TelephonyCallGroup.h b/dom/telephony/TelephonyCallGroup.h index 38c1ba1474cd..8e473b919951 100644 --- a/dom/telephony/TelephonyCallGroup.h +++ b/dom/telephony/TelephonyCallGroup.h @@ -30,6 +30,8 @@ class TelephonyCallGroup final : public DOMEventTargetHelper NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(TelephonyCallGroup, DOMEventTargetHelper) + friend class Telephony; + nsPIDOMWindow* GetParentObject() const { @@ -108,6 +110,12 @@ class TelephonyCallGroup final : public DOMEventTargetHelper explicit TelephonyCallGroup(nsPIDOMWindow* aOwner); ~TelephonyCallGroup(); + nsresult + Hold(nsITelephonyCallback* aCallback); + + nsresult + Resume(nsITelephonyCallback* aCallback); + nsresult NotifyCallsChanged(TelephonyCall* aCall); diff --git a/dom/webidl/Telephony.webidl b/dom/webidl/Telephony.webidl index 5eb460b74bbc..19fd9dd80c41 100644 --- a/dom/webidl/Telephony.webidl +++ b/dom/webidl/Telephony.webidl @@ -49,6 +49,12 @@ interface Telephony : EventTarget { [Throws] void stopTone(optional unsigned long serviceId); + // Calling this method, the app will be treated as owner of the telephony + // calls from the AudioChannel policy. + [Throws, + CheckAllPermissions="audio-channel-telephony"] + void ownAudioChannel(); + [Throws] attribute boolean muted; From d7eb3d233817f7ac8ff5d2260cf81026814d7ffe Mon Sep 17 00:00:00 2001 From: Alastor Wu Date: Mon, 10 Aug 2015 17:23:33 +0800 Subject: [PATCH 113/208] Bug 1129882 - Add mozInterrupt in telephony object. r=baku --- dom/telephony/Telephony.cpp | 22 ++++++++++++++++++++-- dom/telephony/Telephony.h | 2 ++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/dom/telephony/Telephony.cpp b/dom/telephony/Telephony.cpp index 75734c97e93c..6aafc045ff4e 100644 --- a/dom/telephony/Telephony.cpp +++ b/dom/telephony/Telephony.cpp @@ -21,7 +21,7 @@ #include "nsServiceManagerUtils.h" #include "nsThreadUtils.h" -#include "AudioChannelAgent.h" +#include "AudioChannelService.h" #include "CallsList.h" #include "TelephonyCall.h" #include "TelephonyCallGroup.h" @@ -66,7 +66,8 @@ class Telephony::Listener : public nsITelephonyListener Telephony::Telephony(nsPIDOMWindow* aOwner) : DOMEventTargetHelper(aOwner), mIsAudioStartPlaying(false), - mAudioAgentNotify(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY) + mAudioAgentNotify(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY), + mHaveDispatchedInterruptBeginEvent(false) { MOZ_ASSERT(aOwner); nsCOMPtr global = do_QueryInterface(aOwner); @@ -77,6 +78,7 @@ Telephony::Telephony(nsPIDOMWindow* aOwner) MOZ_ASSERT(!rv.Failed()); mReadyPromise = promise; + mMuted = AudioChannelService::IsAudioChannelMutedByDefault(); } Telephony::~Telephony() @@ -681,6 +683,22 @@ Telephony::WindowVolumeChanged(float aVolume, bool aMuted) return rv.StealNSResult(); } + // These events will be triggered when the telephony is interrupted by other + // audio channel. + if (mMuted != aMuted) { + mMuted = aMuted; + // We should not dispatch "mozinterruptend" when the system app initializes + // the telephony audio from muted to unmuted at the first time. The event + // "mozinterruptend" must be dispatched after the "mozinterruptbegin". + if (!mHaveDispatchedInterruptBeginEvent && mMuted) { + DispatchTrustedEvent(NS_LITERAL_STRING("mozinterruptbegin")); + mHaveDispatchedInterruptBeginEvent = mMuted; + } else if (mHaveDispatchedInterruptBeginEvent && !mMuted) { + DispatchTrustedEvent(NS_LITERAL_STRING("mozinterruptend")); + mHaveDispatchedInterruptBeginEvent = mMuted; + } + } + return NS_OK; } diff --git a/dom/telephony/Telephony.h b/dom/telephony/Telephony.h index 77863fec624a..bf99917facb9 100644 --- a/dom/telephony/Telephony.h +++ b/dom/telephony/Telephony.h @@ -61,6 +61,8 @@ class Telephony final : public DOMEventTargetHelper, bool mIsAudioStartPlaying; uint32_t mAudioAgentNotify; + bool mHaveDispatchedInterruptBeginEvent; + bool mMuted; public: NS_DECL_ISUPPORTS_INHERITED From 9ef3afb70065150fe494eba5503ba9bdac9d6082 Mon Sep 17 00:00:00 2001 From: Hiroyuki Ikezoe Date: Thu, 20 Aug 2015 04:23:00 -0400 Subject: [PATCH 114/208] Bug 1196691 - Update testharness.js in imptests. r=Ms2ger --- dom/imptests/testharness.js | 142 +++++++++++++++++++++++++----------- 1 file changed, 99 insertions(+), 43 deletions(-) diff --git a/dom/imptests/testharness.js b/dom/imptests/testharness.js index 9433d12bdb0c..f4c66aae6219 100644 --- a/dom/imptests/testharness.js +++ b/dom/imptests/testharness.js @@ -517,19 +517,27 @@ policies and contribution forms [3]. function promise_test(func, name, properties) { var test = async_test(name, properties); - Promise.resolve(test.step(func, test, test)) - .then( - function() { - test.done(); - }) - .catch(test.step_func( - function(value) { - if (value instanceof AssertionError) { - throw value; - } - assert(false, "promise_test", null, - "Unhandled rejection with value: ${value}", {value:value}); - })); + // If there is no promise tests queue make one. + test.step(function() { + if (!tests.promise_tests) { + tests.promise_tests = Promise.resolve(); + } + }); + tests.promise_tests = tests.promise_tests.then(function() { + return Promise.resolve(test.step(func, test, test)) + .then( + function() { + test.done(); + }) + .catch(test.step_func( + function(value) { + if (value instanceof AssertionError) { + throw value; + } + assert(false, "promise_test", null, + "Unhandled rejection with value: ${value}", {value:value}); + })); + }); } function promise_rejects(test, expected, promise) { @@ -650,6 +658,14 @@ policies and contribution forms [3]. object.addEventListener(event, callback, false); } + function step_timeout(f, t) { + var outer_this = this; + var args = Array.prototype.slice.call(arguments, 2); + return setTimeout(function() { + f.apply(outer_this, args); + }, t * tests.timeout_multiplier); + } + expose(test, 'test'); expose(async_test, 'async_test'); expose(promise_test, 'promise_test'); @@ -658,6 +674,7 @@ policies and contribution forms [3]. expose(setup, 'setup'); expose(done, 'done'); expose(on_event, 'on_event'); + expose(step_timeout, 'step_timeout'); /* * Return a string truncated to the given length, with ... added at the end @@ -1414,6 +1431,14 @@ policies and contribution forms [3]. }); }; + Test.prototype.step_timeout = function(f, timeout) { + var test_this = this; + var args = Array.prototype.slice.call(arguments, 2); + return setTimeout(this.step_func(function() { + return f.apply(test_this, args); + }, timeout * tests.timeout_multiplier)); + } + Test.prototype.add_cleanup = function(callback) { this.cleanup_callbacks.push(callback); }; @@ -2048,28 +2073,11 @@ policies and contribution forms [3]. log.removeChild(log.lastChild); } - var script_prefix = null; - var scripts = document.getElementsByTagName("script"); - for (var i = 0; i < scripts.length; i++) { - var src; - if (scripts[i].src) { - src = scripts[i].src; - } else if (scripts[i].href) { - //SVG case - src = scripts[i].href.baseVal; - } - - var matches = src && src.match(/^(.*\/|)testharness\.js$/); - if (matches) { - script_prefix = matches[1]; - break; - } - } - - if (script_prefix !== null) { + var harness_url = get_harness_url(); + if (harness_url !== null) { var stylesheet = output_document.createElementNS(xhtml_ns, "link"); stylesheet.setAttribute("rel", "stylesheet"); - stylesheet.setAttribute("href", script_prefix + "testharness.css"); + stylesheet.setAttribute("href", harness_url + "testharness.css"); var heads = output_document.getElementsByTagName("head"); if (heads.length) { heads[0].appendChild(stylesheet); @@ -2425,6 +2433,7 @@ policies and contribution forms [3]. AssertionError.prototype.get_stack = function() { var stack = new Error().stack; + // IE11 does not initialize 'Error.stack' until the object is thrown. if (!stack) { try { throw new Error(); @@ -2432,18 +2441,30 @@ policies and contribution forms [3]. stack = e.stack; } } + var lines = stack.split("\n"); - var rv = []; - var re = /\/resources\/testharness\.js/; + + // Create a pattern to match stack frames originating within testharness.js. These include the + // script URL, followed by the line/col (e.g., '/resources/testharness.js:120:21'). + var re = new RegExp((get_script_url() || "\\btestharness.js") + ":\\d+:\\d+"); + + // Some browsers include a preamble that specifies the type of the error object. Skip this by + // advancing until we find the first stack frame originating from testharness.js. var i = 0; - // Fire remove any preamble that doesn't match the regexp - while (!re.test(lines[i])) { - i++ + while (!re.test(lines[i]) && i < lines.length) { + i++; + } + + // Then skip the top frames originating from testharness.js to begin the stack at the test code. + while (re.test(lines[i]) && i < lines.length) { + i++; } - // Then remove top frames in testharness.js itself - while (re.test(lines[i])) { - i++ + + // Paranoid check that we didn't skip all frames. If so, return the original stack unmodified. + if (i >= lines.length) { + return stack; } + return lines.slice(i).join("\n"); } @@ -2491,7 +2512,7 @@ policies and contribution forms [3]. Array.prototype.push.apply(array, items); } - function forEach (array, callback, thisObj) + function forEach(array, callback, thisObj) { for (var i = 0; i < array.length; i++) { if (array.hasOwnProperty(i)) { @@ -2535,11 +2556,46 @@ policies and contribution forms [3]. } } + /** Returns the 'src' URL of the first - - - - diff --git a/browser/modules/PluginContent.jsm b/browser/modules/PluginContent.jsm index 670728df0c3d..18881d3daff1 100644 --- a/browser/modules/PluginContent.jsm +++ b/browser/modules/PluginContent.jsm @@ -311,8 +311,6 @@ PluginContent.prototype = { return "PluginVulnerableUpdatable"; case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE: return "PluginVulnerableNoUpdate"; - case Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW: - return "PluginPlayPreview"; default: // Not all states map to a handler return null; @@ -417,10 +415,6 @@ PluginContent.prototype = { shouldShowNotification = true; break; - case "PluginPlayPreview": - this._handlePlayPreviewEvent(plugin); - break; - case "PluginDisabled": let manageLink = this.getPluginUI(plugin, "managePluginsLink"); this.addLinkClickCallback(manageLink, "forwardCallback", "managePlugins"); @@ -531,12 +525,6 @@ PluginContent.prototype = { objLoadingContent.pluginFallbackType >= Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY && objLoadingContent.pluginFallbackType <= Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE; - if (objLoadingContent.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW) { - // checking if play preview is subject to CTP rules - let playPreviewInfo = pluginHost.getPlayPreviewInfo(objLoadingContent.actualType); - isFallbackTypeValid = !playPreviewInfo.ignoreCTP; - } - return !objLoadingContent.activated && pluginPermission != Ci.nsIPermissionManager.DENY_ACTION && isFallbackTypeValid; @@ -549,17 +537,6 @@ PluginContent.prototype = { } }, - stopPlayPreview: function (plugin, playPlugin) { - let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent); - if (objLoadingContent.activated) - return; - - if (playPlugin) - objLoadingContent.playPlugin(); - else - objLoadingContent.cancelPlayPreview(); - }, - // Forward a link click callback to the chrome process. forwardCallback: function (name) { this.global.sendAsyncMessage("PluginContent:LinkClickCallback", { name: name }); @@ -641,49 +618,6 @@ PluginContent.prototype = { } }, - _handlePlayPreviewEvent: function (plugin) { - let doc = plugin.ownerDocument; - let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); - let pluginInfo = this._getPluginInfo(plugin); - let playPreviewInfo = pluginHost.getPlayPreviewInfo(pluginInfo.mimetype); - - let previewContent = this.getPluginUI(plugin, "previewPluginContent"); - let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0]; - if (!iframe) { - // lazy initialization of the iframe - iframe = doc.createElementNS("http://www.w3.org/1999/xhtml", "iframe"); - iframe.className = "previewPluginContentFrame"; - previewContent.appendChild(iframe); - - // Force a style flush, so that we ensure our binding is attached. - plugin.clientTop; - } - iframe.src = playPreviewInfo.redirectURL; - - // MozPlayPlugin event can be dispatched from the extension chrome - // code to replace the preview content with the native plugin - let playPluginHandler = (event) => { - if (!event.isTrusted) - return; - - previewContent.removeEventListener("MozPlayPlugin", playPluginHandler, true); - - let playPlugin = !event.detail; - this.stopPlayPreview(plugin, playPlugin); - - // cleaning up: removes overlay iframe from the DOM - let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0]; - if (iframe) - previewContent.removeChild(iframe); - }; - - previewContent.addEventListener("MozPlayPlugin", playPluginHandler, true); - - if (!playPreviewInfo.ignoreCTP) { - this._showClickToPlayNotification(plugin, false); - } - }, - reshowClickToPlayNotification: function () { let contentWindow = this.global.content; let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor) diff --git a/dom/base/nsIObjectLoadingContent.idl b/dom/base/nsIObjectLoadingContent.idl index 6cf0c535f10b..953a2591187c 100644 --- a/dom/base/nsIObjectLoadingContent.idl +++ b/dom/base/nsIObjectLoadingContent.idl @@ -25,7 +25,7 @@ class nsNPAPIPluginInstance; * interface to mirror this interface when changing it. */ -[scriptable, uuid(5efbd411-5bbe-4de1-9f3a-1c3459696eb2)] +[scriptable, uuid(2eb3195e-3eea-4083-bb1d-d2d70fa35ccb)] interface nsIObjectLoadingContent : nsISupports { /** @@ -65,8 +65,6 @@ interface nsIObjectLoadingContent : nsISupports const unsigned long PLUGIN_VULNERABLE_UPDATABLE = 9; // The plugin is vulnerable (no update available) const unsigned long PLUGIN_VULNERABLE_NO_UPDATE = 10; - // The plugin is in play preview mode - const unsigned long PLUGIN_PLAY_PREVIEW = 11; /** * The actual mime type (the one we got back from the network @@ -128,8 +126,7 @@ interface nsIObjectLoadingContent : nsISupports in boolean submittedCrashReport); /** - * This method will play a plugin that has been stopped by the - * click-to-play plugins or play-preview features. + * This method will play a plugin that has been stopped by click-to-play. */ void playPlugin(); @@ -144,7 +141,7 @@ interface nsIObjectLoadingContent : nsISupports /** * This attribute will return true if the current content type has been * activated, either explicitly or by passing checks that would have it be - * click-to-play or play-preview. + * click-to-play. */ readonly attribute boolean activated; @@ -184,11 +181,6 @@ interface nsIObjectLoadingContent : nsISupports */ readonly attribute bool hasRunningPlugin; - /** - * This method will disable the play-preview plugin state. - */ - void cancelPlayPreview(); - /** * If this plugin runs out-of-process, it has a runID to differentiate * between different times the plugin process has been instantiated. diff --git a/dom/base/nsObjectLoadingContent.cpp b/dom/base/nsObjectLoadingContent.cpp index 1f0dad3a856e..7e805a68b7dc 100644 --- a/dom/base/nsObjectLoadingContent.cpp +++ b/dom/base/nsObjectLoadingContent.cpp @@ -715,7 +715,6 @@ nsObjectLoadingContent::nsObjectLoadingContent() , mInstantiating(false) , mNetworkCreated(true) , mActivated(false) - , mPlayPreviewCanceled(false) , mIsStopping(false) , mIsLoading(false) , mScriptRequested(false) {} @@ -1406,8 +1405,6 @@ nsObjectLoadingContent::ObjectState() const return NS_EVENT_STATE_USERDISABLED; case eFallbackClickToPlay: return NS_EVENT_STATE_TYPE_CLICK_TO_PLAY; - case eFallbackPlayPreview: - return NS_EVENT_STATE_TYPE_PLAY_PREVIEW; case eFallbackDisabled: return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_DISABLED; case eFallbackBlocklisted: @@ -3122,7 +3119,7 @@ nsObjectLoadingContent::PlayPlugin() LOG(("OBJLC [%p]: Activated by user", this)); } - // If we're in a click-to-play or play preview state, we need to reload + // If we're in a click-to-play state, reload. // Fallback types >= eFallbackClickToPlay are plugin-replacement types, see // header if (mType == eType_Null && mFallbackType >= eFallbackClickToPlay) { @@ -3137,7 +3134,6 @@ nsObjectLoadingContent::Reload(bool aClearActivation) { if (aClearActivation) { mActivated = false; - mPlayPreviewCanceled = false; } return LoadObject(true, true); @@ -3177,22 +3173,6 @@ nsObjectLoadingContent::GetHasRunningPlugin(bool *aHasPlugin) return NS_OK; } -NS_IMETHODIMP -nsObjectLoadingContent::CancelPlayPreview() -{ - if (!nsContentUtils::IsCallerChrome()) - return NS_ERROR_NOT_AVAILABLE; - - mPlayPreviewCanceled = true; - - // If we're in play preview state already, reload - if (mType == eType_Null && mFallbackType == eFallbackPlayPreview) { - return LoadObject(true, true); - } - - return NS_OK; -} - NS_IMETHODIMP nsObjectLoadingContent::GetRunID(uint32_t* aRunID) { @@ -3238,31 +3218,6 @@ nsObjectLoadingContent::ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentTyp nsRefPtr pluginHost = nsPluginHost::GetInst(); - nsCOMPtr playPreviewInfo; - bool isPlayPreviewSpecified = NS_SUCCEEDED(pluginHost->GetPlayPreviewInfo( - mContentType, getter_AddRefs(playPreviewInfo))); - if (isPlayPreviewSpecified) { - // Checking PlayPreview whitelist as well. - nsCString uriSpec, baseSpec; - if (mURI) { - mURI->GetSpec(uriSpec); - } - if (mBaseURI) { - mBaseURI->GetSpec(baseSpec); - } - playPreviewInfo->CheckWhitelist(baseSpec, uriSpec, &isPlayPreviewSpecified); - } - bool ignoreCTP = false; - if (isPlayPreviewSpecified) { - playPreviewInfo->GetIgnoreCTP(&ignoreCTP); - } - if (isPlayPreviewSpecified && !mPlayPreviewCanceled && - ignoreCTP) { - // play preview in ignoreCTP mode is shown even if the native plugin - // is not present/installed - aReason = eFallbackPlayPreview; - return false; - } // at this point if it's not a plugin, we let it play/fallback if (!aIgnoreCurrentType && mType != eType_Plugin) { return true; @@ -3272,8 +3227,6 @@ nsObjectLoadingContent::ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentTyp // * Assume a default of click-to-play // * If globally disabled, per-site permissions cannot override. // * If blocklisted, override the reason with the blocklist reason - // * If not blocklisted but playPreview, override the reason with the - // playPreview reason. // * Check per-site permissions and follow those if specified. // * Honor per-plugin disabled permission // * Blocklisted plugins are forced to CtP @@ -3309,12 +3262,6 @@ nsObjectLoadingContent::ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentTyp aReason = eFallbackVulnerableNoUpdate; } - if (aReason == eFallbackClickToPlay && isPlayPreviewSpecified && - !mPlayPreviewCanceled && !ignoreCTP) { - // play preview in click-to-play mode is shown instead of standard CTP UI - aReason = eFallbackPlayPreview; - } - // Check the permission manager for permission based on the principal of // the toplevel content. diff --git a/dom/base/nsObjectLoadingContent.h b/dom/base/nsObjectLoadingContent.h index d246eac042cb..d12c1fa01677 100644 --- a/dom/base/nsObjectLoadingContent.h +++ b/dom/base/nsObjectLoadingContent.h @@ -94,9 +94,6 @@ class nsObjectLoadingContent : public nsImageLoadingContent eFallbackVulnerableUpdatable = nsIObjectLoadingContent::PLUGIN_VULNERABLE_UPDATABLE, // The plugin is vulnerable (no update available) eFallbackVulnerableNoUpdate = nsIObjectLoadingContent::PLUGIN_VULNERABLE_NO_UPDATE, - // The plugin is disabled and play preview content is displayed until - // the extension code enables it by sending the MozPlayPlugin event - eFallbackPlayPreview = nsIObjectLoadingContent::PLUGIN_PLAY_PREVIEW }; nsObjectLoadingContent(); @@ -225,10 +222,6 @@ class nsObjectLoadingContent : public nsImageLoadingContent { return !!mInstanceOwner; } - void CancelPlayPreview(mozilla::ErrorResult& aRv) - { - aRv = CancelPlayPreview(); - } void SwapFrameLoaders(nsXULElement& aOtherOwner, mozilla::ErrorResult& aRv) { aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); @@ -622,16 +615,13 @@ class nsObjectLoadingContent : public nsImageLoadingContent // activated by PlayPlugin(). (see ShouldPlay()) bool mActivated : 1; - // Used to keep track of whether or not a plugin is blocked by play-preview. - bool mPlayPreviewCanceled : 1; - // Protects DoStopPlugin from reentry (bug 724781). bool mIsStopping : 1; // Protects LoadObject from re-entry bool mIsLoading : 1; - // For plugin stand-in types (click-to-play, play preview, ...) tracks + // For plugin stand-in types (click-to-play) tracks // whether content js has tried to access the plugin script object. bool mScriptRequested : 1; diff --git a/dom/events/EventStates.h b/dom/events/EventStates.h index e6a3854cc8b5..3fc72cd34e98 100644 --- a/dom/events/EventStates.h +++ b/dom/events/EventStates.h @@ -262,8 +262,6 @@ class EventStates #define NS_EVENT_STATE_LTR NS_DEFINE_EVENT_STATE_MACRO(42) // Element is rtl (for :dir pseudo-class) #define NS_EVENT_STATE_RTL NS_DEFINE_EVENT_STATE_MACRO(43) -// Handler for play preview plugin -#define NS_EVENT_STATE_TYPE_PLAY_PREVIEW NS_DEFINE_EVENT_STATE_MACRO(44) // Element is highlighted (devtools inspector) #define NS_EVENT_STATE_DEVTOOLS_HIGHLIGHTED NS_DEFINE_EVENT_STATE_MACRO(45) // Element is an unresolved custom element candidate diff --git a/dom/plugins/base/moz.build b/dom/plugins/base/moz.build index 7528b45ae618..e971eeb43f98 100644 --- a/dom/plugins/base/moz.build +++ b/dom/plugins/base/moz.build @@ -32,7 +32,6 @@ EXPORTS += [ 'nsPluginLogging.h', 'nsPluginNativeWindow.h', 'nsPluginNativeWindowGtk.h', - 'nsPluginPlayPreviewInfo.h', 'nsPluginsCID.h', 'nsPluginsDir.h', 'nsPluginTags.h', @@ -48,7 +47,6 @@ UNIFIED_SOURCES += [ 'nsNPAPIPluginStreamListener.cpp', 'nsPluginInstanceOwner.cpp', 'nsPluginModule.cpp', - 'nsPluginPlayPreviewInfo.cpp', 'nsPluginStreamListenerPeer.cpp', 'nsPluginTags.cpp', 'PluginPRLibrary.cpp', diff --git a/dom/plugins/base/nsIPluginHost.idl b/dom/plugins/base/nsIPluginHost.idl index d6b01f6bc5c9..ae349bea2a26 100644 --- a/dom/plugins/base/nsIPluginHost.idl +++ b/dom/plugins/base/nsIPluginHost.idl @@ -12,21 +12,6 @@ "@mozilla.org/plugin/host;1" %} -[scriptable, uuid(57069ada-2845-46ef-b57f-233596d1c02c)] -interface nsIPluginPlayPreviewInfo : nsISupports -{ - readonly attribute AUTF8String mimeType; - readonly attribute boolean ignoreCTP; - readonly attribute AUTF8String redirectURL; - readonly attribute AUTF8String whitelist; - - /** - * Checks if pageURI and objectURI matches once of the entries in - * the whitelist. If whitelist is empty, returns true. - */ - boolean checkWhitelist(in AUTF8String pageURI, in AUTF8String objectURI); -}; - [scriptable, function, uuid(9c311778-7c2c-4ad8-b439-b8a2786a20dd)] interface nsIClearSiteDataCallback : nsISupports { @@ -36,7 +21,7 @@ interface nsIClearSiteDataCallback : nsISupports void callback(in nsresult rv); }; -[scriptable, uuid(0f73bbd2-fc89-41df-b31b-38c09903d187)] +[scriptable, uuid(f938f5ba-7093-42cd-a559-af8039d99204)] interface nsIPluginHost : nsISupports { /** @@ -102,27 +87,6 @@ interface nsIPluginHost : nsISupports */ boolean siteHasData(in nsIPluginTag plugin, in AUTF8String domain); - /** - * Registers the play preview plugin mode for specific mime type - * - * @param mimeType: specifies plugin mime type. - * @param ignoreCTP: if true, the play preview ignores CTP rules, e.g. - whitelisted websites, will not notify about plugin - presence in the address bar. - * @param redirectURL: specifies url for the overlay iframe - * @param whitelist: specifies plugin whitelist in form of comma separated - * "[@page_url object_url|@page_url|object_url]" entries, - * e.g. @http://example.org/* http://example.org/t.swf - */ - void registerPlayPreviewMimeType(in AUTF8String mimeType, - [optional] in boolean ignoreCTP, - [optional] in AUTF8String redirectURL, - [optional] in AUTF8String whitelist); - - void unregisterPlayPreviewMimeType(in AUTF8String mimeType); - - nsIPluginPlayPreviewInfo getPlayPreviewInfo(in AUTF8String mimeType); - /** * Get the "permission string" for the plugin. This is a string that can be * passed to the permission manager to see whether the plugin is allowed to diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index 24114cae4e66..96347e29b577 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -1598,58 +1598,6 @@ nsPluginHost::UnregisterFakePlugin(const nsACString& aHandlerURI) return NS_OK; } -NS_IMETHODIMP -nsPluginHost::RegisterPlayPreviewMimeType(const nsACString& mimeType, - bool ignoreCTP, - const nsACString& redirectURL, - const nsACString& whitelist) -{ - nsAutoCString mt(mimeType); - nsAutoCString url(redirectURL); - if (url.Length() == 0) { - // using default play preview iframe URL, if redirectURL is not specified - url.AssignLiteral("data:application/x-moz-playpreview;,"); - url.Append(mimeType); - } - nsAutoCString wl(whitelist); - - nsRefPtr playPreview = - new nsPluginPlayPreviewInfo(mt.get(), ignoreCTP, url.get(), wl.get()); - mPlayPreviewMimeTypes.AppendElement(playPreview); - return NS_OK; -} - -NS_IMETHODIMP -nsPluginHost::UnregisterPlayPreviewMimeType(const nsACString& mimeType) -{ - nsAutoCString mimeTypeToRemove(mimeType); - for (uint32_t i = mPlayPreviewMimeTypes.Length(); i > 0; i--) { - nsRefPtr pp = mPlayPreviewMimeTypes[i - 1]; - if (PL_strcasecmp(pp.get()->mMimeType.get(), mimeTypeToRemove.get()) == 0) { - mPlayPreviewMimeTypes.RemoveElementAt(i - 1); - break; - } - } - return NS_OK; -} - -NS_IMETHODIMP -nsPluginHost::GetPlayPreviewInfo(const nsACString& mimeType, - nsIPluginPlayPreviewInfo** aResult) -{ - nsAutoCString mimeTypeToFind(mimeType); - for (uint32_t i = 0; i < mPlayPreviewMimeTypes.Length(); i++) { - nsRefPtr pp = mPlayPreviewMimeTypes[i]; - if (PL_strcasecmp(pp.get()->mMimeType.get(), mimeTypeToFind.get()) == 0) { - *aResult = new nsPluginPlayPreviewInfo(pp.get()); - NS_ADDREF(*aResult); - return NS_OK; - } - } - *aResult = nullptr; - return NS_ERROR_NOT_AVAILABLE; -} - // FIXME-jsplugins Is this method actually needed? NS_IMETHODIMP nsPluginHost::GetFakePlugin(const nsACString & aMimeType, diff --git a/dom/plugins/base/nsPluginHost.h b/dom/plugins/base/nsPluginHost.h index 7fe797054eea..9d30c147c49b 100644 --- a/dom/plugins/base/nsPluginHost.h +++ b/dom/plugins/base/nsPluginHost.h @@ -12,7 +12,6 @@ #include "prlink.h" #include "prclist.h" #include "nsIPluginTag.h" -#include "nsPluginPlayPreviewInfo.h" #include "nsPluginsDir.h" #include "nsPluginDirServiceProvider.h" #include "nsAutoPtr.h" @@ -369,7 +368,6 @@ class nsPluginHost final : public nsIPluginHost, nsRefPtr mPlugins; nsRefPtr mCachedPlugins; nsRefPtr mInvalidPlugins; - nsTArray< nsRefPtr > mPlayPreviewMimeTypes; nsTArray< nsRefPtr > mFakePlugins; diff --git a/dom/plugins/base/nsPluginPlayPreviewInfo.cpp b/dom/plugins/base/nsPluginPlayPreviewInfo.cpp deleted file mode 100644 index c2a4ae18ed79..000000000000 --- a/dom/plugins/base/nsPluginPlayPreviewInfo.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* -*- 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/. */ - -#include "nsPluginPlayPreviewInfo.h" -#include "nsWildCard.h" - -using namespace mozilla; - -nsPluginPlayPreviewInfo::nsPluginPlayPreviewInfo(const char* aMimeType, - bool aIgnoreCTP, - const char* aRedirectURL, - const char* aWhitelist) - : mMimeType(aMimeType), mIgnoreCTP(aIgnoreCTP), mRedirectURL(aRedirectURL), - mWhitelist(aWhitelist) {} - -nsPluginPlayPreviewInfo::nsPluginPlayPreviewInfo( - const nsPluginPlayPreviewInfo* aSource) -{ - MOZ_ASSERT(aSource); - - mMimeType = aSource->mMimeType; - mIgnoreCTP = aSource->mIgnoreCTP; - mRedirectURL = aSource->mRedirectURL; - mWhitelist = aSource->mWhitelist; -} - -nsPluginPlayPreviewInfo::~nsPluginPlayPreviewInfo() -{ -} - -NS_IMPL_ISUPPORTS(nsPluginPlayPreviewInfo, nsIPluginPlayPreviewInfo) - -NS_IMETHODIMP -nsPluginPlayPreviewInfo::GetMimeType(nsACString& aMimeType) -{ - aMimeType = mMimeType; - return NS_OK; -} - -NS_IMETHODIMP -nsPluginPlayPreviewInfo::GetIgnoreCTP(bool* aIgnoreCTP) -{ - *aIgnoreCTP = mIgnoreCTP; - return NS_OK; -} - -NS_IMETHODIMP -nsPluginPlayPreviewInfo::GetRedirectURL(nsACString& aRedirectURL) -{ - aRedirectURL = mRedirectURL; - return NS_OK; -} - -NS_IMETHODIMP -nsPluginPlayPreviewInfo::GetWhitelist(nsACString& aWhitelist) -{ - aWhitelist = mWhitelist; - return NS_OK; -} - -/* static */ nsresult -nsPluginPlayPreviewInfo::CheckWhitelist(const nsACString& aPageURI, - const nsACString& aObjectURI, - const nsACString& aWhitelist, - bool *_retval) -{ - if (aWhitelist.Length() == 0) { - // Considering empty whitelist as '*' entry. - *_retval = true; - return NS_OK; - } - - // Parses whitelist as comma separated entries of - // [@page_url object_url|@page_url|object_url] - // where page_url and object_url pattern matches for aPageURI - // and aObjectURI, and performs matching as the same time. - nsACString::const_iterator start, end; - aWhitelist.BeginReading(start); - aWhitelist.EndReading(end); - - nsAutoCString pageURI(aPageURI); - nsAutoCString objectURI(aObjectURI); - nsACString::const_iterator pos = start, entryStart, entryEnd; - nsACString::const_iterator pagePatternStart, pagePatternEnd; - nsACString::const_iterator objectPatternStart, objectPatternEnd; - int matchResult; - bool matched, didMatching; - while (pos != end) { - matched = true; - didMatching = false; - entryStart = pos; - // Looking for end of the entry. - while (pos != end && *pos != ',') { - pos++; - } - entryEnd = pos; - if (entryStart != entryEnd && *entryStart == '@') { - // Pattern for aPageURL is found, finding a space or end of the entry. - pagePatternStart = entryStart; - pagePatternStart++; - pagePatternEnd = pagePatternStart; - while (pagePatternEnd != entryEnd && *pagePatternEnd != ' ') { - pagePatternEnd++; - } - nsAutoCString pagePattern(Substring(pagePatternStart, pagePatternEnd)); - matchResult = NS_WildCardMatch(pageURI.get(), pagePattern.get(), true); - matched &= matchResult == MATCH; - didMatching = true; - objectPatternStart = pagePatternEnd; - } else { - objectPatternStart = entryStart; - } - while (objectPatternStart != entryEnd && *objectPatternStart == ' ') { - objectPatternStart++; - } - if (objectPatternStart != entryEnd) { - // Pattern for aObjectURL is found, removing trailing spaces. - objectPatternEnd = entryEnd; - --objectPatternEnd; - while (objectPatternStart != objectPatternEnd && - *objectPatternEnd == ' ') { - objectPatternEnd--; - }; - objectPatternEnd++; - nsAutoCString objectPattern(Substring(objectPatternStart, - objectPatternEnd)); - matchResult = NS_WildCardMatch(objectURI.get(), objectPattern.get(), true); - matched &= matchResult == MATCH; - didMatching = true; - } - // Ignoring match result for empty entries. - if (didMatching && matched) { - *_retval = true; - return NS_OK; - } - if (pos == end) { - break; - } - pos++; - } - - *_retval = false; - return NS_OK; -} - -NS_IMETHODIMP -nsPluginPlayPreviewInfo::CheckWhitelist(const nsACString& aPageURI, - const nsACString& aObjectURI, - bool *_retval) -{ - return CheckWhitelist(aPageURI, aObjectURI, mWhitelist, _retval); -} diff --git a/dom/plugins/base/nsPluginPlayPreviewInfo.h b/dom/plugins/base/nsPluginPlayPreviewInfo.h deleted file mode 100644 index a28bba593a7b..000000000000 --- a/dom/plugins/base/nsPluginPlayPreviewInfo.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- 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 nsPluginPlayPreviewInfo_h_ -#define nsPluginPlayPreviewInfo_h_ - -#include "nsString.h" -#include "nsIPluginHost.h" - -class nsPluginPlayPreviewInfo : public nsIPluginPlayPreviewInfo -{ - virtual ~nsPluginPlayPreviewInfo(); - -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIPLUGINPLAYPREVIEWINFO - - nsPluginPlayPreviewInfo(const char* aMimeType, - bool aIgnoreCTP, - const char* aRedirectURL, - const char* aWhitelist); - explicit nsPluginPlayPreviewInfo(const nsPluginPlayPreviewInfo* aSource); - - /** This function checks aPageURI and aObjectURI against the whitelist - * specified in aWhitelist. This is public static function because this - * whitelist checking code needs to be accessed without any instances of - * nsIPluginPlayPreviewInfo. In particular, the Shumway whitelist is - * obtained directly from prefs and compared using this code for telemetry - * purposes. - */ - static nsresult CheckWhitelist(const nsACString& aPageURI, - const nsACString& aObjectURI, - const nsACString& aWhitelist, - bool *_retval); - - nsCString mMimeType; - bool mIgnoreCTP; - nsCString mRedirectURL; - nsCString mWhitelist; -}; - - -#endif // nsPluginPlayPreviewInfo_h_ diff --git a/dom/plugins/ipc/PluginInstanceParent.cpp b/dom/plugins/ipc/PluginInstanceParent.cpp index afb2c3535e90..5bb6a827e299 100644 --- a/dom/plugins/ipc/PluginInstanceParent.cpp +++ b/dom/plugins/ipc/PluginInstanceParent.cpp @@ -167,26 +167,7 @@ PluginInstanceParent::InitMetadata(const nsACString& aMimeType, return false; } nsCOMPtr baseUri(owner->GetBaseURI()); - nsresult rv = NS_MakeAbsoluteURI(mSrcAttribute, aSrcAttribute, baseUri); - if (NS_FAILED(rv)) { - return false; - } - // Check the whitelist - nsAutoCString baseUrlSpec; - rv = baseUri->GetSpec(baseUrlSpec); - if (NS_FAILED(rv)) { - return false; - } - auto whitelist = Preferences::GetCString(kShumwayWhitelistPref); - // Empty whitelist is interpreted by CheckWhitelist as "allow everything," - // which is not valid for our use case and should be treated as a failure. - if (whitelist.IsEmpty()) { - return false; - } - rv = nsPluginPlayPreviewInfo::CheckWhitelist(baseUrlSpec, mSrcAttribute, - whitelist, - &mIsWhitelistedForShumway); - return NS_SUCCEEDED(rv); + return NS_SUCCEEDED(NS_MakeAbsoluteURI(mSrcAttribute, aSrcAttribute, baseUri)); } void diff --git a/dom/webidl/HTMLObjectElement.webidl b/dom/webidl/HTMLObjectElement.webidl index 43aaa0dd4009..4bfa1a80352d 100644 --- a/dom/webidl/HTMLObjectElement.webidl +++ b/dom/webidl/HTMLObjectElement.webidl @@ -129,9 +129,6 @@ interface MozObjectLoadingContent { // The plugin is vulnerable (no update available) [ChromeOnly] const unsigned long PLUGIN_VULNERABLE_NO_UPDATE = 10; - // The plugin is in play preview mode - [ChromeOnly] - const unsigned long PLUGIN_PLAY_PREVIEW = 11; /** * The actual mime type (the one we got back from the network @@ -163,8 +160,8 @@ interface MozObjectLoadingContent { sequence getPluginParameters(); /** - * This method will play a plugin that has been stopped by the - * click-to-play plugins or play-preview features. + * This method will play a plugin that has been stopped by the click-to-play + * feature. */ [ChromeOnly, Throws] void playPlugin(); @@ -181,7 +178,7 @@ interface MozObjectLoadingContent { /** * This attribute will return true if the current content type has been * activated, either explicitly or by passing checks that would have it be - * click-to-play or play-preview. + * click-to-play. */ [ChromeOnly] readonly attribute boolean activated; @@ -206,12 +203,6 @@ interface MozObjectLoadingContent { [ChromeOnly] readonly attribute boolean hasRunningPlugin; - /** - * This method will disable the play-preview plugin state. - */ - [ChromeOnly, Throws] - void cancelPlayPreview(); - [ChromeOnly, Throws] readonly attribute unsigned long runID; }; diff --git a/layout/style/nsCSSPseudoClassList.h b/layout/style/nsCSSPseudoClassList.h index 913dd2f5eaf8..45947cd63356 100644 --- a/layout/style/nsCSSPseudoClassList.h +++ b/layout/style/nsCSSPseudoClassList.h @@ -179,8 +179,6 @@ CSS_STATE_PSEUDO_CLASS(mozTypeUnsupportedPlatform, ":-moz-type-unsupported-platf NS_EVENT_STATE_TYPE_UNSUPPORTED_PLATFORM) CSS_STATE_PSEUDO_CLASS(mozHandlerClickToPlay, ":-moz-handler-clicktoplay", 0, "", NS_EVENT_STATE_TYPE_CLICK_TO_PLAY) -CSS_STATE_PSEUDO_CLASS(mozHandlerPlayPreview, ":-moz-handler-playpreview", 0, "", - NS_EVENT_STATE_TYPE_PLAY_PREVIEW) CSS_STATE_PSEUDO_CLASS(mozHandlerVulnerableUpdatable, ":-moz-handler-vulnerable-updatable", 0, "", NS_EVENT_STATE_VULNERABLE_UPDATABLE) CSS_STATE_PSEUDO_CLASS(mozHandlerVulnerableNoUpdate, ":-moz-handler-vulnerable-no-update", 0, "", diff --git a/mobile/android/chrome/content/PluginHelper.js b/mobile/android/chrome/content/PluginHelper.js index 4c4a81198fb3..b684a74555cf 100644 --- a/mobile/android/chrome/content/PluginHelper.js +++ b/mobile/android/chrome/content/PluginHelper.js @@ -87,17 +87,6 @@ var PluginHelper = { objLoadingContent.playPlugin(); }, - stopPlayPreview: function(plugin, playPlugin) { - let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent); - if (objLoadingContent.activated) - return; - - if (playPlugin) - objLoadingContent.playPlugin(); - else - objLoadingContent.cancelPlayPreview(); - }, - getPluginPreference: function getPluginPreference() { let pluginDisable = Services.prefs.getBoolPref("plugin.disable"); if (pluginDisable) @@ -212,54 +201,6 @@ var PluginHelper = { break; } - case "PluginPlayPreview": { - let previewContent = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent"); - let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); - let mimeType = PluginHelper.getPluginMimeType(plugin); - let playPreviewInfo = pluginHost.getPlayPreviewInfo(mimeType); - - if (!playPreviewInfo.ignoreCTP) { - // Check if plugins have already been activated for this page, or if - // the user has set a permission to always play plugins on the site - if (aTab.clickToPlayPluginsActivated || - Services.perms.testPermission(aTab.browser.currentURI, "plugins") == - Services.perms.ALLOW_ACTION) { - PluginHelper.playPlugin(plugin); - return; - } - - // Always show door hanger for play preview plugins - PluginHelper.delayAndShowDoorHanger(aTab); - } - - let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0]; - if (!iframe) { - // lazy initialization of the iframe - iframe = doc.createElementNS("http://www.w3.org/1999/xhtml", "iframe"); - iframe.className = "previewPluginContentFrame"; - previewContent.appendChild(iframe); - } - iframe.src = playPreviewInfo.redirectURL; - - // MozPlayPlugin event can be dispatched from the extension chrome - // code to replace the preview content with the native plugin - previewContent.addEventListener("MozPlayPlugin", function playPluginHandler(e) { - if (!e.isTrusted) - return; - - previewContent.removeEventListener("MozPlayPlugin", playPluginHandler, true); - - let playPlugin = !aEvent.detail; - PluginHelper.stopPlayPreview(plugin, playPlugin); - - // cleaning up: removes overlay iframe from the DOM - let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0]; - if (iframe) - previewContent.removeChild(iframe); - }, true); - break; - } - case "PluginNotFound": { // On devices where we don't support Flash, there will be a // "Learn More..." link in the missing plugin error message. @@ -283,8 +224,6 @@ var PluginHelper = { return "PluginNotFound"; case Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY: return "PluginClickToPlay"; - case Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW: - return "PluginPlayPreview"; default: // Not all states map to a handler return null; diff --git a/toolkit/mozapps/plugins/content/pluginProblem.xml b/toolkit/mozapps/plugins/content/pluginProblem.xml index e20ae3c83069..5b3c9f99f956 100644 --- a/toolkit/mozapps/plugins/content/pluginProblem.xml +++ b/toolkit/mozapps/plugins/content/pluginProblem.xml @@ -67,7 +67,6 @@ - diff --git a/toolkit/mozapps/plugins/content/pluginProblemBinding.css b/toolkit/mozapps/plugins/content/pluginProblemBinding.css index abf4b00a0204..bf9f1c222483 100644 --- a/toolkit/mozapps/plugins/content/pluginProblemBinding.css +++ b/toolkit/mozapps/plugins/content/pluginProblemBinding.css @@ -8,21 +8,18 @@ embed:-moz-handler-disabled, embed:-moz-handler-blocked, embed:-moz-handler-crashed, embed:-moz-handler-clicktoplay, -embed:-moz-handler-playpreview, embed:-moz-handler-vulnerable-updatable, embed:-moz-handler-vulnerable-no-update, applet:-moz-handler-disabled, applet:-moz-handler-blocked, applet:-moz-handler-crashed, applet:-moz-handler-clicktoplay, -applet:-moz-handler-playpreview, applet:-moz-handler-vulnerable-updatable, applet:-moz-handler-vulnerable-no-update, object:-moz-handler-disabled, object:-moz-handler-blocked, object:-moz-handler-crashed, object:-moz-handler-clicktoplay, -object:-moz-handler-playpreview, object:-moz-handler-vulnerable-updatable, object:-moz-handler-vulnerable-no-update { display: inline-block; diff --git a/toolkit/mozapps/plugins/content/pluginProblemContent.css b/toolkit/mozapps/plugins/content/pluginProblemContent.css index 91bcda016c1d..0f7c7d39a709 100644 --- a/toolkit/mozapps/plugins/content/pluginProblemContent.css +++ b/toolkit/mozapps/plugins/content/pluginProblemContent.css @@ -71,10 +71,6 @@ html|applet:not([height]), html|applet[height=""] { direction: rtl; } -:-moz-handler-playpreview .mainBox { - display: none; -} - :-moz-handler-clicktoplay .hoverBox, :-moz-handler-vulnerable-updatable .hoverBox, :-moz-handler-vulnerable-no-update .hoverBox { @@ -88,23 +84,6 @@ html|applet:not([height]), html|applet[height=""] { cursor: inherit; } -.previewPluginContent { - display: none; -} - -.previewPluginContent > iframe { - width: inherit; - height: inherit; - border: none; -} - -:-moz-handler-playpreview .previewPluginContent { - display: block; - width: inherit; - height: inherit; - overflow: hidden; -} - .msg { display: none; } From cf2c394ac224c4cb7ac6dcbf54e51c9feb56209b Mon Sep 17 00:00:00 2001 From: Christoph Kerschbaumer Date: Tue, 18 Aug 2015 11:42:43 -0700 Subject: [PATCH 126/208] Bug 1096724 - Update csp/test_base-uri to rely on postmessage instead of observers. r=dveditz --- dom/security/test/csp/file_base-uri.html | 2 +- dom/security/test/csp/test_base-uri.html | 61 +++++++++++++----------- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/dom/security/test/csp/file_base-uri.html b/dom/security/test/csp/file_base-uri.html index d86ed1846897..cb12684b98b4 100644 --- a/dom/security/test/csp/file_base-uri.html +++ b/dom/security/test/csp/file_base-uri.html @@ -4,7 +4,7 @@ Bug 1045897 - Test CSP base-uri directive - + diff --git a/dom/security/test/csp/test_base-uri.html b/dom/security/test/csp/test_base-uri.html index 7e326401d3df..be455a51e706 100644 --- a/dom/security/test/csp/test_base-uri.html +++ b/dom/security/test/csp/test_base-uri.html @@ -23,45 +23,47 @@ SimpleTest.waitForExplicitFinish(); -var testPolicies = [ - "base-uri http://example.com", - "base-uri https:", - "base-uri 'none'", +var tests = [ + { + policy: "base-uri http://mochi.test;", + result: "http://mochi.test" + }, + { + policy: "base-uri http://example.com;", + result: "http://example.com" + }, + { + policy: "base-uri https:", + result: "http://example.com" + }, + { + policy: "base-uri 'none'", + result: "http://example.com" + } ]; // initializing to -1 so we start at index 0 when we start the test var counter = -1; -function examiner() { - SpecialPowers.addObserver(this, "csp-on-violate-policy", false); -} -examiner.prototype = { - observe: function(subject, topic, data) { - if (topic === "csp-on-violate-policy") { - var spec = SpecialPowers.getPrivilegedProps( - SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec"); - - if (spec === "http://mochi.test/") { - // 'data' holds the violated directive - is(data, testPolicies[counter], "Disallowed setting the base-uri in test " + counter + "!"); - loadNextTest(); - } - } - }, - remove: function() { - SpecialPowers.removeObserver(this, "csp-on-violate-policy"); - } -} -window.BaseURIExaminer = new examiner(); - function finishTest() { - window.BaseURIExaminer.remove(); + window.removeEventListener("message", receiveMessage, false); SimpleTest.finish(); } +// a postMessage handler that is used by sandboxed iframes without +// 'allow-same-origin' to bubble up results back to this main page. +window.addEventListener("message", receiveMessage, false); +function receiveMessage(event) { + var result = event.data.result; + // we only care about the base uri, so instead of comparing the complete uri + // we just make sure that the base is correct which is sufficient here. + ok(result.startsWith(tests[counter].result), "Restricting base-uri in test " + counter + "!"); + loadNextTest(); +} + function loadNextTest() { counter++; - if (counter == testPolicies.length) { + if (counter == tests.length) { finishTest(); return; } @@ -69,7 +71,8 @@ // append the file that should be served src += "?file=" + escape("tests/dom/security/test/csp/file_base-uri.html"); // append the CSP that should be used to serve the file - src += "&csp=" + escape(testPolicies[counter]); + // please note that we have to include 'unsafe-inline' to permit sending the postMessage + src += "&csp=" + escape("script-src 'unsafe-inline'; " + tests[counter].policy); document.getElementById("testframe").src = src; } From f266f0ca9b09433c11fdc367a4d17db2f59cbcb1 Mon Sep 17 00:00:00 2001 From: Hiroyuki Ikezoe Date: Thu, 20 Aug 2015 15:30:00 -0400 Subject: [PATCH 127/208] Bug 1150818 - Part 1: Output mozinfo into a file. r=ted --- testing/mozbase/mozinfo/mozinfo/mozinfo.py | 6 ++++++ testing/mozbase/mozinfo/tests/test.py | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/testing/mozbase/mozinfo/mozinfo/mozinfo.py b/testing/mozbase/mozinfo/mozinfo/mozinfo.py index 9362dd7fef9a..6b24601a63a2 100755 --- a/testing/mozbase/mozinfo/mozinfo/mozinfo.py +++ b/testing/mozbase/mozinfo/mozinfo/mozinfo.py @@ -215,6 +215,11 @@ def find_and_update_from_json(*dirs): return None +def output_to_file(path): + import json + with open(path, 'w') as f: + f.write(json.dumps(info)); + update({}) # exports @@ -227,6 +232,7 @@ def find_and_update_from_json(*dirs): 'choices', 'update', 'find_and_update_from_json', + 'output_to_file', 'StringVersion', ] diff --git a/testing/mozbase/mozinfo/tests/test.py b/testing/mozbase/mozinfo/tests/test.py index a890aa725617..dc752f924823 100644 --- a/testing/mozbase/mozinfo/tests/test.py +++ b/testing/mozbase/mozinfo/tests/test.py @@ -84,6 +84,12 @@ def test_find_and_update_file_mozbuild(self): self.assertEqual(mozinfo.find_and_update_from_json(), j) self.assertEqual(mozinfo.info["foo"], "123456") + def test_output_to_file(self): + """Test that mozinfo.output_to_file works.""" + path = os.path.join(self.tempdir, "mozinfo.json") + mozinfo.output_to_file(path) + self.assertEqual(open(path).read(), json.dumps(mozinfo.info)) + class TestStringVersion(unittest.TestCase): def test_os_version_is_a_StringVersion(self): From 63b2e34b160f64aced0791e726c2950ff7de21f7 Mon Sep 17 00:00:00 2001 From: Hiroyuki Ikezoe Date: Thu, 20 Aug 2015 16:06:00 -0400 Subject: [PATCH 128/208] Bug 1150818 - Part 2: Load mozinfo.json into xpcshell tests. r=ted --- testing/xpcshell/head.js | 27 ++++++++++++++++ testing/xpcshell/remotexpcshelltests.py | 8 +++++ testing/xpcshell/runxpcshelltests.py | 17 +++++++--- testing/xpcshell/selftest.py | 43 +++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 4 deletions(-) diff --git a/testing/xpcshell/head.js b/testing/xpcshell/head.js index a3cfcec75e6c..ce72eb0d9e18 100644 --- a/testing/xpcshell/head.js +++ b/testing/xpcshell/head.js @@ -1215,6 +1215,7 @@ function do_load_child_test_harness() let command = "const _HEAD_JS_PATH=" + uneval(_HEAD_JS_PATH) + "; " + "const _HEAD_FILES=" + uneval(_HEAD_FILES) + "; " + + "const _MOZINFO_JS_PATH=" + uneval(_MOZINFO_JS_PATH) + "; " + "const _TAIL_FILES=" + uneval(_TAIL_FILES) + "; " + "const _TEST_NAME=" + uneval(_TEST_NAME) + "; " // We'll need more magic to get the debugger working in the child @@ -1520,3 +1521,29 @@ try { prefs.deleteBranch("browser.devedition.theme.enabled"); } } catch (e) { } + +function _load_mozinfo() { + let mozinfoFile = Components.classes["@mozilla.org/file/local;1"] + .createInstance(Components.interfaces.nsIFile); + mozinfoFile.initWithPath(_MOZINFO_JS_PATH); + let stream = Components.classes["@mozilla.org/network/file-input-stream;1"] + .createInstance(Components.interfaces.nsIFileInputStream); + stream.init(mozinfoFile, -1, 0, 0); + let json = Components.classes["@mozilla.org/dom/json;1"] + .createInstance(Components.interfaces.nsIJSON); + let mozinfo = json.decodeFromStream(stream, stream.available()); + stream.close(); + return mozinfo; +} + +Object.defineProperty(this, "mozinfo", { + configurable: true, + get() { + let _mozinfo = _load_mozinfo(); + Object.defineProperty(this, "mozinfo", { + configurable: false, + value: _mozinfo + }); + return _mozinfo; + } +}); diff --git a/testing/xpcshell/remotexpcshelltests.py b/testing/xpcshell/remotexpcshelltests.py index c65caa99bf39..0428804720e7 100644 --- a/testing/xpcshell/remotexpcshelltests.py +++ b/testing/xpcshell/remotexpcshelltests.py @@ -71,6 +71,14 @@ def setupProfileDir(self): self.log.info("profile dir is %s" % self.profileDir) return self.profileDir + def setupMozinfoJS(self): + local = tempfile.mktemp() + mozinfo.output_to_file(local) + mozInfoJSPath = remoteJoin(self.profileDir, "mozinfo.json") + self.device.pushFile(local, mozInfoJSPath) + os.remove(local) + return mozInfoJSPath + def logCommand(self, name, completeCmd, testdir): self.log.info("%s | full command: %r" % (name, completeCmd)) self.log.info("%s | current directory: %r" % (name, self.remoteHere)) diff --git a/testing/xpcshell/runxpcshelltests.py b/testing/xpcshell/runxpcshelltests.py index f5335b092b88..7e6e5c67f98e 100755 --- a/testing/xpcshell/runxpcshelltests.py +++ b/testing/xpcshell/runxpcshelltests.py @@ -392,6 +392,12 @@ def setupProfileDir(self): self.log.info("profile dir is %s" % profileDir) return profileDir + def setupMozinfoJS(self): + mozInfoJSPath = os.path.join(self.profileDir, 'mozinfo.json') + mozInfoJSPath = mozInfoJSPath.replace('\\', '\\\\') + mozinfo.output_to_file(mozInfoJSPath) + return mozInfoJSPath + def buildCmdHead(self, headfiles, tailfiles, xpcscmd): """ Build the command line arguments for the head and tail files, @@ -456,7 +462,8 @@ def buildXpcsCmd(self, testdir): '-r', self.httpdManifest, '-m', '-s', - '-e', 'const _HEAD_JS_PATH = "%s";' % self.headJSPath + '-e', 'const _HEAD_JS_PATH = "%s";' % self.headJSPath, + '-e', 'const _MOZINFO_JS_PATH = "%s";' % self.mozInfoJSPath, ] if self.testingModulesDir: @@ -633,14 +640,16 @@ def run_test(self): self.appPath = None test_dir = os.path.dirname(path) - self.buildXpcsCmd(test_dir) - head_files, tail_files = self.getHeadAndTailFiles(self.test_object) - cmdH = self.buildCmdHead(head_files, tail_files, self.xpcsCmd) # Create a profile and a temp dir that the JS harness can stick # a profile and temporary data in self.profileDir = self.setupProfileDir() self.tempDir = self.setupTempDir() + self.mozInfoJSPath = self.setupMozinfoJS() + + self.buildXpcsCmd(test_dir) + head_files, tail_files = self.getHeadAndTailFiles(self.test_object) + cmdH = self.buildCmdHead(head_files, tail_files, self.xpcsCmd) # The test file will have to be loaded after the head files. cmdT = self.buildCmdTestFile(path) diff --git a/testing/xpcshell/selftest.py b/testing/xpcshell/selftest.py index aa54b49fda70..5ed4fe6cf220 100644 --- a/testing/xpcshell/selftest.py +++ b/testing/xpcshell/selftest.py @@ -349,7 +349,21 @@ }); ''' +LOAD_MOZINFO = ''' +function run_test() { + do_check_neq(typeof mozinfo, undefined); + do_check_neq(typeof mozinfo.os, undefined); +} +''' +CHILD_MOZINFO = ''' +function run_test () { run_next_test(); } + +add_test(function test_child_mozinfo () { + run_test_in_child("test_mozinfo.js"); + run_next_test(); +}); +''' class XPCShellTestsTests(unittest.TestCase): """ Yes, these are unit tests for a unit test harness. @@ -1203,5 +1217,34 @@ def testNoRunTestAddTaskMultiple(self): self.assertInLog(TEST_PASS_STRING) self.assertNotInLog(TEST_FAIL_STRING) + def testMozinfo(self): + """ + Check that mozinfo.json is loaded + """ + self.writeFile("test_mozinfo.js", LOAD_MOZINFO) + self.writeManifest(["test_mozinfo.js"]) + self.assertTestResult(True) + self.assertEquals(1, self.x.testCount) + self.assertEquals(1, self.x.passCount) + self.assertEquals(0, self.x.failCount) + self.assertEquals(0, self.x.todoCount) + self.assertInLog(TEST_PASS_STRING) + self.assertNotInLog(TEST_FAIL_STRING) + + def testChildMozinfo(self): + """ + Check that mozinfo.json is loaded in child process + """ + self.writeFile("test_mozinfo.js", LOAD_MOZINFO) + self.writeFile("test_child_mozinfo.js", CHILD_MOZINFO) + self.writeManifest(["test_child_mozinfo.js"]) + self.assertTestResult(True) + self.assertEquals(1, self.x.testCount) + self.assertEquals(1, self.x.passCount) + self.assertEquals(0, self.x.failCount) + self.assertEquals(0, self.x.todoCount) + self.assertInLog(TEST_PASS_STRING) + self.assertNotInLog(TEST_FAIL_STRING) + if __name__ == "__main__": unittest.main(verbosity=3) From 9a04ab22b20420c10af69d327caf1dd0a3d9216e Mon Sep 17 00:00:00 2001 From: Jamie Nicol Date: Tue, 18 Aug 2015 15:11:25 +0100 Subject: [PATCH 129/208] Bug 1192058 - For DXGI_PRESENT_PARAMETERS, set pDirtyRects to nullptr if DirtyRectsCount == 0. r=BenWa --- gfx/layers/d3d11/CompositorD3D11.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/layers/d3d11/CompositorD3D11.cpp b/gfx/layers/d3d11/CompositorD3D11.cpp index 87eac4d19c3c..e6ba57717673 100644 --- a/gfx/layers/d3d11/CompositorD3D11.cpp +++ b/gfx/layers/d3d11/CompositorD3D11.cpp @@ -1105,7 +1105,7 @@ CompositorD3D11::EndFrame() i++; } - params.pDirtyRects = rects.data(); + params.pDirtyRects = params.DirtyRectsCount ? rects.data() : nullptr; chain->Present1(presentInterval, mDisableSequenceForNextFrame ? DXGI_PRESENT_DO_NOT_SEQUENCE : 0, ¶ms); } else { mSwapChain->Present(presentInterval, mDisableSequenceForNextFrame ? DXGI_PRESENT_DO_NOT_SEQUENCE : 0); From 10aa40e142e180d6de68b6b7e3173f43fcad1e9e Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Fri, 27 Feb 2015 14:17:35 -0500 Subject: [PATCH 130/208] Bug 1136766 - Don't allow more draw calls after culling. r=mattwoodrow --- gfx/layers/composite/LayerManagerComposite.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gfx/layers/composite/LayerManagerComposite.cpp b/gfx/layers/composite/LayerManagerComposite.cpp index f218bf2969b5..92042f531922 100644 --- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -226,7 +226,11 @@ LayerManagerComposite::ApplyOcclusionCulling(Layer* aLayer, nsIntRegion& aOpaque LayerComposite *composite = aLayer->AsLayerComposite(); if (!localOpaque.IsEmpty()) { nsIntRegion visible = composite->GetShadowVisibleRegion(); - visible.Sub(visible, localOpaque); + nsIntRegion afterCulling; + afterCulling.Sub(visible, localOpaque); + // Intersect the original region with the bounds of the culled region so + // that we don't increase the region's complexity. + visible.AndWith(afterCulling.GetBounds()); composite->SetShadowVisibleRegion(visible); } From be9af7d95a7a30ee34d853ed4fc3617990b3b2c0 Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Sat, 21 Feb 2015 18:16:53 -0500 Subject: [PATCH 131/208] Bug 1136766 - Before compositing, clip the visible region of a layer to the layer's clip rect, and don't increase the complexity of the visible region. r=mattwoodrow --- .../composite/LayerManagerComposite.cpp | 76 ++++++++++++------- gfx/layers/composite/LayerManagerComposite.h | 2 +- 2 files changed, 51 insertions(+), 27 deletions(-) diff --git a/gfx/layers/composite/LayerManagerComposite.cpp b/gfx/layers/composite/LayerManagerComposite.cpp index 92042f531922..914a4f018fad 100644 --- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -204,40 +204,66 @@ LayerManagerComposite::BeginTransactionWithDrawTarget(DrawTarget* aTarget, const mTargetBounds = aRect; } -void -LayerManagerComposite::ApplyOcclusionCulling(Layer* aLayer, nsIntRegion& aOpaqueRegion) +static bool +IsIntegerTranslation(const Matrix4x4& aMatrix, nsIntPoint* aOutTranslation) { - nsIntRegion localOpaque; Matrix transform2d; - bool isTranslation = false; + if (aMatrix.Is2D(&transform2d)) { + if (transform2d.IsIntegerTranslation()) { + *aOutTranslation = nsIntPoint(transform2d._31, transform2d._32); + return true; + } + } + return false; +} + +void +LayerManagerComposite::ApplyOcclusionCulling(Layer* aLayer, nsIntRegion& aOpaqueRegion, const nsIntRect* aClipFromAncestors) +{ // If aLayer has a simple transform (only an integer translation) then we // can easily convert aOpaqueRegion into pre-transform coordinates and include // that region. - if (aLayer->GetLocalTransform().Is2D(&transform2d)) { - if (transform2d.IsIntegerTranslation()) { - isTranslation = true; - localOpaque = aOpaqueRegion; - localOpaque.MoveBy(-transform2d._31, -transform2d._32); + nsIntPoint translation; + bool isTranslation = IsIntegerTranslation(aLayer->GetLocalTransform(), &translation); + + LayerComposite* composite = aLayer->AsLayerComposite(); + + nsIntRegion localOpaque; + nsIntRect clip; + bool haveClip = false; + + if (isTranslation) { + localOpaque = aOpaqueRegion.MovedBy(-translation); + + // Combine our clip with the one from our descendants. + const Maybe& selfClip = aLayer->GetEffectiveClipRect(); + if (aClipFromAncestors) { + clip = *aClipFromAncestors - translation; + if (selfClip) { + // *selfClip is in parent layer coordinates. + clip = clip.Intersect(ParentLayerPixel::ToUntyped(*selfClip) - translation); + } + haveClip = true; + } else if (selfClip) { + clip = ParentLayerPixel::ToUntyped(*selfClip) - translation; + haveClip = true; } - } - // Subtract any areas that we know to be opaque from our - // visible region. - LayerComposite *composite = aLayer->AsLayerComposite(); - if (!localOpaque.IsEmpty()) { + // Subtract any areas that we know to be opaque from our + // visible region. nsIntRegion visible = composite->GetShadowVisibleRegion(); nsIntRegion afterCulling; afterCulling.Sub(visible, localOpaque); - // Intersect the original region with the bounds of the culled region so - // that we don't increase the region's complexity. - visible.AndWith(afterCulling.GetBounds()); + if (haveClip) { + afterCulling.AndWith(clip); + } composite->SetShadowVisibleRegion(visible); } // Compute occlusions for our descendants (in front-to-back order) and allow them to // contribute to localOpaque. for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) { - ApplyOcclusionCulling(child, localOpaque); + ApplyOcclusionCulling(child, localOpaque, haveClip ? &clip : nullptr); } // If we have a simple transform, then we can add our opaque area into @@ -246,14 +272,12 @@ LayerManagerComposite::ApplyOcclusionCulling(Layer* aLayer, nsIntRegion& aOpaque !aLayer->HasMaskLayers() && aLayer->GetLocalOpacity() == 1.0f) { if (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) { - localOpaque.Or(localOpaque, composite->GetFullyRenderedRegion()); + localOpaque.OrWith(composite->GetFullyRenderedRegion()); } - localOpaque.MoveBy(transform2d._31, transform2d._32); - const Maybe& clip = aLayer->GetEffectiveClipRect(); - if (clip) { - localOpaque.And(localOpaque, ParentLayerIntRect::ToUntyped(*clip)); + if (haveClip) { + localOpaque.AndWith(clip); } - aOpaqueRegion.Or(aOpaqueRegion, localOpaque); + aOpaqueRegion.OrWith(localOpaque.MovedBy(translation)); } } @@ -309,7 +333,7 @@ LayerManagerComposite::EndTransaction(const TimeStamp& aTimeStamp, mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4()); nsIntRegion opaque; - ApplyOcclusionCulling(mRoot, opaque); + ApplyOcclusionCulling(mRoot, opaque, nullptr); Render(); #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) @@ -976,7 +1000,7 @@ LayerManagerComposite::RenderToPresentationSurface() mRoot->ComputeEffectiveTransforms(matrix); nsIntRegion opaque; - ApplyOcclusionCulling(mRoot, opaque); + ApplyOcclusionCulling(mRoot, opaque, nullptr); nsIntRegion invalid; Rect bounds(0.0f, 0.0f, scale * pageWidth, (float)actualHeight); diff --git a/gfx/layers/composite/LayerManagerComposite.h b/gfx/layers/composite/LayerManagerComposite.h index 98c19bb200e8..0fba6d3e65e8 100644 --- a/gfx/layers/composite/LayerManagerComposite.h +++ b/gfx/layers/composite/LayerManagerComposite.h @@ -173,7 +173,7 @@ class LayerManagerComposite final : public LayerManager * opaque content. aOpaqueRegion is the region already known to be covered * with opaque content, in the post-transform coordinate space of aLayer. */ - void ApplyOcclusionCulling(Layer* aLayer, nsIntRegion& aOpaqueRegion); + void ApplyOcclusionCulling(Layer* aLayer, nsIntRegion& aOpaqueRegion, const nsIntRect* aClipFromAncestors); /** * RAII helper class to add a mask effect with the compositable from aMaskLayer From 5082e0cb872c6c986844441da138b7ceaaac9f6e Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Thu, 20 Aug 2015 09:51:36 -0400 Subject: [PATCH 132/208] Bug 1188754 - Do not notify the audio channel agent on Firefox OS when the document activity change callback detects that the element is muted by the audio channel; r=baku --- dom/html/HTMLMediaElement.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index bd470b58f8c4..56b22a639b8f 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -4006,7 +4006,15 @@ bool HTMLMediaElement::IsBeingDestroyed() void HTMLMediaElement::NotifyOwnerDocumentActivityChanged() { bool pauseElement = NotifyOwnerDocumentActivityChangedInternal(); - if (pauseElement && mAudioChannelAgent) { + if (pauseElement && mAudioChannelAgent +#ifdef PAUSE_MEDIA_ELEMENT_FROM_AUDIOCHANNEL + // On B2G, NotifyOwnerDocumentActivityChangedInternal may return true for + // two reasons: the document no longer being active, or the element being + // paused by the audio channel. However we are only interested in the + // first case here, so we need to filter out the second case. + && !ComputedMuted() +#endif + ) { // If the element is being paused since we are navigating away from the // document, notify the audio channel agent. // Be careful to ignore this event during a docshell frame swap. From eb8418ac6cb5421d569eb61fba2ccce035dea052 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 22 Aug 2015 01:43:41 +0900 Subject: [PATCH 133/208] Bug 1189396 part.1 Implement IMENotification::SelectionChangeData::Clear() to initialize its members r=smaug --- widget/IMEData.h | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/widget/IMEData.h b/widget/IMEData.h index 7ae5ee8a7e6f..af4a88dae5cb 100644 --- a/widget/IMEData.h +++ b/widget/IMEData.h @@ -410,12 +410,8 @@ struct IMENotification final { switch (aMessage) { case NOTIFY_IME_OF_SELECTION_CHANGE: - mSelectionChangeData.mOffset = UINT32_MAX; mSelectionChangeData.mString = new nsString(); - mSelectionChangeData.mWritingMode = 0; - mSelectionChangeData.mReversed = false; - mSelectionChangeData.mCausedByComposition = false; - mSelectionChangeData.mCausedBySelectionEvent = false; + mSelectionChangeData.Clear(); break; case NOTIFY_IME_OF_TEXT_CHANGE: mTextChangeData.Clear(); @@ -601,6 +597,19 @@ struct IMENotification final { return mOffset + Length() <= INT32_MAX; } + void Clear() + { + mOffset = UINT32_MAX; + mString->Truncate(); + mWritingMode = 0; + mReversed = false; + mCausedByComposition = false; + mCausedBySelectionEvent = false; + } + bool IsValid() const + { + return mOffset != UINT32_MAX; + } }; struct TextChangeDataBase From 3f492e48d3d383a969d246a70eb4a0a94e95f19a Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 22 Aug 2015 01:43:41 +0900 Subject: [PATCH 134/208] Bug 1189396 part.2 Implement IMENotification::SelectionChangeData::Assign() to copy its members r=smaug --- widget/IMEData.h | 49 +++++++++++++++++++----------------------------- 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/widget/IMEData.h b/widget/IMEData.h index af4a88dae5cb..9b6443708438 100644 --- a/widget/IMEData.h +++ b/widget/IMEData.h @@ -431,14 +431,17 @@ struct IMENotification final void Assign(const IMENotification& aOther) { - Clear(); - mMessage = aOther.mMessage; + bool changingMessage = mMessage != aOther.mMessage; + if (changingMessage) { + Clear(); + mMessage = aOther.mMessage; + } switch (mMessage) { case NOTIFY_IME_OF_SELECTION_CHANGE: - mSelectionChangeData = aOther.mSelectionChangeData; - // mString should be different instance because of ownership issue. - mSelectionChangeData.mString = - new nsString(aOther.mSelectionChangeData.String()); + if (changingMessage) { + mSelectionChangeData.mString = new nsString(); + } + mSelectionChangeData.Assign(aOther.mSelectionChangeData); break; case NOTIFY_IME_OF_TEXT_CHANGE: mTextChangeData = aOther.mTextChangeData; @@ -481,30 +484,7 @@ struct IMENotification final break; case NOTIFY_IME_OF_SELECTION_CHANGE: MOZ_ASSERT(aNotification.mMessage == NOTIFY_IME_OF_SELECTION_CHANGE); - mSelectionChangeData.mOffset = - aNotification.mSelectionChangeData.mOffset; - *mSelectionChangeData.mString = - aNotification.mSelectionChangeData.String(); - mSelectionChangeData.mWritingMode = - aNotification.mSelectionChangeData.mWritingMode; - mSelectionChangeData.mReversed = - aNotification.mSelectionChangeData.mReversed; - if (!mSelectionChangeData.mCausedByComposition) { - mSelectionChangeData.mCausedByComposition = - aNotification.mSelectionChangeData.mCausedByComposition; - } else { - mSelectionChangeData.mCausedByComposition = - mSelectionChangeData.mCausedByComposition && - aNotification.mSelectionChangeData.mCausedByComposition; - } - if (!mSelectionChangeData.mCausedBySelectionEvent) { - mSelectionChangeData.mCausedBySelectionEvent = - aNotification.mSelectionChangeData.mCausedBySelectionEvent; - } else { - mSelectionChangeData.mCausedBySelectionEvent = - mSelectionChangeData.mCausedBySelectionEvent && - aNotification.mSelectionChangeData.mCausedBySelectionEvent; - } + mSelectionChangeData.Assign(aNotification.mSelectionChangeData); break; case NOTIFY_IME_OF_TEXT_CHANGE: MOZ_ASSERT(aNotification.mMessage == NOTIFY_IME_OF_TEXT_CHANGE); @@ -610,6 +590,15 @@ struct IMENotification final { return mOffset != UINT32_MAX; } + void Assign(const SelectionChangeData& aOther) + { + mOffset = aOther.mOffset; + *mString = aOther.String(); + mWritingMode = aOther.mWritingMode; + mReversed = aOther.mReversed; + mCausedByComposition = aOther.mCausedByComposition; + mCausedBySelectionEvent = aOther.mCausedBySelectionEvent; + } }; struct TextChangeDataBase From e1a6a4f8f1d84e1ad58aec702449b751cce49cba Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 22 Aug 2015 01:43:41 +0900 Subject: [PATCH 135/208] Bug 1189396 part.3 Make IMENotification::SelectionChangeData useful even outside of IMENotification r=smaug --- widget/IMEData.h | 46 ++++++++++++++++++++++++++++++--- widget/gtk/IMContextWrapper.cpp | 2 +- widget/nsBaseWidget.cpp | 4 +-- widget/nsGUIEventIPC.h | 4 +-- widget/windows/TSFTextStore.cpp | 2 +- 5 files changed, 49 insertions(+), 9 deletions(-) diff --git a/widget/IMEData.h b/widget/IMEData.h index 9b6443708438..efa798c26870 100644 --- a/widget/IMEData.h +++ b/widget/IMEData.h @@ -539,7 +539,7 @@ struct IMENotification final }; // NOTIFY_IME_OF_SELECTION_CHANGE specific data - struct SelectionChangeData + struct SelectionChangeDataBase { // Selection range. uint32_t mOffset; @@ -590,7 +590,7 @@ struct IMENotification final { return mOffset != UINT32_MAX; } - void Assign(const SelectionChangeData& aOther) + void Assign(const SelectionChangeDataBase& aOther) { mOffset = aOther.mOffset; *mString = aOther.String(); @@ -601,6 +601,46 @@ struct IMENotification final } }; + // SelectionChangeDataBase cannot have constructors because it's used in + // the union. Therefore, SelectionChangeData should only implement + // constructors. In other words, add other members to + // SelectionChangeDataBase. + struct SelectionChangeData final : public SelectionChangeDataBase + { + SelectionChangeData() + { + mString = &mStringInstance; + Clear(); + } + explicit SelectionChangeData(const SelectionChangeDataBase& aOther) + { + mString = &mStringInstance; + Assign(aOther); + } + SelectionChangeData(const SelectionChangeData& aOther) + { + mString = &mStringInstance; + Assign(aOther); + } + SelectionChangeData& operator=(const SelectionChangeDataBase& aOther) + { + mString = &mStringInstance; + Assign(aOther); + return *this; + } + SelectionChangeData& operator=(const SelectionChangeData& aOther) + { + mString = &mStringInstance; + Assign(aOther); + return *this; + } + + private: + // When SelectionChangeData is used outside of union, it shouldn't create + // nsString instance in the heap as far as possible. + nsString mStringInstance; + }; + struct TextChangeDataBase { // mStartOffset is the start offset of modified or removed text in @@ -708,7 +748,7 @@ struct IMENotification final union { // NOTIFY_IME_OF_SELECTION_CHANGE specific data - SelectionChangeData mSelectionChangeData; + SelectionChangeDataBase mSelectionChangeData; // NOTIFY_IME_OF_TEXT_CHANGE specific data TextChangeDataBase mTextChangeData; diff --git a/widget/gtk/IMContextWrapper.cpp b/widget/gtk/IMContextWrapper.cpp index f67deddef722..162fa8f09cae 100644 --- a/widget/gtk/IMContextWrapper.cpp +++ b/widget/gtk/IMContextWrapper.cpp @@ -883,7 +883,7 @@ IMContextWrapper::OnSelectionChange(nsWindow* aCaller, return; } - const IMENotification::SelectionChangeData& selectionChangeData = + const IMENotification::SelectionChangeDataBase& selectionChangeData = aIMENotification.mSelectionChangeData; MOZ_LOG(gGtkIMLog, LogLevel::Info, diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index a68132a4fb46..7fdbe04b7e66 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -106,14 +106,14 @@ namespace mozilla { namespace widget { void -IMENotification::SelectionChangeData::SetWritingMode( +IMENotification::SelectionChangeDataBase::SetWritingMode( const WritingMode& aWritingMode) { mWritingMode = aWritingMode.mWritingMode; } WritingMode -IMENotification::SelectionChangeData::GetWritingMode() const +IMENotification::SelectionChangeDataBase::GetWritingMode() const { return WritingMode(mWritingMode); } diff --git a/widget/nsGUIEventIPC.h b/widget/nsGUIEventIPC.h index a57ddd2b1569..476f916121e2 100644 --- a/widget/nsGUIEventIPC.h +++ b/widget/nsGUIEventIPC.h @@ -701,9 +701,9 @@ struct ParamTraits }; template<> -struct ParamTraits +struct ParamTraits { - typedef mozilla::widget::IMENotification::SelectionChangeData paramType; + typedef mozilla::widget::IMENotification::SelectionChangeDataBase paramType; static void Write(Message* aMsg, const paramType& aParam) { diff --git a/widget/windows/TSFTextStore.cpp b/widget/windows/TSFTextStore.cpp index 16c003b994fe..35d3accebe59 100644 --- a/widget/windows/TSFTextStore.cpp +++ b/widget/windows/TSFTextStore.cpp @@ -4508,7 +4508,7 @@ TSFTextStore::NotifyTSFOfTextChange(const TS_TEXTCHANGE& aTextChange) nsresult TSFTextStore::OnSelectionChangeInternal(const IMENotification& aIMENotification) { - const IMENotification::SelectionChangeData& selectionChangeData = + const IMENotification::SelectionChangeDataBase& selectionChangeData = aIMENotification.mSelectionChangeData; MOZ_LOG(sTextStoreLog, LogLevel::Debug, ("TSF: 0x%p TSFTextStore::OnSelectionChangeInternal(" From cc1f59a2e2d51b2a57fdcca02b72bcacbd6d01e9 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 22 Aug 2015 01:43:41 +0900 Subject: [PATCH 136/208] Bug 1189396 part.4 IMEContentObserver should cache the selection data at notifying IME of selection change r=smaug --- dom/events/IMEContentObserver.cpp | 50 ++++++++++++++++++++----------- dom/events/IMEContentObserver.h | 15 ++++++++++ widget/IMEData.h | 21 +++++++++++++ 3 files changed, 69 insertions(+), 17 deletions(-) diff --git a/dom/events/IMEContentObserver.cpp b/dom/events/IMEContentObserver.cpp index ec5d2f3b1976..ef8dd49b0170 100644 --- a/dom/events/IMEContentObserver.cpp +++ b/dom/events/IMEContentObserver.cpp @@ -852,6 +852,35 @@ IMEContentObserver::PostSelectionChangeNotification( mIsSelectionChangeEventPending = true; } +bool +IMEContentObserver::UpdateSelectionCache() +{ + MOZ_ASSERT(IsSafeToNotifyIME()); + + if (!mUpdatePreference.WantSelectionChange()) { + return false; + } + + mSelectionData.Clear(); + + // XXX Cannot we cache some information for reducing the cost to compute + // selection offset and writing mode? + WidgetQueryContentEvent selection(true, NS_QUERY_SELECTED_TEXT, mWidget); + ContentEventHandler handler(GetPresContext()); + handler.OnQuerySelectedText(&selection); + if (NS_WARN_IF(!selection.mSucceeded)) { + return false; + } + + mSelectionData.mOffset = selection.mReply.mOffset; + *mSelectionData.mString = selection.mReply.mString; + mSelectionData.SetWritingMode(selection.GetWritingMode()); + mSelectionData.mReversed = selection.mReply.mReversed; + mSelectionData.mCausedByComposition = false; + mSelectionData.mCausedBySelectionEvent = false; + return mSelectionData.IsValid(); +} + void IMEContentObserver::PostPositionChangeNotification() { @@ -1060,13 +1089,7 @@ IMEContentObserver::SelectionChangeEvent::Run() return NS_OK; } - // XXX Cannot we cache some information for reducing the cost to compute - // selection offset and writing mode? - WidgetQueryContentEvent selection(true, NS_QUERY_SELECTED_TEXT, - mIMEContentObserver->mWidget); - ContentEventHandler handler(mIMEContentObserver->GetPresContext()); - handler.OnQuerySelectedText(&selection); - if (NS_WARN_IF(!selection.mSucceeded)) { + if (NS_WARN_IF(!mIMEContentObserver->UpdateSelectionCache())) { return NS_OK; } @@ -1076,15 +1099,8 @@ IMEContentObserver::SelectionChangeEvent::Run() } IMENotification notification(NOTIFY_IME_OF_SELECTION_CHANGE); - notification.mSelectionChangeData.mOffset = selection.mReply.mOffset; - *notification.mSelectionChangeData.mString = selection.mReply.mString; - notification.mSelectionChangeData.SetWritingMode( - selection.GetWritingMode()); - notification.mSelectionChangeData.mReversed = selection.mReply.mReversed; - notification.mSelectionChangeData.mCausedByComposition = - mCausedByComposition; - notification.mSelectionChangeData.mCausedBySelectionEvent = - mCausedBySelectionEvent; + notification.SetData(mIMEContentObserver->mSelectionData, + mCausedByComposition, mCausedBySelectionEvent); IMEStateManager::NotifyIME(notification, mIMEContentObserver->mWidget); return NS_OK; } @@ -1106,7 +1122,7 @@ IMEContentObserver::TextChangeEvent::Run() } IMENotification notification(NOTIFY_IME_OF_TEXT_CHANGE); - notification.mTextChangeData = mTextChangeData; + notification.SetData(mTextChangeData); IMEStateManager::NotifyIME(notification, mIMEContentObserver->mWidget); return NS_OK; } diff --git a/dom/events/IMEContentObserver.h b/dom/events/IMEContentObserver.h index 77e09f8408a6..b22c6d7e88a6 100644 --- a/dom/events/IMEContentObserver.h +++ b/dom/events/IMEContentObserver.h @@ -40,6 +40,7 @@ class IMEContentObserver final : public nsISelectionListener , public nsIEditorObserver { public: + typedef widget::IMENotification::SelectionChangeData SelectionChangeData; typedef widget::IMENotification::TextChangeData TextChangeData; typedef widget::IMENotification::TextChangeDataBase TextChangeDataBase; @@ -167,6 +168,15 @@ class IMEContentObserver final : public nsISelectionListener mTextChangeData.Clear(); } + /** + * UpdateSelectionCache() updates mSelectionData with the latest selection. + * This should be called only when IsSafeToNotifyIME() returns true. + * + * Note that this does nothing if mUpdatePreference.WantSelectionChange() + * returns false. + */ + bool UpdateSelectionCache(); + nsCOMPtr mWidget; nsCOMPtr mSelection; nsCOMPtr mRootContent; @@ -230,6 +240,11 @@ class IMEContentObserver final : public nsISelectionListener TextChangeData mTextChangeData; + // mSelectionData is the last selection data which was notified. This is + // modified by UpdateSelectionCache(). Note that mCausedBy* are always + // false. Do NOT refer them. + SelectionChangeData mSelectionData; + EventStateManager* mESM; nsIMEUpdatePreference mUpdatePreference; diff --git a/widget/IMEData.h b/widget/IMEData.h index efa798c26870..c0b0ba841276 100644 --- a/widget/IMEData.h +++ b/widget/IMEData.h @@ -757,6 +757,27 @@ struct IMENotification final MouseButtonEventData mMouseButtonEventData; }; + void SetData(const SelectionChangeDataBase& aSelectionChangeData) + { + MOZ_RELEASE_ASSERT(mMessage == NOTIFY_IME_OF_SELECTION_CHANGE); + mSelectionChangeData.Assign(aSelectionChangeData); + } + void SetData(const SelectionChangeDataBase& aSelectionChangeData, + bool aCausedByComposition, + bool aCausedBySelectionEvent) + { + MOZ_RELEASE_ASSERT(mMessage == NOTIFY_IME_OF_SELECTION_CHANGE); + mSelectionChangeData.Assign(aSelectionChangeData); + mSelectionChangeData.mCausedByComposition = aCausedByComposition; + mSelectionChangeData.mCausedBySelectionEvent = aCausedBySelectionEvent; + } + + void SetData(const TextChangeDataBase& aTextChangeData) + { + MOZ_RELEASE_ASSERT(mMessage == NOTIFY_IME_OF_TEXT_CHANGE); + mTextChangeData = aTextChangeData; + } + bool IsCausedByComposition() const { switch (mMessage) { From 878bfb055b4649207efbb1450e406fe66ba248b2 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 22 Aug 2015 01:43:42 +0900 Subject: [PATCH 137/208] Bug 1189396 part.5 IMEContentObserver should cache selection at gets focus and every selection change r=smaug --- dom/events/IMEContentObserver.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/dom/events/IMEContentObserver.cpp b/dom/events/IMEContentObserver.cpp index ef8dd49b0170..35d45e18dcea 100644 --- a/dom/events/IMEContentObserver.cpp +++ b/dom/events/IMEContentObserver.cpp @@ -409,16 +409,11 @@ IMEContentObserver::NotifySelectionChanged(nsIDOMDocument* aDOMDocument, nsISelection* aSelection, int16_t aReason) { - bool causedByComposition = IsEditorHandlingEventForComposition(); - if (causedByComposition && - !mUpdatePreference.WantChangesCausedByComposition()) { - return NS_OK; - } - int32_t count = 0; nsresult rv = aSelection->GetRangeCount(&count); NS_ENSURE_SUCCESS(rv, rv); if (count > 0 && mWidget) { + bool causedByComposition = IsEditorHandlingEventForComposition(); bool causedBySelectionEvent = TextComposition::IsHandlingSelectionEvent(); MaybeNotifyIMEOfSelectionChange(causedByComposition, causedBySelectionEvent); @@ -1067,6 +1062,8 @@ IMEContentObserver::FocusSetEvent::Run() } mIMEContentObserver->mIMEHasFocus = true; + // Initialize selection cache with the first selection data. + mIMEContentObserver->UpdateSelectionCache(); IMEStateManager::NotifyIME(IMENotification(NOTIFY_IME_OF_FOCUS), mIMEContentObserver->mWidget); return NS_OK; @@ -1093,6 +1090,14 @@ IMEContentObserver::SelectionChangeEvent::Run() return NS_OK; } + // If the IME doesn't want selection change notifications caused by + // composition, we should do nothing anymore. + if (mCausedByComposition && + !mIMEContentObserver-> + mUpdatePreference.WantChangesCausedByComposition()) { + return NS_OK; + } + // The state may be changed since querying content causes flushing layout. if (!CanNotifyIME()) { return NS_OK; From b84e64ba1bc514327b5fedb32eb5ebc52de44337 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 22 Aug 2015 01:43:42 +0900 Subject: [PATCH 138/208] Bug 1189396 part.6 IMEContentObserver shouldn't notify IME of selection change when the range isn't actually changed r=smaug --- dom/events/IMEContentObserver.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dom/events/IMEContentObserver.cpp b/dom/events/IMEContentObserver.cpp index 35d45e18dcea..54625a5f56cc 100644 --- a/dom/events/IMEContentObserver.cpp +++ b/dom/events/IMEContentObserver.cpp @@ -1086,6 +1086,7 @@ IMEContentObserver::SelectionChangeEvent::Run() return NS_OK; } + SelectionChangeData lastSelChangeData = mIMEContentObserver->mSelectionData; if (NS_WARN_IF(!mIMEContentObserver->UpdateSelectionCache())) { return NS_OK; } @@ -1103,6 +1104,17 @@ IMEContentObserver::SelectionChangeEvent::Run() return NS_OK; } + // If the selection isn't changed actually, we shouldn't notify IME of + // selection change. + SelectionChangeData& newSelChangeData = mIMEContentObserver->mSelectionData; + if (lastSelChangeData.IsValid() && + lastSelChangeData.mOffset == newSelChangeData.mOffset && + lastSelChangeData.String() == newSelChangeData.String() && + lastSelChangeData.GetWritingMode() == newSelChangeData.GetWritingMode() && + lastSelChangeData.mReversed == newSelChangeData.mReversed) { + return NS_OK; + } + IMENotification notification(NOTIFY_IME_OF_SELECTION_CHANGE); notification.SetData(mIMEContentObserver->mSelectionData, mCausedByComposition, mCausedBySelectionEvent); From e8e4a8fd159dd0fdf677b944bad73e717a6a3fc7 Mon Sep 17 00:00:00 2001 From: dimi Date: Thu, 20 Aug 2015 18:20:19 +0800 Subject: [PATCH 139/208] Bug 1189235 - Use originAttribute for ServiceWorkerRegistrar. r=baku --- dom/workers/ServiceWorkerRegistrar.cpp | 34 ++++++++---------------- dom/workers/ServiceWorkerRegistrar.h | 2 +- dom/workers/test/gtest/TestReadWrite.cpp | 19 ++++++++----- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/dom/workers/ServiceWorkerRegistrar.cpp b/dom/workers/ServiceWorkerRegistrar.cpp index ccef21f565da..a215d220960a 100644 --- a/dom/workers/ServiceWorkerRegistrar.cpp +++ b/dom/workers/ServiceWorkerRegistrar.cpp @@ -322,25 +322,17 @@ ServiceWorkerRegistrar::ReadData() return NS_ERROR_FAILURE; \ } - GET_LINE(line); - - uint32_t appId = line.ToInteger(&rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - GET_LINE(line); + nsAutoCString suffix; + GET_LINE(suffix); - if (!line.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE) && - !line.EqualsLiteral(SERVICEWORKERREGISTRAR_FALSE)) { - return NS_ERROR_FAILURE; + OriginAttributes attrs; + if (!attrs.PopulateFromSuffix(suffix)) { + return NS_ERROR_INVALID_ARG; } - bool isInBrowserElement = line.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE); - GET_LINE(line); entry->principal() = - mozilla::ipc::ContentPrincipalInfo(appId, isInBrowserElement, line); + mozilla::ipc::ContentPrincipalInfo(attrs.mAppId, attrs.mInBrowser, line); GET_LINE(entry->scope()); GET_LINE(entry->scriptSpec()); @@ -555,19 +547,15 @@ ServiceWorkerRegistrar::WriteData() const mozilla::ipc::ContentPrincipalInfo& cInfo = info.get_ContentPrincipalInfo(); + OriginAttributes attrs(cInfo.appId(), cInfo.isInBrowserElement()); + nsAutoCString suffix; + attrs.CreateSuffix(suffix); + buffer.Truncate(); - buffer.AppendInt(cInfo.appId()); + buffer.Append(suffix.get()); buffer.Append('\n'); - if (cInfo.isInBrowserElement()) { - buffer.AppendLiteral(SERVICEWORKERREGISTRAR_TRUE); - } else { - buffer.AppendLiteral(SERVICEWORKERREGISTRAR_FALSE); - } - - buffer.Append('\n'); buffer.Append(cInfo.spec()); - buffer.Append('\n'); buffer.Append(data[i].scope()); diff --git a/dom/workers/ServiceWorkerRegistrar.h b/dom/workers/ServiceWorkerRegistrar.h index fcdc3b981566..13f0e471d7ed 100644 --- a/dom/workers/ServiceWorkerRegistrar.h +++ b/dom/workers/ServiceWorkerRegistrar.h @@ -16,7 +16,7 @@ #include "nsTArray.h" #define SERVICEWORKERREGISTRAR_FILE "serviceworker.txt" -#define SERVICEWORKERREGISTRAR_VERSION "1" +#define SERVICEWORKERREGISTRAR_VERSION "2" #define SERVICEWORKERREGISTRAR_TERMINATOR "#" #define SERVICEWORKERREGISTRAR_TRUE "true" #define SERVICEWORKERREGISTRAR_FALSE "false" diff --git a/dom/workers/test/gtest/TestReadWrite.cpp b/dom/workers/test/gtest/TestReadWrite.cpp index 38ad9aa64abb..9955dec89527 100644 --- a/dom/workers/test/gtest/TestReadWrite.cpp +++ b/dom/workers/test/gtest/TestReadWrite.cpp @@ -5,6 +5,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "gtest/gtest.h" +#include "mozilla/BasePrincipal.h" #include "mozilla/dom/ServiceWorkerRegistrar.h" #include "mozilla/dom/ServiceWorkerRegistrarTypes.h" #include "mozilla/ipc/PBackgroundSharedTypes.h" @@ -140,11 +141,11 @@ TEST(ServiceWorkerRegistrar, TestReadData) { nsAutoCString buffer(SERVICEWORKERREGISTRAR_VERSION "\n"); - buffer.Append("123\n" SERVICEWORKERREGISTRAR_TRUE "\n"); + buffer.Append("^appId=123&inBrowser=1\n"); buffer.Append("spec 0\nscope 0\nscriptSpec 0\ncurrentWorkerURL 0\nactiveCache 0\nwaitingCache 0\n"); buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n"); - buffer.Append("0\n" SERVICEWORKERREGISTRAR_FALSE "\n"); + buffer.Append("\n"); buffer.Append("spec 1\nscope 1\nscriptSpec 1\ncurrentWorkerURL 1\nactiveCache 1\nwaitingCache 1\n"); buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n"); @@ -162,8 +163,11 @@ TEST(ServiceWorkerRegistrar, TestReadData) ASSERT_EQ(info0.type(), mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) << "First principal must be content"; const mozilla::ipc::ContentPrincipalInfo& cInfo0 = data[0].principal(); - ASSERT_EQ((uint32_t)123, cInfo0.appId()); - ASSERT_EQ((uint32_t)true, cInfo0.isInBrowserElement()); + mozilla::OriginAttributes attrs0(cInfo0.appId(), cInfo0.isInBrowserElement()); + nsAutoCString suffix0; + attrs0.CreateSuffix(suffix0); + + ASSERT_STREQ("^appId=123&inBrowser=1", suffix0.get()); ASSERT_STREQ("spec 0", cInfo0.spec().get()); ASSERT_STREQ("scope 0", data[0].scope().get()); ASSERT_STREQ("scriptSpec 0", data[0].scriptSpec().get()); @@ -175,8 +179,11 @@ TEST(ServiceWorkerRegistrar, TestReadData) ASSERT_EQ(info1.type(), mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) << "First principal must be content"; const mozilla::ipc::ContentPrincipalInfo& cInfo1 = data[1].principal(); - ASSERT_EQ((uint32_t)0, cInfo1.appId()); - ASSERT_EQ((uint32_t)false, cInfo1.isInBrowserElement()); + mozilla::OriginAttributes attrs1(cInfo1.appId(), cInfo1.isInBrowserElement()); + nsAutoCString suffix1; + attrs1.CreateSuffix(suffix1); + + ASSERT_STREQ("", suffix1.get()); ASSERT_STREQ("spec 1", cInfo1.spec().get()); ASSERT_STREQ("scope 1", data[1].scope().get()); ASSERT_STREQ("scriptSpec 1", data[1].scriptSpec().get()); From bd2b290caace2eb79361bdbf64066f2e6510c527 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Fri, 21 Aug 2015 13:21:58 -0400 Subject: [PATCH 140/208] Bug 1195401 - Use gfxPrefs (threadsafe) rather than crashing on debug builds for off-main-thread pref access. r=snorp --- gfx/gl/AndroidSurfaceTexture.cpp | 4 ++-- gfx/thebes/gfxPrefs.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/gfx/gl/AndroidSurfaceTexture.cpp b/gfx/gl/AndroidSurfaceTexture.cpp index 2537046571d1..e7fa1cc21c7b 100644 --- a/gfx/gl/AndroidSurfaceTexture.cpp +++ b/gfx/gl/AndroidSurfaceTexture.cpp @@ -11,13 +11,13 @@ #include #include "AndroidSurfaceTexture.h" #include "gfxImageSurface.h" +#include "gfxPrefs.h" #include "AndroidBridge.h" #include "nsThreadUtils.h" #include "mozilla/gfx/Matrix.h" #include "GeneratedJNIWrappers.h" #include "SurfaceTexture.h" #include "GLContext.h" -#include "mozilla/Preferences.h" using namespace mozilla; using namespace mozilla::jni; @@ -132,7 +132,7 @@ AndroidSurfaceTexture::UpdateCanDetach() // The API for attach/detach only exists on 16+, and PowerVR has some sort of // fencing issue. Additionally, attach/detach seems to be busted on at least some // Mali adapters (400MP2 for sure, bug 1131793) - bool canDetach = Preferences::GetBool("gfx.SurfaceTexture.detach.enabled", true); + bool canDetach = gfxPrefs::SurfaceTextureDetachEnabled(); mCanDetach = AndroidBridge::Bridge()->GetAPIVersion() >= 16 && (!mAttachedContext || mAttachedContext->Vendor() != GLVendor::Imagination) && diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index 820387cae35e..d99bcec0f815 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -240,6 +240,7 @@ class gfxPrefs final // Note that "gfx.logging.level" is defined in Logging.h DECL_GFX_PREF(Once, "gfx.logging.crash.length", GfxLoggingCrashLength, uint32_t, 6); DECL_GFX_PREF(Live, "gfx.perf-warnings.enabled", PerfWarnings, bool, false); + DECL_GFX_PREF(Live, "gfx.SurfaceTexture.detach.enabled", SurfaceTextureDetachEnabled, bool, true); DECL_GFX_PREF(Live, "gfx.testing.device-reset", DeviceResetForTesting, int32_t, 0); DECL_GFX_PREF(Live, "gfx.testing.device-fail", DeviceFailForTesting, bool, false); From a57f3661e1e2689bdc7a86935ad0c6e565bd537a Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Fri, 21 Aug 2015 13:21:58 -0400 Subject: [PATCH 141/208] Bug 1197233 - When fullscreening a video make sure we don't show garbage in the toolbar area. r=rbarker --- .../android/base/gfx/DynamicToolbarAnimator.java | 14 +++++++++++++- mobile/android/base/gfx/GeckoLayerClient.java | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/mobile/android/base/gfx/DynamicToolbarAnimator.java b/mobile/android/base/gfx/DynamicToolbarAnimator.java index 079f7fdb66c4..e9c6ba883b6a 100644 --- a/mobile/android/base/gfx/DynamicToolbarAnimator.java +++ b/mobile/android/base/gfx/DynamicToolbarAnimator.java @@ -235,9 +235,17 @@ public void run() { } IntSize getViewportSize() { + ThreadUtils.assertOnUiThread(); + int viewWidth = mTarget.getView().getWidth(); int viewHeight = mTarget.getView().getHeight(); - int viewHeightVisible = viewHeight - Math.round(mMaxTranslation - mToolbarTranslation); + float toolbarTranslation = mToolbarTranslation; + if (mAnimationTask != null) { + // If we have an animation going, mToolbarTranslation may be in flux + // and we should use the final value it will settle on. + toolbarTranslation = mAnimationTask.getFinalToolbarTranslation(); + } + int viewHeightVisible = viewHeight - Math.round(mMaxTranslation - toolbarTranslation); return new IntSize(viewWidth, viewHeightVisible); } @@ -482,6 +490,10 @@ public DynamicToolbarAnimationTask(float aTranslation, boolean aImmediate, boole mShiftLayerView = aShiftLayerView; } + float getFinalToolbarTranslation() { + return mEndTranslation; + } + @Override public boolean internalRun(long timeDelta, long currentFrameStartTime) { if (!mContinueAnimation) { diff --git a/mobile/android/base/gfx/GeckoLayerClient.java b/mobile/android/base/gfx/GeckoLayerClient.java index effedc50b9e8..01083459f580 100644 --- a/mobile/android/base/gfx/GeckoLayerClient.java +++ b/mobile/android/base/gfx/GeckoLayerClient.java @@ -221,7 +221,7 @@ boolean setViewportSize(int width, int height, PointF scrollChange) { } mViewportMetrics = mViewportMetrics.setViewportSize(width, height); if (scrollChange != null) { - mViewportMetrics = mViewportMetrics.offsetViewportBy(scrollChange.x, scrollChange.y); + mViewportMetrics = mViewportMetrics.offsetViewportByAndClamp(scrollChange.x, scrollChange.y); } if (mGeckoIsReady) { From e0a8386eeeb0cae73dbcc25ba1acf245ccf0da85 Mon Sep 17 00:00:00 2001 From: Neil Deakin Date: Fri, 21 Aug 2015 13:30:04 -0400 Subject: [PATCH 142/208] Bug 1195931, use option.text instead of option.textContent so that spaces get handled properly in select lists, r=felipe --- .../test/general/browser_selectpopup.js | 18 +++++++++++------- toolkit/modules/SelectContentHelper.jsm | 9 +++------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/browser/base/content/test/general/browser_selectpopup.js b/browser/base/content/test/general/browser_selectpopup.js index 253bc9a35ff7..6e043d9139d6 100644 --- a/browser/base/content/test/general/browser_selectpopup.js +++ b/browser/base/content/test/general/browser_selectpopup.js @@ -5,6 +5,8 @@ // in a child process. This is different than single-process as a is used // to implement the dropdown list. +const XHTML_DTD = ''; + const PAGECONTENT = "" + "" + ""; @@ -58,11 +60,11 @@ function getChangeEvents() }); } -function doSelectTests(contentType) +function doSelectTests(contentType, dtd) { let tab = gBrowser.selectedTab = gBrowser.addTab(); let browser = gBrowser.getBrowserForTab(tab); - yield promiseTabLoadEvent(tab, "data:" + contentType + "," + escape(PAGECONTENT)); + yield promiseTabLoadEvent(tab, "data:" + contentType + "," + escape(dtd + "\n" + PAGECONTENT)); yield SimpleTest.promiseFocus(browser.contentWindow); @@ -127,15 +129,17 @@ function doSelectTests(contentType) EventUtils.synthesizeKey("VK_TAB", { shiftKey: true }); is((yield getChangeEvents()), isWindows ? 2 : 1, "Tab away from select with change - number of change events"); + is(selectPopup.lastChild.previousSibling.label, "Seven", "Spaces collapsed"); + is(selectPopup.lastChild.label, "\xA0\xA0Eight\xA0\xA0", "Non-breaking spaces not collapsed"); + gBrowser.removeCurrentTab(); } add_task(function*() { - yield doSelectTests("text/html"); + yield doSelectTests("text/html", ""); }); add_task(function*() { - yield doSelectTests("application/xhtml+xml"); + yield doSelectTests("application/xhtml+xml", XHTML_DTD); }); - diff --git a/toolkit/modules/SelectContentHelper.jsm b/toolkit/modules/SelectContentHelper.jsm index 4bc6a781236f..fb3e0c840d56 100644 --- a/toolkit/modules/SelectContentHelper.jsm +++ b/toolkit/modules/SelectContentHelper.jsm @@ -101,12 +101,9 @@ function buildOptionListForChildren(node) { if (tagName == 'OPTION' || tagName == 'OPTGROUP') { let textContent = tagName == 'OPTGROUP' ? child.getAttribute("label") - : child.textContent; - - if (textContent != null) { - textContent = textContent.trim(); - } else { - textContent = "" + : child.text; + if (textContent == null) { + textContent = ""; } let info = { From 08569b98cfefc6a26347fdb2d3c6d73e7b948e32 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Fri, 21 Aug 2015 20:35:02 +0300 Subject: [PATCH 143/208] Backout Bug 1166347 (pointer events on nightlies) because of crashes (see Bug 1181564), r=khuey --- b2g/app/b2g.js | 5 ----- b2g/dev/app/mulet.js | 5 ----- browser/app/profile/firefox.js | 11 ++--------- dom/tests/mochitest/general/test_interfaces.html | 2 +- modules/libpref/init/all.js | 5 +++-- 5 files changed, 6 insertions(+), 22 deletions(-) diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index 8c23d4cd1255..9c06756c087a 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -352,11 +352,6 @@ pref("dom.w3c_touch_events.enabled", 1); pref("dom.w3c_touch_events.safetyX", 0); // escape borders in units of 1/240" pref("dom.w3c_touch_events.safetyY", 120); // escape borders in units of 1/240" -// W3C draft pointer events -pref("dom.w3c_pointer_events.enabled", false); -// W3C touch-action css property (related to touch and pointer events) -pref("layout.css.touch_action.enabled", false); - #ifdef MOZ_SAFE_BROWSING // Safe browsing does nothing unless this pref is set pref("browser.safebrowsing.enabled", false); diff --git a/b2g/dev/app/mulet.js b/b2g/dev/app/mulet.js index 5d59c1e18760..7be519855249 100644 --- a/b2g/dev/app/mulet.js +++ b/b2g/dev/app/mulet.js @@ -18,8 +18,3 @@ pref("devtools.toolbox.sidebar.width", 800); pref("browser.tabs.remote.autostart", false); pref("browser.tabs.remote.autostart.1", false); pref("browser.tabs.remote.autostart.2", false); - -// W3C draft pointer events -pref("dom.w3c_pointer_events.enabled", false); -// W3C touch-action css property (related to touch and pointer events) -pref("layout.css.touch_action.enabled", false); diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 9bf0bcc1dea8..fd70598c1fd7 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -489,17 +489,10 @@ pref("dom.disable_window_move_resize", false); // prevent JS from monkeying with window focus, etc pref("dom.disable_window_flip", true); -// Disable touch events on Desktop Firefox by default -// until they are properly supported (bug 736048) +// Disable touch events on Desktop Firefox by default until they are properly +// supported (bug 736048) pref("dom.w3c_touch_events.enabled", 0); -#ifdef NIGHTLY_BUILD -// W3C draft pointer events -pref("dom.w3c_pointer_events.enabled", true); -// W3C touch-action css property (related to touch and pointer events) -pref("layout.css.touch_action.enabled", true); -#endif - // popups.policy 1=allow,2=reject pref("privacy.popups.policy", 1); pref("privacy.popups.usecustom", true); diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index 352265c038c4..7aa79b57425c 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -910,7 +910,7 @@ // IMPORTANT: Do not change this list without review from a DOM peer! "PluginArray", // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "PointerEvent", nightly: true, desktop: true}, + {name: "PointerEvent", nightly: true, desktop: true, disabled: true}, // IMPORTANT: Do not change this list without review from a DOM peer! "PopStateEvent", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index e430afda0537..6992ca0e7dc9 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4525,12 +4525,13 @@ pref("dom.w3c_touch_events.enabled", 2); // W3C draft pointer events pref("dom.w3c_pointer_events.enabled", false); -// W3C touch-action css property (related to touch and pointer events) -pref("layout.css.touch_action.enabled", false); // W3C draft ImageCapture API pref("dom.imagecapture.enabled", false); +// W3C touch-action css property (related to touch and pointer events) +pref("layout.css.touch_action.enabled", false); + // Enables some assertions in nsStyleContext that are too expensive // for general use, but might be useful to enable for specific tests. // This only has an effect in DEBUG-builds. From 51dc6a6d4262024ee442bd6a4cbca0933741fd75 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Fri, 21 Aug 2015 11:40:15 -0600 Subject: [PATCH 144/208] Bug 1190733 - Test initializedLength() instead of length() during the fast path for reversing unboxed arrays, r=jandem. --- js/src/jit-test/tests/basic/bug1190733.js | 7 +++++++ js/src/jsarray.cpp | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 js/src/jit-test/tests/basic/bug1190733.js diff --git a/js/src/jit-test/tests/basic/bug1190733.js b/js/src/jit-test/tests/basic/bug1190733.js new file mode 100644 index 000000000000..2b3f4a419df8 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug1190733.js @@ -0,0 +1,7 @@ + +x = []; +Array.prototype.push.call(x, Uint8ClampedArray); +(function() { + x.length = 9; +})(); +Array.prototype.reverse.call(x); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 94f74281e1fb..e2e9e9533005 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1250,10 +1250,10 @@ ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length) /* Fill out the array's initialized length to its proper length. */ obj->as().ensureDenseInitializedLength(cx, length, 0); } else { - // Unboxed arrays can only be reversed if their initialized length + // Unboxed arrays can only be reversed here if their initialized length // matches their actual length. Otherwise the reversal will place holes // at the beginning of the array, which we don't support. - if (length != obj->as().length()) + if (length != obj->as().initializedLength()) return DenseElementResult::Incomplete; } From 6adf8c4425e7d664fd4ecfc574054a6d3642d98d Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Fri, 21 Aug 2015 11:49:50 -0600 Subject: [PATCH 145/208] Bug 1176451 - Optimize Array.concat when used on different types of boxed vs. unboxed arrays, r=jandem. --- js/src/jit/BaselineIC.cpp | 48 +++++++--- js/src/jit/CodeGenerator.cpp | 21 ++--- js/src/jit/MCallOptimize.cpp | 20 ++--- js/src/jit/MIR.h | 23 +++-- js/src/jsarray.cpp | 84 +++++++++++++---- js/src/vm/UnboxedObject-inl.h | 164 ++++++++++++++++++++++++++++------ js/src/vm/UnboxedObject.cpp | 24 +++-- 7 files changed, 291 insertions(+), 93 deletions(-) diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index f20a532ad12b..78e1a1d7a292 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -8829,7 +8829,7 @@ TryAttachFunCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, static bool GetTemplateObjectForNative(JSContext* cx, Native native, const CallArgs& args, - MutableHandleObject res) + MutableHandleObject res, bool* skipAttach) { // Check for natives to which template objects can be attached. This is // done to provide templates to Ion for inlining these natives later on. @@ -8845,10 +8845,17 @@ GetTemplateObjectForNative(JSContext* cx, Native native, const CallArgs& args, count = args[0].toInt32(); if (count <= ArrayObject::EagerAllocationMaxLength) { + ObjectGroup* group = ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array); + if (!group) + return false; + if (group->maybePreliminaryObjects()) { + *skipAttach = true; + return true; + } + // With this and other array templates, set forceAnalyze so that we // don't end up with a template whose structure might change later. - res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, count, TenuredObject, - /* forceAnalyze = */ true)); + res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, count, TenuredObject)); if (!res) return false; return true; @@ -8856,17 +8863,30 @@ GetTemplateObjectForNative(JSContext* cx, Native native, const CallArgs& args, } if (native == js::array_concat || native == js::array_slice) { - if (args.thisv().isObject() && !args.thisv().toObject().isSingleton()) { - res.set(NewFullyAllocatedArrayTryReuseGroup(cx, &args.thisv().toObject(), 0, - TenuredObject, /* forceAnalyze = */ true)); - if (!res) - return false; + if (args.thisv().isObject()) { + JSObject* obj = &args.thisv().toObject(); + if (!obj->isSingleton()) { + if (obj->group()->maybePreliminaryObjects()) { + *skipAttach = true; + return true; + } + res.set(NewFullyAllocatedArrayTryReuseGroup(cx, &args.thisv().toObject(), 0, + TenuredObject)); + return !!res; + } } } if (native == js::str_split && args.length() == 1 && args[0].isString()) { - res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, 0, TenuredObject, - /* forceAnalyze = */ true)); + ObjectGroup* group = ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array); + if (!group) + return false; + if (group->maybePreliminaryObjects()) { + *skipAttach = true; + return true; + } + + res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, 0, TenuredObject)); if (!res) return false; return true; @@ -9165,9 +9185,15 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb RootedObject templateObject(cx); if (MOZ_LIKELY(!isSpread)) { + bool skipAttach = false; CallArgs args = CallArgsFromVp(argc, vp); - if (!GetTemplateObjectForNative(cx, fun->native(), args, &templateObject)) + if (!GetTemplateObjectForNative(cx, fun->native(), args, &templateObject, &skipAttach)) return false; + if (skipAttach) { + *handled = true; + return true; + } + MOZ_ASSERT_IF(templateObject, !templateObject->group()->maybePreliminaryObjects()); } JitSpew(JitSpew_BaselineIC, " Generating Call_Native stub (fun=%p, cons=%s, spread=%s)", diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index a63820f05f39..87bbe8bc4251 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -7242,22 +7242,23 @@ CodeGenerator::visitArrayConcat(LArrayConcat* lir) // inline and pass it to the stub. Else, we just pass nullptr and the stub falls // back to a slow path. Label fail, call; - if (lir->mir()->unboxedType() == JSVAL_TYPE_MAGIC) { - masm.loadPtr(Address(lhs, NativeObject::offsetOfElements()), temp1); - masm.load32(Address(temp1, ObjectElements::offsetOfInitializedLength()), temp2); - masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail); - - masm.loadPtr(Address(rhs, NativeObject::offsetOfElements()), temp1); - masm.load32(Address(temp1, ObjectElements::offsetOfInitializedLength()), temp2); - masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail); - } else { + if (lir->mir()->unboxedThis()) { masm.load32(Address(lhs, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), temp1); masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp1); masm.branch32(Assembler::NotEqual, Address(lhs, UnboxedArrayObject::offsetOfLength()), temp1, &fail); - + } else { + masm.loadPtr(Address(lhs, NativeObject::offsetOfElements()), temp1); + masm.load32(Address(temp1, ObjectElements::offsetOfInitializedLength()), temp2); + masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail); + } + if (lir->mir()->unboxedArg()) { masm.load32(Address(rhs, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), temp1); masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp1); masm.branch32(Assembler::NotEqual, Address(rhs, UnboxedArrayObject::offsetOfLength()), temp1, &fail); + } else { + masm.loadPtr(Address(rhs, NativeObject::offsetOfElements()), temp1); + masm.load32(Address(temp1, ObjectElements::offsetOfInitializedLength()), temp2); + masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail); } // Try to allocate an object. diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 807180dd2deb..370145c2bee3 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -862,9 +862,10 @@ IonBuilder::inlineArrayConcat(CallInfo& callInfo) if (!thisTypes || !argTypes) return InliningStatus_NotInlined; - const Class* clasp = thisTypes->getKnownClass(constraints()); - if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_) + const Class* thisClasp = thisTypes->getKnownClass(constraints()); + if (thisClasp != &ArrayObject::class_ && thisClasp != &UnboxedArrayObject::class_) return InliningStatus_NotInlined; + bool unboxedThis = (thisClasp == &UnboxedArrayObject::class_); if (thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES | OBJECT_FLAG_LENGTH_OVERFLOW)) { @@ -872,8 +873,10 @@ IonBuilder::inlineArrayConcat(CallInfo& callInfo) return InliningStatus_NotInlined; } - if (argTypes->getKnownClass(constraints()) != clasp) + const Class* argClasp = argTypes->getKnownClass(constraints()); + if (argClasp != &ArrayObject::class_ && argClasp != &UnboxedArrayObject::class_) return InliningStatus_NotInlined; + bool unboxedArg = (argClasp == &UnboxedArrayObject::class_); if (argTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES | OBJECT_FLAG_LENGTH_OVERFLOW)) { @@ -881,15 +884,6 @@ IonBuilder::inlineArrayConcat(CallInfo& callInfo) return InliningStatus_NotInlined; } - JSValueType unboxedType = JSVAL_TYPE_MAGIC; - if (clasp == &UnboxedArrayObject::class_) { - unboxedType = UnboxedArrayElementType(constraints(), thisArg, nullptr); - if (unboxedType == JSVAL_TYPE_MAGIC) - return InliningStatus_NotInlined; - if (unboxedType != UnboxedArrayElementType(constraints(), objArg, nullptr)) - return InliningStatus_NotInlined; - } - // Watch out for indexed properties on the prototype. if (ArrayPrototypeHasIndexedProperty(this, script())) { trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps); @@ -956,7 +950,7 @@ IonBuilder::inlineArrayConcat(CallInfo& callInfo) MArrayConcat* ins = MArrayConcat::New(alloc(), constraints(), thisArg, objArg, templateObj, templateObj->group()->initialHeap(constraints()), - unboxedType); + unboxedThis, unboxedArg); current->add(ins); current->push(ins); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index f34a840c38fe..0284e018440a 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -9217,14 +9217,16 @@ class MArrayConcat { CompilerObject templateObj_; gc::InitialHeap initialHeap_; - JSValueType unboxedType_; + bool unboxedThis_, unboxedArg_; MArrayConcat(CompilerConstraintList* constraints, MDefinition* lhs, MDefinition* rhs, - JSObject* templateObj, gc::InitialHeap initialHeap, JSValueType unboxedType) + JSObject* templateObj, gc::InitialHeap initialHeap, + bool unboxedThis, bool unboxedArg) : MBinaryInstruction(lhs, rhs), templateObj_(templateObj), initialHeap_(initialHeap), - unboxedType_(unboxedType) + unboxedThis_(unboxedThis), + unboxedArg_(unboxedArg) { setResultType(MIRType_Object); setResultTypeSet(MakeSingletonTypeSet(constraints, templateObj)); @@ -9236,10 +9238,10 @@ class MArrayConcat static MArrayConcat* New(TempAllocator& alloc, CompilerConstraintList* constraints, MDefinition* lhs, MDefinition* rhs, JSObject* templateObj, gc::InitialHeap initialHeap, - JSValueType unboxedType) + bool unboxedThis, bool unboxedArg) { return new(alloc) MArrayConcat(constraints, lhs, rhs, templateObj, - initialHeap, unboxedType); + initialHeap, unboxedThis, unboxedArg); } JSObject* templateObj() const { @@ -9250,12 +9252,17 @@ class MArrayConcat return initialHeap_; } - JSValueType unboxedType() const { - return unboxedType_; + bool unboxedThis() const { + return unboxedThis_; + } + + bool unboxedArg() const { + return unboxedArg_; } AliasSet getAliasSet() const override { - return AliasSet::Store(AliasSet::BoxedOrUnboxedElements(unboxedType()) | + return AliasSet::Store(AliasSet::BoxedOrUnboxedElements(unboxedThis() ? JSVAL_TYPE_INT32 : JSVAL_TYPE_MAGIC) | + AliasSet::BoxedOrUnboxedElements(unboxedArg() ? JSVAL_TYPE_INT32 : JSVAL_TYPE_MAGIC) | AliasSet::ObjectFields); } bool possiblyCalls() const override { diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index e2e9e9533005..15564ccc2985 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -2532,40 +2532,41 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI return true; } -template +template DenseElementResult ArrayConcatDenseKernel(JSContext* cx, JSObject* obj1, JSObject* obj2, JSObject* result) { - uint32_t initlen1 = GetBoxedOrUnboxedInitializedLength(obj1); + uint32_t initlen1 = GetBoxedOrUnboxedInitializedLength(obj1); MOZ_ASSERT(initlen1 == GetAnyBoxedOrUnboxedArrayLength(obj1)); - uint32_t initlen2 = GetBoxedOrUnboxedInitializedLength(obj2); + uint32_t initlen2 = GetBoxedOrUnboxedInitializedLength(obj2); MOZ_ASSERT(initlen2 == GetAnyBoxedOrUnboxedArrayLength(obj2)); /* No overflow here due to nelements limit. */ uint32_t len = initlen1 + initlen2; - MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength(result) == 0); + MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength(result) == 0); - if (!EnsureBoxedOrUnboxedDenseElements(cx, result, len)) - return DenseElementResult::Failure; + DenseElementResult rv = EnsureBoxedOrUnboxedDenseElements(cx, result, len); + if (rv != DenseElementResult::Success) + return rv; - CopyBoxedOrUnboxedDenseElements(cx, result, obj1, 0, 0, initlen1); - CopyBoxedOrUnboxedDenseElements(cx, result, obj2, initlen1, 0, initlen2); + CopyBoxedOrUnboxedDenseElements(cx, result, obj1, 0, 0, initlen1); + CopyBoxedOrUnboxedDenseElements(cx, result, obj2, initlen1, 0, initlen2); SetAnyBoxedOrUnboxedArrayLength(cx, result, len); return DenseElementResult::Success; } -DefineBoxedOrUnboxedFunctor4(ArrayConcatDenseKernel, - JSContext*, JSObject*, JSObject*, JSObject*); +DefineBoxedOrUnboxedFunctorPair4(ArrayConcatDenseKernel, + JSContext*, JSObject*, JSObject*, JSObject*); bool js::array_concat_dense(JSContext* cx, HandleObject obj1, HandleObject obj2, HandleObject result) { ArrayConcatDenseKernelFunctor functor(cx, obj1, obj2, result); - DenseElementResult rv = CallBoxedOrUnboxedSpecialization(functor, result); + DenseElementResult rv = CallBoxedOrUnboxedSpecialization(functor, obj1, obj2); MOZ_ASSERT(rv != DenseElementResult::Incomplete); return rv == DenseElementResult::Success; } @@ -2596,17 +2597,63 @@ js::array_concat(JSContext* cx, unsigned argc, Value* vp) narr = NewFullyAllocatedArrayTryReuseGroup(cx, aobj, initlen); if (!narr) return false; + CopyAnyBoxedOrUnboxedDenseElements(cx, narr, aobj, 0, 0, initlen); SetAnyBoxedOrUnboxedArrayLength(cx, narr, length); - DebugOnly result = - CopyAnyBoxedOrUnboxedDenseElements(cx, narr, aobj, 0, 0, initlen); - MOZ_ASSERT(result.value == DenseElementResult::Success); - args.rval().setObject(*narr); if (argc == 0) return true; argc--; p++; + + if (length == initlen) { + while (argc) { + HandleValue v = HandleValue::fromMarkedLocation(p); + if (!v.isObject()) + break; + RootedObject obj(cx, &v.toObject()); + + // This should be IsConcatSpreadable + if (!IsArray(obj, cx) || ObjectMayHaveExtraIndexedProperties(obj)) + break; + + uint32_t argLength; + if (!GetLengthProperty(cx, obj, &argLength)) + return false; + + initlen = GetAnyBoxedOrUnboxedInitializedLength(obj); + if (argLength != initlen) + break; + + DenseElementResult result = + EnsureAnyBoxedOrUnboxedDenseElements(cx, narr, length + argLength); + if (result == DenseElementResult::Failure) + return false; + if (result == DenseElementResult::Incomplete) + break; + + SetAnyBoxedOrUnboxedInitializedLength(cx, narr, length + argLength); + + bool success = true; + for (size_t i = 0; i < initlen; i++) { + Value v = GetAnyBoxedOrUnboxedDenseElement(obj, i); + if (!InitAnyBoxedOrUnboxedDenseElement(cx, narr, length + i, v)) { + success = false; + break; + } + } + if (!success) { + SetAnyBoxedOrUnboxedInitializedLength(cx, narr, length); + break; + } + + length += argLength; + SetAnyBoxedOrUnboxedArrayLength(cx, narr, length); + + argc--; + p++; + } + } } else { narr = NewDenseEmptyArray(cx); if (!narr) @@ -2903,9 +2950,10 @@ ArraySliceDenseKernel(JSContext* cx, JSObject* obj, int32_t beginArg, int32_t en if (initlen > begin) { size_t count = Min(initlen - begin, end - begin); if (count) { - if (!EnsureBoxedOrUnboxedDenseElements(cx, result, count)) - return DenseElementResult::Failure; - CopyBoxedOrUnboxedDenseElements(cx, result, obj, 0, begin, count); + DenseElementResult rv = EnsureBoxedOrUnboxedDenseElements(cx, result, count); + if (rv != DenseElementResult::Success) + return rv; + CopyBoxedOrUnboxedDenseElements(cx, result, obj, 0, begin, count); } } diff --git a/js/src/vm/UnboxedObject-inl.h b/js/src/vm/UnboxedObject-inl.h index c02440c46622..abd824d18c26 100644 --- a/js/src/vm/UnboxedObject-inl.h +++ b/js/src/vm/UnboxedObject-inl.h @@ -272,6 +272,12 @@ UnboxedArrayObject::triggerPreBarrier(size_t index) // Combined methods for NativeObject and UnboxedArrayObject accesses. ///////////////////////////////////////////////////////////////////// +static inline bool +HasAnyBoxedOrUnboxedDenseElements(JSObject* obj) +{ + return obj->isNative() || obj->is(); +} + static inline size_t GetAnyBoxedOrUnboxedInitializedLength(JSObject* obj) { @@ -330,6 +336,16 @@ SetAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, con return obj->as().setElement(cx, index, value); } +static inline bool +InitAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value) +{ + if (obj->isNative()) { + obj->as().initDenseElementWithType(cx, index, value); + return true; + } + return obj->as().initElement(cx, index, value); +} + ///////////////////////////////////////////////////////////////////// // Template methods for NativeObject and UnboxedArrayObject accesses. ///////////////////////////////////////////////////////////////////// @@ -417,19 +433,19 @@ SetBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const } template -static inline bool +static inline DenseElementResult EnsureBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count) { if (Type == JSVAL_TYPE_MAGIC) { if (!obj->as().ensureElements(cx, count)) - return false; + return DenseElementResult::Failure; } else { if (obj->as().capacity() < count) { if (!obj->as().growElements(cx, count)) - return false; + return DenseElementResult::Failure; } } - return true; + return DenseElementResult::Success; } template @@ -547,33 +563,54 @@ MoveBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, uint32_t dstStart, return DenseElementResult::Success; } -template +template static inline DenseElementResult CopyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src, uint32_t dstStart, uint32_t srcStart, uint32_t length) { - MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(src)); - MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(dst)); - MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength(dst) == dstStart); - MOZ_ASSERT(GetBoxedOrUnboxedCapacity(dst) >= length); - - SetBoxedOrUnboxedInitializedLength(cx, dst, dstStart + length); - - if (Type == JSVAL_TYPE_MAGIC) { - const Value* vp = src->as().getDenseElements() + srcStart; - dst->as().initDenseElements(dstStart, vp, length); - } else { + MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(src)); + MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(dst)); + MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength(dst) == dstStart); + MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength(src) >= srcStart + length); + MOZ_ASSERT(GetBoxedOrUnboxedCapacity(dst) >= dstStart + length); + + SetBoxedOrUnboxedInitializedLength(cx, dst, dstStart + length); + + if (DstType == JSVAL_TYPE_MAGIC) { + if (SrcType == JSVAL_TYPE_MAGIC) { + const Value* vp = src->as().getDenseElements() + srcStart; + dst->as().initDenseElements(dstStart, vp, length); + } else { + for (size_t i = 0; i < length; i++) { + Value v = GetBoxedOrUnboxedDenseElement(src, srcStart + i); + dst->as().initDenseElement(dstStart + i, v); + } + } + } else if (DstType == SrcType) { uint8_t* dstData = dst->as().elements(); uint8_t* srcData = src->as().elements(); - size_t elementSize = UnboxedTypeSize(Type); + size_t elementSize = UnboxedTypeSize(DstType); memcpy(dstData + dstStart * elementSize, srcData + srcStart * elementSize, length * elementSize); // Add a store buffer entry if we might have copied a nursery pointer to dst. - if (UnboxedTypeNeedsPostBarrier(Type) && !IsInsideNursery(dst)) + if (UnboxedTypeNeedsPostBarrier(DstType) && !IsInsideNursery(dst)) dst->runtimeFromMainThread()->gc.storeBuffer.putWholeCellFromMainThread(dst); + } else if (DstType == JSVAL_TYPE_DOUBLE && SrcType == JSVAL_TYPE_INT32) { + uint8_t* dstData = dst->as().elements(); + uint8_t* srcData = src->as().elements(); + + for (size_t i = 0; i < length; i++) { + int32_t v = *reinterpret_cast(srcData + (srcStart + i) * sizeof(int32_t)); + *reinterpret_cast(dstData + (dstStart + i) * sizeof(double)) = v; + } + } else { + for (size_t i = 0; i < length; i++) { + Value v = GetBoxedOrUnboxedDenseElement(src, srcStart + i); + dst->as().initElementNoTypeChangeSpecific(dstStart + i, v); + } } return DenseElementResult::Success; @@ -598,19 +635,70 @@ template DenseElementResult CallBoxedOrUnboxedSpecialization(F f, JSObject* obj) { - if (HasBoxedOrUnboxedDenseElements(obj)) + if (!HasAnyBoxedOrUnboxedDenseElements(obj)) + return DenseElementResult::Incomplete; + switch (GetBoxedOrUnboxedType(obj)) { + case JSVAL_TYPE_MAGIC: return f. DEPENDENT_TEMPLATE_HINT operator()(); - if (HasBoxedOrUnboxedDenseElements(obj)) + case JSVAL_TYPE_BOOLEAN: return f. DEPENDENT_TEMPLATE_HINT operator()(); - if (HasBoxedOrUnboxedDenseElements(obj)) + case JSVAL_TYPE_INT32: return f. DEPENDENT_TEMPLATE_HINT operator()(); - if (HasBoxedOrUnboxedDenseElements(obj)) + case JSVAL_TYPE_DOUBLE: return f. DEPENDENT_TEMPLATE_HINT operator()(); - if (HasBoxedOrUnboxedDenseElements(obj)) + case JSVAL_TYPE_STRING: return f. DEPENDENT_TEMPLATE_HINT operator()(); - if (HasBoxedOrUnboxedDenseElements(obj)) + case JSVAL_TYPE_OBJECT: return f. DEPENDENT_TEMPLATE_HINT operator()(); - return DenseElementResult::Incomplete; + default: + MOZ_CRASH(); + } +} + +// As above, except the specialization can reflect the unboxed type of two objects. +template +DenseElementResult +CallBoxedOrUnboxedSpecialization(F f, JSObject* obj1, JSObject* obj2) +{ + if (!HasAnyBoxedOrUnboxedDenseElements(obj1) || !HasAnyBoxedOrUnboxedDenseElements(obj2)) + return DenseElementResult::Incomplete; + +#define SPECIALIZE_OBJ2(TYPE) \ + switch (GetBoxedOrUnboxedType(obj2)) { \ + case JSVAL_TYPE_MAGIC: \ + return f. DEPENDENT_TEMPLATE_HINT operator()(); \ + case JSVAL_TYPE_BOOLEAN: \ + return f. DEPENDENT_TEMPLATE_HINT operator()(); \ + case JSVAL_TYPE_INT32: \ + return f. DEPENDENT_TEMPLATE_HINT operator()(); \ + case JSVAL_TYPE_DOUBLE: \ + return f. DEPENDENT_TEMPLATE_HINT operator()(); \ + case JSVAL_TYPE_STRING: \ + return f. DEPENDENT_TEMPLATE_HINT operator()(); \ + case JSVAL_TYPE_OBJECT: \ + return f. DEPENDENT_TEMPLATE_HINT operator()(); \ + default: \ + MOZ_CRASH(); \ + } + + switch (GetBoxedOrUnboxedType(obj1)) { + case JSVAL_TYPE_MAGIC: + SPECIALIZE_OBJ2(JSVAL_TYPE_MAGIC) + case JSVAL_TYPE_BOOLEAN: + SPECIALIZE_OBJ2(JSVAL_TYPE_BOOLEAN) + case JSVAL_TYPE_INT32: + SPECIALIZE_OBJ2(JSVAL_TYPE_INT32) + case JSVAL_TYPE_DOUBLE: + SPECIALIZE_OBJ2(JSVAL_TYPE_DOUBLE) + case JSVAL_TYPE_STRING: + SPECIALIZE_OBJ2(JSVAL_TYPE_STRING) + case JSVAL_TYPE_OBJECT: + SPECIALIZE_OBJ2(JSVAL_TYPE_OBJECT) + default: + MOZ_CRASH(); + } + +#undef SPECIALIZE_OBJ2 } #undef DEPENDENT_TEMPLATE_HINT @@ -651,6 +739,18 @@ struct Signature ## Functor { \ } \ } +#define DefineBoxedOrUnboxedFunctorPair4(Signature, A, B, C, D) \ +struct Signature ## Functor { \ + A a; B b; C c; D d; \ + Signature ## Functor(A a, B b, C c, D d) \ + : a(a), b(b), c(c), d(d) \ + {} \ + template \ + DenseElementResult operator()() { \ + return Signature(a, b, c, d); \ + } \ +} + #define DefineBoxedOrUnboxedFunctor5(Signature, A, B, C, D, E) \ struct Signature ## Functor { \ A a; B b; C c; D d; E e; \ @@ -675,6 +775,18 @@ struct Signature ## Functor { \ } \ } +#define DefineBoxedOrUnboxedFunctorPair6(Signature, A, B, C, D, E, F) \ +struct Signature ## Functor { \ + A a; B b; C c; D d; E e; F f; \ + Signature ## Functor(A a, B b, C c, D d, E e, F f) \ + : a(a), b(b), c(c), d(d), e(e), f(f) \ + {} \ + template \ + DenseElementResult operator()() { \ + return Signature(a, b, c, d, e, f); \ + } \ +} + DenseElementResult SetOrExtendAnyBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj, uint32_t start, const Value* vp, uint32_t count, @@ -691,7 +803,7 @@ CopyAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src, void SetAnyBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen); -bool +DenseElementResult EnsureAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count); } // namespace js diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index 860291ea1e1f..99031560d802 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -1679,11 +1679,9 @@ CombineArrayObjectElements(ExclusiveContext* cx, ArrayObject* obj, JSValueType* { if (obj->inDictionaryMode() || obj->lastProperty()->propid() != AtomToId(cx->names().length) || - !obj->lastProperty()->previous()->isEmptyShape() || - !obj->getDenseInitializedLength()) + !obj->lastProperty()->previous()->isEmptyShape()) { - // Only use an unboxed representation if the object has at - // least one element, and no properties. + // Only use an unboxed representation if the object has no properties. return false; } @@ -1838,6 +1836,8 @@ UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx, setLength(cx, NextValue(values, valueCursor).toInt32()); int32_t initlen = NextValue(values, valueCursor).toInt32(); + if (!initlen) + return; if (!growElements(cx, initlen)) CrashAtUnhandlableOOM("UnboxedArrayObject::fillAfterConvert"); @@ -2063,15 +2063,15 @@ js::MoveAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, return CallBoxedOrUnboxedSpecialization(functor, obj); } -DefineBoxedOrUnboxedFunctor6(CopyBoxedOrUnboxedDenseElements, - JSContext*, JSObject*, JSObject*, uint32_t, uint32_t, uint32_t); +DefineBoxedOrUnboxedFunctorPair6(CopyBoxedOrUnboxedDenseElements, + JSContext*, JSObject*, JSObject*, uint32_t, uint32_t, uint32_t); DenseElementResult js::CopyAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src, uint32_t dstStart, uint32_t srcStart, uint32_t length) { CopyBoxedOrUnboxedDenseElementsFunctor functor(cx, dst, src, dstStart, srcStart, length); - return CallBoxedOrUnboxedSpecialization(functor, dst); + return CallBoxedOrUnboxedSpecialization(functor, dst, src); } DefineBoxedOrUnboxedFunctor3(SetBoxedOrUnboxedInitializedLength, @@ -2083,3 +2083,13 @@ js::SetAnyBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t i SetBoxedOrUnboxedInitializedLengthFunctor functor(cx, obj, initlen); JS_ALWAYS_TRUE(CallBoxedOrUnboxedSpecialization(functor, obj) == DenseElementResult::Success); } + +DefineBoxedOrUnboxedFunctor3(EnsureBoxedOrUnboxedDenseElements, + JSContext*, JSObject*, size_t); + +DenseElementResult +js::EnsureAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t initlen) +{ + EnsureBoxedOrUnboxedDenseElementsFunctor functor(cx, obj, initlen); + return CallBoxedOrUnboxedSpecialization(functor, obj); +} From d8733e1534c4544378dab51aae40d85627b4b517 Mon Sep 17 00:00:00 2001 From: Andrew Halberstadt Date: Thu, 6 Aug 2015 17:40:54 -0400 Subject: [PATCH 146/208] Bug 1185761 - [mochitest] Allow boolean values to --keep-open for overriding the default, r=ted Most of the time the default is to close the browser after tests run. And that can be overridden with --keep-open. But in some corner cases, the default is to leave the browser open after tests have run. In these cases, it is not currently possible to override. This patch allows the syntax --keep-open or --keep-open=false, the latter overrides the edge case default. --- testing/mochitest/mach_commands.py | 9 ++++++--- testing/mochitest/mochitest_options.py | 11 +++++++---- testing/mochitest/runtests.py | 8 +++++--- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/testing/mochitest/mach_commands.py b/testing/mochitest/mach_commands.py index 8b53bcaeac12..cdc777b7fb9c 100644 --- a/testing/mochitest/mach_commands.py +++ b/testing/mochitest/mach_commands.py @@ -339,9 +339,12 @@ def run_desktop_test(self, context, tests=None, suite=None, **kwargs): manifest.tests.extend(tests) options.manifestFile = manifest - # XXX why is this such a special case? - if len(tests) == 1 and options.closeWhenDone and suite == 'plain': - options.closeWhenDone = False + # When developing mochitest-plain tests, it's often useful to be able to + # refresh the page to pick up modifications. Therefore leave the browser + # open if only running a single mochitest-plain test. This behaviour can + # be overridden by passing in --keep-open=false. + if len(tests) == 1 and options.keep_open is None and suite == 'plain': + options.keep_open = True # We need this to enable colorization of output. self.log_manager.enable_unstructured() diff --git a/testing/mochitest/mochitest_options.py b/testing/mochitest/mochitest_options.py index b3ecb9b8f5a4..fe4fb64203b9 100644 --- a/testing/mochitest/mochitest_options.py +++ b/testing/mochitest/mochitest_options.py @@ -4,6 +4,7 @@ from abc import ABCMeta, abstractmethod, abstractproperty from argparse import ArgumentParser, SUPPRESS +from distutils.util import strtobool from urlparse import urlparse import os import tempfile @@ -66,10 +67,12 @@ class MochitestArguments(ArgumentContainer): "(to run recursively). If omitted, the entire suite is run.", }], [["--keep-open"], - {"action": "store_false", - "dest": "closeWhenDone", - "default": True, - "help": "Always keep the browser open after tests complete.", + {"nargs": "?", + "type": strtobool, + "const": "true", + "default": None, + "help": "Always keep the browser open after tests complete. Or always close the " + "browser with --keep-open=false", }], [["--appname"], {"dest": "app", diff --git a/testing/mochitest/runtests.py b/testing/mochitest/runtests.py index d4e0176cada2..d15077f78358 100644 --- a/testing/mochitest/runtests.py +++ b/testing/mochitest/runtests.py @@ -332,7 +332,7 @@ def __init__(self, options, logger): if isinstance(options, Namespace): options = vars(options) self._log = logger - self._closeWhenDone = options['closeWhenDone'] + self._keep_open = bool(options['keep_open']) self._utilityPath = options['utilityPath'] self._xrePath = options['xrePath'] self._profileDir = options['profilePath'] @@ -390,7 +390,7 @@ def start(self): "server": self.webServer, "testPrefix": self.testPrefix, "displayResults": str( - not self._closeWhenDone).lower()}, + self._keep_open).lower()}, "-f", os.path.join( SCRIPT_DIR, @@ -594,7 +594,7 @@ def buildURLOptions(self, options, env): self.urlOpts.append("timeout=%d" % options.timeout) if options.maxTimeouts: self.urlOpts.append("maxTimeouts=%d" % options.maxTimeouts) - if options.closeWhenDone: + if not options.keep_open: self.urlOpts.append("closeWhenDone=1") if options.webapprtContent: self.urlOpts.append("testRoot=webapprtContent") @@ -2531,6 +2531,8 @@ def makeTestConfig(self, options): d = dict((k, v) for k, v in options.__dict__.items() if (v is None) or isinstance(v,(basestring,numbers.Number))) d['testRoot'] = self.testRoot + if not options.keep_open: + d['closeWhenDone'] = '1' content = json.dumps(d) with open(os.path.join(options.profilePath, "testConfig.js"), "w") as config: From 0bb3571468203e6481712e1f0098ffb7aafa3207 Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Fri, 21 Aug 2015 14:19:26 -0400 Subject: [PATCH 147/208] Bug 1194817: disable PMTUD in DataChannels/SCTP, set initial MTU per spec r=tuexen --- netwerk/sctp/datachannel/DataChannel.cpp | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/netwerk/sctp/datachannel/DataChannel.cpp b/netwerk/sctp/datachannel/DataChannel.cpp index 5a649381383e..7b23114ae12c 100644 --- a/netwerk/sctp/datachannel/DataChannel.cpp +++ b/netwerk/sctp/datachannel/DataChannel.cpp @@ -599,6 +599,32 @@ DataChannelConnection::CompleteConnect(TransportFlow *flow, TransportLayer::Stat LOG(("Calling usrsctp_connect")); r = usrsctp_connect(mMasterSocket, reinterpret_cast(&addr), sizeof(addr)); + if (r >= 0 || errno == EINPROGRESS) { + struct sctp_paddrparams paddrparams; + socklen_t opt_len; + + memset(&paddrparams, 0, sizeof(struct sctp_paddrparams)); + memcpy(&paddrparams.spp_address, &addr, sizeof(struct sockaddr_conn)); + opt_len = (socklen_t)sizeof(struct sctp_paddrparams); + r = usrsctp_getsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, + &paddrparams, &opt_len); + if (r < 0) { + LOG(("usrsctp_getsockopt failed: %d", r)); + } else { + // draft-ietf-rtcweb-data-channel-13 section 5: max initial MTU IPV4 1200, IPV6 1280 + paddrparams.spp_pathmtu = 1200; // safe for either + paddrparams.spp_flags &= !SPP_PMTUD_ENABLE; + paddrparams.spp_flags |= SPP_PMTUD_DISABLE; + opt_len = (socklen_t)sizeof(struct sctp_paddrparams); + r = usrsctp_setsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, + &paddrparams, opt_len); + if (r < 0) { + LOG(("usrsctp_getsockopt failed: %d", r)); + } else { + LOG(("usrsctp: PMTUD disabled, MTU set to %u", paddrparams.spp_pathmtu)); + } + } + } if (r < 0) { if (errno == EINPROGRESS) { // non-blocking From 9d19c3a413b639377aa7e31113e4185988543e8e Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Fri, 7 Aug 2015 02:58:05 -0400 Subject: [PATCH 148/208] Bug 1192291 - use llvm-symbolizer when running xpcshell tests under TSan; r=ted --- testing/xpcshell/runxpcshelltests.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/testing/xpcshell/runxpcshelltests.py b/testing/xpcshell/runxpcshelltests.py index 7e6e5c67f98e..36bd063359ae 100755 --- a/testing/xpcshell/runxpcshelltests.py +++ b/testing/xpcshell/runxpcshelltests.py @@ -905,14 +905,19 @@ def buildEnvironment(self): else: self.env["LD_LIBRARY_PATH"] = ":".join([self.xrePath, self.env["LD_LIBRARY_PATH"]]) - if "asan" in self.mozInfo and self.mozInfo["asan"]: - # ASan symbolizer support + usingASan = "asan" in self.mozInfo and self.mozInfo["asan"] + usingTSan = "tsan" in self.mozInfo and self.mozInfo["tsan"] + if usingASan or usingTSan: + # symbolizer support llvmsym = os.path.join(self.xrePath, "llvm-symbolizer") if os.path.isfile(llvmsym): - self.env["ASAN_SYMBOLIZER_PATH"] = llvmsym - self.log.info("runxpcshelltests.py | ASan using symbolizer at %s" % llvmsym) + if usingASan: + self.env["ASAN_SYMBOLIZER_PATH"] = llvmsym + else: + self.env["TSAN_OPTIONS"] = "external_symbolizer_path=%s" % llvmsym + self.log.info("runxpcshelltests.py | using symbolizer at %s" % llvmsym) else: - self.log.error("TEST-UNEXPECTED-FAIL | runxpcshelltests.py | Failed to find ASan symbolizer at %s" % llvmsym) + self.log.error("TEST-UNEXPECTED-FAIL | runxpcshelltests.py | Failed to find symbolizer at %s" % llvmsym) return self.env From 7cd7f8373832e8bae20542de96c663f495f68ad2 Mon Sep 17 00:00:00 2001 From: Eitan Isaacson Date: Fri, 21 Aug 2015 11:32:57 -0700 Subject: [PATCH 149/208] Bug 1182208 - Add support for android scrolling and range accessibility actions. r=mfinkle r=yzen --- accessible/jsat/AccessFu.jsm | 16 +++++++++++++ accessible/jsat/ContentControl.jsm | 24 ++++++++++++++++++- accessible/tests/mochitest/jsat/jsatcommon.js | 14 +++++++++++ .../jsat/test_content_integration.html | 2 ++ mobile/android/base/GeckoAccessibility.java | 10 ++++++++ 5 files changed, 65 insertions(+), 1 deletion(-) diff --git a/accessible/jsat/AccessFu.jsm b/accessible/jsat/AccessFu.jsm index 7dfcba89492c..a3cf74f0fa52 100644 --- a/accessible/jsat/AccessFu.jsm +++ b/accessible/jsat/AccessFu.jsm @@ -134,6 +134,8 @@ this.AccessFu = { // jshint ignore:line Services.obs.addObserver(this, 'Accessibility:Focus', false); Services.obs.addObserver(this, 'Accessibility:ActivateObject', false); Services.obs.addObserver(this, 'Accessibility:LongPress', false); + Services.obs.addObserver(this, 'Accessibility:ScrollForward', false); + Services.obs.addObserver(this, 'Accessibility:ScrollBackward', false); Services.obs.addObserver(this, 'Accessibility:MoveByGranularity', false); Utils.win.addEventListener('TabOpen', this); Utils.win.addEventListener('TabClose', this); @@ -187,6 +189,8 @@ this.AccessFu = { // jshint ignore:line Services.obs.removeObserver(this, 'Accessibility:Focus'); Services.obs.removeObserver(this, 'Accessibility:ActivateObject'); Services.obs.removeObserver(this, 'Accessibility:LongPress'); + Services.obs.removeObserver(this, 'Accessibility:ScrollForward'); + Services.obs.removeObserver(this, 'Accessibility:ScrollBackward'); Services.obs.removeObserver(this, 'Accessibility:MoveByGranularity'); delete this._quicknavModesPref; @@ -315,6 +319,12 @@ this.AccessFu = { // jshint ignore:line case 'Accessibility:LongPress': this.Input.sendContextMenuMessage(); break; + case 'Accessibility:ScrollForward': + this.Input.androidScroll('forward'); + break; + case 'Accessibility:ScrollBackward': + this.Input.androidScroll('backward'); + break; case 'Accessibility:Focus': this._focused = JSON.parse(aData); if (this._focused) { @@ -837,6 +847,12 @@ var Input = { adjustRange: aAdjustRange }); }, + androidScroll: function androidScroll(aDirection) { + let mm = Utils.getMessageManager(Utils.CurrentBrowser); + mm.sendAsyncMessage('AccessFu:AndroidScroll', + { direction: aDirection, origin: 'top' }); + }, + moveByGranularity: function moveByGranularity(aDetails) { const MOVEMENT_GRANULARITY_PARAGRAPH = 8; diff --git a/accessible/jsat/ContentControl.jsm b/accessible/jsat/ContentControl.jsm index 11b75a0fb306..c726fa52b7a2 100644 --- a/accessible/jsat/ContentControl.jsm +++ b/accessible/jsat/ContentControl.jsm @@ -38,7 +38,8 @@ this.ContentControl.prototype = { 'AccessFu:AutoMove', 'AccessFu:Activate', 'AccessFu:MoveCaret', - 'AccessFu:MoveByGranularity'], + 'AccessFu:MoveByGranularity', + 'AccessFu:AndroidScroll'], start: function cc_start() { let cs = this._contentScope.get(); @@ -91,6 +92,27 @@ this.ContentControl.prototype = { } }, + handleAndroidScroll: function cc_handleAndroidScroll(aMessage) { + let vc = this.vc; + let position = vc.position; + + if (aMessage.json.origin != 'child' && this.sendToChild(vc, aMessage)) { + // Forwarded succesfully to child cursor. + return; + } + + // Counter-intuitive, but scrolling backward (ie. up), actually should + // increase range values. + if (this.adjustRange(position, aMessage.json.direction === 'backward')) { + return; + } + + this._contentScope.get().sendAsyncMessage('AccessFu:DoScroll', + { bounds: Utils.getBounds(position, true), + page: aMessage.json.direction === 'forward' ? 1 : -1, + horizontal: false }); + }, + handleMoveCursor: function cc_handleMoveCursor(aMessage) { let origin = aMessage.json.origin; let action = aMessage.json.action; diff --git a/accessible/tests/mochitest/jsat/jsatcommon.js b/accessible/tests/mochitest/jsat/jsatcommon.js index f1de7ac8c99e..706e75df7e1a 100644 --- a/accessible/tests/mochitest/jsat/jsatcommon.js +++ b/accessible/tests/mochitest/jsat/jsatcommon.js @@ -391,6 +391,20 @@ var ContentMessages = { } }, + androidScrollForward: function adjustUp() { + return { + name: 'AccessFu:AndroidScroll', + json: { origin: 'top', direction: 'forward' } + }; + }, + + androidScrollBackward: function adjustDown() { + return { + name: 'AccessFu:AndroidScroll', + json: { origin: 'top', direction: 'backward' } + }; + }, + focusSelector: function focusSelector(aSelector, aBlur) { return { name: 'AccessFuTest:Focus', diff --git a/accessible/tests/mochitest/jsat/test_content_integration.html b/accessible/tests/mochitest/jsat/test_content_integration.html index a21a6bc06072..229102ef976a 100644 --- a/accessible/tests/mochitest/jsat/test_content_integration.html +++ b/accessible/tests/mochitest/jsat/test_content_integration.html @@ -81,6 +81,8 @@ [ContentMessages.simpleMovePrevious, new ExpectedCursorChange(['much range', '6', {'string': 'slider'}, 'such app'])], [ContentMessages.moveOrAdjustDown(), new ExpectedValueChange('5')], + [ContentMessages.androidScrollForward(), new ExpectedValueChange('6')], + [ContentMessages.androidScrollBackward(), new ExpectedValueChange('5')], [ContentMessages.simpleMovePrevious, new ExpectedCursorChange(['much range', {'string': 'label'}])], [ContentMessages.simpleMovePrevious, diff --git a/mobile/android/base/GeckoAccessibility.java b/mobile/android/base/GeckoAccessibility.java index 5212d4ee89cb..1443dc558b8a 100644 --- a/mobile/android/base/GeckoAccessibility.java +++ b/mobile/android/base/GeckoAccessibility.java @@ -348,6 +348,8 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualDescendantId info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); @@ -388,6 +390,14 @@ public boolean performAction (int virtualViewId, int action, Bundle arguments) { GeckoAppShell. sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:LongPress", null)); return true; + } else if (action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD && virtualViewId == VIRTUAL_CURSOR_POSITION) { + GeckoAppShell. + sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:ScrollForward", null)); + return true; + } else if (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD && virtualViewId == VIRTUAL_CURSOR_POSITION) { + GeckoAppShell. + sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:ScrollBackward", null)); + return true; } else if (action == AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY && virtualViewId == VIRTUAL_CURSOR_POSITION) { // XXX: Self brailling gives this action with a bogus argument instead of an actual click action; From 2f523d376d99e4d35c6a42a9f9a86ace8271ab86 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Fri, 21 Aug 2015 20:38:58 +0200 Subject: [PATCH 150/208] Bug 1197215 - Remove now unnecessary uses of ok in the predictor. r=hurley --- netwerk/base/Predictor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/netwerk/base/Predictor.cpp b/netwerk/base/Predictor.cpp index 10efa21fedad..956de2aadea5 100644 --- a/netwerk/base/Predictor.cpp +++ b/netwerk/base/Predictor.cpp @@ -1515,7 +1515,7 @@ Predictor::SpaceCleaner::OnMetaDataElement(const char *key, const char *value) nsCString uri; nsresult rv = parsedURI->GetAsciiSpec(uri); uint32_t uriLength = uri.Length(); - if (ok && NS_SUCCEEDED(rv) && + if (NS_SUCCEEDED(rv) && uriLength > mPredictor->mMaxURILength) { // Default to getting rid of URIs that are too long and were put in before // we had our limit on URI length, in order to free up some space. @@ -1525,9 +1525,9 @@ Predictor::SpaceCleaner::OnMetaDataElement(const char *key, const char *value) return NS_OK; } - if (!ok || !mLRUKeyToDelete || lastHit < mLRUStamp) { + if (!mLRUKeyToDelete || lastHit < mLRUStamp) { mLRUKeyToDelete = key; - mLRUStamp = ok ? lastHit : 0; + mLRUStamp = lastHit; } return NS_OK; From 1ba554548fa590af9ddd73c6dce55f00e938b0e2 Mon Sep 17 00:00:00 2001 From: Armen Zambrano Gasparnian Date: Fri, 21 Aug 2015 16:05:17 -0400 Subject: [PATCH 151/208] Bug 1192309. Create releng generic tester and builder configs. DONTBUILD. r=bhearsum --- .../builders.py} | 0 .../configs/releng_infra_configs/testers.py | 71 +++++++++++++++++++ 2 files changed, 71 insertions(+) rename testing/mozharness/configs/{generic_releng_config.py => releng_infra_configs/builders.py} (100%) create mode 100644 testing/mozharness/configs/releng_infra_configs/testers.py diff --git a/testing/mozharness/configs/generic_releng_config.py b/testing/mozharness/configs/releng_infra_configs/builders.py similarity index 100% rename from testing/mozharness/configs/generic_releng_config.py rename to testing/mozharness/configs/releng_infra_configs/builders.py diff --git a/testing/mozharness/configs/releng_infra_configs/testers.py b/testing/mozharness/configs/releng_infra_configs/testers.py new file mode 100644 index 000000000000..2a2bf1a144d8 --- /dev/null +++ b/testing/mozharness/configs/releng_infra_configs/testers.py @@ -0,0 +1,71 @@ +# This config file has generic values needed for any job and any platform running +# on Release Engineering machines inside the VPN +import os + +import mozharness + +from mozharness.base.script import platform_name + +external_tools_path = os.path.join( + os.path.abspath(os.path.dirname(os.path.dirname(mozharness.__file__))), + 'external_tools', +) + +# These are values specific to each platform on Release Engineering machines +PYTHON_WIN32 = 'c:/mozilla-build/python27/python.exe' +# These are values specific to running machines on Release Engineering machines +# to run it locally on your machines append --cfg developer_config.py +PLATFORM_CONFIG = { + 'linux': { + 'exes': { + 'gittool.py': os.path.join(external_tools_path, 'gittool.py'), + 'hgtool.py': os.path.join(external_tools_path, 'hgtool.py'), + 'virtualenv': ['/tools/buildbot/bin/python', '/tools/misc-python/virtualenv.py'], + }, + 'env': { + 'DISPLAY': ':0', + 'PATH': '%(PATH)s:' + external_tools_path, + } + }, + 'linux64': { + 'exes': { + 'gittool.py': os.path.join(external_tools_path, 'gittool.py'), + 'hgtool.py': os.path.join(external_tools_path, 'hgtool.py'), + 'virtualenv': ['/tools/buildbot/bin/python', '/tools/misc-python/virtualenv.py'], + }, + 'env': { + 'DISPLAY': ':0', + 'PATH': '%(PATH)s:' + external_tools_path, + } + }, + 'macosx': { + 'exes': { + 'gittool.py': os.path.join(external_tools_path, 'gittool.py'), + 'hgtool.py': os.path.join(external_tools_path, 'hgtool.py'), + 'virtualenv': ['/tools/buildbot/bin/python', '/tools/misc-python/virtualenv.py'], + }, + 'env': { + 'PATH': '%(PATH)s:' + external_tools_path, + } + }, + 'win32': { + "exes": { + 'gittool.py': [PYTHON_WIN32, os.path.join(external_tools_path, 'gittool.py')], + 'hgtool.py': [PYTHON_WIN32, os.path.join(external_tools_path, 'hgtool.py')], + # Otherwise, depending on the PATH we can pick python 2.6 up + 'python': PYTHON_WIN32, + 'virtualenv': [PYTHON_WIN32, 'c:/mozilla-build/buildbotve/virtualenv.py'], + } + } +} + +config = PLATFORM_CONFIG[platform_name()] +# Generic values +config.update({ + "find_links": [ + "http://pypi.pvt.build.mozilla.org/pub", + "http://pypi.pub.build.mozilla.org/pub", + ], + 'pip_index': False, + 'virtualenv_path': 'venv', +}) From e66436ec39157cf7042e4c549f21ca15cb36d4ac Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Fri, 21 Aug 2015 13:19:48 -0700 Subject: [PATCH 152/208] Backed out 2 changesets (bug 1136766) for osx reftest assertions Backed out changeset c574db1b372e (bug 1136766) Backed out changeset 674f8f76a58b (bug 1136766) --- .../composite/LayerManagerComposite.cpp | 76 ++++++------------- gfx/layers/composite/LayerManagerComposite.h | 2 +- 2 files changed, 25 insertions(+), 53 deletions(-) diff --git a/gfx/layers/composite/LayerManagerComposite.cpp b/gfx/layers/composite/LayerManagerComposite.cpp index 914a4f018fad..f218bf2969b5 100644 --- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -204,66 +204,36 @@ LayerManagerComposite::BeginTransactionWithDrawTarget(DrawTarget* aTarget, const mTargetBounds = aRect; } -static bool -IsIntegerTranslation(const Matrix4x4& aMatrix, nsIntPoint* aOutTranslation) -{ - Matrix transform2d; - if (aMatrix.Is2D(&transform2d)) { - if (transform2d.IsIntegerTranslation()) { - *aOutTranslation = nsIntPoint(transform2d._31, transform2d._32); - return true; - } - } - return false; -} - void -LayerManagerComposite::ApplyOcclusionCulling(Layer* aLayer, nsIntRegion& aOpaqueRegion, const nsIntRect* aClipFromAncestors) +LayerManagerComposite::ApplyOcclusionCulling(Layer* aLayer, nsIntRegion& aOpaqueRegion) { + nsIntRegion localOpaque; + Matrix transform2d; + bool isTranslation = false; // If aLayer has a simple transform (only an integer translation) then we // can easily convert aOpaqueRegion into pre-transform coordinates and include // that region. - nsIntPoint translation; - bool isTranslation = IsIntegerTranslation(aLayer->GetLocalTransform(), &translation); - - LayerComposite* composite = aLayer->AsLayerComposite(); - - nsIntRegion localOpaque; - nsIntRect clip; - bool haveClip = false; - - if (isTranslation) { - localOpaque = aOpaqueRegion.MovedBy(-translation); - - // Combine our clip with the one from our descendants. - const Maybe& selfClip = aLayer->GetEffectiveClipRect(); - if (aClipFromAncestors) { - clip = *aClipFromAncestors - translation; - if (selfClip) { - // *selfClip is in parent layer coordinates. - clip = clip.Intersect(ParentLayerPixel::ToUntyped(*selfClip) - translation); - } - haveClip = true; - } else if (selfClip) { - clip = ParentLayerPixel::ToUntyped(*selfClip) - translation; - haveClip = true; + if (aLayer->GetLocalTransform().Is2D(&transform2d)) { + if (transform2d.IsIntegerTranslation()) { + isTranslation = true; + localOpaque = aOpaqueRegion; + localOpaque.MoveBy(-transform2d._31, -transform2d._32); } + } - // Subtract any areas that we know to be opaque from our - // visible region. + // Subtract any areas that we know to be opaque from our + // visible region. + LayerComposite *composite = aLayer->AsLayerComposite(); + if (!localOpaque.IsEmpty()) { nsIntRegion visible = composite->GetShadowVisibleRegion(); - nsIntRegion afterCulling; - afterCulling.Sub(visible, localOpaque); - if (haveClip) { - afterCulling.AndWith(clip); - } + visible.Sub(visible, localOpaque); composite->SetShadowVisibleRegion(visible); } // Compute occlusions for our descendants (in front-to-back order) and allow them to // contribute to localOpaque. for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) { - ApplyOcclusionCulling(child, localOpaque, haveClip ? &clip : nullptr); + ApplyOcclusionCulling(child, localOpaque); } // If we have a simple transform, then we can add our opaque area into @@ -272,12 +242,14 @@ LayerManagerComposite::ApplyOcclusionCulling(Layer* aLayer, nsIntRegion& aOpaque !aLayer->HasMaskLayers() && aLayer->GetLocalOpacity() == 1.0f) { if (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) { - localOpaque.OrWith(composite->GetFullyRenderedRegion()); + localOpaque.Or(localOpaque, composite->GetFullyRenderedRegion()); } - if (haveClip) { - localOpaque.AndWith(clip); + localOpaque.MoveBy(transform2d._31, transform2d._32); + const Maybe& clip = aLayer->GetEffectiveClipRect(); + if (clip) { + localOpaque.And(localOpaque, ParentLayerIntRect::ToUntyped(*clip)); } - aOpaqueRegion.OrWith(localOpaque.MovedBy(translation)); + aOpaqueRegion.Or(aOpaqueRegion, localOpaque); } } @@ -333,7 +305,7 @@ LayerManagerComposite::EndTransaction(const TimeStamp& aTimeStamp, mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4()); nsIntRegion opaque; - ApplyOcclusionCulling(mRoot, opaque, nullptr); + ApplyOcclusionCulling(mRoot, opaque); Render(); #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) @@ -1000,7 +972,7 @@ LayerManagerComposite::RenderToPresentationSurface() mRoot->ComputeEffectiveTransforms(matrix); nsIntRegion opaque; - ApplyOcclusionCulling(mRoot, opaque, nullptr); + ApplyOcclusionCulling(mRoot, opaque); nsIntRegion invalid; Rect bounds(0.0f, 0.0f, scale * pageWidth, (float)actualHeight); diff --git a/gfx/layers/composite/LayerManagerComposite.h b/gfx/layers/composite/LayerManagerComposite.h index 0fba6d3e65e8..98c19bb200e8 100644 --- a/gfx/layers/composite/LayerManagerComposite.h +++ b/gfx/layers/composite/LayerManagerComposite.h @@ -173,7 +173,7 @@ class LayerManagerComposite final : public LayerManager * opaque content. aOpaqueRegion is the region already known to be covered * with opaque content, in the post-transform coordinate space of aLayer. */ - void ApplyOcclusionCulling(Layer* aLayer, nsIntRegion& aOpaqueRegion, const nsIntRect* aClipFromAncestors); + void ApplyOcclusionCulling(Layer* aLayer, nsIntRegion& aOpaqueRegion); /** * RAII helper class to add a mask effect with the compositable from aMaskLayer From f8fc32f71e3e0b77a52e73942adf5b95150602f0 Mon Sep 17 00:00:00 2001 From: Andrew Comminos Date: Wed, 19 Aug 2015 15:42:17 -0400 Subject: [PATCH 153/208] Bug 1187203 - Implement GtkInfoBar appearance style on GTK3. r=karlt --- gfx/src/nsThemeConstants.h | 2 ++ layout/style/nsCSSKeywordList.h | 2 ++ layout/style/nsCSSProps.cpp | 2 ++ widget/LookAndFeel.h | 3 +++ widget/gtk/gtk3drawing.c | 40 +++++++++++++++++++++++++++++++++ widget/gtk/gtkdrawing.h | 4 +++- widget/gtk/mozgtk/mozgtk.c | 2 ++ widget/gtk/nsLookAndFeel.cpp | 18 +++++++++++++++ widget/gtk/nsLookAndFeel.h | 3 +++ widget/gtk/nsNativeThemeGTK.cpp | 6 +++++ 10 files changed, 81 insertions(+), 1 deletion(-) diff --git a/gfx/src/nsThemeConstants.h b/gfx/src/nsThemeConstants.h index 07e7073eebed..2552e75f6b3b 100644 --- a/gfx/src/nsThemeConstants.h +++ b/gfx/src/nsThemeConstants.h @@ -286,3 +286,5 @@ #define NS_THEME_MAC_VIBRANCY_DARK 244 #define NS_THEME_MAC_DISCLOSURE_BUTTON_OPEN 245 #define NS_THEME_MAC_DISCLOSURE_BUTTON_CLOSED 246 + +#define NS_THEME_GTK_INFO_BAR 247 diff --git a/layout/style/nsCSSKeywordList.h b/layout/style/nsCSSKeywordList.h index 44509b40bb4f..e66d3abc4014 100644 --- a/layout/style/nsCSSKeywordList.h +++ b/layout/style/nsCSSKeywordList.h @@ -71,6 +71,8 @@ CSS_KEY(-moz-grid-group, _moz_grid_group) CSS_KEY(-moz-grid-line, _moz_grid_line) CSS_KEY(-moz-grid, _moz_grid) CSS_KEY(-moz-groupbox, _moz_groupbox) +CSS_KEY(-moz-gtk-info-bar, _moz_gtk_info_bar) +CSS_KEY(-moz-gtk-info-bar-text, _moz_gtk_info_bar_text) CSS_KEY(-moz-hidden-unscrollable, _moz_hidden_unscrollable) CSS_KEY(-moz-hyperlinktext, _moz_hyperlinktext) CSS_KEY(-moz-html-cellhighlight, _moz_html_cellhighlight) diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp index 96d6ad2d9b8d..bf0008250bef 100644 --- a/layout/style/nsCSSProps.cpp +++ b/layout/style/nsCSSProps.cpp @@ -745,6 +745,7 @@ const KTableValue nsCSSProps::kAppearanceKTable[] = { eCSSKeyword__moz_mac_vibrancy_dark, NS_THEME_MAC_VIBRANCY_DARK, eCSSKeyword__moz_mac_disclosure_button_open, NS_THEME_MAC_DISCLOSURE_BUTTON_OPEN, eCSSKeyword__moz_mac_disclosure_button_closed, NS_THEME_MAC_DISCLOSURE_BUTTON_CLOSED, + eCSSKeyword__moz_gtk_info_bar, NS_THEME_GTK_INFO_BAR, eCSSKeyword_UNKNOWN,-1 }; @@ -960,6 +961,7 @@ const KTableValue nsCSSProps::kColorKTable[] = { eCSSKeyword__moz_dialog, LookAndFeel::eColorID__moz_dialog, eCSSKeyword__moz_dialogtext, LookAndFeel::eColorID__moz_dialogtext, eCSSKeyword__moz_dragtargetzone, LookAndFeel::eColorID__moz_dragtargetzone, + eCSSKeyword__moz_gtk_info_bar_text, LookAndFeel::eColorID__moz_gtk_info_bar_text, eCSSKeyword__moz_hyperlinktext, NS_COLOR_MOZ_HYPERLINKTEXT, eCSSKeyword__moz_html_cellhighlight, LookAndFeel::eColorID__moz_html_cellhighlight, eCSSKeyword__moz_html_cellhighlighttext, LookAndFeel::eColorID__moz_html_cellhighlighttext, diff --git a/widget/LookAndFeel.h b/widget/LookAndFeel.h index ed9995553c40..079417af292c 100644 --- a/widget/LookAndFeel.h +++ b/widget/LookAndFeel.h @@ -174,6 +174,9 @@ class LookAndFeel eColorID__moz_comboboxtext, eColorID__moz_combobox, + // GtkInfoBar + eColorID__moz_gtk_info_bar_text, + // keep this one last, please eColorID_LAST_COLOR }; diff --git a/widget/gtk/gtk3drawing.c b/widget/gtk/gtk3drawing.c index 2bdaa6a4bcc5..bf29b1989e62 100644 --- a/widget/gtk/gtk3drawing.c +++ b/widget/gtk/gtk3drawing.c @@ -61,6 +61,7 @@ static GtkWidget* gMenuSeparatorWidget; static GtkWidget* gHPanedWidget; static GtkWidget* gVPanedWidget; static GtkWidget* gScrolledWindowWidget; +static GtkWidget* gInfoBar; static style_prop_t style_prop_func; static gboolean have_arrow_scaling; @@ -358,6 +359,15 @@ ensure_combo_box_widgets() return MOZ_GTK_SUCCESS; } +static void +ensure_info_bar() +{ + if (!gInfoBar) { + gInfoBar = gtk_info_bar_new(); + setup_widget_prototype(gInfoBar); + } +} + /* We need to have pointers to the inner widgets (entry, button, arrow) of * the ComboBoxEntry to get the correct rendering from theme engines which * special cases their look. Since the inner layout can change, we ask GTK @@ -2603,6 +2613,29 @@ moz_gtk_check_menu_item_paint(cairo_t *cr, GdkRectangle* rect, return MOZ_GTK_SUCCESS; } +static gint +moz_gtk_info_bar_paint(cairo_t *cr, GdkRectangle* rect, + GtkWidgetState* state) +{ + GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); + GtkStyleContext *style; + ensure_info_bar(); + + style = gtk_widget_get_style_context(gInfoBar); + gtk_style_context_save(style); + + gtk_style_context_set_state(style, state_flags); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_INFO); + + gtk_render_background(style, cr, rect->x, rect->y, rect->width, + rect->height); + gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height); + + gtk_style_context_restore(style); + + return MOZ_GTK_SUCCESS; +} + static void moz_gtk_add_style_border(GtkStyleContext* style, gint* left, gint* top, gint* right, gint* bottom) @@ -2829,6 +2862,10 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, left, top, right, bottom); return MOZ_GTK_SUCCESS; } + case MOZ_GTK_INFO_BAR: + ensure_info_bar(); + w = gInfoBar; + break; /* These widgets have no borders, since they are not containers. */ case MOZ_GTK_CHECKBUTTON_LABEL: case MOZ_GTK_RADIOBUTTON_LABEL: @@ -3310,6 +3347,9 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, cairo_t *cr, case MOZ_GTK_WINDOW: return moz_gtk_window_paint(cr, rect, direction); break; + case MOZ_GTK_INFO_BAR: + return moz_gtk_info_bar_paint(cr, rect, state); + break; default: g_warning("Unknown widget type: %d", widget); } diff --git a/widget/gtk/gtkdrawing.h b/widget/gtk/gtkdrawing.h index 51578b6da323..9e5c38dc59bb 100644 --- a/widget/gtk/gtkdrawing.h +++ b/widget/gtk/gtkdrawing.h @@ -185,7 +185,9 @@ typedef enum { /* Paints a GtkHPaned separator */ MOZ_GTK_SPLITTER_VERTICAL, /* Paints the background of a window, dialog or page. */ - MOZ_GTK_WINDOW + MOZ_GTK_WINDOW, + /* Paints a GtkInfoBar, for notifications. */ + MOZ_GTK_INFO_BAR } GtkThemeWidgetType; /*** General library functions ***/ diff --git a/widget/gtk/mozgtk/mozgtk.c b/widget/gtk/mozgtk/mozgtk.c index a9232ff38506..9158d51358f9 100644 --- a/widget/gtk/mozgtk/mozgtk.c +++ b/widget/gtk/mozgtk/mozgtk.c @@ -254,6 +254,8 @@ STUB(gtk_im_context_set_surrounding) STUB(gtk_im_context_simple_new) STUB(gtk_im_multicontext_get_type) STUB(gtk_im_multicontext_new) +STUB(gtk_info_bar_get_type) +STUB(gtk_info_bar_new) STUB(gtk_init) STUB(gtk_invisible_new) STUB(gtk_key_snooper_install) diff --git a/widget/gtk/nsLookAndFeel.cpp b/widget/gtk/nsLookAndFeel.cpp index d6778f054d4e..9f5f3591f45c 100644 --- a/widget/gtk/nsLookAndFeel.cpp +++ b/widget/gtk/nsLookAndFeel.cpp @@ -414,6 +414,13 @@ nsLookAndFeel::NativeGetColor(ColorID aID, nscolor& aColor) case eColorID__moz_menubarhovertext: aColor = sMenuBarHoverText; break; + case eColorID__moz_gtk_info_bar_text: +#if (MOZ_WIDGET_GTK == 3) + aColor = sInfoBarText; +#else + aColor = sInfoText; +#endif + break; default: /* default color is BLACK */ aColor = 0; @@ -1193,6 +1200,17 @@ nsLookAndFeel::Init() sFrameInnerDarkBorder = sFrameOuterLightBorder = GDK_RGBA_TO_NS_RGBA(color); gtk_widget_path_free(path); + + // GtkInfoBar + path = gtk_widget_path_new(); + gtk_widget_path_append_type(path, GTK_TYPE_WINDOW); + gtk_widget_path_append_type(path, GTK_TYPE_INFO_BAR); + style = create_context(path); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_INFO); + gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color); + sInfoBarText = GDK_RGBA_TO_NS_RGBA(color); + g_object_unref(style); + gtk_widget_path_free(path); #endif // Some themes have a unified menu bar, and support window dragging on it gboolean supports_menubar_drag = FALSE; diff --git a/widget/gtk/nsLookAndFeel.h b/widget/gtk/nsLookAndFeel.h index 0da43f444beb..9058250b9aa2 100644 --- a/widget/gtk/nsLookAndFeel.h +++ b/widget/gtk/nsLookAndFeel.h @@ -78,6 +78,9 @@ class nsLookAndFeel: public nsXPLookAndFeel { nscolor sTextSelectedText; nscolor sTextSelectedBackground; nscolor sMozScrollbar; +#if (MOZ_WIDGET_GTK == 3) + nscolor sInfoBarText; +#endif char16_t sInvisibleCharacter; float sCaretRatio; bool sMenuSupportsDrag; diff --git a/widget/gtk/nsNativeThemeGTK.cpp b/widget/gtk/nsNativeThemeGTK.cpp index 8fef43c9eb61..456bdd017a8c 100644 --- a/widget/gtk/nsNativeThemeGTK.cpp +++ b/widget/gtk/nsNativeThemeGTK.cpp @@ -684,6 +684,9 @@ nsNativeThemeGTK::GetGtkWidgetAndState(uint8_t aWidgetType, nsIFrame* aFrame, case NS_THEME_DIALOG: aGtkWidgetType = MOZ_GTK_WINDOW; break; + case NS_THEME_GTK_INFO_BAR: + aGtkWidgetType = MOZ_GTK_INFO_BAR; + break; default: return false; } @@ -1773,6 +1776,9 @@ nsNativeThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext, case NS_THEME_SPLITTER: case NS_THEME_WINDOW: case NS_THEME_DIALOG: +#if (MOZ_WIDGET_GTK == 3) + case NS_THEME_GTK_INFO_BAR: +#endif return !IsWidgetStyled(aPresContext, aFrame, aWidgetType); case NS_THEME_DROPDOWN_BUTTON: From 8acb8f39fc8cb519b7750d36e4bc0c00ffc18b21 Mon Sep 17 00:00:00 2001 From: Andrew Comminos Date: Wed, 19 Aug 2015 15:42:33 -0400 Subject: [PATCH 154/208] Bug 1187203 - Use -moz-gtk-info-bar for notifications on Linux. r=karlt --- toolkit/themes/linux/global/notification.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/toolkit/themes/linux/global/notification.css b/toolkit/themes/linux/global/notification.css index 4c5d27ed42cb..079f4081e1cd 100644 --- a/toolkit/themes/linux/global/notification.css +++ b/toolkit/themes/linux/global/notification.css @@ -5,14 +5,16 @@ @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); notification { - color: InfoText; + color: -moz-gtk-info-bar-text; background-color: InfoBackground; + -moz-appearance: -moz-gtk-info-bar; text-shadow: none; } notification[type="info"] { color: -moz-DialogText; background-color: -moz-Dialog; + -moz-appearance: none; } notification[type="critical"] { From 76f7dd87a9fc8fe0ac70147885bd13ff5481520f Mon Sep 17 00:00:00 2001 From: Andrew Comminos Date: Wed, 19 Aug 2015 15:23:03 -0400 Subject: [PATCH 155/208] Bug 1187203 - Use -moz-gtk-info-bar for RSS feed CSS on Linux. r=karlt --- browser/themes/linux/feeds/subscribe.css | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/browser/themes/linux/feeds/subscribe.css b/browser/themes/linux/feeds/subscribe.css index 4cd70faa7001..03b534a50a32 100644 --- a/browser/themes/linux/feeds/subscribe.css +++ b/browser/themes/linux/feeds/subscribe.css @@ -20,6 +20,7 @@ html { border-radius: 10px; margin: -4em auto 0 auto; background-color: InfoBackground; + -moz-appearance: -moz-gtk-info-bar; } #feedHeader { @@ -29,19 +30,19 @@ html { -moz-margin-end: 1em; -moz-padding-start: 2.9em; font-size: 110%; - color: InfoText; + color: -moz-gtk-info-bar-text; } .feedBackground { - background: url("chrome://browser/skin/feeds/feedIcon.png") 0% 10% no-repeat InfoBackground; + background: url("chrome://browser/skin/feeds/feedIcon.png") 0% 10% no-repeat; } .videoPodcastBackground { - background: url("chrome://browser/skin/feeds/videoFeedIcon.png") 0% 10% no-repeat InfoBackground; + background: url("chrome://browser/skin/feeds/videoFeedIcon.png") 0% 10% no-repeat; } .audioPodcastBackground { - background: url("chrome://browser/skin/feeds/audioFeedIcon.png") 0% 10% no-repeat InfoBackground; + background: url("chrome://browser/skin/feeds/audioFeedIcon.png") 0% 10% no-repeat; } #feedHeader[dir="rtl"] { From 7765446b391755b45b308895bdc907e3f8c299d2 Mon Sep 17 00:00:00 2001 From: Francois Marier Date: Fri, 21 Aug 2015 13:53:53 -0700 Subject: [PATCH 156/208] Bug 1197000 - Better debugging output for Safe Browsing list updates. r=gcp --- netwerk/base/nsChannelClassifier.cpp | 3 +- .../nsUrlClassifierStreamUpdater.cpp | 30 ++++++++++++------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/netwerk/base/nsChannelClassifier.cpp b/netwerk/base/nsChannelClassifier.cpp index cafe1805ef26..57dac1098d8d 100644 --- a/netwerk/base/nsChannelClassifier.cpp +++ b/netwerk/base/nsChannelClassifier.cpp @@ -620,8 +620,9 @@ nsChannelClassifier::OnClassifyComplete(nsresult aErrorCode) aErrorCode = NS_OK; } - LOG(("nsChannelClassifier[%p]:OnClassifyComplete %d", this, aErrorCode)); if (mSuspendedChannel) { + LOG(("nsChannelClassifier[%p]:OnClassifyComplete %d (suspended channel)", + this, aErrorCode)); MarkEntryClassified(aErrorCode); if (NS_FAILED(aErrorCode)) { diff --git a/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp b/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp index e84ca3ee526b..a238571c6738 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp @@ -15,6 +15,7 @@ #include "nsStringStream.h" #include "nsToolkitCompsCID.h" #include "nsUrlClassifierStreamUpdater.h" +#include "mozilla/ErrorNames.h" #include "mozilla/Logging.h" #include "nsIInterfaceRequestor.h" #include "mozilla/LoadContext.h" @@ -456,10 +457,21 @@ nsUrlClassifierStreamUpdater::OnStartRequest(nsIRequest *request, nsCOMPtr httpChannel = do_QueryInterface(request); if (httpChannel) { rv = httpChannel->GetStatus(&status); - LOG(("nsUrlClassifierStreamUpdater::OnStartRequest (status=%x, this=%p)", - status, this)); NS_ENSURE_SUCCESS(rv, rv); + if (MOZ_LOG_TEST(gUrlClassifierStreamUpdaterLog, mozilla::LogLevel::Debug)) { + nsAutoCString errorName, spec; + mozilla::GetErrorName(status, errorName); + nsCOMPtr uri; + rv = httpChannel->GetURI(getter_AddRefs(uri)); + if (NS_SUCCEEDED(rv) && uri) { + uri->GetAsciiSpec(spec); + } + LOG(("nsUrlClassifierStreamUpdater::OnStartRequest " + "(status=%s, uri=%s, this=%p)", errorName.get(), + spec.get(), this)); + } + if (NS_FAILED(status)) { // Assume we're overloading the server and trigger backoff. downloadError = true; @@ -468,17 +480,13 @@ nsUrlClassifierStreamUpdater::OnStartRequest(nsIRequest *request, rv = httpChannel->GetRequestSucceeded(&succeeded); NS_ENSURE_SUCCESS(rv, rv); - LOG(("nsUrlClassifierStreamUpdater::OnStartRequest (%s)", succeeded ? - "succeeded" : "failed")); + uint32_t requestStatus; + rv = httpChannel->GetResponseStatus(&requestStatus); + NS_ENSURE_SUCCESS(rv, rv); + LOG(("nsUrlClassifierStreamUpdater::OnStartRequest %s (%d)", succeeded ? + "succeeded" : "failed", requestStatus)); if (!succeeded) { // 404 or other error, pass error status back - LOG(("HTTP request returned failure code.")); - - uint32_t requestStatus; - rv = httpChannel->GetResponseStatus(&requestStatus); - LOG(("HTTP request returned failure code: %d.", requestStatus)); - NS_ENSURE_SUCCESS(rv, rv); - strStatus.AppendInt(requestStatus); downloadError = true; } From e89ac6a4693da06a68d0c23e529dc510b0f7451d Mon Sep 17 00:00:00 2001 From: William Chen Date: Thu, 20 Aug 2015 17:25:05 -0700 Subject: [PATCH 157/208] Bug 1196290 - Do not update orientation lock when app docshell is activated. r=smaug --- docshell/base/nsDocShell.cpp | 9 +++++++-- dom/base/nsScreen.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 931afeaccbff..d4b6986a016c 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -5936,7 +5936,10 @@ nsDocShell::SetIsActive(bool aIsActive) if (mScriptGlobal) { mScriptGlobal->SetIsBackground(!aIsActive); if (nsCOMPtr doc = mScriptGlobal->GetExtantDoc()) { - if (aIsActive) { + // Update orientation when the top-level browsing context becomes active. + // We make an exception for apps because they currently rely on + // orientation locks persisting across browsing contexts. + if (aIsActive && !GetIsApp()) { nsCOMPtr parent; GetSameTypeParent(getter_AddRefs(parent)); if (!parent) { @@ -10071,7 +10074,9 @@ nsDocShell::InternalLoad(nsIURI* aURI, // lock the orientation of the document to the document's default // orientation. We don't explicitly check for a top-level browsing context // here because orientation is only set on top-level browsing contexts. - if (OrientationLock() != eScreenOrientation_None) { + // We make an exception for apps because they currently rely on + // orientation locks persisting across browsing contexts. + if (OrientationLock() != eScreenOrientation_None && !GetIsApp()) { #ifdef DEBUG nsCOMPtr parent; GetSameTypeParent(getter_AddRefs(parent)); diff --git a/dom/base/nsScreen.cpp b/dom/base/nsScreen.cpp index 06d86d47536a..5dd1fbdb33d8 100644 --- a/dom/base/nsScreen.cpp +++ b/dom/base/nsScreen.cpp @@ -197,6 +197,29 @@ nsScreen::GetSlowMozOrientation(nsAString& aOrientation) return NS_OK; } +static void +UpdateDocShellOrientationLock(nsPIDOMWindow* aWindow, + ScreenOrientationInternal aOrientation) +{ + if (!aWindow) { + return; + } + + nsCOMPtr docShell = aWindow->GetDocShell(); + if (!docShell) { + return; + } + + nsCOMPtr root; + docShell->GetSameTypeRootTreeItem(getter_AddRefs(root)); + nsCOMPtr rootShell(do_QueryInterface(root)); + if (!rootShell) { + return; + } + + rootShell->SetOrientationLock(aOrientation); +} + bool nsScreen::MozLockOrientation(const nsAString& aOrientation, ErrorResult& aRv) { @@ -245,8 +268,10 @@ nsScreen::MozLockOrientation(const Sequence& aOrientations, case ScreenOrientation::LOCK_DENIED: return false; case ScreenOrientation::LOCK_ALLOWED: + UpdateDocShellOrientationLock(GetOwner(), orientation); return mScreenOrientation->LockDeviceOrientation(orientation, false, aRv); case ScreenOrientation::FULLSCREEN_LOCK_ALLOWED: + UpdateDocShellOrientationLock(GetOwner(), orientation); return mScreenOrientation->LockDeviceOrientation(orientation, true, aRv); } @@ -258,6 +283,7 @@ nsScreen::MozLockOrientation(const Sequence& aOrientations, void nsScreen::MozUnlockOrientation() { + UpdateDocShellOrientationLock(GetOwner(), eScreenOrientation_None); mScreenOrientation->UnlockDeviceOrientation(); } From d98d050c5aa9e1038804c5c7bd4cd111828b96ea Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Wed, 19 Aug 2015 10:59:50 -0700 Subject: [PATCH 158/208] Bug 1196378 - js_delete should accept a const pointer like builtin delete, r=fitzgen --- js/public/Utility.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/js/public/Utility.h b/js/public/Utility.h index 77566dd1ec05..d0e5c33a3402 100644 --- a/js/public/Utility.h +++ b/js/public/Utility.h @@ -194,7 +194,7 @@ static inline char* js_strdup(const char* s) * general SpiderMonkey idiom that a JSContext-taking function reports its * own errors.) * - * - Otherwise, use js_malloc/js_realloc/js_calloc/js_free/js_new + * - Otherwise, use js_malloc/js_realloc/js_calloc/js_new * * Deallocation: * @@ -248,22 +248,22 @@ JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE) template static MOZ_ALWAYS_INLINE void -js_delete(T* p) +js_delete(const T* p) { if (p) { p->~T(); - js_free(p); + js_free(const_cast(p)); } } template static MOZ_ALWAYS_INLINE void -js_delete_poison(T* p) +js_delete_poison(const T* p) { if (p) { p->~T(); - memset(p, 0x3B, sizeof(T)); - js_free(p); + memset(const_cast(p), 0x3B, sizeof(T)); + js_free(const_cast(p)); } } From 7060b59e4b5c4e36b3494989490b3bcfb387e076 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Wed, 19 Aug 2015 11:29:32 -0700 Subject: [PATCH 159/208] Bug 1196378 - Fix mismatched js_new/js_free in ShellPrincipals, r=fitzgen --- js/src/shell/js.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index db74598a9929..8762f4018c65 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -227,7 +227,7 @@ class ShellPrincipals: public JSPrincipals { static void destroy(JSPrincipals* principals) { MOZ_ASSERT(principals != &fullyTrusted); MOZ_ASSERT(principals->refcount == 0); - js_free(static_cast(principals)); + js_delete(static_cast(principals)); } static bool subsumes(JSPrincipals* first, JSPrincipals* second) { From a010388e9ff51613f87d63297842aa98f757ae33 Mon Sep 17 00:00:00 2001 From: Jan Gerber Date: Sat, 8 Aug 2015 09:28:52 +0200 Subject: [PATCH 160/208] Bug 1192226 - Enable libvpx size limit in update.py. r=rillian Bounds match those in VideoUtils.h. --- media/libvpx/update.py | 1 + 1 file changed, 1 insertion(+) diff --git a/media/libvpx/update.py b/media/libvpx/update.py index 9fbc6d17ee57..917cfb788ec7 100755 --- a/media/libvpx/update.py +++ b/media/libvpx/update.py @@ -398,6 +398,7 @@ def prepare_upstream(prefix, commit=None): configure = ['../../configure', '--target=%s' % target, '--disable-examples', '--disable-install-docs', '--enable-multi-res-encoding', + '--size-limit=4000x3000' ] if 'darwin9' in target: From bbfb740ad14b164ac3ed549353826ee12b2c93e7 Mon Sep 17 00:00:00 2001 From: Jan Gerber Date: Fri, 21 Aug 2015 12:01:41 +0200 Subject: [PATCH 161/208] Bug 1192226 - Apply libvpx size limit. r=rillian --- media/libvpx/vpx_config_armv7-android-gcc.asm | 2 +- media/libvpx/vpx_config_armv7-android-gcc.h | 4 +++- media/libvpx/vpx_config_generic-gnu.asm | 2 +- media/libvpx/vpx_config_generic-gnu.h | 4 +++- media/libvpx/vpx_config_x86-darwin9-gcc.asm | 2 +- media/libvpx/vpx_config_x86-darwin9-gcc.h | 4 +++- media/libvpx/vpx_config_x86-linux-gcc.asm | 2 +- media/libvpx/vpx_config_x86-linux-gcc.h | 4 +++- media/libvpx/vpx_config_x86-win32-gcc.asm | 2 +- media/libvpx/vpx_config_x86-win32-gcc.h | 4 +++- media/libvpx/vpx_config_x86-win32-vs12.asm | 2 +- media/libvpx/vpx_config_x86-win32-vs12.h | 4 +++- media/libvpx/vpx_config_x86_64-darwin9-gcc.asm | 2 +- media/libvpx/vpx_config_x86_64-darwin9-gcc.h | 4 +++- media/libvpx/vpx_config_x86_64-linux-gcc.asm | 2 +- media/libvpx/vpx_config_x86_64-linux-gcc.h | 4 +++- media/libvpx/vpx_config_x86_64-win64-gcc.asm | 2 +- media/libvpx/vpx_config_x86_64-win64-gcc.h | 4 +++- media/libvpx/vpx_config_x86_64-win64-vs12.asm | 2 +- media/libvpx/vpx_config_x86_64-win64-vs12.h | 4 +++- 20 files changed, 40 insertions(+), 20 deletions(-) diff --git a/media/libvpx/vpx_config_armv7-android-gcc.asm b/media/libvpx/vpx_config_armv7-android-gcc.asm index 6a21c78ecdd6..2816b335b1ac 100644 --- a/media/libvpx/vpx_config_armv7-android-gcc.asm +++ b/media/libvpx/vpx_config_armv7-android-gcc.asm @@ -79,7 +79,7 @@ .equ CONFIG_COEFFICIENT_RANGE_CHECKING , 0 .equ CONFIG_VP9_HIGHBITDEPTH , 0 .equ CONFIG_EXPERIMENTAL , 0 -.equ CONFIG_SIZE_LIMIT , 0 +.equ CONFIG_SIZE_LIMIT , 1 .equ CONFIG_SPATIAL_SVC , 0 .equ CONFIG_FP_MB_STATS , 0 .equ CONFIG_EMULATE_HARDWARE , 0 diff --git a/media/libvpx/vpx_config_armv7-android-gcc.h b/media/libvpx/vpx_config_armv7-android-gcc.h index 468099c3a90f..ff7e42f715c2 100644 --- a/media/libvpx/vpx_config_armv7-android-gcc.h +++ b/media/libvpx/vpx_config_armv7-android-gcc.h @@ -88,8 +88,10 @@ #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 #define CONFIG_VP9_HIGHBITDEPTH 0 #define CONFIG_EXPERIMENTAL 0 -#define CONFIG_SIZE_LIMIT 0 +#define CONFIG_SIZE_LIMIT 1 #define CONFIG_SPATIAL_SVC 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 +#define DECODE_WIDTH_LIMIT 4000 +#define DECODE_HEIGHT_LIMIT 3000 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/vpx_config_generic-gnu.asm b/media/libvpx/vpx_config_generic-gnu.asm index ac108f9eb0f3..0b3ddc569c4e 100644 --- a/media/libvpx/vpx_config_generic-gnu.asm +++ b/media/libvpx/vpx_config_generic-gnu.asm @@ -79,7 +79,7 @@ .equ CONFIG_COEFFICIENT_RANGE_CHECKING , 0 .equ CONFIG_VP9_HIGHBITDEPTH , 0 .equ CONFIG_EXPERIMENTAL , 0 -.equ CONFIG_SIZE_LIMIT , 0 +.equ CONFIG_SIZE_LIMIT , 1 .equ CONFIG_SPATIAL_SVC , 0 .equ CONFIG_FP_MB_STATS , 0 .equ CONFIG_EMULATE_HARDWARE , 0 diff --git a/media/libvpx/vpx_config_generic-gnu.h b/media/libvpx/vpx_config_generic-gnu.h index db883cf060f1..724edd6ede8f 100644 --- a/media/libvpx/vpx_config_generic-gnu.h +++ b/media/libvpx/vpx_config_generic-gnu.h @@ -88,8 +88,10 @@ #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 #define CONFIG_VP9_HIGHBITDEPTH 0 #define CONFIG_EXPERIMENTAL 0 -#define CONFIG_SIZE_LIMIT 0 +#define CONFIG_SIZE_LIMIT 1 #define CONFIG_SPATIAL_SVC 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 +#define DECODE_WIDTH_LIMIT 4000 +#define DECODE_HEIGHT_LIMIT 3000 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/vpx_config_x86-darwin9-gcc.asm b/media/libvpx/vpx_config_x86-darwin9-gcc.asm index 9b6b8509b0f0..09e26a70ce16 100644 --- a/media/libvpx/vpx_config_x86-darwin9-gcc.asm +++ b/media/libvpx/vpx_config_x86-darwin9-gcc.asm @@ -76,7 +76,7 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0 CONFIG_VP9_HIGHBITDEPTH equ 0 CONFIG_EXPERIMENTAL equ 0 -CONFIG_SIZE_LIMIT equ 0 +CONFIG_SIZE_LIMIT equ 1 CONFIG_SPATIAL_SVC equ 0 CONFIG_FP_MB_STATS equ 0 CONFIG_EMULATE_HARDWARE equ 0 diff --git a/media/libvpx/vpx_config_x86-darwin9-gcc.h b/media/libvpx/vpx_config_x86-darwin9-gcc.h index 40502b410daa..7cca4b699d2a 100644 --- a/media/libvpx/vpx_config_x86-darwin9-gcc.h +++ b/media/libvpx/vpx_config_x86-darwin9-gcc.h @@ -88,8 +88,10 @@ #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 #define CONFIG_VP9_HIGHBITDEPTH 0 #define CONFIG_EXPERIMENTAL 0 -#define CONFIG_SIZE_LIMIT 0 +#define CONFIG_SIZE_LIMIT 1 #define CONFIG_SPATIAL_SVC 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 +#define DECODE_WIDTH_LIMIT 4000 +#define DECODE_HEIGHT_LIMIT 3000 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/vpx_config_x86-linux-gcc.asm b/media/libvpx/vpx_config_x86-linux-gcc.asm index 5400f57d5a5f..63b48bb176c4 100644 --- a/media/libvpx/vpx_config_x86-linux-gcc.asm +++ b/media/libvpx/vpx_config_x86-linux-gcc.asm @@ -76,7 +76,7 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0 CONFIG_VP9_HIGHBITDEPTH equ 0 CONFIG_EXPERIMENTAL equ 0 -CONFIG_SIZE_LIMIT equ 0 +CONFIG_SIZE_LIMIT equ 1 CONFIG_SPATIAL_SVC equ 0 CONFIG_FP_MB_STATS equ 0 CONFIG_EMULATE_HARDWARE equ 0 diff --git a/media/libvpx/vpx_config_x86-linux-gcc.h b/media/libvpx/vpx_config_x86-linux-gcc.h index e7b472e84fea..edcf0ee9fc69 100644 --- a/media/libvpx/vpx_config_x86-linux-gcc.h +++ b/media/libvpx/vpx_config_x86-linux-gcc.h @@ -88,8 +88,10 @@ #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 #define CONFIG_VP9_HIGHBITDEPTH 0 #define CONFIG_EXPERIMENTAL 0 -#define CONFIG_SIZE_LIMIT 0 +#define CONFIG_SIZE_LIMIT 1 #define CONFIG_SPATIAL_SVC 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 +#define DECODE_WIDTH_LIMIT 4000 +#define DECODE_HEIGHT_LIMIT 3000 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/vpx_config_x86-win32-gcc.asm b/media/libvpx/vpx_config_x86-win32-gcc.asm index 29c89a5186b1..86f39772f923 100644 --- a/media/libvpx/vpx_config_x86-win32-gcc.asm +++ b/media/libvpx/vpx_config_x86-win32-gcc.asm @@ -76,7 +76,7 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0 CONFIG_VP9_HIGHBITDEPTH equ 0 CONFIG_EXPERIMENTAL equ 0 -CONFIG_SIZE_LIMIT equ 0 +CONFIG_SIZE_LIMIT equ 1 CONFIG_SPATIAL_SVC equ 0 CONFIG_FP_MB_STATS equ 0 CONFIG_EMULATE_HARDWARE equ 0 diff --git a/media/libvpx/vpx_config_x86-win32-gcc.h b/media/libvpx/vpx_config_x86-win32-gcc.h index e60f84d8c171..abc34be9d6dd 100644 --- a/media/libvpx/vpx_config_x86-win32-gcc.h +++ b/media/libvpx/vpx_config_x86-win32-gcc.h @@ -89,8 +89,10 @@ #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 #define CONFIG_VP9_HIGHBITDEPTH 0 #define CONFIG_EXPERIMENTAL 0 -#define CONFIG_SIZE_LIMIT 0 +#define CONFIG_SIZE_LIMIT 1 #define CONFIG_SPATIAL_SVC 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 +#define DECODE_WIDTH_LIMIT 4000 +#define DECODE_HEIGHT_LIMIT 3000 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/vpx_config_x86-win32-vs12.asm b/media/libvpx/vpx_config_x86-win32-vs12.asm index da0e226da7de..d290abc6072a 100644 --- a/media/libvpx/vpx_config_x86-win32-vs12.asm +++ b/media/libvpx/vpx_config_x86-win32-vs12.asm @@ -76,7 +76,7 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0 CONFIG_VP9_HIGHBITDEPTH equ 0 CONFIG_EXPERIMENTAL equ 0 -CONFIG_SIZE_LIMIT equ 0 +CONFIG_SIZE_LIMIT equ 1 CONFIG_SPATIAL_SVC equ 0 CONFIG_FP_MB_STATS equ 0 CONFIG_EMULATE_HARDWARE equ 0 diff --git a/media/libvpx/vpx_config_x86-win32-vs12.h b/media/libvpx/vpx_config_x86-win32-vs12.h index a91bb8396eac..9c1d36df8405 100644 --- a/media/libvpx/vpx_config_x86-win32-vs12.h +++ b/media/libvpx/vpx_config_x86-win32-vs12.h @@ -88,8 +88,10 @@ #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 #define CONFIG_VP9_HIGHBITDEPTH 0 #define CONFIG_EXPERIMENTAL 0 -#define CONFIG_SIZE_LIMIT 0 +#define CONFIG_SIZE_LIMIT 1 #define CONFIG_SPATIAL_SVC 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 +#define DECODE_WIDTH_LIMIT 4000 +#define DECODE_HEIGHT_LIMIT 3000 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/vpx_config_x86_64-darwin9-gcc.asm b/media/libvpx/vpx_config_x86_64-darwin9-gcc.asm index 3dbb38fc2e61..7c808c83f37c 100644 --- a/media/libvpx/vpx_config_x86_64-darwin9-gcc.asm +++ b/media/libvpx/vpx_config_x86_64-darwin9-gcc.asm @@ -76,7 +76,7 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0 CONFIG_VP9_HIGHBITDEPTH equ 0 CONFIG_EXPERIMENTAL equ 0 -CONFIG_SIZE_LIMIT equ 0 +CONFIG_SIZE_LIMIT equ 1 CONFIG_SPATIAL_SVC equ 0 CONFIG_FP_MB_STATS equ 0 CONFIG_EMULATE_HARDWARE equ 0 diff --git a/media/libvpx/vpx_config_x86_64-darwin9-gcc.h b/media/libvpx/vpx_config_x86_64-darwin9-gcc.h index 0d0477ceeca1..d04556d4585f 100644 --- a/media/libvpx/vpx_config_x86_64-darwin9-gcc.h +++ b/media/libvpx/vpx_config_x86_64-darwin9-gcc.h @@ -88,8 +88,10 @@ #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 #define CONFIG_VP9_HIGHBITDEPTH 0 #define CONFIG_EXPERIMENTAL 0 -#define CONFIG_SIZE_LIMIT 0 +#define CONFIG_SIZE_LIMIT 1 #define CONFIG_SPATIAL_SVC 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 +#define DECODE_WIDTH_LIMIT 4000 +#define DECODE_HEIGHT_LIMIT 3000 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/vpx_config_x86_64-linux-gcc.asm b/media/libvpx/vpx_config_x86_64-linux-gcc.asm index 6da93489bfb4..481d00df05c5 100644 --- a/media/libvpx/vpx_config_x86_64-linux-gcc.asm +++ b/media/libvpx/vpx_config_x86_64-linux-gcc.asm @@ -76,7 +76,7 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0 CONFIG_VP9_HIGHBITDEPTH equ 0 CONFIG_EXPERIMENTAL equ 0 -CONFIG_SIZE_LIMIT equ 0 +CONFIG_SIZE_LIMIT equ 1 CONFIG_SPATIAL_SVC equ 0 CONFIG_FP_MB_STATS equ 0 CONFIG_EMULATE_HARDWARE equ 0 diff --git a/media/libvpx/vpx_config_x86_64-linux-gcc.h b/media/libvpx/vpx_config_x86_64-linux-gcc.h index 21228cd1dd09..dcd1ad82a9f5 100644 --- a/media/libvpx/vpx_config_x86_64-linux-gcc.h +++ b/media/libvpx/vpx_config_x86_64-linux-gcc.h @@ -88,8 +88,10 @@ #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 #define CONFIG_VP9_HIGHBITDEPTH 0 #define CONFIG_EXPERIMENTAL 0 -#define CONFIG_SIZE_LIMIT 0 +#define CONFIG_SIZE_LIMIT 1 #define CONFIG_SPATIAL_SVC 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 +#define DECODE_WIDTH_LIMIT 4000 +#define DECODE_HEIGHT_LIMIT 3000 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/vpx_config_x86_64-win64-gcc.asm b/media/libvpx/vpx_config_x86_64-win64-gcc.asm index 20ba15baee06..6d2ded296425 100644 --- a/media/libvpx/vpx_config_x86_64-win64-gcc.asm +++ b/media/libvpx/vpx_config_x86_64-win64-gcc.asm @@ -76,7 +76,7 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0 CONFIG_VP9_HIGHBITDEPTH equ 0 CONFIG_EXPERIMENTAL equ 0 -CONFIG_SIZE_LIMIT equ 0 +CONFIG_SIZE_LIMIT equ 1 CONFIG_SPATIAL_SVC equ 0 CONFIG_FP_MB_STATS equ 0 CONFIG_EMULATE_HARDWARE equ 0 diff --git a/media/libvpx/vpx_config_x86_64-win64-gcc.h b/media/libvpx/vpx_config_x86_64-win64-gcc.h index b056a0ea3850..cf8a66268eb1 100644 --- a/media/libvpx/vpx_config_x86_64-win64-gcc.h +++ b/media/libvpx/vpx_config_x86_64-win64-gcc.h @@ -89,8 +89,10 @@ #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 #define CONFIG_VP9_HIGHBITDEPTH 0 #define CONFIG_EXPERIMENTAL 0 -#define CONFIG_SIZE_LIMIT 0 +#define CONFIG_SIZE_LIMIT 1 #define CONFIG_SPATIAL_SVC 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 +#define DECODE_WIDTH_LIMIT 4000 +#define DECODE_HEIGHT_LIMIT 3000 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/vpx_config_x86_64-win64-vs12.asm b/media/libvpx/vpx_config_x86_64-win64-vs12.asm index 39c17a07c3ee..a3d10b8d814a 100644 --- a/media/libvpx/vpx_config_x86_64-win64-vs12.asm +++ b/media/libvpx/vpx_config_x86_64-win64-vs12.asm @@ -76,7 +76,7 @@ CONFIG_VP9_TEMPORAL_DENOISING equ 0 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0 CONFIG_VP9_HIGHBITDEPTH equ 0 CONFIG_EXPERIMENTAL equ 0 -CONFIG_SIZE_LIMIT equ 0 +CONFIG_SIZE_LIMIT equ 1 CONFIG_SPATIAL_SVC equ 0 CONFIG_FP_MB_STATS equ 0 CONFIG_EMULATE_HARDWARE equ 0 diff --git a/media/libvpx/vpx_config_x86_64-win64-vs12.h b/media/libvpx/vpx_config_x86_64-win64-vs12.h index 4ad69bdb8445..17cd9421ed24 100644 --- a/media/libvpx/vpx_config_x86_64-win64-vs12.h +++ b/media/libvpx/vpx_config_x86_64-win64-vs12.h @@ -88,8 +88,10 @@ #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 #define CONFIG_VP9_HIGHBITDEPTH 0 #define CONFIG_EXPERIMENTAL 0 -#define CONFIG_SIZE_LIMIT 0 +#define CONFIG_SIZE_LIMIT 1 #define CONFIG_SPATIAL_SVC 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 +#define DECODE_WIDTH_LIMIT 4000 +#define DECODE_HEIGHT_LIMIT 3000 #endif /* VPX_CONFIG_H */ From 8dd6d1d0f92135eb373180292c1138a2ab3df1a9 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Fri, 21 Aug 2015 12:09:06 -0400 Subject: [PATCH 162/208] Bug 1185351 - Don't force inline style CSP checks on native anonymous content; r=ckerschb --- dom/base/nsStyledElement.cpp | 7 +++-- dom/base/test/mochitest.ini | 2 ++ .../test/test_anonymousContent_style_csp.html | 28 +++++++++++++++++++ ...t_anonymousContent_style_csp.html^headers^ | 1 + 4 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 dom/base/test/test_anonymousContent_style_csp.html create mode 100644 dom/base/test/test_anonymousContent_style_csp.html^headers^ diff --git a/dom/base/nsStyledElement.cpp b/dom/base/nsStyledElement.cpp index a8d4d984aec9..fd0d1df8ddc4 100644 --- a/dom/base/nsStyledElement.cpp +++ b/dom/base/nsStyledElement.cpp @@ -151,8 +151,10 @@ nsStyledElementNotElementCSSInlineStyle::ParseStyleAttribute(const nsAString& aV bool aForceInDataDoc) { nsIDocument* doc = OwnerDoc(); + bool isNativeAnon = IsInNativeAnonymousSubtree(); - if (!nsStyleUtil::CSPAllowsInlineStyle(nullptr, NodePrincipal(), + if (!isNativeAnon && + !nsStyleUtil::CSPAllowsInlineStyle(nullptr, NodePrincipal(), doc->GetDocumentURI(), 0, aValue, nullptr)) return; @@ -162,8 +164,7 @@ nsStyledElementNotElementCSSInlineStyle::ParseStyleAttribute(const nsAString& aV doc->IsStaticDocument()) { bool isCSS = true; // assume CSS until proven otherwise - if (!IsInNativeAnonymousSubtree()) { // native anonymous content - // always assumes CSS + if (!isNativeAnon) { // native anonymous content always assumes CSS nsAutoString styleType; doc->GetHeaderData(nsGkAtoms::headerContentStyleType, styleType); if (!styleType.IsEmpty()) { diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index 208616b974fb..5538a7847c36 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -252,11 +252,13 @@ support-files = iframe_postMessages.html test_performance_observer.js performance_observer.html + test_anonymousContent_style_csp.html^headers^ [test_anonymousContent_api.html] [test_anonymousContent_append_after_reflow.html] [test_anonymousContent_insert.html] [test_anonymousContent_manipulate_content.html] +[test_anonymousContent_style_csp.html] [test_appname_override.html] [test_async_setTimeout_stack.html] [test_async_setTimeout_stack_across_globals.html] diff --git a/dom/base/test/test_anonymousContent_style_csp.html b/dom/base/test/test_anonymousContent_style_csp.html new file mode 100644 index 000000000000..69d133aad233 --- /dev/null +++ b/dom/base/test/test_anonymousContent_style_csp.html @@ -0,0 +1,28 @@ + + + + + + Test for Bug 1185351 - Make sure that we don't enforce CSP on styles for AnonymousContent + + + + +
+
text content
+
+ + + diff --git a/dom/base/test/test_anonymousContent_style_csp.html^headers^ b/dom/base/test/test_anonymousContent_style_csp.html^headers^ new file mode 100644 index 000000000000..b7b3c8a4f9ea --- /dev/null +++ b/dom/base/test/test_anonymousContent_style_csp.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' From 857c1206f10b6f8e447c1f2ecaca1703363ede11 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Fri, 21 Aug 2015 08:59:23 -0400 Subject: [PATCH 163/208] Bug 1197185 - Give NonE10s a virtual destructor; r=jesup The Parent template class inherits from both NonE10s and PMediaParent, and the latter has a virtual destructor. This confuses clang-tidy when it wants to rewrite ~Parent() which is currently marked as virtual, and it makes ~Parent() override which breaks the build since ~NonE10s() is not virtual. The easiest way to work around this seems to be making ~NonE10s() virtual. See the discussion in https://llvm.org/bugs/show_bug.cgi?id=24496 as well. --- dom/media/systemservices/MediaParent.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dom/media/systemservices/MediaParent.h b/dom/media/systemservices/MediaParent.h index cad36d65ad84..5db7a0b45207 100644 --- a/dom/media/systemservices/MediaParent.h +++ b/dom/media/systemservices/MediaParent.h @@ -24,6 +24,8 @@ class NonE10s { typedef mozilla::ipc::IProtocolManager::ActorDestroyReason ActorDestroyReason; +public: + virtual ~NonE10s() {} protected: virtual bool RecvGetOriginKey(const uint32_t& aRequestId, const nsCString& aOrigin, From feb9c6a853ce0b41e1f7a32ca03c660a57e52561 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Mon, 17 Aug 2015 17:05:45 -0700 Subject: [PATCH 164/208] Bug 1191236 - Fix UCS canonicalization, r=jonco --- js/src/devtools/rootAnalysis/annotations.js | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/js/src/devtools/rootAnalysis/annotations.js b/js/src/devtools/rootAnalysis/annotations.js index e64cd5806b18..f019d35e1f7f 100644 --- a/js/src/devtools/rootAnalysis/annotations.js +++ b/js/src/devtools/rootAnalysis/annotations.js @@ -251,23 +251,8 @@ function ignoreGCFunction(mangled) function stripUCSAndNamespace(name) { - if (name.startsWith('struct ')) - name = name.substr(7); - if (name.startsWith('class ')) - name = name.substr(6); - if (name.startsWith('const ')) - name = name.substr(6); - if (name.startsWith('js::ctypes::')) - name = name.substr(12); - if (name.startsWith('js::')) - name = name.substr(4); - if (name.startsWith('JS::')) - name = name.substr(4); - if (name.startsWith('mozilla::dom::')) - name = name.substr(14); - if (name.startsWith('mozilla::')) - name = name.substr(9); - + name = name.replace(/(struct|class|union|const) /g, ""); + name = name.replace(/(js::ctypes::|js::|JS::|mozilla::dom::|mozilla::)/g, ""); return name; } From c08972303fceab3ed4b6505150b1906e65871d7f Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 5 Aug 2015 02:38:00 -0700 Subject: [PATCH 165/208] Bug 1191236 - Remove extract() methods used by operation forwarding on rooting types, r=terrence --- js/public/TraceableHashTable.h | 32 +----- js/public/TraceableVector.h | 49 ++-------- js/public/Value.h | 173 ++++++++++++--------------------- js/src/gc/Barrier.h | 7 +- js/src/jsapi.h | 99 ++++++++----------- js/src/jsscript.h | 23 +---- js/src/vm/Interpreter.cpp | 7 +- js/src/vm/ObjectGroup.h | 30 ++---- 8 files changed, 126 insertions(+), 294 deletions(-) diff --git a/js/public/TraceableHashTable.h b/js/public/TraceableHashTable.h index 256e1f98f77e..83f29dffc514 100644 --- a/js/public/TraceableHashTable.h +++ b/js/public/TraceableHashTable.h @@ -76,7 +76,7 @@ class TraceableHashMapOperations using Range = typename Map::Range; using Enum = typename Map::Enum; - const Map& map() const { return static_cast(this)->extract(); } + const Map& map() const { return static_cast(this)->get(); } public: bool initialized() const { return map().initialized(); } @@ -101,7 +101,7 @@ class MutableTraceableHashMapOperations using Range = typename Map::Range; using Enum = typename Map::Enum; - Map& map() { return static_cast(this)->extract(); } + Map& map() { return static_cast(this)->get(); } public: bool init(uint32_t len = 16) { return map().init(len); } @@ -140,40 +140,18 @@ class MutableTraceableHashMapOperations template class RootedBase> : public MutableTraceableHashMapOperations>, A,B,C,D,E,F> -{ - using Map = TraceableHashMap; - - friend class TraceableHashMapOperations, A,B,C,D,E,F>; - const Map& extract() const { return *static_cast*>(this)->address(); } - - friend class MutableTraceableHashMapOperations, A,B,C,D,E,F>; - Map& extract() { return *static_cast*>(this)->address(); } -}; +{}; template class MutableHandleBase> : public MutableTraceableHashMapOperations>, A,B,C,D,E,F> -{ - using Map = TraceableHashMap; - - friend class TraceableHashMapOperations, A,B,C,D,E,F>; - const Map& extract() const { - return *static_cast*>(this)->address(); - } - - friend class MutableTraceableHashMapOperations, A,B,C,D,E,F>; - Map& extract() { return *static_cast*>(this)->address(); } -}; +{}; template class HandleBase> : public TraceableHashMapOperations>, A,B,C,D,E,F> -{ - using Map = TraceableHashMap; - friend class TraceableHashMapOperations, A,B,C,D,E,F>; - const Map& extract() const { return *static_cast*>(this)->address(); } -}; +{}; } /* namespace js */ diff --git a/js/public/TraceableVector.h b/js/public/TraceableVector.h index a86f653ed883..53c66961ba17 100644 --- a/js/public/TraceableVector.h +++ b/js/public/TraceableVector.h @@ -59,7 +59,7 @@ template ; - const Vec& vec() const { return static_cast(this)->extract(); } + const Vec& vec() const { return static_cast(this)->get(); } public: const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); } @@ -81,8 +81,8 @@ class MutableTraceableVectorOperations : public TraceableVectorOperations { using Vec = TraceableVector; - const Vec& vec() const { return static_cast(this)->extract(); } - Vec& vec() { return static_cast(this)->extract(); } + const Vec& vec() const { return static_cast(this)->get(); } + Vec& vec() { return static_cast(this)->get(); } public: const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); } @@ -144,59 +144,24 @@ class MutableTraceableVectorOperations template class RootedBase> : public MutableTraceableVectorOperations>, T,N,AP,TP> -{ - using Vec = TraceableVector; - - friend class TraceableVectorOperations, T,N,AP,TP>; - const Vec& extract() const { return *static_cast*>(this)->address(); } - - friend class MutableTraceableVectorOperations, T,N,AP,TP>; - Vec& extract() { return *static_cast*>(this)->address(); } -}; +{}; template class MutableHandleBase> : public MutableTraceableVectorOperations>, T,N,AP,TP> -{ - using Vec = TraceableVector; - - friend class TraceableVectorOperations, T,N,AP,TP>; - const Vec& extract() const { - return *static_cast*>(this)->address(); - } - - friend class MutableTraceableVectorOperations, T,N,AP,TP>; - Vec& extract() { return *static_cast*>(this)->address(); } -}; +{}; template class HandleBase> : public TraceableVectorOperations>, T,N,AP,TP> -{ - using Vec = TraceableVector; - - friend class TraceableVectorOperations, T,N,AP,TP>; - const Vec& extract() const { - return *static_cast*>(this)->address(); - } -}; +{}; template class PersistentRootedBase> : public MutableTraceableVectorOperations>, T,N,AP,TP> -{ - using Vec = TraceableVector; - - friend class TraceableVectorOperations, T,N,AP,TP>; - const Vec& extract() const { - return *static_cast*>(this)->address(); - } - - friend class MutableTraceableVectorOperations, T,N,AP,TP>; - Vec& extract() { return *static_cast*>(this)->address(); } -}; +{}; } // namespace js diff --git a/js/public/Value.h b/js/public/Value.h index 9f7c44369c32..fefc7dbc3ced 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -1676,82 +1676,82 @@ template class MutableValueOperations; /* * A class designed for CRTP use in implementing the non-mutating parts of the * Value interface in Value-like classes. Outer must be a class inheriting - * ValueOperations with a visible extract() method returning the - * const Value* abstracted by Outer. + * ValueOperations with a visible get() method returning a const + * reference to the Value abstracted by Outer. */ template class ValueOperations { friend class MutableValueOperations; - const JS::Value * value() const { return static_cast(this)->extract(); } + const JS::Value& value() const { return static_cast(this)->get(); } public: - bool isUndefined() const { return value()->isUndefined(); } - bool isNull() const { return value()->isNull(); } - bool isBoolean() const { return value()->isBoolean(); } - bool isTrue() const { return value()->isTrue(); } - bool isFalse() const { return value()->isFalse(); } - bool isNumber() const { return value()->isNumber(); } - bool isInt32() const { return value()->isInt32(); } - bool isInt32(int32_t i32) const { return value()->isInt32(i32); } - bool isDouble() const { return value()->isDouble(); } - bool isString() const { return value()->isString(); } - bool isSymbol() const { return value()->isSymbol(); } - bool isObject() const { return value()->isObject(); } - bool isMagic() const { return value()->isMagic(); } - bool isMagic(JSWhyMagic why) const { return value()->isMagic(why); } - bool isMarkable() const { return value()->isMarkable(); } - bool isPrimitive() const { return value()->isPrimitive(); } - bool isGCThing() const { return value()->isGCThing(); } - - bool isNullOrUndefined() const { return value()->isNullOrUndefined(); } - bool isObjectOrNull() const { return value()->isObjectOrNull(); } - - bool toBoolean() const { return value()->toBoolean(); } - double toNumber() const { return value()->toNumber(); } - int32_t toInt32() const { return value()->toInt32(); } - double toDouble() const { return value()->toDouble(); } - JSString* toString() const { return value()->toString(); } - JS::Symbol* toSymbol() const { return value()->toSymbol(); } - JSObject& toObject() const { return value()->toObject(); } - JSObject* toObjectOrNull() const { return value()->toObjectOrNull(); } - gc::Cell* toGCThing() const { return value()->toGCThing(); } - JS::TraceKind traceKind() const { return value()->traceKind(); } - uint64_t asRawBits() const { return value()->asRawBits(); } - - JSValueType extractNonDoubleType() const { return value()->extractNonDoubleType(); } - uint32_t toPrivateUint32() const { return value()->toPrivateUint32(); } - - JSWhyMagic whyMagic() const { return value()->whyMagic(); } - uint32_t magicUint32() const { return value()->magicUint32(); } + bool isUndefined() const { return value().isUndefined(); } + bool isNull() const { return value().isNull(); } + bool isBoolean() const { return value().isBoolean(); } + bool isTrue() const { return value().isTrue(); } + bool isFalse() const { return value().isFalse(); } + bool isNumber() const { return value().isNumber(); } + bool isInt32() const { return value().isInt32(); } + bool isInt32(int32_t i32) const { return value().isInt32(i32); } + bool isDouble() const { return value().isDouble(); } + bool isString() const { return value().isString(); } + bool isSymbol() const { return value().isSymbol(); } + bool isObject() const { return value().isObject(); } + bool isMagic() const { return value().isMagic(); } + bool isMagic(JSWhyMagic why) const { return value().isMagic(why); } + bool isMarkable() const { return value().isMarkable(); } + bool isPrimitive() const { return value().isPrimitive(); } + bool isGCThing() const { return value().isGCThing(); } + + bool isNullOrUndefined() const { return value().isNullOrUndefined(); } + bool isObjectOrNull() const { return value().isObjectOrNull(); } + + bool toBoolean() const { return value().toBoolean(); } + double toNumber() const { return value().toNumber(); } + int32_t toInt32() const { return value().toInt32(); } + double toDouble() const { return value().toDouble(); } + JSString* toString() const { return value().toString(); } + JS::Symbol* toSymbol() const { return value().toSymbol(); } + JSObject& toObject() const { return value().toObject(); } + JSObject* toObjectOrNull() const { return value().toObjectOrNull(); } + gc::Cell* toGCThing() const { return value().toGCThing(); } + JS::TraceKind traceKind() const { return value().traceKind(); } + uint64_t asRawBits() const { return value().asRawBits(); } + + JSValueType extractNonDoubleType() const { return value().extractNonDoubleType(); } + uint32_t toPrivateUint32() const { return value().toPrivateUint32(); } + + JSWhyMagic whyMagic() const { return value().whyMagic(); } + uint32_t magicUint32() const { return value().magicUint32(); } }; /* * A class designed for CRTP use in implementing all the mutating parts of the * Value interface in Value-like classes. Outer must be a class inheriting - * MutableValueOperations with visible extractMutable() and extract() - * methods returning the const Value* and Value* abstracted by Outer. + * MutableValueOperations with visible get() methods returning const and + * non-const references to the Value abstracted by Outer. */ template class MutableValueOperations : public ValueOperations { - JS::Value * value() { return static_cast(this)->extractMutable(); } + JS::Value& value() { return static_cast(this)->get(); } public: - void setNull() { value()->setNull(); } - void setUndefined() { value()->setUndefined(); } - void setInt32(int32_t i) { value()->setInt32(i); } - void setDouble(double d) { value()->setDouble(d); } + void setNull() { value().setNull(); } + void setUndefined() { value().setUndefined(); } + void setInt32(int32_t i) { value().setInt32(i); } + void setDouble(double d) { value().setDouble(d); } void setNaN() { setDouble(JS::GenericNaN()); } - void setBoolean(bool b) { value()->setBoolean(b); } - void setMagic(JSWhyMagic why) { value()->setMagic(why); } - bool setNumber(uint32_t ui) { return value()->setNumber(ui); } - bool setNumber(double d) { return value()->setNumber(d); } - void setString(JSString* str) { this->value()->setString(str); } - void setSymbol(JS::Symbol* sym) { this->value()->setSymbol(sym); } - void setObject(JSObject& obj) { this->value()->setObject(obj); } - void setObjectOrNull(JSObject* arg) { this->value()->setObjectOrNull(arg); } + void setBoolean(bool b) { value().setBoolean(b); } + void setMagic(JSWhyMagic why) { value().setMagic(why); } + bool setNumber(uint32_t ui) { return value().setNumber(ui); } + bool setNumber(double d) { return value().setNumber(d); } + void setString(JSString* str) { this->value().setString(str); } + void setSymbol(JS::Symbol* sym) { this->value().setSymbol(sym); } + void setObject(JSObject& obj) { this->value().setObject(obj); } + void setObjectOrNull(JSObject* arg) { this->value().setObjectOrNull(arg); } }; /* @@ -1765,8 +1765,6 @@ class HeapBase : public ValueOperations > friend class ValueOperations; - const JS::Value * extract() const { return static_cast(this)->address(); } - void setBarriered(const JS::Value& v) { *static_cast*>(this) = v; } @@ -1812,72 +1810,21 @@ class HeapBase : public ValueOperations > } }; -/* - * Augment the generic Handle interface when T = Value with type-querying - * and value-extracting operations. - */ template <> class HandleBase : public ValueOperations > -{ - friend class ValueOperations >; - const JS::Value * extract() const { - return static_cast*>(this)->address(); - } -}; +{}; -/* - * Augment the generic MutableHandle interface when T = Value with - * type-querying, value-extracting, and mutating operations. - */ template <> class MutableHandleBase : public MutableValueOperations > -{ - friend class ValueOperations >; - const JS::Value * extract() const { - return static_cast*>(this)->address(); - } - - friend class MutableValueOperations >; - JS::Value * extractMutable() { - return static_cast*>(this)->address(); - } -}; +{}; -/* - * Augment the generic Rooted interface when T = Value with type-querying, - * value-extracting, and mutating operations. - */ template <> class RootedBase : public MutableValueOperations > -{ - friend class ValueOperations >; - const JS::Value * extract() const { - return static_cast*>(this)->address(); - } - - friend class MutableValueOperations >; - JS::Value * extractMutable() { - return static_cast*>(this)->address(); - } -}; +{}; -/* - * Augment the generic PersistentRooted interface when T = Value with type-querying, - * value-extracting, and mutating operations. - */ template <> class PersistentRootedBase : public MutableValueOperations> -{ - friend class ValueOperations>; - const JS::Value * extract() const { - return static_cast*>(this)->address(); - } - - friend class MutableValueOperations>; - JS::Value * extractMutable() { - return static_cast*>(this)->address(); - } -}; +{}; /* * If the Value is a GC pointer type, convert to that type and call |f| with diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index be47844b3485..7be7bfcc1a95 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -342,12 +342,7 @@ class BarrieredBase : public BarrieredBaseMixins template <> class BarrieredBaseMixins : public ValueOperations > -{ - friend class ValueOperations >; - const JS::Value * extract() const { - return static_cast*>(this)->unsafeGet(); - } -}; +{}; /* * PreBarriered only automatically handles pre-barriers. Post-barriers must diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 89294e736b81..81b9f7ad5d4b 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2437,20 +2437,20 @@ namespace JS { template class PropertyDescriptorOperations { - const JSPropertyDescriptor* desc() const { return static_cast(this)->extract(); } + const JSPropertyDescriptor& desc() const { return static_cast(this)->get(); } bool has(unsigned bit) const { MOZ_ASSERT(bit != 0); MOZ_ASSERT((bit & (bit - 1)) == 0); // only a single bit - return (desc()->attrs & bit) != 0; + return (desc().attrs & bit) != 0; } bool hasAny(unsigned bits) const { - return (desc()->attrs & bits) != 0; + return (desc().attrs & bits) != 0; } bool hasAll(unsigned bits) const { - return (desc()->attrs & bits) == bits; + return (desc().attrs & bits) == bits; } // Non-API attributes bit used internally for arguments objects. @@ -2461,7 +2461,7 @@ class PropertyDescriptorOperations // descriptors. It's complicated. bool isAccessorDescriptor() const { return hasAny(JSPROP_GETTER | JSPROP_SETTER); } bool isGenericDescriptor() const { - return (desc()->attrs& + return (desc().attrs& (JSPROP_GETTER | JSPROP_SETTER | JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE)) == (JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE); } @@ -2475,7 +2475,7 @@ class PropertyDescriptorOperations bool hasValue() const { return !isAccessorDescriptor() && !has(JSPROP_IGNORE_VALUE); } JS::HandleValue value() const { - return JS::HandleValue::fromMarkedLocation(&desc()->value); + return JS::HandleValue::fromMarkedLocation(&desc().value); } bool hasWritable() const { return !isAccessorDescriptor() && !has(JSPROP_IGNORE_READONLY); } @@ -2485,24 +2485,24 @@ class PropertyDescriptorOperations JS::HandleObject getterObject() const { MOZ_ASSERT(hasGetterObject()); return JS::HandleObject::fromMarkedLocation( - reinterpret_cast(&desc()->getter)); + reinterpret_cast(&desc().getter)); } bool hasSetterObject() const { return has(JSPROP_SETTER); } JS::HandleObject setterObject() const { MOZ_ASSERT(hasSetterObject()); return JS::HandleObject::fromMarkedLocation( - reinterpret_cast(&desc()->setter)); + reinterpret_cast(&desc().setter)); } - bool hasGetterOrSetter() const { return desc()->getter || desc()->setter; } + bool hasGetterOrSetter() const { return desc().getter || desc().setter; } bool isShared() const { return has(JSPROP_SHARED); } JS::HandleObject object() const { - return JS::HandleObject::fromMarkedLocation(&desc()->obj); + return JS::HandleObject::fromMarkedLocation(&desc().obj); } - unsigned attributes() const { return desc()->attrs; } - JSGetterOp getter() const { return desc()->getter; } - JSSetterOp setter() const { return desc()->setter; } + unsigned attributes() const { return desc().attrs; } + JSGetterOp getter() const { return desc().getter; } + JSSetterOp setter() const { return desc().setter; } void assertValid() const { #ifdef DEBUG @@ -2569,7 +2569,7 @@ class PropertyDescriptorOperations template class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations { - JSPropertyDescriptor * desc() { return static_cast(this)->extractMutable(); } + JSPropertyDescriptor& desc() { return static_cast(this)->get(); } public: void clear() { @@ -2615,63 +2615,63 @@ class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations< } JS::MutableHandleObject object() { - return JS::MutableHandleObject::fromMarkedLocation(&desc()->obj); + return JS::MutableHandleObject::fromMarkedLocation(&desc().obj); } - unsigned& attributesRef() { return desc()->attrs; } - JSGetterOp& getter() { return desc()->getter; } - JSSetterOp& setter() { return desc()->setter; } + unsigned& attributesRef() { return desc().attrs; } + JSGetterOp& getter() { return desc().getter; } + JSSetterOp& setter() { return desc().setter; } JS::MutableHandleValue value() { - return JS::MutableHandleValue::fromMarkedLocation(&desc()->value); + return JS::MutableHandleValue::fromMarkedLocation(&desc().value); } void setValue(JS::HandleValue v) { - MOZ_ASSERT(!(desc()->attrs & (JSPROP_GETTER | JSPROP_SETTER))); + MOZ_ASSERT(!(desc().attrs & (JSPROP_GETTER | JSPROP_SETTER))); attributesRef() &= ~JSPROP_IGNORE_VALUE; value().set(v); } void setConfigurable(bool configurable) { - setAttributes((desc()->attrs & ~(JSPROP_IGNORE_PERMANENT | JSPROP_PERMANENT)) | + setAttributes((desc().attrs & ~(JSPROP_IGNORE_PERMANENT | JSPROP_PERMANENT)) | (configurable ? 0 : JSPROP_PERMANENT)); } void setEnumerable(bool enumerable) { - setAttributes((desc()->attrs & ~(JSPROP_IGNORE_ENUMERATE | JSPROP_ENUMERATE)) | + setAttributes((desc().attrs & ~(JSPROP_IGNORE_ENUMERATE | JSPROP_ENUMERATE)) | (enumerable ? JSPROP_ENUMERATE : 0)); } void setWritable(bool writable) { - MOZ_ASSERT(!(desc()->attrs & (JSPROP_GETTER | JSPROP_SETTER))); - setAttributes((desc()->attrs & ~(JSPROP_IGNORE_READONLY | JSPROP_READONLY)) | + MOZ_ASSERT(!(desc().attrs & (JSPROP_GETTER | JSPROP_SETTER))); + setAttributes((desc().attrs & ~(JSPROP_IGNORE_READONLY | JSPROP_READONLY)) | (writable ? 0 : JSPROP_READONLY)); } - void setAttributes(unsigned attrs) { desc()->attrs = attrs; } + void setAttributes(unsigned attrs) { desc().attrs = attrs; } void setGetter(JSGetterOp op) { MOZ_ASSERT(op != JS_PropertyStub); - desc()->getter = op; + desc().getter = op; } void setSetter(JSSetterOp op) { MOZ_ASSERT(op != JS_StrictPropertyStub); - desc()->setter = op; + desc().setter = op; } void setGetterObject(JSObject* obj) { - desc()->getter = reinterpret_cast(obj); - desc()->attrs &= ~(JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY | JSPROP_READONLY); - desc()->attrs |= JSPROP_GETTER | JSPROP_SHARED; + desc().getter = reinterpret_cast(obj); + desc().attrs &= ~(JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY | JSPROP_READONLY); + desc().attrs |= JSPROP_GETTER | JSPROP_SHARED; } void setSetterObject(JSObject* obj) { - desc()->setter = reinterpret_cast(obj); - desc()->attrs &= ~(JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY | JSPROP_READONLY); - desc()->attrs |= JSPROP_SETTER | JSPROP_SHARED; + desc().setter = reinterpret_cast(obj); + desc().attrs &= ~(JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY | JSPROP_READONLY); + desc().attrs |= JSPROP_SETTER | JSPROP_SHARED; } JS::MutableHandleObject getterObject() { MOZ_ASSERT(this->hasGetterObject()); return JS::MutableHandleObject::fromMarkedLocation( - reinterpret_cast(&desc()->getter)); + reinterpret_cast(&desc().getter)); } JS::MutableHandleObject setterObject() { MOZ_ASSERT(this->hasSetterObject()); return JS::MutableHandleObject::fromMarkedLocation( - reinterpret_cast(&desc()->setter)); + reinterpret_cast(&desc().setter)); } }; @@ -2682,40 +2682,17 @@ namespace js { template <> class RootedBase : public JS::MutablePropertyDescriptorOperations> -{ - friend class JS::PropertyDescriptorOperations>; - friend class JS::MutablePropertyDescriptorOperations>; - const JSPropertyDescriptor* extract() const { - return static_cast*>(this)->address(); - } - JSPropertyDescriptor* extractMutable() { - return static_cast*>(this)->address(); - } -}; +{}; template <> class HandleBase : public JS::PropertyDescriptorOperations> -{ - friend class JS::PropertyDescriptorOperations>; - const JSPropertyDescriptor* extract() const { - return static_cast*>(this)->address(); - } -}; +{}; template <> class MutableHandleBase : public JS::MutablePropertyDescriptorOperations> -{ - friend class JS::PropertyDescriptorOperations>; - friend class JS::MutablePropertyDescriptorOperations>; - const JSPropertyDescriptor* extract() const { - return static_cast*>(this)->address(); - } - JSPropertyDescriptor* extractMutable() { - return static_cast*>(this)->address(); - } -}; +{}; } /* namespace js */ diff --git a/js/src/jsscript.h b/js/src/jsscript.h index ab58d35d6aa8..187163363607 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -349,7 +349,7 @@ class Bindings : public JS::Traceable template class BindingsOperations { - const Bindings& bindings() const { return static_cast(this)->extract(); } + const Bindings& bindings() const { return static_cast(this)->get(); } public: // Direct data access to the underlying bindings. @@ -413,7 +413,7 @@ class BindingsOperations template class MutableBindingsOperations : public BindingsOperations { - Bindings& bindings() { return static_cast(this)->extractMutable(); } + Bindings& bindings() { return static_cast(this)->get(); } public: void setCallObjShape(HandleShape shape) { bindings().callObjShape_ = shape; } @@ -438,27 +438,12 @@ class MutableBindingsOperations : public BindingsOperations template <> class HandleBase : public BindingsOperations> -{ - friend class BindingsOperations>; - const Bindings& extract() const { - return static_cast*>(this)->get(); - } -}; +{}; template <> class MutableHandleBase : public MutableBindingsOperations> -{ - friend class BindingsOperations>; - const Bindings& extract() const { - return static_cast*>(this)->get(); - } - - friend class MutableBindingsOperations>; - Bindings& extractMutable() { - return static_cast*>(this)->get(); - } -}; +{}; class ScriptCounts { diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index c82bbd1ba298..c63a5d959217 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -1770,12 +1770,7 @@ class ReservedRooted : public ReservedRootedBase template <> class ReservedRootedBase : public ValueOperations> -{ - friend class ValueOperations>; - const Value* extract() const { - return static_cast*>(this)->address(); - } -}; +{}; static MOZ_NEVER_INLINE bool Interpret(JSContext* cx, RunState& state) diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h index cc5d3c1978e4..4ba10d86cbff 100644 --- a/js/src/vm/ObjectGroup.h +++ b/js/src/vm/ObjectGroup.h @@ -81,36 +81,26 @@ template <> struct GCMethods template class TaggedProtoOperations { - const TaggedProto* value() const { - return static_cast(this)->extract(); + const TaggedProto& value() const { + return static_cast(this)->get(); } public: - uintptr_t toWord() const { return value()->toWord(); } - inline bool isLazy() const { return value()->isLazy(); } - inline bool isObject() const { return value()->isObject(); } - inline JSObject* toObject() const { return value()->toObject(); } - inline JSObject* toObjectOrNull() const { return value()->toObjectOrNull(); } - JSObject* raw() const { return value()->raw(); } + uintptr_t toWord() const { return value().toWord(); } + inline bool isLazy() const { return value().isLazy(); } + inline bool isObject() const { return value().isObject(); } + inline JSObject* toObject() const { return value().toObject(); } + inline JSObject* toObjectOrNull() const { return value().toObjectOrNull(); } + JSObject* raw() const { return value().raw(); } }; template <> class HandleBase : public TaggedProtoOperations > -{ - friend class TaggedProtoOperations >; - const TaggedProto * extract() const { - return static_cast*>(this)->address(); - } -}; +{}; template <> class RootedBase : public TaggedProtoOperations > -{ - friend class TaggedProtoOperations >; - const TaggedProto* extract() const { - return static_cast*>(this)->address(); - } -}; +{}; // Since JSObject pointers are either nullptr or a valid object and since the // object layout of TaggedProto is identical to a bare object pointer, we can From 63046139b056ea9f860c8aeadd7e0dadaba5f393 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Fri, 24 Jul 2015 13:05:01 -0700 Subject: [PATCH 166/208] Bug 789589 - Implement JS_NewDataView, r=Waldo --- js/src/jsapi-tests/testArrayBufferView.cpp | 55 +++++++++++++++------- js/src/jsfriendapi.h | 10 ++++ js/src/vm/TypedArrayObject.cpp | 49 ++++++++++++++----- 3 files changed, 85 insertions(+), 29 deletions(-) diff --git a/js/src/jsapi-tests/testArrayBufferView.cpp b/js/src/jsapi-tests/testArrayBufferView.cpp index 34afbf7b33dd..853d55780d02 100644 --- a/js/src/jsapi-tests/testArrayBufferView.cpp +++ b/js/src/jsapi-tests/testArrayBufferView.cpp @@ -86,23 +86,10 @@ BEGIN_TEST(testArrayBufferView_type) static JSObject* CreateDataView(JSContext* cx) { - JS::Rooted global(cx, JS::CurrentGlobalOrNull(cx)); - if (!global) + JS::Rooted buffer(cx, JS_NewArrayBuffer(cx, 8)); + if (!buffer) return nullptr; - - static const char code[] = "new DataView(new ArrayBuffer(8))"; - - JS::Rooted val(cx); - JS::CompileOptions opts(cx); - if (!JS::Evaluate(cx, opts.setFileAndLine(__FILE__, __LINE__), - code, strlen(code), &val)) - return nullptr; - - JS::Rooted dv(cx, &val.toObject()); - if (!JS_IsDataViewObject(dv)) - return nullptr; - - return dv; + return JS_NewDataView(cx, buffer, 0, 8); } template buffer(cx); + { + AutoCompartment ac(cx, otherGlobal); + buffer = JS_NewArrayBuffer(cx, 8); + CHECK(buffer); + CHECK(buffer->as().byteLength() == 8); + } + CHECK(buffer->compartment() == otherGlobal->compartment()); + CHECK(JS_WrapObject(cx, &buffer)); + CHECK(buffer->compartment() == global->compartment()); + + JS::Rooted dataview(cx, JS_NewDataView(cx, buffer, 4, 4)); + CHECK(dataview); + CHECK(dataview->is()); + + JS::Rooted val(cx); + + val = ObjectValue(*dataview); + CHECK(JS_SetProperty(cx, global, "view", val)); + + EVAL("view.buffer", &val); + CHECK(val.toObject().is()); + + CHECK(dataview->compartment() == global->compartment()); + JS::Rooted otherView(cx, js::UncheckedUnwrap(dataview)); + CHECK(otherView->compartment() == otherGlobal->compartment()); + JS::Rooted otherBuffer(cx, js::UncheckedUnwrap(&val.toObject())); + CHECK(otherBuffer->compartment() == otherGlobal->compartment()); + + EVAL("Object.getPrototypeOf(view) === DataView.prototype", &val); + CHECK(val.toBoolean() == true); + return true; } diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 5bd2c786ea25..c14cd030ca15 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -2127,6 +2127,16 @@ JS_IsNeuteredArrayBufferObject(JSObject* obj); JS_FRIEND_API(bool) JS_IsDataViewObject(JSObject* obj); +/* + * Create a new DataView using the given ArrayBuffer for storage. The given + * buffer must be an ArrayBuffer (or a cross-compartment wrapper of an + * ArrayBuffer), and the offset and length must fit within the bounds of the + * arrayBuffer. Currently, nullptr will be returned and an exception will be + * thrown if these conditions do not hold, but do not depend on that behavior. + */ +JS_FRIEND_API(JSObject*) +JS_NewDataView(JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, int32_t byteLength); + /* * Return the byte offset of a data view into its array buffer. |obj| must be a * DataView. diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index c5a8a2e205e4..2e1fdf05fa77 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -481,8 +481,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject public: static JSObject* fromBuffer(JSContext* cx, HandleObject bufobj, uint32_t byteOffset, int32_t lengthInt) { - RootedObject proto(cx, nullptr); - return fromBufferWithProto(cx, bufobj, byteOffset, lengthInt, proto); + return fromBufferWithProto(cx, bufobj, byteOffset, lengthInt, nullptr); } static JSObject* @@ -969,17 +968,11 @@ DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength, { MOZ_ASSERT(byteOffset <= INT32_MAX); MOZ_ASSERT(byteLength <= INT32_MAX); + MOZ_ASSERT(byteOffset + byteLength < UINT32_MAX); RootedObject proto(cx, protoArg); RootedObject obj(cx); - // This is overflow-safe: 2 * INT32_MAX is still a valid uint32_t. - if (byteOffset + byteLength > arrayBuffer->byteLength()) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1"); - return nullptr; - - } - NewObjectKind newKind = DataViewNewObjectKind(cx, byteLength, proto); obj = NewBuiltinClassInstance(cx, &class_, newKind); if (!obj) @@ -1002,12 +995,17 @@ DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength, } } + // Caller should have established these preconditions, and no + // (non-self-hosted) JS code has had an opportunity to run so nothing can + // have invalidated them. + MOZ_ASSERT(byteOffset <= arrayBuffer->byteLength()); + MOZ_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength()); + DataViewObject& dvobj = obj->as(); dvobj.setFixedSlot(TypedArrayLayout::BYTEOFFSET_SLOT, Int32Value(byteOffset)); dvobj.setFixedSlot(TypedArrayLayout::LENGTH_SLOT, Int32Value(byteLength)); dvobj.setFixedSlot(TypedArrayLayout::BUFFER_SLOT, ObjectValue(*arrayBuffer)); dvobj.initPrivate(arrayBuffer->dataPointer() + byteOffset); - MOZ_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength()); // Include a barrier if the data view's data pointer is in the nursery, as // is done for typed arrays. @@ -1033,9 +1031,8 @@ DataViewObject::construct(JSContext* cx, JSObject* bufobj, const CallArgs& args, } Rooted buffer(cx, &AsArrayBuffer(bufobj)); - uint32_t bufferLength = buffer->byteLength(); uint32_t byteOffset = 0; - uint32_t byteLength = bufferLength; + uint32_t byteLength = buffer->byteLength(); if (args.length() > 1) { if (!ToUint32(cx, args[1], &byteOffset)) @@ -1055,6 +1052,8 @@ DataViewObject::construct(JSContext* cx, JSObject* bufobj, const CallArgs& args, return false; } } else { + uint32_t bufferLength = buffer->byteLength(); + if (byteOffset > bufferLength) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1"); @@ -1069,7 +1068,7 @@ DataViewObject::construct(JSContext* cx, JSObject* bufobj, const CallArgs& args, MOZ_ASSERT(byteOffset <= INT32_MAX); MOZ_ASSERT(byteLength <= INT32_MAX); - if (byteOffset + byteLength > bufferLength) { + if (byteOffset + byteLength > buffer->byteLength()) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1"); return false; } @@ -2348,3 +2347,27 @@ JS_GetDataViewByteLength(JSObject* obj) return 0; return obj->as().byteLength(); } + +JS_FRIEND_API(JSObject*) +JS_NewDataView(JSContext* cx, HandleObject arrayBuffer, uint32_t byteOffset, int32_t byteLength) +{ + ConstructArgs cargs(cx); + if (!cargs.init(3)) + return nullptr; + + RootedObject constructor(cx); + JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(&DataViewObject::class_); + if (!GetBuiltinConstructor(cx, key, &constructor)) + return nullptr; + + cargs[0].setObject(*arrayBuffer); + cargs[1].setNumber(byteOffset); + cargs[2].setInt32(byteLength); + + RootedValue fun(cx, ObjectValue(*constructor)); + RootedValue rval(cx); + if (!Construct(cx, fun, cargs, fun, &rval)) + return nullptr; + MOZ_ASSERT(rval.isObject()); + return &rval.toObject(); +} From 9cf663069baf5366c0416359b72cab2dc07e29d2 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Tue, 28 Jul 2015 18:13:16 -0700 Subject: [PATCH 167/208] Bug 789589 - Fix the ABO class hierarchy comment to be accurate, r=Waldo --- js/src/vm/ArrayBufferObject.h | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h index 03b25b75de21..c75c20718e6f 100644 --- a/js/src/vm/ArrayBufferObject.h +++ b/js/src/vm/ArrayBufferObject.h @@ -21,23 +21,24 @@ class ArrayBufferViewObject; // The inheritance hierarchy for the various classes relating to typed arrays // is as follows. // -// - JSObject +// - NativeObject // - ArrayBufferObjectMaybeShared // - ArrayBufferObject // - SharedArrayBufferObject -// - ArrayBufferViewObject -// - DataViewObject -// - TypedArrayObject (declared in vm/TypedArrayObject.h) -// - TypedArrayObjectTemplate -// - Int8ArrayObject -// - Uint8ArrayObject -// - ... -// - TypedObject (declared in builtin/TypedObject.h) +// - DataViewObject +// - TypedArrayObject (declared in vm/TypedArrayObject.h) +// - TypedArrayObjectTemplate +// - Int8ArrayObject +// - Uint8ArrayObject +// - ... // - SharedTypedArrayObject (declared in vm/SharedTypedArrayObject.h) // - SharedTypedArrayObjectTemplate // - SharedInt8ArrayObject // - SharedUint8ArrayObject // - ... +// - JSObject +// - ArrayBufferViewObject +// - TypedObject (declared in builtin/TypedObject.h) // // Note that |TypedArrayObjectTemplate| is just an implementation // detail that makes implementing its various subclasses easier. From 7db41f1199ef9f9e05c99e877b5a326c7f0f44e2 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Tue, 28 Jul 2015 18:14:36 -0700 Subject: [PATCH 168/208] Bug 789594 - Implement DataView cloning, r=Waldo --- .../js1_8_5/extensions/clone-transferables.js | 20 +++++-- js/src/vm/ArrayBufferObject.h | 12 ++-- js/src/vm/StructuredClone.cpp | 58 +++++++++++++++++++ 3 files changed, 78 insertions(+), 12 deletions(-) diff --git a/js/src/tests/js1_8_5/extensions/clone-transferables.js b/js/src/tests/js1_8_5/extensions/clone-transferables.js index 86e8e93ae99e..13657e5513d7 100644 --- a/js/src/tests/js1_8_5/extensions/clone-transferables.js +++ b/js/src/tests/js1_8_5/extensions/clone-transferables.js @@ -23,20 +23,26 @@ function test() { Uint32Array, Float32Array, Float64Array, - Uint8ClampedArray ]; + Uint8ClampedArray, + DataView ]; for (var ctor of constructors) { + var dataview = (ctor === DataView); + var buf = new buffer_ctor(size); var old_arr = new ctor(buf); assertEq(buf.byteLength, size); assertEq(buf, old_arr.buffer); - assertEq(old_arr.length, size / old_arr.BYTES_PER_ELEMENT); + if (!dataview) + assertEq(old_arr.length, size / old_arr.BYTES_PER_ELEMENT); var copy_arr = deserialize(serialize(old_arr, [ buf ])); assertEq(buf.byteLength, 0, "donor array buffer should be neutered"); - assertEq(old_arr.length, 0, "donor typed array should be neutered"); + if (!dataview) + assertEq(old_arr.length, 0, "donor typed array should be neutered"); assertEq(copy_arr.buffer.byteLength == size, true); - assertEq(copy_arr.length, size / old_arr.BYTES_PER_ELEMENT); + if (!dataview) + assertEq(copy_arr.length, size / old_arr.BYTES_PER_ELEMENT); buf = null; old_arr = null; @@ -44,12 +50,16 @@ function test() { } for (var ctor of constructors) { + var dataview = (ctor === DataView); + var buf = new buffer_ctor(size); var old_arr = new ctor(buf); var dv = new DataView(buf); // Second view var copy_arr = deserialize(serialize(old_arr, [ buf ])); assertEq(buf.byteLength, 0, "donor array buffer should be neutered"); - assertEq(old_arr.length, 0, "donor typed array should be neutered"); + assertEq(old_arr.byteLength, 0, "donor typed array should be neutered"); + if (!dataview) + assertEq(old_arr.length, 0, "donor typed array should be neutered"); assertEq(dv.byteLength, 0, "all views of donor array buffer should be neutered"); buf = null; diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h index c75c20718e6f..5d807a27a223 100644 --- a/js/src/vm/ArrayBufferObject.h +++ b/js/src/vm/ArrayBufferObject.h @@ -40,8 +40,6 @@ class ArrayBufferViewObject; // - ArrayBufferViewObject // - TypedObject (declared in builtin/TypedObject.h) // -// Note that |TypedArrayObjectTemplate| is just an implementation -// detail that makes implementing its various subclasses easier. // Note that |TypedArrayObjectTemplate| and |SharedTypedArrayObjectTemplate| are // just implementation details that make implementing their various subclasses easier. // @@ -95,11 +93,11 @@ class ArrayBufferObjectMaybeShared : public NativeObject /* * ArrayBufferObject * - * This class holds the underlying raw buffer that the various - * ArrayBufferViewObject subclasses (DataViewObject and the TypedArrays) - * access. It can be created explicitly and passed to an ArrayBufferViewObject - * subclass, or can be created lazily when it is first accessed for a - * TypedArrayObject or TypedObject that doesn't have an explicit buffer. + * This class holds the underlying raw buffer that the various ArrayBufferViews + * (eg DataViewObject, the TypedArrays, TypedObjects) access. It can be created + * explicitly and used to construct an ArrayBufferView, or can be created + * lazily when it is first accessed for a TypedArrayObject or TypedObject that + * doesn't have an explicit buffer. * * ArrayBufferObject (or really the underlying memory) /is not racy/: the * memory is private to a single worker. diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index 268dd02f571f..c86f218e2954 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -91,6 +91,7 @@ enum StructuredDataType : uint32_t { SCTAG_SET_OBJECT, SCTAG_END_OF_KEYS, SCTAG_SHARED_TYPED_ARRAY_OBJECT, + SCTAG_DATA_VIEW_OBJECT, SCTAG_TYPED_ARRAY_V1_MIN = 0xFFFF0100, SCTAG_TYPED_ARRAY_V1_INT8 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Int8, @@ -238,6 +239,7 @@ struct JSStructuredCloneReader { bool checkDouble(double d); bool readTypedArray(uint32_t arrayType, uint32_t nelems, MutableHandleValue vp, bool v1Read = false); + bool readDataView(uint32_t byteLength, MutableHandleValue vp); bool readSharedTypedArray(uint32_t arrayType, uint32_t nelems, MutableHandleValue vp); bool readArrayBuffer(uint32_t nbytes, MutableHandleValue vp); bool readV1ArrayBuffer(uint32_t arrayType, uint32_t nelems, MutableHandleValue vp); @@ -295,6 +297,7 @@ struct JSStructuredCloneWriter { bool writeString(uint32_t tag, JSString* str); bool writeArrayBuffer(HandleObject obj); bool writeTypedArray(HandleObject obj); + bool writeDataView(HandleObject obj); bool writeSharedArrayBuffer(HandleObject obj); bool writeSharedTypedArray(HandleObject obj); bool startObject(HandleObject obj, bool* backref); @@ -863,6 +866,23 @@ JSStructuredCloneWriter::writeTypedArray(HandleObject obj) return out.write(tarr->byteOffset()); } +bool +JSStructuredCloneWriter::writeDataView(HandleObject obj) +{ + Rooted view(context(), &CheckedUnwrap(obj)->as()); + JSAutoCompartment ac(context(), view); + + if (!out.writePair(SCTAG_DATA_VIEW_OBJECT, view->byteLength())) + return false; + + // Write out the ArrayBuffer tag and contents + RootedValue val(context(), DataViewObject::bufferValue(view)); + if (!startWrite(val)) + return false; + + return out.write(view->byteOffset()); +} + bool JSStructuredCloneWriter::writeArrayBuffer(HandleObject obj) { @@ -1046,6 +1066,8 @@ JSStructuredCloneWriter::startWrite(HandleValue v) return out.writePair(SCTAG_DATE_OBJECT, 0) && out.writeDouble(unboxed.toNumber()); } else if (JS_IsTypedArrayObject(obj)) { return writeTypedArray(obj); + } else if (JS_IsDataViewObject(obj)) { + return writeDataView(obj); } else if (JS_IsArrayBufferObject(obj) && JS_ArrayBufferHasData(obj)) { return writeArrayBuffer(obj); } else if (JS_IsSharedTypedArrayObject(obj)) { @@ -1410,6 +1432,37 @@ JSStructuredCloneReader::readTypedArray(uint32_t arrayType, uint32_t nelems, Mut return true; } +bool +JSStructuredCloneReader::readDataView(uint32_t byteLength, MutableHandleValue vp) +{ + // Push a placeholder onto the allObjs list to stand in for the DataView. + uint32_t placeholderIndex = allObjs.length(); + Value dummy = UndefinedValue(); + if (!allObjs.append(dummy)) + return false; + + // Read the ArrayBuffer object and its contents (but no properties). + RootedValue v(context()); + if (!startRead(&v)) + return false; + + // Read byteOffset. + uint64_t n; + if (!in.read(&n)) + return false; + uint32_t byteOffset = n; + + RootedObject buffer(context(), &v.toObject()); + RootedObject obj(context(), JS_NewDataView(context(), buffer, byteOffset, byteLength)); + if (!obj) + return false; + vp.setObject(*obj); + + allObjs[placeholderIndex].set(vp); + + return true; +} + bool JSStructuredCloneReader::readSharedTypedArray(uint32_t arrayType, uint32_t nelems, MutableHandleValue vp) { @@ -1673,6 +1726,11 @@ JSStructuredCloneReader::startRead(MutableHandleValue vp) return readTypedArray(arrayType, data, vp); } + case SCTAG_DATA_VIEW_OBJECT: { + // readDataView adds the array to allObjs. + return readDataView(data, vp); + } + case SCTAG_SHARED_TYPED_ARRAY_OBJECT: { // readSharedTypedArray adds the array to allObjs. uint64_t arrayType; From 9c995690156b24573db95306d1b77b377e757bab Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Fri, 21 Aug 2015 16:19:27 -0600 Subject: [PATCH 169/208] Bug 1184388 - Try to use uniform groups for multidimensional constant arrays and structures, r=jandem. --- js/src/frontend/BytecodeEmitter.cpp | 12 +- js/src/frontend/ParseNode.h | 1 + .../tests/basic/homogenous-literals.js | 50 +++++ js/src/vm/JSONParser.cpp | 14 ++ js/src/vm/ObjectGroup.cpp | 200 ++++++++++++++++++ js/src/vm/ObjectGroup.h | 8 + js/src/vm/TypeInference.cpp | 13 ++ js/src/vm/TypeInference.h | 1 + js/src/vm/UnboxedObject.cpp | 54 ++++- js/src/vm/UnboxedObject.h | 4 + 10 files changed, 344 insertions(+), 13 deletions(-) create mode 100644 js/src/jit-test/tests/basic/homogenous-literals.js diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index de87a3d8a7ed..ae6a5748b8f2 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -4574,7 +4574,7 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs) bool ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObjects, MutableHandleValue vp, - NewObjectKind newKind) + Value* compare, size_t ncompare, NewObjectKind newKind) { MOZ_ASSERT(newKind == TenuredObject || newKind == SingletonObject); @@ -4625,7 +4625,7 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje return false; size_t idx; for (idx = 0; pn; idx++, pn = pn->pn_next) { - if (!pn->getConstantValue(cx, allowObjects, values[idx])) + if (!pn->getConstantValue(cx, allowObjects, values[idx], values.begin(), idx)) return false; if (values[idx].isMagic(JS_GENERIC_MAGIC)) { vp.setMagic(JS_GENERIC_MAGIC); @@ -4639,6 +4639,9 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje if (!obj) return false; + if (!CombineArrayElementTypes(cx, obj, compare, ncompare)) + return false; + vp.setObject(*obj); return true; } @@ -4685,6 +4688,9 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje if (!obj) return false; + if (!CombinePlainObjectPropertyTypes(cx, obj, compare, ncompare)) + return false; + vp.setObject(*obj); return true; } @@ -4700,7 +4706,7 @@ BytecodeEmitter::emitSingletonInitialiser(ParseNode* pn) NewObjectKind newKind = (pn->getKind() == PNK_OBJECT) ? SingletonObject : TenuredObject; RootedValue value(cx); - if (!pn->getConstantValue(cx, ParseNode::AllowObjects, &value, newKind)) + if (!pn->getConstantValue(cx, ParseNode::AllowObjects, &value, nullptr, 0, newKind)) return false; MOZ_ASSERT_IF(newKind == SingletonObject, value.toObject().isSingleton()); diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 46c1a2677ca1..cead3676fe49 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -916,6 +916,7 @@ class ParseNode }; bool getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObjects, MutableHandleValue vp, + Value* compare = nullptr, size_t ncompare = 0, NewObjectKind newKind = TenuredObject); inline bool isConstant(); diff --git a/js/src/jit-test/tests/basic/homogenous-literals.js b/js/src/jit-test/tests/basic/homogenous-literals.js new file mode 100644 index 000000000000..d9e3e7761054 --- /dev/null +++ b/js/src/jit-test/tests/basic/homogenous-literals.js @@ -0,0 +1,50 @@ + +function processNoProperty(a) { + var total = 0; + for (var i = 0; i < a.length; i++) { + var sa = a[i]; + for (var j = 0; j < sa.length; j++) + total += sa[j]; + } + assertEq(total, 22); +} + +var literalArray = [ + [1,2,3,4], + [1.5,2.5,3.5,4.5] +]; + +var jsonArray = JSON.parse(`[ + [1,2,3,4], + [1.5,2.5,3.5,4.5] +]`); + +for (var i = 0; i < 1000; i++) { + processNoProperty(literalArray); + processNoProperty(jsonArray); +} + +function processWithProperty(a) { + var total = 0; + for (var i = 0; i < a.length; i++) { + var sa = a[i].p; + for (var j = 0; j < sa.length; j++) + total += sa[j]; + } + assertEq(total, 22); +} + +var literalPropertyArray = [ + {p:[1,2,3,4]}, + {p:[1.5,2.5,3.5,4.5]} +]; + +var jsonPropertyArray = JSON.parse(`[ + {"p":[1,2,3,4]}, + {"p":[1.5,2.5,3.5,4.5]} +]`); + +for (var i = 0; i < 1000; i++) { + processWithProperty(literalPropertyArray); + processWithProperty(jsonPropertyArray); +} diff --git a/js/src/vm/JSONParser.cpp b/js/src/vm/JSONParser.cpp index d4ba7bfe3d35..4ac4d254557e 100644 --- a/js/src/vm/JSONParser.cpp +++ b/js/src/vm/JSONParser.cpp @@ -590,6 +590,13 @@ JSONParserBase::finishObject(MutableHandleValue vp, PropertyVector& properties) if (!freeProperties.append(&properties)) return false; stack.popBack(); + + if (!stack.empty() && stack.back().state == FinishArrayElement) { + const ElementVector& elements = stack.back().elements(); + if (!CombinePlainObjectPropertyTypes(cx, obj, elements.begin(), elements.length())) + return false; + } + return true; } @@ -607,6 +614,13 @@ JSONParserBase::finishArray(MutableHandleValue vp, ElementVector& elements) if (!freeElements.append(&elements)) return false; stack.popBack(); + + if (!stack.empty() && stack.back().state == FinishArrayElement) { + const ElementVector& elements = stack.back().elements(); + if (!CombineArrayElementTypes(cx, obj, elements.begin(), elements.length())) + return false; + } + return true; } diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 70b6a4478442..780069c33f2a 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -868,6 +868,206 @@ ObjectGroup::newArrayObject(ExclusiveContext* cx, ShouldUpdateTypes::DontUpdate); } +static bool +GiveObjectGroup(ExclusiveContext* cx, JSObject* source, JSObject* target) +{ + MOZ_ASSERT(source->group() != target->group()); + + if (!target->is() && !target->is()) + return true; + + if (target->group()->maybePreliminaryObjects()) { + bool force = IsInsideNursery(source); + target->group()->maybePreliminaryObjects()->maybeAnalyze(cx, target->group(), force); + } + + if (target->is()) { + ObjectGroup* sourceGroup = source->group(); + + if (source->is()) { + Shape* shape = target->as().lastProperty(); + if (!UnboxedArrayObject::convertToNativeWithGroup(cx, source, target->group(), shape)) + return false; + } else if (source->is()) { + source->setGroup(target->group()); + } else { + return true; + } + + if (sourceGroup->maybePreliminaryObjects()) + sourceGroup->maybePreliminaryObjects()->unregisterObject(source); + if (target->group()->maybePreliminaryObjects()) + target->group()->maybePreliminaryObjects()->registerNewObject(source); + + for (size_t i = 0; i < source->as().getDenseInitializedLength(); i++) { + Value v = source->as().getDenseElement(i); + AddTypePropertyId(cx, source->group(), source, JSID_VOID, v); + } + + return true; + } + + if (target->is()) { + if (!source->is()) + return true; + if (source->as().elementType() != JSVAL_TYPE_INT32) + return true; + if (target->as().elementType() != JSVAL_TYPE_DOUBLE) + return true; + + return source->as().convertInt32ToDouble(cx, target->group()); + } + + return true; +} + +static bool +SameGroup(JSObject* first, JSObject* second) +{ + return first->group() == second->group(); +} + +// When generating a multidimensional array of literals, such as +// [[1,2],[3,4],[5.5,6.5]], try to ensure that each element of the array has +// the same group. This is mainly important when the elements might have +// different native vs. unboxed layouts, or different unboxed layouts, and +// accessing the heterogenous layouts from JIT code will be much slower than +// if they were homogenous. +// +// To do this, with each new array element we compare it with one of the +// previous ones, and try to mutate the group of the new element to fit that +// of the old element. If this isn't possible, the groups for all old elements +// are mutated to fit that of the new element. +bool +js::CombineArrayElementTypes(ExclusiveContext* cx, JSObject* newObj, + const Value* compare, size_t ncompare) +{ + if (!ncompare || !compare[0].isObject()) + return true; + + JSObject* oldObj = &compare[0].toObject(); + if (SameGroup(oldObj, newObj)) + return true; + + if (!GiveObjectGroup(cx, oldObj, newObj)) + return false; + + if (SameGroup(oldObj, newObj)) + return true; + + if (!GiveObjectGroup(cx, newObj, oldObj)) + return false; + + if (SameGroup(oldObj, newObj)) { + for (size_t i = 1; i < ncompare; i++) { + if (compare[i].isObject() && !SameGroup(&compare[i].toObject(), newObj)) { + if (!GiveObjectGroup(cx, newObj, &compare[i].toObject())) + return false; + } + } + } + + return true; +} + +// Similarly to CombineArrayElementTypes, if we are generating an array of +// plain objects with a consistent property layout, such as +// [{p:[1,2]},{p:[3,4]},{p:[5.5,6.5]}], where those plain objects in +// turn have arrays as their own properties, try to ensure that a consistent +// group is given to each array held by the same property of the plain objects. +bool +js::CombinePlainObjectPropertyTypes(ExclusiveContext* cx, JSObject* newObj, + const Value* compare, size_t ncompare) +{ + if (!ncompare || !compare[0].isObject()) + return true; + + JSObject* oldObj = &compare[0].toObject(); + if (!SameGroup(oldObj, newObj)) + return true; + + if (newObj->is()) { + MOZ_ASSERT(newObj->as().lastProperty() == oldObj->as().lastProperty()); + + for (size_t slot = 0; slot < newObj->as().slotSpan(); slot++) { + Value newValue = newObj->as().getSlot(slot); + Value oldValue = oldObj->as().getSlot(slot); + + if (!newValue.isObject() || !oldValue.isObject()) + continue; + + JSObject* newInnerObj = &newValue.toObject(); + JSObject* oldInnerObj = &oldValue.toObject(); + + if (SameGroup(oldInnerObj, newInnerObj)) + continue; + + if (!GiveObjectGroup(cx, oldInnerObj, newInnerObj)) + return false; + + if (SameGroup(oldInnerObj, newInnerObj)) + continue; + + if (!GiveObjectGroup(cx, newInnerObj, oldInnerObj)) + return false; + + if (SameGroup(oldInnerObj, newInnerObj)) { + for (size_t i = 1; i < ncompare; i++) { + if (compare[i].isObject() && SameGroup(&compare[i].toObject(), newObj)) { + Value otherValue = compare[i].toObject().as().getSlot(slot); + if (otherValue.isObject() && !SameGroup(&otherValue.toObject(), newInnerObj)) { + if (!GiveObjectGroup(cx, newInnerObj, &otherValue.toObject())) + return false; + } + } + } + } + } + } else if (newObj->is()) { + const UnboxedLayout& layout = newObj->as().layout(); + const int32_t* traceList = layout.traceList(); + if (!traceList) + return true; + + uint8_t* newData = newObj->as().data(); + uint8_t* oldData = oldObj->as().data(); + + for (; *traceList != -1; traceList++) {} + traceList++; + for (; *traceList != -1; traceList++) { + JSObject* newInnerObj = *reinterpret_cast(newData + *traceList); + JSObject* oldInnerObj = *reinterpret_cast(oldData + *traceList); + + if (!newInnerObj || !oldInnerObj || SameGroup(oldInnerObj, newInnerObj)) + continue; + + if (!GiveObjectGroup(cx, oldInnerObj, newInnerObj)) + return false; + + if (SameGroup(oldInnerObj, newInnerObj)) + continue; + + if (!GiveObjectGroup(cx, newInnerObj, oldInnerObj)) + return false; + + if (SameGroup(oldInnerObj, newInnerObj)) { + for (size_t i = 1; i < ncompare; i++) { + if (compare[i].isObject() && SameGroup(&compare[i].toObject(), newObj)) { + uint8_t* otherData = compare[i].toObject().as().data(); + JSObject* otherInnerObj = *reinterpret_cast(otherData + *traceList); + if (otherInnerObj && !SameGroup(otherInnerObj, newInnerObj)) { + if (!GiveObjectGroup(cx, newInnerObj, otherInnerObj)) + return false; + } + } + } + } + } + } + + return true; +} + ///////////////////////////////////////////////////////////////////// // ObjectGroupCompartment PlainObjectTable ///////////////////////////////////////////////////////////////////// diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h index 4ba10d86cbff..cb46b1edd654 100644 --- a/js/src/vm/ObjectGroup.h +++ b/js/src/vm/ObjectGroup.h @@ -720,6 +720,14 @@ PlainObject* NewPlainObjectWithProperties(ExclusiveContext* cx, IdValuePair* properties, size_t nproperties, NewObjectKind newKind); +bool +CombineArrayElementTypes(ExclusiveContext* cx, JSObject* newObj, + const Value* compare, size_t ncompare); + +bool +CombinePlainObjectPropertyTypes(ExclusiveContext* cx, JSObject* newObj, + const Value* compare, size_t ncompare); + } // namespace js #endif /* vm_ObjectGroup_h */ diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index c1b223618f37..755616340392 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -3312,6 +3312,19 @@ PreliminaryObjectArray::registerNewObject(JSObject* res) MOZ_CRASH("There should be room for registering the new object"); } +void +PreliminaryObjectArray::unregisterObject(JSObject* obj) +{ + for (size_t i = 0; i < COUNT; i++) { + if (objects[i] == obj) { + objects[i] = nullptr; + return; + } + } + + MOZ_CRASH("The object should be in the array"); +} + bool PreliminaryObjectArray::full() const { diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h index 443f1d713e64..2e15d39d41de 100644 --- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -794,6 +794,7 @@ class PreliminaryObjectArray } void registerNewObject(JSObject* res); + void unregisterObject(JSObject* obj); JSObject* get(size_t i) const { MOZ_ASSERT(i < COUNT); diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index 99031560d802..760dd0112354 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -979,15 +979,9 @@ DefineBoxedOrUnboxedFunctor3(AppendUnboxedDenseElements, UnboxedArrayObject*, uint32_t, AutoValueVector*); /* static */ bool -UnboxedArrayObject::convertToNative(JSContext* cx, JSObject* obj) +UnboxedArrayObject::convertToNativeWithGroup(ExclusiveContext* cx, JSObject* obj, + ObjectGroup* group, Shape* shape) { - const UnboxedLayout& layout = obj->as().layout(); - - if (!layout.nativeGroup()) { - if (!UnboxedLayout::makeNativeGroup(cx, obj->group())) - return false; - } - size_t length = obj->as().length(); size_t initlen = obj->as().initializedLength(); @@ -999,10 +993,10 @@ UnboxedArrayObject::convertToNative(JSContext* cx, JSObject* obj) DebugOnly result = CallBoxedOrUnboxedSpecialization(functor, obj); MOZ_ASSERT(result.value == DenseElementResult::Success); - obj->setGroup(layout.nativeGroup()); + obj->setGroup(group); ArrayObject* aobj = &obj->as(); - aobj->setLastPropertyMakeNative(cx, layout.nativeShape()); + aobj->setLastPropertyMakeNative(cx, shape); // Make sure there is at least one element, so that this array does not // use emptyObjectElements. @@ -1017,6 +1011,46 @@ UnboxedArrayObject::convertToNative(JSContext* cx, JSObject* obj) return true; } +/* static */ bool +UnboxedArrayObject::convertToNative(JSContext* cx, JSObject* obj) +{ + const UnboxedLayout& layout = obj->as().layout(); + + if (!layout.nativeGroup()) { + if (!UnboxedLayout::makeNativeGroup(cx, obj->group())) + return false; + } + + return convertToNativeWithGroup(cx, obj, layout.nativeGroup(), layout.nativeShape()); +} + +bool +UnboxedArrayObject::convertInt32ToDouble(ExclusiveContext* cx, ObjectGroup* group) +{ + MOZ_ASSERT(elementType() == JSVAL_TYPE_INT32); + MOZ_ASSERT(group->unboxedLayout().elementType() == JSVAL_TYPE_DOUBLE); + + Vector values(cx); + if (!values.reserve(initializedLength())) + return false; + for (size_t i = 0; i < initializedLength(); i++) + values.infallibleAppend(getElementSpecific(i).toInt32()); + + uint8_t* newElements = ReallocateObjectBuffer(cx, this, elements(), + capacity() * sizeof(int32_t), + capacity() * sizeof(double)); + if (!newElements) + return false; + + setGroup(group); + elements_ = newElements; + + for (size_t i = 0; i < initializedLength(); i++) + setElementNoTypeChangeSpecific(i, DoubleValue(values[i])); + + return true; +} + /* static */ UnboxedArrayObject* UnboxedArrayObject::create(ExclusiveContext* cx, HandleObjectGroup group, uint32_t length, NewObjectKind newKind, uint32_t maxLength) diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h index 04be43646f09..313bb58cb48d 100644 --- a/js/src/vm/UnboxedObject.h +++ b/js/src/vm/UnboxedObject.h @@ -421,6 +421,10 @@ class UnboxedArrayObject : public JSObject uint32_t length, NewObjectKind newKind, uint32_t maxLength = MaximumCapacity); + static bool convertToNativeWithGroup(ExclusiveContext* cx, JSObject* obj, + ObjectGroup* group, Shape* shape); + bool convertInt32ToDouble(ExclusiveContext* cx, ObjectGroup* group); + void fillAfterConvert(ExclusiveContext* cx, const AutoValueVector& values, size_t* valueCursor); From 9b3010f84413263fa992c79bed5a818823f48908 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Fri, 21 Aug 2015 14:19:04 -0700 Subject: [PATCH 170/208] Bug 1197377 - Read callgraph.txt line by line to avoid string size limits, r=terrence --- js/src/devtools/rootAnalysis/loadCallgraph.js | 5 ++-- js/src/devtools/rootAnalysis/utility.js | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/js/src/devtools/rootAnalysis/loadCallgraph.js b/js/src/devtools/rootAnalysis/loadCallgraph.js index 022fcdeb8a84..934635fe17e9 100644 --- a/js/src/devtools/rootAnalysis/loadCallgraph.js +++ b/js/src/devtools/rootAnalysis/loadCallgraph.js @@ -74,8 +74,9 @@ function loadCallgraph(file) var suppressedFieldCalls = {}; var resolvedFunctions = {}; - var textLines = snarf(file).split('\n'); - for (var line of textLines) { + for (var line of readFileLines_gen(file)) { + line = line.replace(/\n/, ""); + var match; if (match = line.charAt(0) == "#" && /^\#(\d+) (.*)/.exec(line)) { assert(functionNames.length == match[1]); diff --git a/js/src/devtools/rootAnalysis/utility.js b/js/src/devtools/rootAnalysis/utility.js index a460117e207c..b958d226c751 100644 --- a/js/src/devtools/rootAnalysis/utility.js +++ b/js/src/devtools/rootAnalysis/utility.js @@ -145,3 +145,32 @@ function xdbLibrary() free_string: lib.declare("xdb_free", ctypes.default_abi, ctypes.void_t, ctypes.char.ptr) }; } + +function cLibrary() +{ + var lib; + try { + lib = ctypes.open("libc.so.6"); + } catch(e) { + lib = ctypes.open("libc.so"); + } + + return { + fopen: lib.declare("fopen", ctypes.default_abi, ctypes.void_t.ptr, ctypes.char.ptr, ctypes.char.ptr), + getline: lib.declare("getline", ctypes.default_abi, ctypes.ssize_t, ctypes.char.ptr.ptr, ctypes.size_t.ptr, ctypes.void_t.ptr), + fclose: lib.declare("fopen", ctypes.default_abi, ctypes.int, ctypes.void_t.ptr), + setvbuf: lib.declare("setvbuf", ctypes.default_abi, ctypes.int, ctypes.void_t.ptr, ctypes.char.ptr, ctypes.int, ctypes.size_t), + }; +} + +function* readFileLines_gen(filename) +{ + var libc = cLibrary(); + var linebuf = ctypes.char.array(4096)(); + var bufsize = ctypes.size_t(4096); + var fp = libc.fopen(filename, "r"); + var bufp = ctypes.char.ptr(linebuf.addressOfElement(0)); + while (libc.getline(bufp.address(), bufsize.address(), fp) > 0) + yield bufp.readString(); + libc.fclose(fp); +} From 1bea40ee22184bd1d53c2a4e91eb9f2256bf4fc7 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Thu, 20 Aug 2015 10:10:42 -0700 Subject: [PATCH 171/208] Bug 1196027 - check the actual current marking mode instead of the permanent intention, r=terrence --- js/src/jsgc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index a0f0fe6134aa..1b4769cd81e1 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -4034,7 +4034,7 @@ GCRuntime::markWeakReferences(gcstats::Phase phase) for (CompartmentIterT c(rt); !c.done(); c.next()) { if (c->watchpointMap) markedAny |= c->watchpointMap->markIteratively(&marker); - if (marker.weakMapAction() != ExpandWeakMaps) + if (!marker.isWeakMarkingTracer()) markedAny |= WeakMapBase::markCompartmentIteratively(c, &marker); } markedAny |= Debugger::markAllIteratively(&marker); From 2de5cfaf0c1ae84bdf75f629faac1f6e6b8af4c7 Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Fri, 21 Aug 2015 16:21:23 -0700 Subject: [PATCH 172/208] Bug 1197378 - Make docshell tests pass in e10s. r=billm --- docshell/test/navigation/mochitest.ini | 6 ++-- docshell/test/navigation/parent.html | 3 ++ docshell/test/navigation/test_bug13871.html | 35 ++++++++++++++++++++- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/docshell/test/navigation/mochitest.ini b/docshell/test/navigation/mochitest.ini index 99333a1bb5b7..a20600b04fab 100644 --- a/docshell/test/navigation/mochitest.ini +++ b/docshell/test/navigation/mochitest.ini @@ -22,15 +22,15 @@ support-files = parent.html [test_bug13871.html] -skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' || e10s #RANDOM # Bug 1136180 disabled on B2G Desktop and Mulet for intermittent failures +skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' #RANDOM # Bug 1136180 disabled on B2G Desktop and Mulet for intermittent failures [test_bug270414.html] -skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == "android" || e10s # Bug 1136180 disabled on B2G Desktop and Mulet for intermittent failures +skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == "android" # Bug 1136180 disabled on B2G Desktop and Mulet for intermittent failures [test_bug278916.html] skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage [test_bug279495.html] skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage [test_bug344861.html] -skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s +skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' [test_bug386782.html] skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) [test_bug430624.html] diff --git a/docshell/test/navigation/parent.html b/docshell/test/navigation/parent.html index 46028aad9353..74722b8bdfdf 100644 --- a/docshell/test/navigation/parent.html +++ b/docshell/test/navigation/parent.html @@ -5,6 +5,9 @@
diff --git a/docshell/test/navigation/test_bug13871.html b/docshell/test/navigation/test_bug13871.html index 9ff0b9bb553f..e0b563a4a83d 100644 --- a/docshell/test/navigation/test_bug13871.html +++ b/docshell/test/navigation/test_bug13871.html @@ -9,7 +9,7 @@ iframe { width: 90%; height: 50px; } From 369df28f4532f8652f2055c6373d42aa004c2d88 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 22 Aug 2015 10:34:51 +0900 Subject: [PATCH 173/208] Bug 895274 part.1 Rename WidgetEvent::message to WidgetEvent::mMessage r=smaug --- dom/base/Element.cpp | 14 +-- dom/base/FragmentOrElement.cpp | 14 +-- dom/base/TextInputProcessor.cpp | 8 +- dom/base/nsContentUtils.cpp | 24 ++--- dom/base/nsDocument.cpp | 2 +- dom/base/nsGenConImageContent.cpp | 4 +- dom/base/nsGlobalWindow.cpp | 10 +- dom/base/nsQueryContentEventResult.cpp | 2 +- dom/events/ClipboardEvent.cpp | 4 +- dom/events/DataTransfer.h | 2 +- dom/events/Event.cpp | 22 ++--- dom/events/Event.h | 2 +- dom/events/EventDispatcher.cpp | 7 +- dom/events/EventDispatcher.h | 2 +- dom/events/EventListenerManager.cpp | 8 +- dom/events/EventListenerManager.h | 2 +- dom/events/EventStateManager.cpp | 69 +++++++------- dom/events/EventStateManager.h | 4 +- dom/events/IMEContentObserver.cpp | 4 +- dom/events/IMEStateManager.cpp | 18 ++-- dom/events/InternalMutationEvent.h | 2 +- dom/events/KeyboardEvent.cpp | 4 +- dom/events/NotifyPaintEvent.cpp | 2 +- dom/events/TextComposition.cpp | 16 ++-- dom/events/TouchEvent.cpp | 7 +- dom/events/WheelHandlingHelper.cpp | 6 +- dom/html/HTMLButtonElement.cpp | 12 +-- dom/html/HTMLFieldSetElement.cpp | 2 +- dom/html/HTMLFormElement.cpp | 8 +- dom/html/HTMLInputElement.cpp | 62 ++++++------ dom/html/HTMLLabelElement.cpp | 4 +- dom/html/HTMLMenuItemElement.cpp | 4 +- dom/html/HTMLObjectElement.cpp | 2 +- dom/html/HTMLSelectElement.cpp | 6 +- dom/html/HTMLTextAreaElement.cpp | 16 ++-- dom/html/nsGenericHTMLElement.cpp | 2 +- dom/html/nsTextEditorState.cpp | 2 +- dom/ipc/TabChild.cpp | 22 ++--- dom/ipc/TabParent.cpp | 16 ++-- dom/plugins/base/nsPluginInstanceOwner.cpp | 76 +++++++-------- dom/svg/SVGSVGElement.cpp | 2 +- dom/xul/nsXULElement.cpp | 14 +-- editor/libeditor/nsEditor.cpp | 4 +- editor/libeditor/nsEditorEventListener.cpp | 2 +- editor/libeditor/nsHTMLEditor.cpp | 2 +- editor/libeditor/nsPlaintextEditor.cpp | 4 +- gfx/layers/apz/src/APZCTreeManager.cpp | 2 +- gfx/layers/apz/util/APZEventState.cpp | 8 +- layout/base/AccessibleCaretEventHub.cpp | 8 +- layout/base/SelectionCarets.cpp | 18 ++-- layout/base/TouchCaret.cpp | 4 +- layout/base/TouchManager.cpp | 8 +- layout/base/nsPresShell.cpp | 104 +++++++++++---------- layout/forms/nsComboboxControlFrame.cpp | 2 +- layout/forms/nsImageControlFrame.cpp | 2 +- layout/forms/nsListControlFrame.cpp | 6 +- layout/generic/nsFrame.cpp | 12 ++- layout/generic/nsFrameSetFrame.cpp | 4 +- layout/generic/nsImageFrame.cpp | 6 +- layout/generic/nsPluginFrame.cpp | 12 +-- layout/printing/nsPrintPreviewListener.cpp | 6 +- layout/style/nsAnimationManager.h | 3 +- layout/xul/nsButtonBoxFrame.cpp | 2 +- layout/xul/nsMenuFrame.cpp | 14 +-- layout/xul/nsResizerFrame.cpp | 2 +- layout/xul/nsRootBoxFrame.cpp | 2 +- layout/xul/nsScrollBoxFrame.cpp | 3 +- layout/xul/nsScrollbarButtonFrame.cpp | 2 +- layout/xul/nsSliderFrame.cpp | 21 +++-- layout/xul/nsSplitterFrame.cpp | 2 +- layout/xul/nsTitleBarFrame.cpp | 2 +- layout/xul/tree/nsTreeBodyFrame.cpp | 17 ++-- view/nsViewManager.cpp | 6 +- widget/BasicEvents.h | 26 +++--- widget/ContentCache.cpp | 22 ++--- widget/ContentEvents.h | 20 ++-- widget/InputData.cpp | 4 +- widget/MiscEvents.h | 2 +- widget/MouseEvents.h | 18 ++-- widget/TextEvents.h | 48 +++++----- widget/TouchEvents.h | 14 +-- widget/WidgetEventImpl.cpp | 12 +-- widget/android/nsWindow.cpp | 20 ++-- widget/cocoa/TextInputHandler.mm | 14 +-- widget/gtk/IMContextWrapper.cpp | 2 +- widget/gtk/nsGtkKeyUtils.cpp | 8 +- widget/nsBaseWidget.cpp | 14 ++- widget/nsGUIEventIPC.h | 4 +- widget/qt/nsWindow.cpp | 2 +- widget/windows/KeyboardLayout.cpp | 2 +- widget/windows/WinMouseScrollHandler.cpp | 2 +- widget/windows/nsWinGesture.cpp | 16 ++-- widget/windows/nsWindow.cpp | 2 +- 93 files changed, 531 insertions(+), 520 deletions(-) diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 00e1f2318a22..462a7857f691 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -2850,9 +2850,9 @@ Element::CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor, { if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault || (!aVisitor.mEvent->mFlags.mIsTrusted && - (aVisitor.mEvent->message != NS_MOUSE_CLICK) && - (aVisitor.mEvent->message != NS_KEY_PRESS) && - (aVisitor.mEvent->message != NS_UI_ACTIVATE)) || + (aVisitor.mEvent->mMessage != NS_MOUSE_CLICK) && + (aVisitor.mEvent->mMessage != NS_KEY_PRESS) && + (aVisitor.mEvent->mMessage != NS_UI_ACTIVATE)) || !aVisitor.mPresContext || aVisitor.mEvent->mFlags.mMultipleActionsPrevented) { return false; @@ -2867,7 +2867,7 @@ Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor) { // Optimisation: return early if this event doesn't interest us. // IMPORTANT: this switch and the switch below it must be kept in sync! - switch (aVisitor.mEvent->message) { + switch (aVisitor.mEvent->mMessage) { case NS_MOUSE_OVER: case NS_FOCUS_CONTENT: case NS_MOUSE_OUT: @@ -2887,7 +2887,7 @@ Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor) // We do the status bar updates in PreHandleEvent so that the status bar gets // updated even if the event is consumed before we have a chance to set it. - switch (aVisitor.mEvent->message) { + switch (aVisitor.mEvent->mMessage) { // Set the status bar similarly for mouseover and focus case NS_MOUSE_OVER: aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; @@ -2928,7 +2928,7 @@ Element::PostHandleEventForLinks(EventChainPostVisitor& aVisitor) { // Optimisation: return early if this event doesn't interest us. // IMPORTANT: this switch and the switch below it must be kept in sync! - switch (aVisitor.mEvent->message) { + switch (aVisitor.mEvent->mMessage) { case NS_MOUSE_BUTTON_DOWN: case NS_MOUSE_CLICK: case NS_UI_ACTIVATE: @@ -2946,7 +2946,7 @@ Element::PostHandleEventForLinks(EventChainPostVisitor& aVisitor) nsresult rv = NS_OK; - switch (aVisitor.mEvent->message) { + switch (aVisitor.mEvent->mMessage) { case NS_MOUSE_BUTTON_DOWN: { if (aVisitor.mEvent->AsMouseEvent()->button == diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp index 33b3b7cafaa5..7d607be35103 100644 --- a/dom/base/FragmentOrElement.cpp +++ b/dom/base/FragmentOrElement.cpp @@ -677,10 +677,10 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor) // Don't propagate mouseover and mouseout events when mouse is moving // inside chrome access only content. bool isAnonForEvents = IsRootOfChromeAccessOnlySubtree(); - if ((aVisitor.mEvent->message == NS_MOUSE_OVER || - aVisitor.mEvent->message == NS_MOUSE_OUT || - aVisitor.mEvent->message == NS_POINTER_OVER || - aVisitor.mEvent->message == NS_POINTER_OUT) && + if ((aVisitor.mEvent->mMessage == NS_MOUSE_OVER || + aVisitor.mEvent->mMessage == NS_MOUSE_OUT || + aVisitor.mEvent->mMessage == NS_POINTER_OVER || + aVisitor.mEvent->mMessage == NS_POINTER_OUT) && // Check if we should stop event propagation when event has just been // dispatched or when we're about to propagate from // chrome access only subtree or if we are about to propagate out of @@ -739,7 +739,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor) printf("Stopping %s propagation:" "\n\toriginalTarget=%s \n\tcurrentTarget=%s %s" "\n\trelatedTarget=%s %s \n%s", - (aVisitor.mEvent->message == NS_MOUSE_OVER) + (aVisitor.mEvent->mMessage == NS_MOUSE_OVER) ? "mouseover" : "mouseout", NS_ConvertUTF16toUTF8(ot).get(), NS_ConvertUTF16toUTF8(ct).get(), @@ -805,7 +805,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor) // scroll // selectstart bool stopEvent = false; - switch (aVisitor.mEvent->message) { + switch (aVisitor.mEvent->mMessage) { case NS_IMAGE_ABORT: case NS_LOAD_ERROR: case NS_FORM_SELECTED: @@ -841,7 +841,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor) // The load event is special in that we don't ever propagate it // to chrome. nsCOMPtr win = OwnerDoc()->GetWindow(); - EventTarget* parentTarget = win && aVisitor.mEvent->message != NS_LOAD + EventTarget* parentTarget = win && aVisitor.mEvent->mMessage != NS_LOAD ? win->GetParentTarget() : nullptr; aVisitor.mParentTarget = parentTarget; diff --git a/dom/base/TextInputProcessor.cpp b/dom/base/TextInputProcessor.cpp index 1f13e1ba0f9c..7df54a2327cb 100644 --- a/dom/base/TextInputProcessor.cpp +++ b/dom/base/TextInputProcessor.cpp @@ -248,10 +248,10 @@ TextInputProcessor::IsValidEventTypeForComposition( const WidgetKeyboardEvent& aKeyboardEvent) const { // The key event type of composition methods must be "" or "keydown". - if (aKeyboardEvent.message == NS_KEY_DOWN) { + if (aKeyboardEvent.mMessage == NS_KEY_DOWN) { return true; } - if (aKeyboardEvent.message == NS_USER_DEFINED_EVENT && + if (aKeyboardEvent.mMessage == NS_USER_DEFINED_EVENT && aKeyboardEvent.userType && nsDependentAtomString(aKeyboardEvent.userType).EqualsLiteral("on")) { return true; @@ -306,9 +306,9 @@ TextInputProcessor::MaybeDispatchKeyupForComposition( return result; } - // If the message is NS_KEY_DOWN, the caller doesn't want TIP to dispatch + // If the mMessage is NS_KEY_DOWN, the caller doesn't want TIP to dispatch // keyup event. - if (aKeyboardEvent->message == NS_KEY_DOWN) { + if (aKeyboardEvent->mMessage == NS_KEY_DOWN) { return result; } diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 80f93e74d346..973abb83b019 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -5446,8 +5446,8 @@ nsContentUtils::SetDataTransferInEvent(WidgetDragEvent* aDragEvent) // For draggesture and dragstart events, the data transfer object is // created before the event fires, so it should already be set. For other // drag events, get the object from the drag session. - NS_ASSERTION(aDragEvent->message != NS_DRAGDROP_GESTURE && - aDragEvent->message != NS_DRAGDROP_START, + NS_ASSERTION(aDragEvent->mMessage != NS_DRAGDROP_GESTURE && + aDragEvent->mMessage != NS_DRAGDROP_START, "draggesture event created without a dataTransfer"); nsCOMPtr dragSession = GetDragSession(); @@ -5466,20 +5466,22 @@ nsContentUtils::SetDataTransferInEvent(WidgetDragEvent* aDragEvent) // means, for instance calling the drag service directly, or a drag // from another application. In either case, a new dataTransfer should // be created that reflects the data. - initialDataTransfer = new DataTransfer(aDragEvent->target, aDragEvent->message, true, -1); + initialDataTransfer = + new DataTransfer(aDragEvent->target, aDragEvent->mMessage, true, -1); // now set it in the drag session so we don't need to create it again dragSession->SetDataTransfer(initialDataTransfer); } bool isCrossDomainSubFrameDrop = false; - if (aDragEvent->message == NS_DRAGDROP_DROP || - aDragEvent->message == NS_DRAGDROP_DRAGDROP) { + if (aDragEvent->mMessage == NS_DRAGDROP_DROP || + aDragEvent->mMessage == NS_DRAGDROP_DRAGDROP) { isCrossDomainSubFrameDrop = CheckForSubFrameDrop(dragSession, aDragEvent); } // each event should use a clone of the original dataTransfer. - initialDataTransfer->Clone(aDragEvent->target, aDragEvent->message, aDragEvent->userCancelled, + initialDataTransfer->Clone(aDragEvent->target, aDragEvent->mMessage, + aDragEvent->userCancelled, isCrossDomainSubFrameDrop, getter_AddRefs(aDragEvent->dataTransfer)); NS_ENSURE_TRUE(aDragEvent->dataTransfer, NS_ERROR_OUT_OF_MEMORY); @@ -5487,16 +5489,16 @@ nsContentUtils::SetDataTransferInEvent(WidgetDragEvent* aDragEvent) // for the dragenter and dragover events, initialize the drop effect // from the drop action, which platform specific widget code sets before // the event is fired based on the keyboard state. - if (aDragEvent->message == NS_DRAGDROP_ENTER || - aDragEvent->message == NS_DRAGDROP_OVER) { + if (aDragEvent->mMessage == NS_DRAGDROP_ENTER || + aDragEvent->mMessage == NS_DRAGDROP_OVER) { uint32_t action, effectAllowed; dragSession->GetDragAction(&action); aDragEvent->dataTransfer->GetEffectAllowedInt(&effectAllowed); aDragEvent->dataTransfer->SetDropEffectInt(FilterDropEffect(action, effectAllowed)); } - else if (aDragEvent->message == NS_DRAGDROP_DROP || - aDragEvent->message == NS_DRAGDROP_DRAGDROP || - aDragEvent->message == NS_DRAGDROP_END) { + else if (aDragEvent->mMessage == NS_DRAGDROP_DROP || + aDragEvent->mMessage == NS_DRAGDROP_DRAGDROP || + aDragEvent->mMessage == NS_DRAGDROP_END) { // For the drop and dragend events, set the drop effect based on the // last value that the dropEffect had. This will have been set in // EventStateManager::PostHandleEvent for the last dragenter or diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 3f089d895529..60c7ba424f9e 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -8113,7 +8113,7 @@ nsDocument::PreHandleEvent(EventChainPreVisitor& aVisitor) aVisitor.mForceContentDispatch = true; // Load events must not propagate to |window| object, see bug 335251. - if (aVisitor.mEvent->message != NS_LOAD) { + if (aVisitor.mEvent->mMessage != NS_LOAD) { nsGlobalWindow* window = static_cast(GetWindow()); aVisitor.mParentTarget = window ? window->GetTargetForEventTargetChain() : nullptr; diff --git a/dom/base/nsGenConImageContent.cpp b/dom/base/nsGenConImageContent.cpp index 74b017560e99..98fcae28fde3 100644 --- a/dom/base/nsGenConImageContent.cpp +++ b/dom/base/nsGenConImageContent.cpp @@ -49,8 +49,8 @@ class nsGenConImageContent final : public nsXMLElement, virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override { MOZ_ASSERT(IsInNativeAnonymousSubtree()); - if (aVisitor.mEvent->message == NS_LOAD || - aVisitor.mEvent->message == NS_LOAD_ERROR) { + if (aVisitor.mEvent->mMessage == NS_LOAD || + aVisitor.mEvent->mMessage == NS_LOAD_ERROR) { // Don't propagate the events to the parent. return NS_OK; } diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 60cff4fcf9e5..91097df314ba 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -3044,7 +3044,7 @@ nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor) { NS_PRECONDITION(IsInnerWindow(), "PreHandleEvent is used on outer window!?"); static uint32_t count = 0; - uint32_t msg = aVisitor.mEvent->message; + uint32_t msg = aVisitor.mEvent->mMessage; aVisitor.mCanHandle = true; aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119 @@ -3252,7 +3252,7 @@ nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor) NS_PRECONDITION(IsInnerWindow(), "PostHandleEvent is used on outer window!?"); // Return early if there is nothing to do. - switch (aVisitor.mEvent->message) { + switch (aVisitor.mEvent->mMessage) { case NS_RESIZE_EVENT: case NS_PAGE_UNLOAD: case NS_LOAD: @@ -3267,9 +3267,9 @@ nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor) nsCOMPtr kungFuDeathGrip1(mChromeEventHandler); nsCOMPtr kungFuDeathGrip2(GetContextInternal()); - if (aVisitor.mEvent->message == NS_RESIZE_EVENT) { + if (aVisitor.mEvent->mMessage == NS_RESIZE_EVENT) { mIsHandlingResizeEvent = false; - } else if (aVisitor.mEvent->message == NS_PAGE_UNLOAD && + } else if (aVisitor.mEvent->mMessage == NS_PAGE_UNLOAD && aVisitor.mEvent->mFlags.mIsTrusted) { // Execute bindingdetached handlers before we tear ourselves // down. @@ -3277,7 +3277,7 @@ nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor) mDoc->BindingManager()->ExecuteDetachedHandlers(); } mIsDocumentLoaded = false; - } else if (aVisitor.mEvent->message == NS_LOAD && + } else if (aVisitor.mEvent->mMessage == NS_LOAD && aVisitor.mEvent->mFlags.mIsTrusted) { // This is page load event since load events don't propagate to |window|. // @see nsDocument::PreHandleEvent. diff --git a/dom/base/nsQueryContentEventResult.cpp b/dom/base/nsQueryContentEventResult.cpp index 21fbc999394d..a882aeeabee1 100644 --- a/dom/base/nsQueryContentEventResult.cpp +++ b/dom/base/nsQueryContentEventResult.cpp @@ -159,7 +159,7 @@ void nsQueryContentEventResult::SetEventResult(nsIWidget* aWidget, const WidgetQueryContentEvent &aEvent) { - mEventID = aEvent.message; + mEventID = aEvent.mMessage; mSucceeded = aEvent.mSucceeded; mReversed = aEvent.mReply.mReversed; mRect = aEvent.mReply.mRect; diff --git a/dom/events/ClipboardEvent.cpp b/dom/events/ClipboardEvent.cpp index c44fcf38ab96..37d4148d64ec 100644 --- a/dom/events/ClipboardEvent.cpp +++ b/dom/events/ClipboardEvent.cpp @@ -108,8 +108,8 @@ ClipboardEvent::GetClipboardData() new DataTransfer(ToSupports(this), NS_COPY, false, -1); } else { event->clipboardData = - new DataTransfer(ToSupports(this), event->message, - event->message == NS_PASTE, + new DataTransfer(ToSupports(this), event->mMessage, + event->mMessage == NS_PASTE, nsIClipboard::kGlobalClipboard); } } diff --git a/dom/events/DataTransfer.h b/dom/events/DataTransfer.h index 8615bbf15ad4..4fd5ff7d155a 100644 --- a/dom/events/DataTransfer.h +++ b/dom/events/DataTransfer.h @@ -255,7 +255,7 @@ class DataTransfer final : public nsIDOMDataTransfer, nsCOMPtr mParent; // the event type this data transfer is for. This will correspond to an - // event->message value. + // event->mMessage value. uint32_t mEventType; // the drop effect and effect allowed diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp index ce3ae0da624c..0f3ec3442cbb 100644 --- a/dom/events/Event.cpp +++ b/dom/events/Event.cpp @@ -265,12 +265,12 @@ Event::GetType(nsAString& aType) aType = mEvent->typeString; return NS_OK; } - const char* name = GetEventName(mEvent->message); + const char* name = GetEventName(mEvent->mMessage); if (name) { CopyASCIItoUTF16(name, aType); return NS_OK; - } else if (mEvent->message == NS_USER_DEFINED_EVENT && mEvent->userType) { + } else if (mEvent->mMessage == NS_USER_DEFINED_EVENT && mEvent->userType) { aType = Substring(nsDependentAtomString(mEvent->userType), 2); // Remove "on" mEvent->typeString = aType; return NS_OK; @@ -564,10 +564,10 @@ Event::SetEventType(const nsAString& aEventTypeArg) mEvent->typeString.Truncate(); mEvent->userType = nsContentUtils::GetEventIdAndAtom(aEventTypeArg, mEvent->mClass, - &(mEvent->message)); + &(mEvent->mMessage)); } else { mEvent->userType = nullptr; - mEvent->message = NS_USER_DEFINED_EVENT; + mEvent->mMessage = NS_USER_DEFINED_EVENT; mEvent->typeString = aEventTypeArg; } } @@ -715,7 +715,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent) // triggered while handling user input. See // nsPresShell::HandleEventInternal() for details. if (EventStateManager::IsHandlingUserInput()) { - switch(aEvent->message) { + switch(aEvent->mMessage) { case NS_FORM_SELECTED : if (PopupAllowedForEvent("select")) { abuse = openControlled; @@ -734,7 +734,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent) // while handling user input. See // nsPresShell::HandleEventInternal() for details. if (EventStateManager::IsHandlingUserInput()) { - switch(aEvent->message) { + switch(aEvent->mMessage) { case NS_EDITOR_INPUT: if (PopupAllowedForEvent("input")) { abuse = openControlled; @@ -748,7 +748,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent) // while handling user input. See // nsPresShell::HandleEventInternal() for details. if (EventStateManager::IsHandlingUserInput()) { - switch(aEvent->message) { + switch(aEvent->mMessage) { case NS_FORM_CHANGE : if (PopupAllowedForEvent("change")) { abuse = openControlled; @@ -763,7 +763,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent) case eKeyboardEventClass: if (aEvent->mFlags.mIsTrusted) { uint32_t key = aEvent->AsKeyboardEvent()->keyCode; - switch(aEvent->message) { + switch(aEvent->mMessage) { case NS_KEY_PRESS : // return key on focused button. see note at NS_MOUSE_CLICK. if (key == nsIDOMKeyEvent::DOM_VK_RETURN) { @@ -790,7 +790,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent) break; case eTouchEventClass: if (aEvent->mFlags.mIsTrusted) { - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_TOUCH_START : if (PopupAllowedForEvent("touchstart")) { abuse = openControlled; @@ -807,7 +807,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent) case eMouseEventClass: if (aEvent->mFlags.mIsTrusted && aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) { - switch(aEvent->message) { + switch(aEvent->mMessage) { case NS_MOUSE_BUTTON_UP : if (PopupAllowedForEvent("mouseup")) { abuse = openControlled; @@ -840,7 +840,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent) // triggered while handling user input. See // nsPresShell::HandleEventInternal() for details. if (EventStateManager::IsHandlingUserInput()) { - switch(aEvent->message) { + switch(aEvent->mMessage) { case NS_FORM_SUBMIT : if (PopupAllowedForEvent("submit")) { abuse = openControlled; diff --git a/dom/events/Event.h b/dom/events/Event.h index 11b72e39d0a5..c5f261778d50 100644 --- a/dom/events/Event.h +++ b/dom/events/Event.h @@ -270,7 +270,7 @@ class Event : public EventBase, bool mPrivateDataDuplicated; bool mIsMainThreadEvent; // True when popup control check should rely on event.type, not - // WidgetEvent.message. + // WidgetEvent.mMessage. bool mWantsPopupControlCheck; }; diff --git a/dom/events/EventDispatcher.cpp b/dom/events/EventDispatcher.cpp index a347acceabc0..d4a28bcd3f2c 100644 --- a/dom/events/EventDispatcher.cpp +++ b/dom/events/EventDispatcher.cpp @@ -420,12 +420,12 @@ EventDispatcher::Dispatch(nsISupports* aTarget, NS_ASSERTION(aEvent, "Trying to dispatch without WidgetEvent!"); NS_ENSURE_TRUE(!aEvent->mFlags.mIsBeingDispatched, NS_ERROR_DOM_INVALID_STATE_ERR); - NS_ASSERTION(!aTargets || !aEvent->message, "Wrong parameters!"); + NS_ASSERTION(!aTargets || !aEvent->mMessage, "Wrong parameters!"); // If we're dispatching an already created DOMEvent object, make // sure it is initialized! // If aTargets is non-null, the event isn't going to be dispatched. - NS_ENSURE_TRUE(aEvent->message || !aDOMEvent || aTargets, + NS_ENSURE_TRUE(aEvent->mMessage || !aDOMEvent || aTargets, NS_ERROR_DOM_INVALID_STATE_ERR); #ifdef MOZ_TASK_TRACER @@ -493,7 +493,8 @@ EventDispatcher::Dispatch(nsISupports* aTarget, } #ifdef DEBUG - if (aEvent->message != NS_EVENT_NULL && !nsContentUtils::IsSafeToRunScript()) { + if (aEvent->mMessage != NS_EVENT_NULL && + !nsContentUtils::IsSafeToRunScript()) { nsresult rv = NS_ERROR_FAILURE; if (target->GetContextForEventHandlers(&rv) || NS_FAILED(rv)) { diff --git a/dom/events/EventDispatcher.h b/dom/events/EventDispatcher.h index 1e5329b5bd4c..945ff010a266 100644 --- a/dom/events/EventDispatcher.h +++ b/dom/events/EventDispatcher.h @@ -246,7 +246,7 @@ class EventDispatcher * Neither aTarget nor aEvent is allowed to be nullptr. * * If aTargets is non-null, event target chain will be created, but - * event won't be handled. In this case aEvent->message should be + * event won't be handled. In this case aEvent->mMessage should be * NS_EVENT_NULL. * @note Use this method when dispatching a WidgetEvent. */ diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index e5d2ca1a87f0..3c6029c94b59 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -558,20 +558,20 @@ EventListenerManager::ListenerCanHandle(Listener* aListener, WidgetEvent* aEvent) { // This is slightly different from EVENT_TYPE_EQUALS in that it returns - // true even when aEvent->message == NS_USER_DEFINED_EVENT and + // true even when aEvent->mMessage == NS_USER_DEFINED_EVENT and // aListener=>mEventType != NS_USER_DEFINED_EVENT as long as the atoms are // the same if (aListener->mAllEvents) { return true; } - if (aEvent->message == NS_USER_DEFINED_EVENT) { + if (aEvent->mMessage == NS_USER_DEFINED_EVENT) { if (mIsMainThreadELM) { return aListener->mTypeAtom == aEvent->userType; } return aListener->mTypeString.Equals(aEvent->typeString); } MOZ_ASSERT(mIsMainThreadELM); - return aListener->mEventType == aEvent->message; + return aListener->mEventType == aEvent->mMessage; } void @@ -1163,7 +1163,7 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext, aEvent->currentTarget = nullptr; if (mIsMainThreadELM && !hasListener) { - mNoListenerForEvent = aEvent->message; + mNoListenerForEvent = aEvent->mMessage; mNoListenerForEventAtom = aEvent->userType; } diff --git a/dom/events/EventListenerManager.h b/dom/events/EventListenerManager.h index c55f1f53eda5..c898e99a240a 100644 --- a/dom/events/EventListenerManager.h +++ b/dom/events/EventListenerManager.h @@ -321,7 +321,7 @@ class EventListenerManager final } // Check if we already know that there is no event listener for the event. - if (mNoListenerForEvent == aEvent->message && + if (mNoListenerForEvent == aEvent->mMessage && (mNoListenerForEvent != NS_USER_DEFINED_EVENT || mNoListenerForEventAtom == aEvent->userType)) { return; diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index 2fff07faa2ca..dc7d542960b5 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -499,8 +499,8 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext, WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); if (aEvent->mFlags.mIsTrusted && ((mouseEvent && mouseEvent->IsReal() && - mouseEvent->message != NS_MOUSE_ENTER_WIDGET && - mouseEvent->message != NS_MOUSE_EXIT_WIDGET) || + mouseEvent->mMessage != NS_MOUSE_ENTER_WIDGET && + mouseEvent->mMessage != NS_MOUSE_EXIT_WIDGET) || aEvent->mClass == eWheelEventClass || aEvent->mClass == eKeyboardEventClass)) { if (gMouseOrKeyboardEventCounter == 0) { @@ -542,7 +542,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext, *aStatus = nsEventStatus_eIgnore; - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_CONTEXTMENU: if (sIsPointerLocked) { return NS_ERROR_DOM_INVALID_STATE_ERR; @@ -615,7 +615,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext, // Treat it as a synthetic move so we don't generate spurious // "exit" or "move" events. Any necessary "out" or "over" events // will be generated by GenerateMouseEnterExit - mouseEvent->message = NS_MOUSE_MOVE; + mouseEvent->mMessage = NS_MOUSE_MOVE; mouseEvent->reason = WidgetMouseEvent::eSynthesized; // then fall through... } else { @@ -625,7 +625,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext, } GenerateMouseEnterExit(mouseEvent); //This is a window level mouse exit event and should stop here - aEvent->message = 0; + aEvent->mMessage = 0; break; } case NS_MOUSE_MOVE: @@ -717,7 +717,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext, mCurrentTargetContent = content; } - if (aEvent->message != NS_WHEEL_WHEEL) { + if (aEvent->mMessage != NS_WHEEL_WHEEL) { break; } @@ -1167,7 +1167,7 @@ CrossProcessSafeEvent(const WidgetEvent& aEvent) case eWheelEventClass: return true; case eMouseEventClass: - switch (aEvent.message) { + switch (aEvent.mMessage) { case NS_MOUSE_BUTTON_DOWN: case NS_MOUSE_BUTTON_UP: case NS_MOUSE_MOVE: @@ -1179,7 +1179,7 @@ CrossProcessSafeEvent(const WidgetEvent& aEvent) return false; } case eTouchEventClass: - switch (aEvent.message) { + switch (aEvent.mMessage) { case NS_TOUCH_START: case NS_TOUCH_MOVE: case NS_TOUCH_END: @@ -1189,7 +1189,7 @@ CrossProcessSafeEvent(const WidgetEvent& aEvent) return false; } case eDragEventClass: - switch (aEvent.message) { + switch (aEvent.mMessage) { case NS_DRAGDROP_OVER: case NS_DRAGDROP_EXIT: case NS_DRAGDROP_DROP: @@ -1215,7 +1215,7 @@ EventStateManager::HandleCrossProcessEvent(WidgetEvent* aEvent, // NB: the elements of |targets| must be unique, for correctness. nsAutoTArray, 1> targets; if (aEvent->mClass != eTouchEventClass || - aEvent->message == NS_TOUCH_START) { + aEvent->mMessage == NS_TOUCH_START) { // If this event only has one target, and it's remote, add it to // the array. nsIFrame* frame = GetEventTarget(); @@ -2588,7 +2588,7 @@ EventStateManager::DecideGestureEvent(WidgetGestureNotifyEvent* aEvent, nsIFrame* targetFrame) { - NS_ASSERTION(aEvent->message == NS_GESTURENOTIFY_EVENT_START, + NS_ASSERTION(aEvent->mMessage == NS_GESTURENOTIFY_EVENT_START, "DecideGestureEvent called with a non-gesture event"); /* Check the ancestor tree to decide if any frame is willing* to receive @@ -2791,8 +2791,8 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext, // Most of the events we handle below require a frame. // Add special cases here. - if (!mCurrentTarget && aEvent->message != NS_MOUSE_BUTTON_UP && - aEvent->message != NS_MOUSE_BUTTON_DOWN) { + if (!mCurrentTarget && aEvent->mMessage != NS_MOUSE_BUTTON_UP && + aEvent->mMessage != NS_MOUSE_BUTTON_DOWN) { return NS_OK; } @@ -2800,7 +2800,7 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext, nsRefPtr presContext = aPresContext; nsresult ret = NS_OK; - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_MOUSE_BUTTON_DOWN: { WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); @@ -3073,7 +3073,7 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext, ScrollbarsForWheel::PrepareToScrollText(this, aTargetFrame, wheelEvent); - if (aEvent->message != NS_WHEEL_WHEEL || + if (aEvent->mMessage != NS_WHEEL_WHEEL || (!wheelEvent->deltaX && !wheelEvent->deltaY)) { break; } @@ -3237,13 +3237,13 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext, // For now, do this only for dragover. //XXXsmaug dragenter needs some more work. - if (aEvent->message == NS_DRAGDROP_OVER && !isChromeDoc) { + if (aEvent->mMessage == NS_DRAGDROP_OVER && !isChromeDoc) { // Someone has called preventDefault(), check whether is was on // content or chrome. dragSession->SetOnlyChromeDrop( !dragEvent->mDefaultPreventedOnContent); } - } else if (aEvent->message == NS_DRAGDROP_OVER && !isChromeDoc) { + } else if (aEvent->mMessage == NS_DRAGDROP_OVER && !isChromeDoc) { // No one called preventDefault(), so handle drop only in chrome. dragSession->SetOnlyChromeDrop(true); } @@ -4058,7 +4058,7 @@ void EventStateManager::GeneratePointerEnterExit(uint32_t aMessage, WidgetMouseEvent* aEvent) { WidgetPointerEvent pointerEvent(*aEvent); - pointerEvent.message = aMessage; + pointerEvent.mMessage = aMessage; GenerateMouseEnterExit(&pointerEvent); } @@ -4072,7 +4072,7 @@ EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent) // Hold onto old target content through the event and reset after. nsCOMPtr targetBeforeEvent = mCurrentTargetContent; - switch(aMouseEvent->message) { + switch(aMouseEvent->mMessage) { case NS_MOUSE_MOVE: { // Mouse movement is reported on the MouseEvent.movement{X,Y} fields. @@ -4268,7 +4268,7 @@ EventStateManager::GenerateDragDropEnterExit(nsPresContext* aPresContext, //Hold onto old target content through the event and reset after. nsCOMPtr targetBeforeEvent = mCurrentTargetContent; - switch(aDragEvent->message) { + switch(aDragEvent->mMessage) { case NS_DRAGDROP_OVER: { // when dragging from one frame to another, events are fired in the @@ -4420,10 +4420,10 @@ EventStateManager::SetClickCount(nsPresContext* aPresContext, switch (aEvent->button) { case WidgetMouseEvent::eLeftButton: - if (aEvent->message == NS_MOUSE_BUTTON_DOWN) { + if (aEvent->mMessage == NS_MOUSE_BUTTON_DOWN) { mLastLeftMouseDownContent = mouseContent; mLastLeftMouseDownContentParent = mouseContentParent; - } else if (aEvent->message == NS_MOUSE_BUTTON_UP) { + } else if (aEvent->mMessage == NS_MOUSE_BUTTON_UP) { if (mLastLeftMouseDownContent == mouseContent || mLastLeftMouseDownContentParent == mouseContent || mLastLeftMouseDownContent == mouseContentParent) { @@ -4438,10 +4438,10 @@ EventStateManager::SetClickCount(nsPresContext* aPresContext, break; case WidgetMouseEvent::eMiddleButton: - if (aEvent->message == NS_MOUSE_BUTTON_DOWN) { + if (aEvent->mMessage == NS_MOUSE_BUTTON_DOWN) { mLastMiddleMouseDownContent = mouseContent; mLastMiddleMouseDownContentParent = mouseContentParent; - } else if (aEvent->message == NS_MOUSE_BUTTON_UP) { + } else if (aEvent->mMessage == NS_MOUSE_BUTTON_UP) { if (mLastMiddleMouseDownContent == mouseContent || mLastMiddleMouseDownContentParent == mouseContent || mLastMiddleMouseDownContent == mouseContentParent) { @@ -4456,10 +4456,10 @@ EventStateManager::SetClickCount(nsPresContext* aPresContext, break; case WidgetMouseEvent::eRightButton: - if (aEvent->message == NS_MOUSE_BUTTON_DOWN) { + if (aEvent->mMessage == NS_MOUSE_BUTTON_DOWN) { mLastRightMouseDownContent = mouseContent; mLastRightMouseDownContentParent = mouseContentParent; - } else if (aEvent->message == NS_MOUSE_BUTTON_UP) { + } else if (aEvent->mMessage == NS_MOUSE_BUTTON_UP) { if (mLastRightMouseDownContent == mouseContent || mLastRightMouseDownContentParent == mouseContent || mLastRightMouseDownContent == mouseContentParent) { @@ -4573,8 +4573,8 @@ already_AddRefed EventStateManager::GetEventTargetContent(WidgetEvent* aEvent) { if (aEvent && - (aEvent->message == NS_FOCUS_CONTENT || - aEvent->message == NS_BLUR_CONTENT)) { + (aEvent->mMessage == NS_FOCUS_CONTENT || + aEvent->mMessage == NS_BLUR_CONTENT)) { nsCOMPtr content = GetFocusedContent(); return content.forget(); } @@ -4942,7 +4942,7 @@ EventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent) bool EventStateManager::EventStatusOK(WidgetGUIEvent* aEvent) { - return !(aEvent->message == NS_MOUSE_BUTTON_DOWN && + return !(aEvent->mMessage == NS_MOUSE_BUTTON_DOWN && aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton && !sNormalLMouseEventInProcess); } @@ -5038,7 +5038,7 @@ EventStateManager::DoContentCommandEvent(WidgetContentCommandEvent* aEvent) nsCOMPtr root = window->GetTopWindowRoot(); NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); const char* cmd; - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_CONTENT_COMMAND_CUT: cmd = "cmd_cut"; break; @@ -5076,7 +5076,7 @@ EventStateManager::DoContentCommandEvent(WidgetContentCommandEvent* aEvent) NS_ENSURE_SUCCESS(rv, rv); aEvent->mIsEnabled = canDoIt; if (canDoIt && !aEvent->mOnlyEnabledCheck) { - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_CONTENT_COMMAND_PASTE_TRANSFERABLE: { nsCOMPtr commandController = do_QueryInterface(controller); NS_ENSURE_STATE(commandController); @@ -5730,7 +5730,7 @@ AutoHandlingUserInputStatePusher::AutoHandlingUserInputStatePusher( WidgetEvent* aEvent, nsIDocument* aDocument) : mIsHandlingUserInput(aIsHandlingUserInput), - mIsMouseDown(aEvent && aEvent->message == NS_MOUSE_BUTTON_DOWN), + mIsMouseDown(aEvent && aEvent->mMessage == NS_MOUSE_BUTTON_DOWN), mResetFMMouseButtonHandlingState(false) { if (!aIsHandlingUserInput) { @@ -5744,8 +5744,9 @@ AutoHandlingUserInputStatePusher::AutoHandlingUserInputStatePusher( if (!aDocument || !aEvent || !aEvent->mFlags.mIsTrusted) { return; } - mResetFMMouseButtonHandlingState = (aEvent->message == NS_MOUSE_BUTTON_DOWN || - aEvent->message == NS_MOUSE_BUTTON_UP); + mResetFMMouseButtonHandlingState = + (aEvent->mMessage == NS_MOUSE_BUTTON_DOWN || + aEvent->mMessage == NS_MOUSE_BUTTON_UP); if (mResetFMMouseButtonHandlingState) { nsFocusManager* fm = nsFocusManager::GetFocusManager(); NS_ENSURE_TRUE_VOID(fm); diff --git a/dom/events/EventStateManager.h b/dom/events/EventStateManager.h index 4acf246a1a96..8291ec20c379 100644 --- a/dom/events/EventStateManager.h +++ b/dom/events/EventStateManager.h @@ -957,7 +957,7 @@ class AutoHandlingUserInputStatePusher // has no frame. This is required for Web compatibility. #define NS_EVENT_NEEDS_FRAME(event) \ (!(event)->HasPluginActivationEventMessage() && \ - (event)->message != NS_MOUSE_CLICK && \ - (event)->message != NS_MOUSE_DOUBLECLICK) + (event)->mMessage != NS_MOUSE_CLICK && \ + (event)->mMessage != NS_MOUSE_DOUBLECLICK) #endif // mozilla_EventStateManager_h_ diff --git a/dom/events/IMEContentObserver.cpp b/dom/events/IMEContentObserver.cpp index 54625a5f56cc..f5cb2d600a39 100644 --- a/dom/events/IMEContentObserver.cpp +++ b/dom/events/IMEContentObserver.cpp @@ -456,7 +456,7 @@ IMEContentObserver::OnMouseButtonEvent(nsPresContext* aPresContext, return false; } // Now, we need to notify only mouse down and mouse up event. - switch (aMouseEvent->message) { + switch (aMouseEvent->mMessage) { case NS_MOUSE_BUTTON_UP: case NS_MOUSE_BUTTON_DOWN: break; @@ -501,7 +501,7 @@ IMEContentObserver::OnMouseButtonEvent(nsPresContext* aPresContext, } IMENotification notification(NOTIFY_IME_OF_MOUSE_BUTTON_EVENT); - notification.mMouseButtonEventData.mEventMessage = aMouseEvent->message; + notification.mMouseButtonEventData.mEventMessage = aMouseEvent->mMessage; notification.mMouseButtonEventData.mOffset = charAtPt.mReply.mOffset; notification.mMouseButtonEventData.mCursorPos.Set( LayoutDeviceIntPoint::ToUntyped(charAtPt.refPoint)); diff --git a/dom/events/IMEStateManager.cpp b/dom/events/IMEStateManager.cpp index ef563f3f7e39..335664241e93 100644 --- a/dom/events/IMEStateManager.cpp +++ b/dom/events/IMEStateManager.cpp @@ -1137,7 +1137,7 @@ IMEStateManager::DispatchCompositionEvent( "mFlags={ mIsTrusted=%s, mPropagationStopped=%s } }, " "aIsSynthesized=%s), tabParent=%p", aEventTargetNode, aPresContext, - GetEventMessageName(aCompositionEvent->message), + GetEventMessageName(aCompositionEvent->mMessage), GetBoolName(aCompositionEvent->mFlags.mIsTrusted), GetBoolName(aCompositionEvent->mFlags.mPropagationStopped), GetBoolName(aIsSynthesized), tabParent.get())); @@ -1147,7 +1147,7 @@ IMEStateManager::DispatchCompositionEvent( return; } - MOZ_ASSERT(aCompositionEvent->message != NS_COMPOSITION_UPDATE, + MOZ_ASSERT(aCompositionEvent->mMessage != NS_COMPOSITION_UPDATE, "compositionupdate event shouldn't be dispatched manually"); EnsureTextCompositionArray(); @@ -1163,7 +1163,7 @@ IMEStateManager::DispatchCompositionEvent( MOZ_LOG(sISMLog, LogLevel::Debug, ("ISM: IMEStateManager::DispatchCompositionEvent(), " "adding new TextComposition to the array")); - MOZ_ASSERT(aCompositionEvent->message == NS_COMPOSITION_START); + MOZ_ASSERT(aCompositionEvent->mMessage == NS_COMPOSITION_START); composition = new TextComposition(aPresContext, aEventTargetNode, tabParent, aCompositionEvent); @@ -1171,7 +1171,7 @@ IMEStateManager::DispatchCompositionEvent( } #ifdef DEBUG else { - MOZ_ASSERT(aCompositionEvent->message != NS_COMPOSITION_START); + MOZ_ASSERT(aCompositionEvent->mMessage != NS_COMPOSITION_START); } #endif // #ifdef DEBUG @@ -1232,10 +1232,10 @@ IMEStateManager::HandleSelectionEvent(nsPresContext* aPresContext, MOZ_LOG(sISMLog, LogLevel::Info, ("ISM: IMEStateManager::HandleSelectionEvent(aPresContext=0x%p, " - "aEventTargetContent=0x%p, aSelectionEvent={ message=%s, " + "aEventTargetContent=0x%p, aSelectionEvent={ mMessage=%s, " "mFlags={ mIsTrusted=%s } }), tabParent=%p", aPresContext, aEventTargetContent, - GetEventMessageName(aSelectionEvent->message), + GetEventMessageName(aSelectionEvent->mMessage), GetBoolName(aSelectionEvent->mFlags.mIsTrusted), tabParent.get())); @@ -1267,8 +1267,8 @@ IMEStateManager::OnCompositionEventDiscarded( MOZ_LOG(sISMLog, LogLevel::Info, ("ISM: IMEStateManager::OnCompositionEventDiscarded(aCompositionEvent={ " - "message=%s, mFlags={ mIsTrusted=%s } })", - GetEventMessageName(aCompositionEvent->message), + "mMessage=%s, mFlags={ mIsTrusted=%s } })", + GetEventMessageName(aCompositionEvent->mMessage), GetBoolName(aCompositionEvent->mFlags.mIsTrusted))); if (!aCompositionEvent->mFlags.mIsTrusted) { @@ -1277,7 +1277,7 @@ IMEStateManager::OnCompositionEventDiscarded( // Ignore compositionstart for now because sTextCompositions may not have // been created yet. - if (aCompositionEvent->message == NS_COMPOSITION_START) { + if (aCompositionEvent->mMessage == NS_COMPOSITION_START) { return; } diff --git a/dom/events/InternalMutationEvent.h b/dom/events/InternalMutationEvent.h index e44c3d009e5b..75639bc2ab20 100644 --- a/dom/events/InternalMutationEvent.h +++ b/dom/events/InternalMutationEvent.h @@ -30,7 +30,7 @@ class InternalMutationEvent : public WidgetEvent { MOZ_ASSERT(mClass == eMutationEventClass, "Duplicate() must be overridden by sub class"); - InternalMutationEvent* result = new InternalMutationEvent(false, message); + InternalMutationEvent* result = new InternalMutationEvent(false, mMessage); result->AssignMutationEventData(*this, true); result->mFlags = mFlags; return result; diff --git a/dom/events/KeyboardEvent.cpp b/dom/events/KeyboardEvent.cpp index 99ab35e9bae8..793adf94b304 100644 --- a/dom/events/KeyboardEvent.cpp +++ b/dom/events/KeyboardEvent.cpp @@ -151,7 +151,7 @@ KeyboardEvent::CharCode() return mEvent->AsKeyboardEvent()->charCode; } - switch (mEvent->message) { + switch (mEvent->mMessage) { case NS_KEY_BEFORE_DOWN: case NS_KEY_DOWN: case NS_KEY_AFTER_DOWN: @@ -195,7 +195,7 @@ KeyboardEvent::Which() return mInitializedWhichValue; } - switch (mEvent->message) { + switch (mEvent->mMessage) { case NS_KEY_BEFORE_DOWN: case NS_KEY_DOWN: case NS_KEY_AFTER_DOWN: diff --git a/dom/events/NotifyPaintEvent.cpp b/dom/events/NotifyPaintEvent.cpp index 797e3c798303..b14fabf552b6 100644 --- a/dom/events/NotifyPaintEvent.cpp +++ b/dom/events/NotifyPaintEvent.cpp @@ -23,7 +23,7 @@ NotifyPaintEvent::NotifyPaintEvent(EventTarget* aOwner, : Event(aOwner, aPresContext, aEvent) { if (mEvent) { - mEvent->message = aEventType; + mEvent->mMessage = aEventType; } if (aInvalidateRequests) { mInvalidateRequests.AppendElements(Move(aInvalidateRequests->mRequests)); diff --git a/dom/events/TextComposition.cpp b/dom/events/TextComposition.cpp index 487fb35e1bf3..3ec0d06bb42f 100644 --- a/dom/events/TextComposition.cpp +++ b/dom/events/TextComposition.cpp @@ -233,7 +233,7 @@ TextComposition::DispatchCompositionEvent( RemoveControlCharactersFrom(aCompositionEvent->mData, aCompositionEvent->mRanges); } - if (aCompositionEvent->message == NS_COMPOSITION_COMMIT_AS_IS) { + if (aCompositionEvent->mMessage == NS_COMPOSITION_COMMIT_AS_IS) { NS_ASSERTION(!aCompositionEvent->mRanges, "mRanges of NS_COMPOSITION_COMMIT_AS_IS should be null"); aCompositionEvent->mRanges = nullptr; @@ -247,7 +247,7 @@ TextComposition::DispatchCompositionEvent( } else { aCompositionEvent->mData = mLastData; } - } else if (aCompositionEvent->message == NS_COMPOSITION_COMMIT) { + } else if (aCompositionEvent->mMessage == NS_COMPOSITION_COMMIT) { NS_ASSERTION(!aCompositionEvent->mRanges, "mRanges of NS_COMPOSITION_COMMIT should be null"); aCompositionEvent->mRanges = nullptr; @@ -282,7 +282,7 @@ TextComposition::DispatchCompositionEvent( // 2. non-empty string is committed at requesting cancel. if (!aIsSynthesized && (mIsRequestingCommit || mIsRequestingCancel)) { nsString* committingData = nullptr; - switch (aCompositionEvent->message) { + switch (aCompositionEvent->mMessage) { case NS_COMPOSITION_END: case NS_COMPOSITION_CHANGE: case NS_COMPOSITION_COMMIT_AS_IS: @@ -312,7 +312,7 @@ TextComposition::DispatchCompositionEvent( // composition string empty or didn't have clause information), we don't // need to dispatch redundant DOM text event. if (dispatchDOMTextEvent && - aCompositionEvent->message != NS_COMPOSITION_CHANGE && + aCompositionEvent->mMessage != NS_COMPOSITION_CHANGE && !mIsComposing && mLastData == aCompositionEvent->mData) { dispatchEvent = dispatchDOMTextEvent = false; } @@ -321,7 +321,7 @@ TextComposition::DispatchCompositionEvent( // which modifies neither composition string, clauses nor caret // position. In such case, we shouldn't dispatch DOM events. if (dispatchDOMTextEvent && - aCompositionEvent->message == NS_COMPOSITION_CHANGE && + aCompositionEvent->mMessage == NS_COMPOSITION_CHANGE && mLastData == aCompositionEvent->mData && mRanges && aCompositionEvent->mRanges && mRanges->Equals(*aCompositionEvent->mRanges)) { @@ -340,7 +340,7 @@ TextComposition::DispatchCompositionEvent( // the limitation of mapping between event messages and DOM event types, // we cannot map multiple event messages to a DOM event type. if (dispatchDOMTextEvent && - aCompositionEvent->message != NS_COMPOSITION_CHANGE) { + aCompositionEvent->mMessage != NS_COMPOSITION_CHANGE) { aCompositionEvent->mFlags = CloneAndDispatchAs(aCompositionEvent, NS_COMPOSITION_CHANGE, aStatus, aCallBack); @@ -365,7 +365,7 @@ TextComposition::DispatchCompositionEvent( if (aCompositionEvent->CausesDOMCompositionEndEvent()) { // Dispatch a compositionend event if it's necessary. - if (aCompositionEvent->message != NS_COMPOSITION_END) { + if (aCompositionEvent->mMessage != NS_COMPOSITION_END) { CloneAndDispatchAs(aCompositionEvent, NS_COMPOSITION_END); } MOZ_ASSERT(!mIsComposing, "Why is the editor still composing?"); @@ -411,7 +411,7 @@ TextComposition::NotityUpdateComposition( // When compositon start, notify the rect of first offset character. // When not compositon start, notify the rect of selected composition // string if compositionchange event. - if (aCompositionEvent->message == NS_COMPOSITION_START) { + if (aCompositionEvent->mMessage == NS_COMPOSITION_START) { nsCOMPtr widget = mPresContext->GetRootWidget(); // Update composition start offset WidgetQueryContentEvent selectedTextEvent(true, diff --git a/dom/events/TouchEvent.cpp b/dom/events/TouchEvent.cpp index 8416dbddbf06..59da7b6e0e4a 100644 --- a/dom/events/TouchEvent.cpp +++ b/dom/events/TouchEvent.cpp @@ -121,7 +121,8 @@ TouchEvent::Touches() { if (!mTouches) { WidgetTouchEvent* touchEvent = mEvent->AsTouchEvent(); - if (mEvent->message == NS_TOUCH_END || mEvent->message == NS_TOUCH_CANCEL) { + if (mEvent->mMessage == NS_TOUCH_END || + mEvent->mMessage == NS_TOUCH_CANCEL) { // for touchend events, remove any changed touches from the touches array WidgetTouchEvent::AutoTouchArray unchangedTouches; const WidgetTouchEvent::TouchArray& touches = touchEvent->touches; @@ -148,8 +149,8 @@ TouchEvent::TargetTouches() for (uint32_t i = 0; i < touches.Length(); ++i) { // for touchend/cancel events, don't append to the target list if this is a // touch that is ending - if ((mEvent->message != NS_TOUCH_END && - mEvent->message != NS_TOUCH_CANCEL) || !touches[i]->mChanged) { + if ((mEvent->mMessage != NS_TOUCH_END && + mEvent->mMessage != NS_TOUCH_CANCEL) || !touches[i]->mChanged) { if (touches[i]->mTarget == mEvent->originalTarget) { targetTouches.AppendElement(touches[i]); } diff --git a/dom/events/WheelHandlingHelper.cpp b/dom/events/WheelHandlingHelper.cpp index e2835094e7a8..7012ff12a03d 100644 --- a/dom/events/WheelHandlingHelper.cpp +++ b/dom/events/WheelHandlingHelper.cpp @@ -94,7 +94,7 @@ WheelTransaction::BeginTransaction(nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent) { NS_ASSERTION(!sTargetFrame, "previous transaction is not finished!"); - MOZ_ASSERT(aEvent->message == NS_WHEEL_WHEEL, + MOZ_ASSERT(aEvent->mMessage == NS_WHEEL_WHEEL, "Transaction must be started with a wheel event"); ScrollbarsForWheel::OwnWheelTransaction(false); sTargetFrame = aTargetFrame; @@ -175,7 +175,7 @@ WheelTransaction::OnEvent(WidgetEvent* aEvent) return; } - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_WHEEL_WHEEL: if (sMouseMoved != 0 && OutOfTime(sMouseMoved, GetIgnoreMoveDelayTime())) { @@ -413,7 +413,7 @@ ScrollbarsForWheel::PrepareToScrollText(EventStateManager* aESM, nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent) { - if (aEvent->message == NS_WHEEL_START) { + if (aEvent->mMessage == NS_WHEEL_START) { WheelTransaction::OwnScrollbars(false); if (!IsActive()) { TemporarilyActivateAllPossibleScrollTargets(aESM, aTargetFrame, aEvent); diff --git a/dom/html/HTMLButtonElement.cpp b/dom/html/HTMLButtonElement.cpp index 9ced076e53d6..04d86dadaec6 100644 --- a/dom/html/HTMLButtonElement.cpp +++ b/dom/html/HTMLButtonElement.cpp @@ -211,7 +211,7 @@ nsresult HTMLButtonElement::PreHandleEvent(EventChainPreVisitor& aVisitor) { aVisitor.mCanHandle = false; - if (IsDisabledForEvents(aVisitor.mEvent->message)) { + if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) { return NS_OK; } @@ -222,7 +222,7 @@ HTMLButtonElement::PreHandleEvent(EventChainPreVisitor& aVisitor) WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); bool outerActivateEvent = ((mouseEvent && mouseEvent->IsLeftClickEvent()) || - (aVisitor.mEvent->message == NS_UI_ACTIVATE && + (aVisitor.mEvent->mMessage == NS_UI_ACTIVATE && !mInInternalActivate)); if (outerActivateEvent) { @@ -282,7 +282,7 @@ HTMLButtonElement::PostHandleEvent(EventChainPostVisitor& aVisitor) } if (nsEventStatus_eIgnore == aVisitor.mEventStatus) { - switch (aVisitor.mEvent->message) { + switch (aVisitor.mEvent->mMessage) { case NS_KEY_PRESS: case NS_KEY_UP: { @@ -290,9 +290,9 @@ HTMLButtonElement::PostHandleEvent(EventChainPostVisitor& aVisitor) // (bug 25300) WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent(); if ((keyEvent->keyCode == NS_VK_RETURN && - NS_KEY_PRESS == aVisitor.mEvent->message) || + NS_KEY_PRESS == aVisitor.mEvent->mMessage) || (keyEvent->keyCode == NS_VK_SPACE && - NS_KEY_UP == aVisitor.mEvent->message)) { + NS_KEY_UP == aVisitor.mEvent->mMessage)) { nsEventStatus status = nsEventStatus_eIgnore; WidgetMouseEvent event(aVisitor.mEvent->mFlags.mIsTrusted, @@ -383,7 +383,7 @@ HTMLButtonElement::PostHandleEvent(EventChainPostVisitor& aVisitor) // // Using presShell to dispatch the event. It makes sure that // event is not handled if the window is being destroyed. - if (presShell && (event.message != NS_FORM_SUBMIT || + if (presShell && (event.mMessage != NS_FORM_SUBMIT || mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate) || // We know the element is a submit control, if this check is moved, // make sure formnovalidate is used only if it's a submit control. diff --git a/dom/html/HTMLFieldSetElement.cpp b/dom/html/HTMLFieldSetElement.cpp index 1f50418106cc..d929d4cc1fd9 100644 --- a/dom/html/HTMLFieldSetElement.cpp +++ b/dom/html/HTMLFieldSetElement.cpp @@ -74,7 +74,7 @@ HTMLFieldSetElement::PreHandleEvent(EventChainPreVisitor& aVisitor) { // Do not process any DOM events if the element is disabled. aVisitor.mCanHandle = false; - if (IsDisabledForEvents(aVisitor.mEvent->message)) { + if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) { return NS_OK; } diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp index 43eed3a91535..1721d88d0179 100644 --- a/dom/html/HTMLFormElement.cpp +++ b/dom/html/HTMLFormElement.cpp @@ -492,7 +492,7 @@ HTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor) { aVisitor.mWantsWillHandleEvent = true; if (aVisitor.mEvent->originalTarget == static_cast(this)) { - uint32_t msg = aVisitor.mEvent->message; + uint32_t msg = aVisitor.mEvent->mMessage; if (msg == NS_FORM_SUBMIT) { if (mGeneratingSubmit) { aVisitor.mCanHandle = false; @@ -522,8 +522,8 @@ HTMLFormElement::WillHandleEvent(EventChainPostVisitor& aVisitor) // If this is the bubble stage and there is a nested form below us which // received a submit event we do *not* want to handle the submit event // for this form too. - if ((aVisitor.mEvent->message == NS_FORM_SUBMIT || - aVisitor.mEvent->message == NS_FORM_RESET) && + if ((aVisitor.mEvent->mMessage == NS_FORM_SUBMIT || + aVisitor.mEvent->mMessage == NS_FORM_RESET) && aVisitor.mEvent->mFlags.mInBubblingPhase && aVisitor.mEvent->originalTarget != static_cast(this)) { aVisitor.mEvent->mFlags.mPropagationStopped = true; @@ -535,7 +535,7 @@ nsresult HTMLFormElement::PostHandleEvent(EventChainPostVisitor& aVisitor) { if (aVisitor.mEvent->originalTarget == static_cast(this)) { - uint32_t msg = aVisitor.mEvent->message; + uint32_t msg = aVisitor.mEvent->mMessage; if (msg == NS_FORM_SUBMIT) { // let the form know not to defer subsequent submissions mDeferSubmission = false; diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 046e18f7face..cb697cbcb71c 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -3025,7 +3025,7 @@ HTMLInputElement::NeedToInitializeEditorForEvent( return false; } - switch (aVisitor.mEvent->message) { + switch (aVisitor.mEvent->mMessage) { case NS_MOUSE_MOVE: case NS_MOUSE_ENTER_WIDGET: case NS_MOUSE_EXIT_WIDGET: @@ -3050,7 +3050,7 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor) { // Do not process any DOM events if the element is disabled aVisitor.mCanHandle = false; - if (IsDisabledForEvents(aVisitor.mEvent->message)) { + if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) { return NS_OK; } @@ -3088,7 +3088,7 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor) WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); bool outerActivateEvent = ((mouseEvent && mouseEvent->IsLeftClickEvent()) || - (aVisitor.mEvent->message == NS_UI_ACTIVATE && !mInInternalActivate)); + (aVisitor.mEvent->mMessage == NS_UI_ACTIVATE && !mInInternalActivate)); if (outerActivateEvent) { aVisitor.mItemFlags |= NS_OUTER_ACTIVATE_EVENT; @@ -3153,7 +3153,7 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor) aVisitor.mItemFlags |= NS_NO_CONTENT_DISPATCH; } if (IsSingleLineTextControl(false) && - aVisitor.mEvent->message == NS_MOUSE_CLICK && + aVisitor.mEvent->mMessage == NS_MOUSE_CLICK && aVisitor.mEvent->AsMouseEvent()->button == WidgetMouseEvent::eMiddleButton) { aVisitor.mEvent->mFlags.mNoContentDispatch = false; @@ -3163,7 +3163,7 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor) aVisitor.mItemFlags |= mType; // Fire onchange (if necessary), before we do the blur, bug 357684. - if (aVisitor.mEvent->message == NS_BLUR_CONTENT) { + if (aVisitor.mEvent->mMessage == NS_BLUR_CONTENT) { // Experimental mobile types rely on the system UI to prevent users to not // set invalid values but we have to be extra-careful. Especially if the // option has been enabled on desktop. @@ -3178,8 +3178,8 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor) } if (mType == NS_FORM_INPUT_RANGE && - (aVisitor.mEvent->message == NS_FOCUS_CONTENT || - aVisitor.mEvent->message == NS_BLUR_CONTENT)) { + (aVisitor.mEvent->mMessage == NS_FOCUS_CONTENT || + aVisitor.mEvent->mMessage == NS_BLUR_CONTENT)) { // Just as nsGenericHTMLFormElementWithState::PreHandleEvent calls // nsIFormControlFrame::SetFocus, we handle focus here. nsIFrame* frame = GetPrimaryFrame(); @@ -3197,7 +3197,7 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor) // we want to end the spin. We do this here (rather than in // PostHandleEvent) because we don't want to let content preventDefault() // the end of the spin. - if (aVisitor.mEvent->message == NS_MOUSE_MOVE) { + if (aVisitor.mEvent->mMessage == NS_MOUSE_MOVE) { // Be aggressive about stopping the spin: bool stopSpin = true; nsNumberControlFrame* numberControlFrame = @@ -3228,13 +3228,13 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor) if (stopSpin) { StopNumberControlSpinnerSpin(); } - } else if (aVisitor.mEvent->message == NS_MOUSE_BUTTON_UP) { + } else if (aVisitor.mEvent->mMessage == NS_MOUSE_BUTTON_UP) { StopNumberControlSpinnerSpin(); } } - if (aVisitor.mEvent->message == NS_FOCUS_CONTENT || - aVisitor.mEvent->message == NS_BLUR_CONTENT) { - if (aVisitor.mEvent->message == NS_FOCUS_CONTENT) { + if (aVisitor.mEvent->mMessage == NS_FOCUS_CONTENT || + aVisitor.mEvent->mMessage == NS_BLUR_CONTENT) { + if (aVisitor.mEvent->mMessage == NS_FOCUS_CONTENT) { // Tell our frame it's getting focus so that it can make sure focus // is moved to our anonymous text control. nsNumberControlFrame* numberControlFrame = @@ -3254,7 +3254,7 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor) // that). frame->InvalidateFrame(); } - } else if (aVisitor.mEvent->message == NS_KEY_UP) { + } else if (aVisitor.mEvent->mMessage == NS_KEY_UP) { WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent(); if ((keyEvent->keyCode == NS_VK_UP || keyEvent->keyCode == NS_VK_DOWN) && !(keyEvent->IsShift() || keyEvent->IsControl() || @@ -3286,7 +3286,7 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor) textControl = numberControlFrame->GetAnonTextControl(); } if (textControl && aVisitor.mEvent->originalTarget == textControl) { - if (aVisitor.mEvent->message == NS_EDITOR_INPUT) { + if (aVisitor.mEvent->mMessage == NS_EDITOR_INPUT) { // Propogate the anon text control's new value to our HTMLInputElement: nsAutoString value; numberControlFrame->GetValueOfAnonTextControl(value); @@ -3300,7 +3300,7 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor) numberControlFrame->HandlingInputEvent(false); } } - else if (aVisitor.mEvent->message == NS_FORM_CHANGE) { + else if (aVisitor.mEvent->mMessage == NS_FORM_CHANGE) { // We cancel the DOM 'change' event that is fired for any change to our // anonymous text control since we fire our own 'change' events and // content shouldn't be seeing two 'change' events. Besides that we @@ -3588,15 +3588,15 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) return MaybeInitPickers(aVisitor); } - if (aVisitor.mEvent->message == NS_FOCUS_CONTENT || - aVisitor.mEvent->message == NS_BLUR_CONTENT) { - if (aVisitor.mEvent->message == NS_FOCUS_CONTENT && + if (aVisitor.mEvent->mMessage == NS_FOCUS_CONTENT || + aVisitor.mEvent->mMessage == NS_BLUR_CONTENT) { + if (aVisitor.mEvent->mMessage == NS_FOCUS_CONTENT && MayFireChangeOnBlur() && !mIsDraggingRange) { // StartRangeThumbDrag already set mFocusedValue GetValue(mFocusedValue); } - if (aVisitor.mEvent->message == NS_BLUR_CONTENT) { + if (aVisitor.mEvent->mMessage == NS_BLUR_CONTENT) { if (mIsDraggingRange) { FinishRangeThumbDrag(); } else if (mNumberControlSpinnerIsSpinning) { @@ -3604,7 +3604,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) } } - UpdateValidityUIBits(aVisitor.mEvent->message == NS_FOCUS_CONTENT); + UpdateValidityUIBits(aVisitor.mEvent->mMessage == NS_FOCUS_CONTENT); UpdateState(true); } @@ -3721,7 +3721,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) if (NS_SUCCEEDED(rv)) { WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent(); if (mType == NS_FORM_INPUT_NUMBER && - keyEvent && keyEvent->message == NS_KEY_PRESS && + keyEvent && keyEvent->mMessage == NS_KEY_PRESS && aVisitor.mEvent->mFlags.mIsTrusted && (keyEvent->keyCode == NS_VK_UP || keyEvent->keyCode == NS_VK_DOWN) && !(keyEvent->IsShift() || keyEvent->IsControl() || @@ -3744,7 +3744,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } } else if (nsEventStatus_eIgnore == aVisitor.mEventStatus) { - switch (aVisitor.mEvent->message) { + switch (aVisitor.mEvent->mMessage) { case NS_FOCUS_CONTENT: { @@ -3779,9 +3779,9 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) // For backwards compat, trigger checks/radios/buttons with // space or enter (bug 25300) WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent(); - if ((aVisitor.mEvent->message == NS_KEY_PRESS && + if ((aVisitor.mEvent->mMessage == NS_KEY_PRESS && keyEvent->keyCode == NS_VK_RETURN) || - (aVisitor.mEvent->message == NS_KEY_UP && + (aVisitor.mEvent->mMessage == NS_KEY_UP && keyEvent->keyCode == NS_VK_SPACE)) { switch(mType) { case NS_FORM_INPUT_CHECKBOX: @@ -3814,7 +3814,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) } // case } // switch } - if (aVisitor.mEvent->message == NS_KEY_PRESS && + if (aVisitor.mEvent->mMessage == NS_KEY_PRESS && mType == NS_FORM_INPUT_RADIO && !keyEvent->IsAlt() && !keyEvent->IsControl() && !keyEvent->IsMeta()) { bool isMovingBack = false; @@ -3866,7 +3866,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) * not submit, period. */ - if (aVisitor.mEvent->message == NS_KEY_PRESS && + if (aVisitor.mEvent->mMessage == NS_KEY_PRESS && keyEvent->keyCode == NS_VK_RETURN && (IsSingleLineTextControl(false, mType) || mType == NS_FORM_INPUT_NUMBER || @@ -3876,7 +3876,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) NS_ENSURE_SUCCESS(rv, rv); } - if (aVisitor.mEvent->message == NS_KEY_PRESS && + if (aVisitor.mEvent->mMessage == NS_KEY_PRESS && mType == NS_FORM_INPUT_RANGE && !keyEvent->IsAlt() && !keyEvent->IsControl() && !keyEvent->IsMeta() && (keyEvent->keyCode == NS_VK_LEFT || @@ -3966,7 +3966,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) nsNumberControlFrame* numberControlFrame = do_QueryFrame(GetPrimaryFrame()); if (numberControlFrame) { - if (aVisitor.mEvent->message == NS_MOUSE_BUTTON_DOWN && + if (aVisitor.mEvent->mMessage == NS_MOUSE_BUTTON_DOWN && IsMutable()) { switch (numberControlFrame->GetSpinButtonForPointerEvent( aVisitor.mEvent->AsMouseEvent())) { @@ -4028,7 +4028,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) // pres shell. See bug 125624. // TODO: removing this code and have the submit event sent by the // form, see bug 592124. - if (presShell && (event.message != NS_FORM_SUBMIT || + if (presShell && (event.mMessage != NS_FORM_SUBMIT || mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate) || // We know the element is a submit control, if this check is moved, // make sure formnovalidate is used only if it's a submit control. @@ -4083,7 +4083,7 @@ HTMLInputElement::PostHandleEventForRangeThumb(EventChainPostVisitor& aVisitor) return; } - switch (aVisitor.mEvent->message) + switch (aVisitor.mEvent->mMessage) { case NS_MOUSE_BUTTON_DOWN: case NS_TOUCH_START: { @@ -4100,7 +4100,7 @@ HTMLInputElement::PostHandleEventForRangeThumb(EventChainPostVisitor& aVisitor) inputEvent->IsOS()) { break; // ignore } - if (aVisitor.mEvent->message == NS_MOUSE_BUTTON_DOWN) { + if (aVisitor.mEvent->mMessage == NS_MOUSE_BUTTON_DOWN) { if (aVisitor.mEvent->AsMouseEvent()->buttons == WidgetMouseEvent::eLeftButtonFlag) { StartRangeThumbDrag(inputEvent); diff --git a/dom/html/HTMLLabelElement.cpp b/dom/html/HTMLLabelElement.cpp index 6576623aa985..cd41c9bcb18d 100644 --- a/dom/html/HTMLLabelElement.cpp +++ b/dom/html/HTMLLabelElement.cpp @@ -104,7 +104,7 @@ HTMLLabelElement::PostHandleEvent(EventChainPostVisitor& aVisitor) WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); if (mHandlingEvent || (!(mouseEvent && mouseEvent->IsLeftClickEvent()) && - aVisitor.mEvent->message != NS_MOUSE_BUTTON_DOWN) || + aVisitor.mEvent->mMessage != NS_MOUSE_BUTTON_DOWN) || aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault || !aVisitor.mPresContext || // Don't handle the event if it's already been handled by another label @@ -122,7 +122,7 @@ HTMLLabelElement::PostHandleEvent(EventChainPostVisitor& aVisitor) if (content) { mHandlingEvent = true; - switch (aVisitor.mEvent->message) { + switch (aVisitor.mEvent->mMessage) { case NS_MOUSE_BUTTON_DOWN: if (mouseEvent->button == WidgetMouseEvent::eLeftButton) { // We reset the mouse-down point on every event because there is diff --git a/dom/html/HTMLMenuItemElement.cpp b/dom/html/HTMLMenuItemElement.cpp index 2ac74b0cf005..31bb2ffce99c 100644 --- a/dom/html/HTMLMenuItemElement.cpp +++ b/dom/html/HTMLMenuItemElement.cpp @@ -254,7 +254,7 @@ HTMLMenuItemElement::SetChecked(bool aChecked) nsresult HTMLMenuItemElement::PreHandleEvent(EventChainPreVisitor& aVisitor) { - if (aVisitor.mEvent->message == NS_MOUSE_CLICK) { + if (aVisitor.mEvent->mMessage == NS_MOUSE_CLICK) { bool originalCheckedValue = false; switch (mType) { @@ -290,7 +290,7 @@ nsresult HTMLMenuItemElement::PostHandleEvent(EventChainPostVisitor& aVisitor) { // Check to see if the event was cancelled. - if (aVisitor.mEvent->message == NS_MOUSE_CLICK && + if (aVisitor.mEvent->mMessage == NS_MOUSE_CLICK && aVisitor.mItemFlags & NS_CHECKED_IS_TOGGLED && aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault) { bool originalCheckedValue = diff --git a/dom/html/HTMLObjectElement.cpp b/dom/html/HTMLObjectElement.cpp index 3714c2839fef..4623e73abf02 100644 --- a/dom/html/HTMLObjectElement.cpp +++ b/dom/html/HTMLObjectElement.cpp @@ -215,7 +215,7 @@ HTMLObjectElement::HandleFocusBlurPlugin(Element* aElement, if (!aEvent->mFlags.mIsTrusted) { return; } - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_FOCUS_CONTENT: { OnFocusBlurPlugin(aElement, true); break; diff --git a/dom/html/HTMLSelectElement.cpp b/dom/html/HTMLSelectElement.cpp index 766d5ecab12c..8b1c433ed36b 100644 --- a/dom/html/HTMLSelectElement.cpp +++ b/dom/html/HTMLSelectElement.cpp @@ -1501,7 +1501,7 @@ nsresult HTMLSelectElement::PreHandleEvent(EventChainPreVisitor& aVisitor) { aVisitor.mCanHandle = false; - if (IsDisabledForEvents(aVisitor.mEvent->message)) { + if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) { return NS_OK; } @@ -1511,7 +1511,7 @@ HTMLSelectElement::PreHandleEvent(EventChainPreVisitor& aVisitor) nsresult HTMLSelectElement::PostHandleEvent(EventChainPostVisitor& aVisitor) { - if (aVisitor.mEvent->message == NS_FOCUS_CONTENT) { + if (aVisitor.mEvent->mMessage == NS_FOCUS_CONTENT) { // If the invalid UI is shown, we should show it while focused and // update the invalid/valid UI. mCanShowInvalidUI = !IsValid() && ShouldShowValidityUI(); @@ -1522,7 +1522,7 @@ HTMLSelectElement::PostHandleEvent(EventChainPostVisitor& aVisitor) // We don't have to update NS_EVENT_STATE_MOZ_UI_INVALID nor // NS_EVENT_STATE_MOZ_UI_VALID given that the states should not change. - } else if (aVisitor.mEvent->message == NS_BLUR_CONTENT) { + } else if (aVisitor.mEvent->mMessage == NS_BLUR_CONTENT) { mCanShowInvalidUI = true; mCanShowValidUI = true; diff --git a/dom/html/HTMLTextAreaElement.cpp b/dom/html/HTMLTextAreaElement.cpp index 7c2a38d7c861..9f8b8e4752a1 100644 --- a/dom/html/HTMLTextAreaElement.cpp +++ b/dom/html/HTMLTextAreaElement.cpp @@ -480,13 +480,13 @@ nsresult HTMLTextAreaElement::PreHandleEvent(EventChainPreVisitor& aVisitor) { aVisitor.mCanHandle = false; - if (IsDisabledForEvents(aVisitor.mEvent->message)) { + if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) { return NS_OK; } // Don't dispatch a second select event if we are already handling // one. - if (aVisitor.mEvent->message == NS_FORM_SELECTED) { + if (aVisitor.mEvent->mMessage == NS_FORM_SELECTED) { if (mHandlingSelect) { return NS_OK; } @@ -499,14 +499,14 @@ HTMLTextAreaElement::PreHandleEvent(EventChainPreVisitor& aVisitor) if (aVisitor.mEvent->mFlags.mNoContentDispatch) { aVisitor.mItemFlags |= NS_NO_CONTENT_DISPATCH; } - if (aVisitor.mEvent->message == NS_MOUSE_CLICK && + if (aVisitor.mEvent->mMessage == NS_MOUSE_CLICK && aVisitor.mEvent->AsMouseEvent()->button == WidgetMouseEvent::eMiddleButton) { aVisitor.mEvent->mFlags.mNoContentDispatch = false; } // Fire onchange (if necessary), before we do the blur, bug 370521. - if (aVisitor.mEvent->message == NS_BLUR_CONTENT) { + if (aVisitor.mEvent->mMessage == NS_BLUR_CONTENT) { FireChangeEventIfNeeded(); } @@ -534,13 +534,13 @@ HTMLTextAreaElement::FireChangeEventIfNeeded() nsresult HTMLTextAreaElement::PostHandleEvent(EventChainPostVisitor& aVisitor) { - if (aVisitor.mEvent->message == NS_FORM_SELECTED) { + if (aVisitor.mEvent->mMessage == NS_FORM_SELECTED) { mHandlingSelect = false; } - if (aVisitor.mEvent->message == NS_FOCUS_CONTENT || - aVisitor.mEvent->message == NS_BLUR_CONTENT) { - if (aVisitor.mEvent->message == NS_FOCUS_CONTENT) { + if (aVisitor.mEvent->mMessage == NS_FOCUS_CONTENT || + aVisitor.mEvent->mMessage == NS_BLUR_CONTENT) { + if (aVisitor.mEvent->mMessage == NS_FOCUS_CONTENT) { // If the invalid UI is shown, we should show it while focusing (and // update). Otherwise, we should not. GetValueInternal(mFocusedValue, true); diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp index fc4711033848..9ad5f912b4e9 100644 --- a/dom/html/nsGenericHTMLElement.cpp +++ b/dom/html/nsGenericHTMLElement.cpp @@ -2250,7 +2250,7 @@ nsresult nsGenericHTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor) { if (aVisitor.mEvent->mFlags.mIsTrusted) { - switch (aVisitor.mEvent->message) { + switch (aVisitor.mEvent->mMessage) { case NS_FOCUS_CONTENT: { // Check to see if focus has bubbled up from a form control's diff --git a/dom/html/nsTextEditorState.cpp b/dom/html/nsTextEditorState.cpp index b3354dc74ae1..6bc87b3774e2 100644 --- a/dom/html/nsTextEditorState.cpp +++ b/dom/html/nsTextEditorState.cpp @@ -904,7 +904,7 @@ nsTextInputListener::HandleEvent(nsIDOMEvent* aEvent) return NS_ERROR_UNEXPECTED; } - if (keyEvent->message != NS_KEY_PRESS) { + if (keyEvent->mMessage != NS_KEY_PRESS) { return NS_OK; } diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index 5c94d7c9713d..2cf871211077 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -1929,7 +1929,7 @@ TabChild::UpdateTapState(const WidgetTouchEvent& aEvent, nsEventStatus aStatus) } bool currentlyTrackingTouch = (mActivePointerId >= 0); - if (aEvent.message == NS_TOUCH_START) { + if (aEvent.mMessage == NS_TOUCH_START) { if (currentlyTrackingTouch || aEvent.touches.Length() > 1) { // We're tracking a possible tap for another point, or we saw a // touchstart for a later pointer after we canceled tracking of @@ -1969,7 +1969,7 @@ TabChild::UpdateTapState(const WidgetTouchEvent& aEvent, nsEventStatus aStatus) LayoutDevicePoint currentPoint = LayoutDevicePoint(trackedTouch->mRefPoint.x, trackedTouch->mRefPoint.y); int64_t time = aEvent.time; - switch (aEvent.message) { + switch (aEvent.mMessage) { case NS_TOUCH_MOVE: if (std::abs(currentPoint.x - mGestureDownPoint.x) > sDragThreshold.width || std::abs(currentPoint.y - mGestureDownPoint.y) > sDragThreshold.height) { @@ -2046,7 +2046,7 @@ TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent, const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) { - TABC_LOG("Receiving touch event of type %d\n", aEvent.message); + TABC_LOG("Receiving touch event of type %d\n", aEvent.mMessage); WidgetTouchEvent localEvent(aEvent); localEvent.widget = mPuppetWidget; @@ -2054,7 +2054,7 @@ TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent, APZCCallbackHelper::ApplyCallbackTransform(localEvent, aGuid, mPuppetWidget->GetDefaultScale()); - if (localEvent.message == NS_TOUCH_START && AsyncPanZoomEnabled()) { + if (localEvent.mMessage == NS_TOUCH_START && AsyncPanZoomEnabled()) { if (gfxPrefs::TouchActionEnabled()) { APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification(mPuppetWidget, localEvent, aInputBlockId, mSetAllowedTouchBehaviorCallback); @@ -2103,13 +2103,13 @@ TabChild::RecvRealDragEvent(const WidgetDragEvent& aEvent, } } - if (aEvent.message == NS_DRAGDROP_DROP) { + if (aEvent.mMessage == NS_DRAGDROP_DROP) { bool canDrop = true; if (!dragSession || NS_FAILED(dragSession->GetCanDrop(&canDrop)) || !canDrop) { - localEvent.message = NS_DRAGDROP_EXIT; + localEvent.mMessage = NS_DRAGDROP_EXIT; } - } else if (aEvent.message == NS_DRAGDROP_OVER) { + } else if (aEvent.mMessage == NS_DRAGDROP_OVER) { nsCOMPtr dragService = do_GetService("@mozilla.org/widget/dragservice;1"); if (dragService) { @@ -2156,7 +2156,7 @@ TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event, { AutoCacheNativeKeyCommands autoCache(mPuppetWidget); - if (event.message == NS_KEY_PRESS) { + if (event.mMessage == NS_KEY_PRESS) { // If content code called preventDefault() on a keydown event, then we don't // want to process any following keypress events. if (mIgnoreKeyPressEvent) { @@ -2176,7 +2176,7 @@ TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event, localEvent.widget = mPuppetWidget; nsEventStatus status = APZCCallbackHelper::DispatchWidgetEvent(localEvent); - if (event.message == NS_KEY_DOWN) { + if (event.mMessage == NS_KEY_DOWN) { mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault; } @@ -2210,7 +2210,7 @@ TabChild::RecvCompositionEvent(const WidgetCompositionEvent& event) WidgetCompositionEvent localEvent(event); localEvent.widget = mPuppetWidget; APZCCallbackHelper::DispatchWidgetEvent(localEvent); - unused << SendOnEventNeedingAckHandled(event.message); + unused << SendOnEventNeedingAckHandled(event.mMessage); return true; } @@ -2220,7 +2220,7 @@ TabChild::RecvSelectionEvent(const WidgetSelectionEvent& event) WidgetSelectionEvent localEvent(event); localEvent.widget = mPuppetWidget; APZCCallbackHelper::DispatchWidgetEvent(localEvent); - unused << SendOnEventNeedingAckHandled(event.message); + unused << SendOnEventNeedingAckHandled(event.mMessage); return true; } diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 3265ec35b83f..0d7e5c2206e2 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -1368,19 +1368,19 @@ bool TabParent::SendRealMouseEvent(WidgetMouseEvent& event) if (widget) { // When we mouseenter the tab, the tab's cursor should // become the current cursor. When we mouseexit, we stop. - if (NS_MOUSE_ENTER_WIDGET == event.message) { + if (NS_MOUSE_ENTER_WIDGET == event.mMessage) { mTabSetsCursor = true; if (mCustomCursor) { widget->SetCursor(mCustomCursor, mCustomCursorHotspotX, mCustomCursorHotspotY); } else if (mCursor != nsCursor(-1)) { widget->SetCursor(mCursor); } - } else if (NS_MOUSE_EXIT_WIDGET == event.message) { + } else if (NS_MOUSE_EXIT_WIDGET == event.mMessage) { mTabSetsCursor = false; } } - if (NS_MOUSE_MOVE == event.message) { + if (NS_MOUSE_MOVE == event.mMessage) { return SendRealMouseMoveEvent(event); } return SendRealMouseButtonEvent(event); @@ -1722,7 +1722,7 @@ bool TabParent::SendRealKeyEvent(WidgetKeyboardEvent& event) MaybeNativeKeyBinding bindings; bindings = void_t(); - if (event.message == NS_KEY_PRESS) { + if (event.mMessage == NS_KEY_PRESS) { nsCOMPtr widget = GetWidget(); AutoInfallibleTArray singleLine; @@ -1754,7 +1754,7 @@ bool TabParent::SendRealTouchEvent(WidgetTouchEvent& event) // confuses remote content and the panning and zooming logic into thinking // that the added touches are part of the touchend/cancel, when actually // they're not. - if (event.message == NS_TOUCH_END || event.message == NS_TOUCH_CANCEL) { + if (event.mMessage == NS_TOUCH_END || event.mMessage == NS_TOUCH_CANCEL) { for (int i = event.touches.Length() - 1; i >= 0; i--) { if (!event.touches[i]->mChanged) { event.touches.RemoveElementAt(i); @@ -1776,7 +1776,7 @@ bool TabParent::SendRealTouchEvent(WidgetTouchEvent& event) event.touches[i]->mRefPoint += offset; } - return (event.message == NS_TOUCH_MOVE) ? + return (event.mMessage == NS_TOUCH_MOVE) ? PBrowserParent::SendRealTouchMoveEvent(event, guid, blockId, apzResponse) : PBrowserParent::SendRealTouchEvent(event, guid, blockId, apzResponse); } @@ -2263,7 +2263,7 @@ TabParent::RecvDispatchAfterKeyboardEvent(const WidgetKeyboardEvent& aEvent) if (mFrameElement && PresShell::BeforeAfterKeyboardEventEnabled() && - localEvent.message != NS_KEY_PRESS) { + localEvent.mMessage != NS_KEY_PRESS) { presShell->DispatchAfterKeyboardEvent(mFrameElement, localEvent, aEvent.mFlags.mDefaultPrevented); } @@ -2282,7 +2282,7 @@ TabParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent) NS_WARN_IF(!aEvent.mSucceeded)) { return true; } - switch (aEvent.message) { + switch (aEvent.mMessage) { case NS_QUERY_TEXT_RECT: case NS_QUERY_CARET_RECT: case NS_QUERY_EDITOR_RECT: diff --git a/dom/plugins/base/nsPluginInstanceOwner.cpp b/dom/plugins/base/nsPluginInstanceOwner.cpp index 410d0dfdea69..bb46db16d60f 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.cpp +++ b/dom/plugins/base/nsPluginInstanceOwner.cpp @@ -1574,7 +1574,7 @@ nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent) WidgetEvent* theEvent = aFocusEvent->GetInternalNSEvent(); if (theEvent) { - WidgetGUIEvent focusEvent(theEvent->mFlags.mIsTrusted, theEvent->message, + WidgetGUIEvent focusEvent(theEvent->mFlags.mIsTrusted, theEvent->mMessage, nullptr); nsEventStatus rv = ProcessEvent(focusEvent); if (nsEventStatus_eConsumeNoDefault == rv) { @@ -1683,7 +1683,7 @@ nsresult nsPluginInstanceOwner::DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent, aMouseEvent->StopPropagation(); } } - if (mouseEvent->message == NS_MOUSE_BUTTON_UP) { + if (mouseEvent->mMessage == NS_MOUSE_BUTTON_UP) { mLastMouseDownButtonType = -1; } } @@ -1748,8 +1748,9 @@ nsPluginInstanceOwner::HandleEvent(nsIDOMEvent* aEvent) nsCOMPtr dragEvent(do_QueryInterface(aEvent)); if (dragEvent && mInstance) { WidgetEvent* ievent = aEvent->GetInternalNSEvent(); - if ((ievent && ievent->mFlags.mIsTrusted) && - ievent->message != NS_DRAGDROP_ENTER && ievent->message != NS_DRAGDROP_OVER) { + if (ievent && ievent->mFlags.mIsTrusted && + ievent->mMessage != NS_DRAGDROP_ENTER && + ievent->mMessage != NS_DRAGDROP_OVER) { aEvent->PreventDefault(); } @@ -1806,7 +1807,7 @@ CocoaEventTypeForEvent(const WidgetGUIEvent& anEvent, nsIFrame* aObjectFrame) return event->type; } - switch (anEvent.message) { + switch (anEvent.mMessage) { case NS_MOUSE_OVER: return NPCocoaEventMouseEntered; case NS_MOUSE_OUT: @@ -1847,12 +1848,12 @@ TranslateToNPCocoaEvent(WidgetGUIEvent* anEvent, nsIFrame* aObjectFrame) InitializeNPCocoaEvent(&cocoaEvent); cocoaEvent.type = CocoaEventTypeForEvent(*anEvent, aObjectFrame); - if (anEvent->message == NS_MOUSE_MOVE || - anEvent->message == NS_MOUSE_BUTTON_DOWN || - anEvent->message == NS_MOUSE_BUTTON_UP || - anEvent->message == NS_MOUSE_SCROLL || - anEvent->message == NS_MOUSE_OVER || - anEvent->message == NS_MOUSE_OUT) + if (anEvent->mMessage == NS_MOUSE_MOVE || + anEvent->mMessage == NS_MOUSE_BUTTON_DOWN || + anEvent->mMessage == NS_MOUSE_BUTTON_UP || + anEvent->mMessage == NS_MOUSE_SCROLL || + anEvent->mMessage == NS_MOUSE_OVER || + anEvent->mMessage == NS_MOUSE_OUT) { nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(anEvent, aObjectFrame) - aObjectFrame->GetContentRectRelativeToSelf().TopLeft(); @@ -1868,7 +1869,7 @@ TranslateToNPCocoaEvent(WidgetGUIEvent* anEvent, nsIFrame* aObjectFrame) cocoaEvent.data.mouse.pluginY = double(ptPx.y); } - switch (anEvent->message) { + switch (anEvent->mMessage) { case NS_MOUSE_BUTTON_DOWN: case NS_MOUSE_BUTTON_UP: { @@ -1911,7 +1912,8 @@ TranslateToNPCocoaEvent(WidgetGUIEvent* anEvent, nsIFrame* aObjectFrame) // That keyEvent->mPluginTextEventString is non-empty is a signal that we should // create a text event for the plugin, instead of a key event. - if ((anEvent->message == NS_KEY_DOWN) && !keyEvent->mPluginTextEventString.IsEmpty()) { + if (anEvent->mMessage == NS_KEY_DOWN && + !keyEvent->mPluginTextEventString.IsEmpty()) { cocoaEvent.type = NPCocoaEventTextInput; const char16_t* pluginTextEventString = keyEvent->mPluginTextEventString.get(); cocoaEvent.data.text.text = (NPNSString*) @@ -1937,7 +1939,7 @@ TranslateToNPCocoaEvent(WidgetGUIEvent* anEvent, nsIFrame* aObjectFrame) } case NS_FOCUS_CONTENT: case NS_BLUR_CONTENT: - cocoaEvent.data.focus.hasFocus = (anEvent->message == NS_FOCUS_CONTENT); + cocoaEvent.data.focus.hasFocus = (anEvent->mMessage == NS_FOCUS_CONTENT); break; default: break; @@ -1975,7 +1977,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent) // focus unless it lost focus within the window. For example, ignore a blur // event if it's coming due to the plugin's window deactivating. nsCOMPtr content = do_QueryReferent(mContent); - if (anEvent.message == NS_BLUR_CONTENT && + if (anEvent.mMessage == NS_BLUR_CONTENT && ContentIsFocusedWithinWindow(content)) { mShouldBlurOnActivate = true; return nsEventStatus_eIgnore; @@ -1985,7 +1987,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent) // it focus. This might happen if it has focus, its window is blurred, then the // window is made active again. The plugin never lost in-window focus, so it // shouldn't get a focus event again. - if (anEvent.message == NS_FOCUS_CONTENT && + if (anEvent.mMessage == NS_FOCUS_CONTENT && mLastContentFocused == true) { mShouldBlurOnActivate = false; return nsEventStatus_eIgnore; @@ -1994,9 +1996,9 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent) // Now, if we're going to send a focus event, update mLastContentFocused and // tell any plugins in our window that we have taken focus, so they should // perform any delayed blurs. - if (anEvent.message == NS_FOCUS_CONTENT || - anEvent.message == NS_BLUR_CONTENT) { - mLastContentFocused = (anEvent.message == NS_FOCUS_CONTENT); + if (anEvent.mMessage == NS_FOCUS_CONTENT || + anEvent.mMessage == NS_BLUR_CONTENT) { + mLastContentFocused = (anEvent.mMessage == NS_FOCUS_CONTENT); mShouldBlurOnActivate = false; PerformDelayedBlurs(); } @@ -2040,7 +2042,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent) } bool handled = (response == kNPEventHandled || response == kNPEventStartIME); - bool leftMouseButtonDown = (anEvent.message == NS_MOUSE_BUTTON_DOWN) && + bool leftMouseButtonDown = (anEvent.mMessage == NS_MOUSE_BUTTON_DOWN) && (anEvent.AsMouseEvent()->button == WidgetMouseEvent::eLeftButton); if (handled && !(leftMouseButtonDown && !mContentFocused)) { rv = nsEventStatus_eConsumeNoDefault; @@ -2059,7 +2061,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent) // types pluginEvent.event = 0; const WidgetMouseEvent* mouseEvent = anEvent.AsMouseEvent(); - switch (anEvent.message) { + switch (anEvent.mMessage) { case NS_MOUSE_MOVE: pluginEvent.event = WM_MOUSEMOVE; break; @@ -2104,12 +2106,12 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent) // not the widget they were received on. // See use of NPEvent in widget/windows/nsWindow.cpp // for why this assert should be safe - NS_ASSERTION(anEvent.message == NS_MOUSE_BUTTON_DOWN || - anEvent.message == NS_MOUSE_BUTTON_UP || - anEvent.message == NS_MOUSE_DOUBLECLICK || - anEvent.message == NS_MOUSE_OVER || - anEvent.message == NS_MOUSE_OUT || - anEvent.message == NS_MOUSE_MOVE, + NS_ASSERTION(anEvent.mMessage == NS_MOUSE_BUTTON_DOWN || + anEvent.mMessage == NS_MOUSE_BUTTON_UP || + anEvent.mMessage == NS_MOUSE_DOUBLECLICK || + anEvent.mMessage == NS_MOUSE_OVER || + anEvent.mMessage == NS_MOUSE_OUT || + anEvent.mMessage == NS_MOUSE_MOVE, "Incorrect event type for coordinate translation"); nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mPluginFrame) - @@ -2122,7 +2124,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent) } } else if (!pPluginEvent) { - switch (anEvent.message) { + switch (anEvent.mMessage) { case NS_FOCUS_CONTENT: pluginEvent.event = WM_SETFOCUS; pluginEvent.wParam = 0; @@ -2163,7 +2165,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent) switch(anEvent.mClass) { case eMouseEventClass: { - switch (anEvent.message) + switch (anEvent.mMessage) { case NS_MOUSE_CLICK: case NS_MOUSE_DOUBLECLICK: @@ -2191,13 +2193,13 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent) Window root = None; // Could XQueryTree, but this is not important. #endif - switch (anEvent.message) + switch (anEvent.mMessage) { case NS_MOUSE_OVER: case NS_MOUSE_OUT: { XCrossingEvent& event = pluginEvent.xcrossing; - event.type = anEvent.message == NS_MOUSE_OVER ? + event.type = anEvent.mMessage == NS_MOUSE_OVER ? EnterNotify : LeaveNotify; event.root = root; event.time = anEvent.time; @@ -2235,7 +2237,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent) case NS_MOUSE_BUTTON_UP: { XButtonEvent& event = pluginEvent.xbutton; - event.type = anEvent.message == NS_MOUSE_BUTTON_DOWN ? + event.type = anEvent.mMessage == NS_MOUSE_BUTTON_DOWN ? ButtonPress : ButtonRelease; event.root = root; event.time = anEvent.time; @@ -2278,7 +2280,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent) static_cast(anEvent.mPluginEvent); event.keycode = gdkEvent->hardware_keycode; event.state = gdkEvent->state; - switch (anEvent.message) + switch (anEvent.mMessage) { case NS_KEY_DOWN: // Handle NS_KEY_DOWN for modifier key presses @@ -2315,14 +2317,14 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent) break; default: - switch (anEvent.message) + switch (anEvent.mMessage) { case NS_FOCUS_CONTENT: case NS_BLUR_CONTENT: { XFocusChangeEvent &event = pluginEvent.xfocus; event.type = - anEvent.message == NS_FOCUS_CONTENT ? FocusIn : FocusOut; + anEvent.mMessage == NS_FOCUS_CONTENT ? FocusIn : FocusOut; // information lost: event.mode = -1; event.detail = NotifyDetailNone; @@ -2363,7 +2365,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent) switch(anEvent.mClass) { case eMouseEventClass: { - switch (anEvent.message) + switch (anEvent.mMessage) { case NS_MOUSE_CLICK: case NS_MOUSE_DOUBLECLICK: @@ -2379,7 +2381,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent) nsIntPoint pluginPoint(presContext->AppUnitsToDevPixels(appPoint.x), presContext->AppUnitsToDevPixels(appPoint.y)); - switch (anEvent.message) + switch (anEvent.mMessage) { case NS_MOUSE_MOVE: { diff --git a/dom/svg/SVGSVGElement.cpp b/dom/svg/SVGSVGElement.cpp index 3c538565b5ac..21210547ec74 100644 --- a/dom/svg/SVGSVGElement.cpp +++ b/dom/svg/SVGSVGElement.cpp @@ -590,7 +590,7 @@ SVGSVGElement::IsAttributeMapped(const nsIAtom* name) const nsresult SVGSVGElement::PreHandleEvent(EventChainPreVisitor& aVisitor) { - if (aVisitor.mEvent->message == NS_SVG_LOAD) { + if (aVisitor.mEvent->mMessage == NS_SVG_LOAD) { if (mTimedDocumentRoot) { mTimedDocumentRoot->Begin(); // Set 'resample needed' flag, so that if any script calls a DOM method diff --git a/dom/xul/nsXULElement.cpp b/dom/xul/nsXULElement.cpp index 3abc01943be6..736ef6086717 100644 --- a/dom/xul/nsXULElement.cpp +++ b/dom/xul/nsXULElement.cpp @@ -1265,18 +1265,18 @@ nsXULElement::PreHandleEvent(EventChainPreVisitor& aVisitor) aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119 if (IsRootOfNativeAnonymousSubtree() && (IsAnyOfXULElements(nsGkAtoms::scrollbar, nsGkAtoms::scrollcorner)) && - (aVisitor.mEvent->message == NS_MOUSE_CLICK || - aVisitor.mEvent->message == NS_MOUSE_DOUBLECLICK || - aVisitor.mEvent->message == NS_XUL_COMMAND || - aVisitor.mEvent->message == NS_CONTEXTMENU || - aVisitor.mEvent->message == NS_DRAGDROP_START || - aVisitor.mEvent->message == NS_DRAGDROP_GESTURE)) { + (aVisitor.mEvent->mMessage == NS_MOUSE_CLICK || + aVisitor.mEvent->mMessage == NS_MOUSE_DOUBLECLICK || + aVisitor.mEvent->mMessage == NS_XUL_COMMAND || + aVisitor.mEvent->mMessage == NS_CONTEXTMENU || + aVisitor.mEvent->mMessage == NS_DRAGDROP_START || + aVisitor.mEvent->mMessage == NS_DRAGDROP_GESTURE)) { // Don't propagate these events from native anonymous scrollbar. aVisitor.mCanHandle = true; aVisitor.mParentTarget = nullptr; return NS_OK; } - if (aVisitor.mEvent->message == NS_XUL_COMMAND && + if (aVisitor.mEvent->mMessage == NS_XUL_COMMAND && aVisitor.mEvent->mClass == eInputEventClass && aVisitor.mEvent->originalTarget == static_cast(this) && !IsXULElement(nsGkAtoms::command)) { diff --git a/editor/libeditor/nsEditor.cpp b/editor/libeditor/nsEditor.cpp index 6792c47d7f24..774ec140a724 100644 --- a/editor/libeditor/nsEditor.cpp +++ b/editor/libeditor/nsEditor.cpp @@ -4695,7 +4695,7 @@ nsEditor::HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent) WidgetKeyboardEvent* nativeKeyEvent = aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent(); NS_ENSURE_TRUE(nativeKeyEvent, NS_ERROR_UNEXPECTED); - NS_ASSERTION(nativeKeyEvent->message == NS_KEY_PRESS, + NS_ASSERTION(nativeKeyEvent->mMessage == NS_KEY_PRESS, "HandleKeyPressEvent gets non-keypress event"); // if we are readonly or disabled, then do nothing. @@ -5151,7 +5151,7 @@ nsEditor::IsAcceptableInputEvent(nsIDOMEvent* aEvent) // strange event order. bool needsWidget = false; WidgetGUIEvent* widgetGUIEvent = nullptr; - switch (widgetEvent->message) { + switch (widgetEvent->mMessage) { case NS_USER_DEFINED_EVENT: // If events are not created with proper event interface, their message // are initialized with NS_USER_DEFINED_EVENT. Let's ignore such event. diff --git a/editor/libeditor/nsEditorEventListener.cpp b/editor/libeditor/nsEditorEventListener.cpp index bff856781ca3..08cb464c8d0c 100644 --- a/editor/libeditor/nsEditorEventListener.cpp +++ b/editor/libeditor/nsEditorEventListener.cpp @@ -369,7 +369,7 @@ nsEditorEventListener::HandleEvent(nsIDOMEvent* aEvent) // calling it, this queries the specific interface. If it would fail, // each event handler would just ignore the event. So, in this method, // you don't need to check if the QI succeeded before each call. - switch (internalEvent->message) { + switch (internalEvent->mMessage) { // dragenter case NS_DRAGDROP_ENTER: { nsCOMPtr dragEvent = do_QueryInterface(aEvent); diff --git a/editor/libeditor/nsHTMLEditor.cpp b/editor/libeditor/nsHTMLEditor.cpp index 8e0f57ec0b8d..dc403cee0f7d 100644 --- a/editor/libeditor/nsHTMLEditor.cpp +++ b/editor/libeditor/nsHTMLEditor.cpp @@ -594,7 +594,7 @@ nsHTMLEditor::HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent) WidgetKeyboardEvent* nativeKeyEvent = aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent(); NS_ENSURE_TRUE(nativeKeyEvent, NS_ERROR_UNEXPECTED); - NS_ASSERTION(nativeKeyEvent->message == NS_KEY_PRESS, + NS_ASSERTION(nativeKeyEvent->mMessage == NS_KEY_PRESS, "HandleKeyPressEvent gets non-keypress event"); switch (nativeKeyEvent->keyCode) { diff --git a/editor/libeditor/nsPlaintextEditor.cpp b/editor/libeditor/nsPlaintextEditor.cpp index bb6136bb1876..9a055abe64e1 100644 --- a/editor/libeditor/nsPlaintextEditor.cpp +++ b/editor/libeditor/nsPlaintextEditor.cpp @@ -362,7 +362,7 @@ nsPlaintextEditor::HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent) WidgetKeyboardEvent* nativeKeyEvent = aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent(); NS_ENSURE_TRUE(nativeKeyEvent, NS_ERROR_UNEXPECTED); - NS_ASSERTION(nativeKeyEvent->message == NS_KEY_PRESS, + NS_ASSERTION(nativeKeyEvent->mMessage == NS_KEY_PRESS, "HandleKeyPressEvent gets non-keypress event"); switch (nativeKeyEvent->keyCode) { @@ -845,7 +845,7 @@ nsPlaintextEditor::UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent) WidgetCompositionEvent* compositionChangeEvent = aDOMTextEvent->GetInternalNSEvent()->AsCompositionEvent(); NS_ENSURE_TRUE(compositionChangeEvent, NS_ERROR_INVALID_ARG); - MOZ_ASSERT(compositionChangeEvent->message == NS_COMPOSITION_CHANGE, + MOZ_ASSERT(compositionChangeEvent->mMessage == NS_COMPOSITION_CHANGE, "The internal event should be NS_COMPOSITION_CHANGE"); EnsureComposition(compositionChangeEvent); diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp index 763dabcdf822..8f464c4ba59c 100644 --- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -854,7 +854,7 @@ APZCTreeManager::UpdateWheelTransaction(WidgetInputEvent& aEvent) return; } - switch (aEvent.message) { + switch (aEvent.mMessage) { case NS_MOUSE_MOVE: case NS_DRAGDROP_OVER: { WidgetMouseEvent* mouseEvent = aEvent.AsMouseEvent(); diff --git a/gfx/layers/apz/util/APZEventState.cpp b/gfx/layers/apz/util/APZEventState.cpp index 0c67d71b0622..78ae8547643e 100644 --- a/gfx/layers/apz/util/APZEventState.cpp +++ b/gfx/layers/apz/util/APZEventState.cpp @@ -251,14 +251,14 @@ APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent, uint64_t aInputBlockId, nsEventStatus aApzResponse) { - if (aEvent.message == NS_TOUCH_START && aEvent.touches.Length() > 0) { + if (aEvent.mMessage == NS_TOUCH_START && aEvent.touches.Length() > 0) { mActiveElementManager->SetTargetElement(aEvent.touches[0]->GetTarget()); } bool isTouchPrevented = TouchManager::gPreventMouseEvents || aEvent.mFlags.mMultipleActionsPrevented; bool sentContentResponse = false; - switch (aEvent.message) { + switch (aEvent.mMessage) { case NS_TOUCH_START: { mTouchEndCancelled = false; if (mPendingTouchPreventedResponse) { @@ -305,8 +305,8 @@ APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent, aApzResponse == nsEventStatus_eConsumeDoDefault && gfxPrefs::PointerEventsEnabled()) { WidgetTouchEvent cancelEvent(aEvent); - cancelEvent.message = NS_TOUCH_CANCEL; - cancelEvent.mFlags.mCancelable = false; // message != NS_TOUCH_CANCEL; + cancelEvent.mMessage = NS_TOUCH_CANCEL; + cancelEvent.mFlags.mCancelable = false; // mMessage != NS_TOUCH_CANCEL; for (uint32_t i = 0; i < cancelEvent.touches.Length(); ++i) { if (mozilla::dom::Touch* touch = cancelEvent.touches[i]) { touch->convertToPointer = true; diff --git a/layout/base/AccessibleCaretEventHub.cpp b/layout/base/AccessibleCaretEventHub.cpp index eb0cd4d78660..490943895821 100644 --- a/layout/base/AccessibleCaretEventHub.cpp +++ b/layout/base/AccessibleCaretEventHub.cpp @@ -500,7 +500,7 @@ AccessibleCaretEventHub::HandleMouseEvent(WidgetMouseEvent* aEvent) kDefaultTouchId : mActiveTouchId); nsPoint point = GetMouseEventPosition(aEvent); - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_MOUSE_BUTTON_DOWN: AC_LOGV("Before NS_MOUSE_BUTTON_DOWN, state: %s", mState->Name()); rv = mState->OnPress(this, point, id); @@ -538,7 +538,7 @@ AccessibleCaretEventHub::HandleMouseEvent(WidgetMouseEvent* aEvent) nsEventStatus AccessibleCaretEventHub::HandleWheelEvent(WidgetWheelEvent* aEvent) { - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_WHEEL_WHEEL: AC_LOGV("NS_WHEEL_WHEEL, isMomentum %d, state: %s", aEvent->isMomentum, mState->Name()); @@ -573,7 +573,7 @@ AccessibleCaretEventHub::HandleTouchEvent(WidgetTouchEvent* aEvent) aEvent->touches[0]->Identifier() : mActiveTouchId); nsPoint point = GetTouchEventPosition(aEvent, id); - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_TOUCH_START: AC_LOGV("Before NS_TOUCH_START, state: %s", mState->Name()); rv = mState->OnPress(this, point, id); @@ -609,7 +609,7 @@ AccessibleCaretEventHub::HandleTouchEvent(WidgetTouchEvent* aEvent) nsEventStatus AccessibleCaretEventHub::HandleKeyboardEvent(WidgetKeyboardEvent* aEvent) { - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_KEY_UP: case NS_KEY_DOWN: case NS_KEY_PRESS: diff --git a/layout/base/SelectionCarets.cpp b/layout/base/SelectionCarets.cpp index def5269122aa..cf7177696ded 100644 --- a/layout/base/SelectionCarets.cpp +++ b/layout/base/SelectionCarets.cpp @@ -204,11 +204,11 @@ SelectionCarets::HandleEvent(WidgetEvent* aEvent) nsPoint ptInRoot = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, movePoint, rootFrame); - if (aEvent->message == NS_TOUCH_START || - (aEvent->message == NS_MOUSE_BUTTON_DOWN && + if (aEvent->mMessage == NS_TOUCH_START || + (aEvent->mMessage == NS_MOUSE_BUTTON_DOWN && mouseEvent->button == WidgetMouseEvent::eLeftButton)) { // If having a active touch, ignore other touch down event - if (aEvent->message == NS_TOUCH_START && mActiveTouchId >= 0) { + if (aEvent->mMessage == NS_TOUCH_START && mActiveTouchId >= 0) { return nsEventStatus_eConsumeNoDefault; } @@ -231,9 +231,9 @@ SelectionCarets::HandleEvent(WidgetEvent* aEvent) mActiveTouchId = -1; LaunchLongTapDetector(); } - } else if (aEvent->message == NS_TOUCH_END || - aEvent->message == NS_TOUCH_CANCEL || - aEvent->message == NS_MOUSE_BUTTON_UP) { + } else if (aEvent->mMessage == NS_TOUCH_END || + aEvent->mMessage == NS_TOUCH_CANCEL || + aEvent->mMessage == NS_MOUSE_BUTTON_UP) { CancelLongTapDetector(); if (mDragMode != NONE) { // Only care about same id @@ -244,8 +244,8 @@ SelectionCarets::HandleEvent(WidgetEvent* aEvent) } return nsEventStatus_eConsumeNoDefault; } - } else if (aEvent->message == NS_TOUCH_MOVE || - aEvent->message == NS_MOUSE_MOVE) { + } else if (aEvent->mMessage == NS_TOUCH_MOVE || + aEvent->mMessage == NS_MOUSE_MOVE) { if (mDragMode == START_FRAME || mDragMode == END_FRAME) { if (mActiveTouchId == nowTouchId) { ptInRoot.y += mCaretCenterToDownPointOffsetY; @@ -271,7 +271,7 @@ SelectionCarets::HandleEvent(WidgetEvent* aEvent) CancelLongTapDetector(); } - } else if (aEvent->message == NS_MOUSE_MOZLONGTAP) { + } else if (aEvent->mMessage == NS_MOUSE_MOZLONGTAP) { if (!mVisible || !sSelectionCaretDetectsLongTap) { SELECTIONCARETS_LOG("SelectWord from NS_MOUSE_MOZLONGTAP"); diff --git a/layout/base/TouchCaret.cpp b/layout/base/TouchCaret.cpp index 83a517edad37..0775f0c4e920 100644 --- a/layout/base/TouchCaret.cpp +++ b/layout/base/TouchCaret.cpp @@ -759,7 +759,7 @@ TouchCaret::HandleEvent(WidgetEvent* aEvent) nsEventStatus status = nsEventStatus_eIgnore; - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_TOUCH_START: status = HandleTouchDownEvent(aEvent->AsTouchEvent()); break; @@ -790,7 +790,7 @@ TouchCaret::HandleEvent(WidgetEvent* aEvent) case NS_WHEEL_START: case NS_WHEEL_STOP: // Disable touch caret while key/wheel event is received. - TOUCHCARET_LOG("Receive key/wheel event %d", aEvent->message); + TOUCHCARET_LOG("Receive key/wheel event %d", aEvent->mMessage); SetVisibility(false); break; case NS_MOUSE_MOZLONGTAP: diff --git a/layout/base/TouchManager.cpp b/layout/base/TouchManager.cpp index 329507b69fae..6175a958c0af 100644 --- a/layout/base/TouchManager.cpp +++ b/layout/base/TouchManager.cpp @@ -101,7 +101,7 @@ TouchManager::PreHandleEvent(WidgetEvent* aEvent, bool& aIsHandlingUserInput, nsCOMPtr& aCurrentEventContent) { - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_TOUCH_START: { aIsHandlingUserInput = true; WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent(); @@ -123,7 +123,7 @@ TouchManager::PreHandleEvent(WidgetEvent* aEvent, // If it is not already in the queue, it is a new touch touch->mChanged = true; } - touch->mMessage = aEvent->message; + touch->mMessage = aEvent->mMessage; gCaptureTouchList->Put(id, touch); } break; @@ -140,7 +140,7 @@ TouchManager::PreHandleEvent(WidgetEvent* aEvent, continue; } int32_t id = touch->Identifier(); - touch->mMessage = aEvent->message; + touch->mMessage = aEvent->mMessage; nsRefPtr oldTouch = gCaptureTouchList->GetWeak(id); if (!oldTouch) { @@ -203,7 +203,7 @@ TouchManager::PreHandleEvent(WidgetEvent* aEvent, if (!touch) { continue; } - touch->mMessage = aEvent->message; + touch->mMessage = aEvent->mMessage; touch->mChanged = true; int32_t id = touch->Identifier(); diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index a75a550646ba..1d094ec1c8d1 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -467,15 +467,15 @@ class MOZ_STACK_CLASS nsPresShellEventCB : public EventDispatchingCallback virtual void HandleEvent(EventChainPostVisitor& aVisitor) override { if (aVisitor.mPresContext && aVisitor.mEvent->mClass != eBasicEventClass) { - if (aVisitor.mEvent->message == NS_MOUSE_BUTTON_DOWN || - aVisitor.mEvent->message == NS_MOUSE_BUTTON_UP) { + if (aVisitor.mEvent->mMessage == NS_MOUSE_BUTTON_DOWN || + aVisitor.mEvent->mMessage == NS_MOUSE_BUTTON_UP) { // Mouse-up and mouse-down events call nsFrame::HandlePress/Release // which call GetContentOffsetsFromPoint which requires up-to-date layout. // Bring layout up-to-date now so that GetCurrentEventFrame() below // will return a real frame and we don't have to worry about // destroying it by flushing later. mPresShell->FlushPendingNotifications(Flush_Layout); - } else if (aVisitor.mEvent->message == NS_WHEEL_WHEEL && + } else if (aVisitor.mEvent->mMessage == NS_WHEEL_WHEEL && aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) { nsIFrame* frame = mPresShell->GetCurrentEventFrame(); if (frame) { @@ -492,8 +492,8 @@ class MOZ_STACK_CLASS nsPresShellEventCB : public EventDispatchingCallback } nsIFrame* frame = mPresShell->GetCurrentEventFrame(); if (!frame && - (aVisitor.mEvent->message == NS_MOUSE_BUTTON_UP || - aVisitor.mEvent->message == NS_TOUCH_END)) { + (aVisitor.mEvent->mMessage == NS_MOUSE_BUTTON_UP || + aVisitor.mEvent->mMessage == NS_TOUCH_END)) { // Redirect BUTTON_UP and TOUCH_END events to the root frame to ensure // that capturing is released. frame = mPresShell->GetRootFrame(); @@ -6342,7 +6342,7 @@ nsIPresShell::GetPointerInfo(uint32_t aPointerId, bool& aActiveState) void PresShell::UpdateActivePointerState(WidgetGUIEvent* aEvent) { - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_MOUSE_ENTER_WIDGET: // In this case we have to know information about available mouse pointers if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) { @@ -6562,11 +6562,11 @@ PresShell::RecordMouseLocation(WidgetGUIEvent* aEvent) return; } - if ((aEvent->message == NS_MOUSE_MOVE && + if ((aEvent->mMessage == NS_MOUSE_MOVE && aEvent->AsMouseEvent()->reason == WidgetMouseEvent::eReal) || - aEvent->message == NS_MOUSE_ENTER_WIDGET || - aEvent->message == NS_MOUSE_BUTTON_DOWN || - aEvent->message == NS_MOUSE_BUTTON_UP) { + aEvent->mMessage == NS_MOUSE_ENTER_WIDGET || + aEvent->mMessage == NS_MOUSE_BUTTON_DOWN || + aEvent->mMessage == NS_MOUSE_BUTTON_UP) { nsIFrame* rootFrame = GetRootFrame(); if (!rootFrame) { nsView* rootView = mViewManager->GetRootView(); @@ -6577,15 +6577,17 @@ PresShell::RecordMouseLocation(WidgetGUIEvent* aEvent) nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, rootFrame); } #ifdef DEBUG_MOUSE_LOCATION - if (aEvent->message == NS_MOUSE_ENTER_WIDGET) + if (aEvent->mMessage == NS_MOUSE_ENTER_WIDGET) { printf("[ps=%p]got mouse enter for %p\n", this, aEvent->widget); + } printf("[ps=%p]setting mouse location to (%d,%d)\n", this, mMouseLocation.x, mMouseLocation.y); #endif - if (aEvent->message == NS_MOUSE_ENTER_WIDGET) + if (aEvent->mMessage == NS_MOUSE_ENTER_WIDGET) { SynthesizeMouseMove(false); - } else if (aEvent->message == NS_MOUSE_EXIT_WIDGET) { + } + } else if (aEvent->mMessage == NS_MOUSE_EXIT_WIDGET) { // Although we only care about the mouse moving into an area for which this // pres shell doesn't receive mouse move events, we don't check which widget // the mouse exit was for since this seems to vary by platform. Hopefully @@ -6662,7 +6664,7 @@ DispatchPointerFromMouseOrTouch(PresShell* aShell, return NS_OK; } int16_t button = mouseEvent->button; - switch (mouseEvent->message) { + switch (mouseEvent->mMessage) { case NS_MOUSE_MOVE: if (mouseEvent->buttons == 0) { button = -1; @@ -6680,7 +6682,7 @@ DispatchPointerFromMouseOrTouch(PresShell* aShell, } WidgetPointerEvent event(*mouseEvent); - event.message = pointerMessage; + event.mMessage = pointerMessage; event.button = button; event.pressure = event.buttons ? mouseEvent->pressure ? mouseEvent->pressure : 0.5f : @@ -6691,7 +6693,7 @@ DispatchPointerFromMouseOrTouch(PresShell* aShell, WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent(); // loop over all touches and dispatch pointer events on each touch // copy the event - switch (touchEvent->message) { + switch (touchEvent->mMessage) { case NS_TOUCH_MOVE: pointerMessage = NS_POINTER_MOVE; break; @@ -6840,7 +6842,7 @@ PresShell::DispatchBeforeKeyboardEventInternal(const nsTArray } uint32_t message = - (aEvent.message == NS_KEY_DOWN) ? NS_KEY_BEFORE_DOWN : NS_KEY_BEFORE_UP; + (aEvent.mMessage == NS_KEY_DOWN) ? NS_KEY_BEFORE_DOWN : NS_KEY_BEFORE_UP; nsCOMPtr eventTarget; // Dispatch before events from the outermost element. for (int32_t i = length - 1; i >= 0; i--) { @@ -6874,7 +6876,7 @@ PresShell::DispatchAfterKeyboardEventInternal(const nsTArray > } uint32_t message = - (aEvent.message == NS_KEY_DOWN) ? NS_KEY_AFTER_DOWN : NS_KEY_AFTER_UP; + (aEvent.mMessage == NS_KEY_DOWN) ? NS_KEY_AFTER_DOWN : NS_KEY_AFTER_UP; bool embeddedCancelled = aEmbeddedCancelled; nsCOMPtr eventTarget; // Dispatch after events from the innermost element. @@ -6901,8 +6903,8 @@ PresShell::DispatchAfterKeyboardEvent(nsINode* aTarget, MOZ_ASSERT(aTarget); MOZ_ASSERT(BeforeAfterKeyboardEventEnabled()); - if (NS_WARN_IF(aEvent.message != NS_KEY_DOWN && - aEvent.message != NS_KEY_UP)) { + if (NS_WARN_IF(aEvent.mMessage != NS_KEY_DOWN && + aEvent.mMessage != NS_KEY_UP)) { return; } @@ -6931,7 +6933,7 @@ PresShell::HandleKeyboardEvent(nsINode* aTarget, nsEventStatus* aStatus, EventDispatchingCallback* aEventCB) { - if (aEvent.message == NS_KEY_PRESS || + if (aEvent.mMessage == NS_KEY_PRESS || !BeforeAfterKeyboardEventEnabled()) { EventDispatcher::Dispatch(aTarget, mPresContext, &aEvent, nullptr, aStatus, aEventCB); @@ -6939,7 +6941,7 @@ PresShell::HandleKeyboardEvent(nsINode* aTarget, } MOZ_ASSERT(aTarget); - MOZ_ASSERT(aEvent.message == NS_KEY_DOWN || aEvent.message == NS_KEY_UP); + MOZ_ASSERT(aEvent.mMessage == NS_KEY_DOWN || aEvent.mMessage == NS_KEY_UP); // Build up a target chain. Each item in the chain will receive a before event. nsAutoTArray, 5> chain; @@ -7120,7 +7122,7 @@ PresShell::HandleEvent(nsIFrame* aFrame, } #ifdef DEBUG if (aEvent->IsIMERelatedEvent()) { - nsPrintfCString warning("%d event is discarded", aEvent->message); + nsPrintfCString warning("%d event is discarded", aEvent->mMessage); NS_WARNING(warning.get()); } #endif @@ -7175,7 +7177,7 @@ PresShell::HandleEvent(nsIFrame* aFrame, if (presShell != this) { nsIFrame* frame = presShell->GetRootFrame(); if (!frame) { - if (aEvent->message == NS_QUERY_TEXT_CONTENT || + if (aEvent->mMessage == NS_QUERY_TEXT_CONTENT || aEvent->IsContentCommandEvent()) { return NS_OK; } @@ -7194,7 +7196,7 @@ PresShell::HandleEvent(nsIFrame* aFrame, if (aEvent->mClass == eKeyboardEventClass && mDocument && mDocument->EventHandlingSuppressed()) { - if (aEvent->message == NS_KEY_DOWN) { + if (aEvent->mMessage == NS_KEY_DOWN) { mNoDelayedKeyEvents = true; } else if (!mNoDelayedKeyEvents) { DelayedEvent* event = new DelayedKeyEvent(aEvent->AsKeyboardEvent()); @@ -7302,12 +7304,12 @@ PresShell::HandleEvent(nsIFrame* aFrame, // all touch events except for touchstart use a captured target if (aEvent->mClass == eTouchEventClass && - aEvent->message != NS_TOUCH_START) { + aEvent->mMessage != NS_TOUCH_START) { captureRetarget = true; } WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); - bool isWindowLevelMouseExit = (aEvent->message == NS_MOUSE_EXIT_WIDGET) && + bool isWindowLevelMouseExit = (aEvent->mMessage == NS_MOUSE_EXIT_WIDGET) && (mouseEvent && mouseEvent->exit == WidgetMouseEvent::eTopLevel); // Get the frame at the event point. However, don't do this if we're @@ -7318,7 +7320,7 @@ PresShell::HandleEvent(nsIFrame* aFrame, if (!captureRetarget && !isWindowLevelMouseExit) { nsPoint eventPoint; uint32_t flags = 0; - if (aEvent->message == NS_TOUCH_START) { + if (aEvent->mMessage == NS_TOUCH_START) { flags |= INPUT_IGNORE_ROOT_SCROLL_FRAME; WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent(); // if this is a continuing session, ensure that all these events are @@ -7446,7 +7448,7 @@ PresShell::HandleEvent(nsIFrame* aFrame, } if (aEvent->mClass == ePointerEventClass && - aEvent->message != NS_POINTER_DOWN) { + aEvent->mMessage != NS_POINTER_DOWN) { if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) { uint32_t pointerId = pointerEvent->pointerId; nsIContent* pointerCapturingContent = GetPointerCapturingContent(pointerId); @@ -7461,8 +7463,8 @@ PresShell::HandleEvent(nsIFrame* aFrame, frame = capturingFrame; } - if (pointerEvent->message == NS_POINTER_UP || - pointerEvent->message == NS_POINTER_CANCEL) { + if (pointerEvent->mMessage == NS_POINTER_UP || + pointerEvent->mMessage == NS_POINTER_CANCEL) { // Implicitly releasing capture for given pointer. // LOST_POINTER_CAPTURE should be send after NS_POINTER_UP or NS_POINTER_CANCEL. releasePointerCaptureCaller.SetTarget(pointerId, pointerCapturingContent); @@ -7475,9 +7477,10 @@ PresShell::HandleEvent(nsIFrame* aFrame, // a document which needs events suppressed if (aEvent->mClass == eMouseEventClass && frame->PresContext()->Document()->EventHandlingSuppressed()) { - if (aEvent->message == NS_MOUSE_BUTTON_DOWN) { + if (aEvent->mMessage == NS_MOUSE_BUTTON_DOWN) { mNoDelayedMouseEvents = true; - } else if (!mNoDelayedMouseEvents && aEvent->message == NS_MOUSE_BUTTON_UP) { + } else if (!mNoDelayedMouseEvents && + aEvent->mMessage == NS_MOUSE_BUTTON_UP) { DelayedEvent* event = new DelayedMouseEvent(aEvent->AsMouseEvent()); if (!mDelayedEvents.AppendElement(event)) { delete event; @@ -7493,7 +7496,7 @@ PresShell::HandleEvent(nsIFrame* aFrame, PresShell* shell = static_cast(frame->PresContext()->PresShell()); - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_TOUCH_MOVE: case NS_TOUCH_CANCEL: case NS_TOUCH_END: { @@ -7623,11 +7626,12 @@ PresShell::HandleEvent(nsIFrame* aFrame, } } - if (aEvent->message == NS_KEY_DOWN) { + if (aEvent->mMessage == NS_KEY_DOWN) { NS_IF_RELEASE(gKeyDownTarget); NS_IF_ADDREF(gKeyDownTarget = eventTarget); } - else if ((aEvent->message == NS_KEY_PRESS || aEvent->message == NS_KEY_UP) && + else if ((aEvent->mMessage == NS_KEY_PRESS || + aEvent->mMessage == NS_KEY_UP) && gKeyDownTarget) { // If a different element is now focused for the keypress/keyup event // than what was focused during the keydown event, check if the new @@ -7643,7 +7647,7 @@ PresShell::HandleEvent(nsIFrame* aFrame, } } - if (aEvent->message == NS_KEY_UP) { + if (aEvent->mMessage == NS_KEY_UP) { NS_RELEASE(gKeyDownTarget); } } @@ -7831,7 +7835,7 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent, nsEventStatus* aStatus) // XXX How about IME events and input events for plugins? if (aEvent->mFlags.mIsTrusted) { - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_KEY_PRESS: case NS_KEY_DOWN: case NS_KEY_UP: { @@ -7851,7 +7855,7 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent, nsEventStatus* aStatus) // The event listeners in chrome can prevent this ESC behavior by // calling prevent default on the preceding keydown/press events. if (!mIsLastChromeOnlyEscapeKeyConsumed && - aEvent->message == NS_KEY_UP) { + aEvent->mMessage == NS_KEY_UP) { // ESC key released while in DOM fullscreen mode. // Fully exit all browser windows and documents from // fullscreen mode. @@ -7863,7 +7867,7 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent, nsEventStatus* aStatus) if (!mIsLastChromeOnlyEscapeKeyConsumed && pointerLockedDoc) { aEvent->mFlags.mDefaultPrevented = true; aEvent->mFlags.mOnlyChromeDispatch = true; - if (aEvent->message == NS_KEY_UP) { + if (aEvent->mMessage == NS_KEY_UP) { nsIDocument::UnlockPointer(); } } @@ -7902,7 +7906,7 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent, nsEventStatus* aStatus) } } - if (aEvent->message == NS_CONTEXTMENU) { + if (aEvent->mMessage == NS_CONTEXTMENU) { WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); if (mouseEvent->context == WidgetMouseEvent::eContextMenuKey && !AdjustContextMenuKeyEvent(mouseEvent)) { @@ -7917,7 +7921,7 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent, nsEventStatus* aStatus) AutoHandlingUserInputStatePusher userInpStatePusher(isHandlingUserInput, aEvent, mDocument); - if (aEvent->mFlags.mIsTrusted && aEvent->message == NS_MOUSE_MOVE) { + if (aEvent->mFlags.mIsTrusted && aEvent->mMessage == NS_MOUSE_MOVE) { nsIPresShell::AllowMouseCapture( EventStateManager::GetActiveEventStateManager() == manager); } @@ -7962,12 +7966,12 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent, nsEventStatus* aStatus) } } - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_KEY_PRESS: case NS_KEY_DOWN: case NS_KEY_UP: { if (aEvent->AsKeyboardEvent()->keyCode == NS_VK_ESCAPE) { - if (aEvent->message == NS_KEY_UP) { + if (aEvent->mMessage == NS_KEY_UP) { // Reset this flag after key up is handled. mIsLastChromeOnlyEscapeKeyConsumed = false; } else { @@ -8069,9 +8073,9 @@ PresShell::DispatchTouchEventToDOM(WidgetEvent* aEvent, // calling preventDefault on touchstart or the first touchmove for a // point prevents mouse events. calling it on the touchend should // prevent click dispatching. - bool canPrevent = (aEvent->message == NS_TOUCH_START) || - (aEvent->message == NS_TOUCH_MOVE && aTouchIsNew) || - (aEvent->message == NS_TOUCH_END); + bool canPrevent = (aEvent->mMessage == NS_TOUCH_START) || + (aEvent->mMessage == NS_TOUCH_MOVE && aTouchIsNew) || + (aEvent->mMessage == NS_TOUCH_END); bool preventDefault = false; nsEventStatus tmpStatus = nsEventStatus_eIgnore; WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent(); @@ -8099,7 +8103,7 @@ PresShell::DispatchTouchEventToDOM(WidgetEvent* aEvent, } // copy the event WidgetTouchEvent newEvent(touchEvent->mFlags.mIsTrusted, - touchEvent->message, touchEvent->widget); + touchEvent->mMessage, touchEvent->widget); newEvent.AssignTouchEventData(*touchEvent, false); newEvent.target = targetPtr; @@ -9536,7 +9540,7 @@ PresShell::DelayedMouseEvent::DelayedMouseEvent(WidgetMouseEvent* aEvent) : { WidgetMouseEvent* mouseEvent = new WidgetMouseEvent(aEvent->mFlags.mIsTrusted, - aEvent->message, + aEvent->mMessage, aEvent->widget, aEvent->reason, aEvent->context); @@ -9549,7 +9553,7 @@ PresShell::DelayedKeyEvent::DelayedKeyEvent(WidgetKeyboardEvent* aEvent) : { WidgetKeyboardEvent* keyEvent = new WidgetKeyboardEvent(aEvent->mFlags.mIsTrusted, - aEvent->message, + aEvent->mMessage, aEvent->widget); keyEvent->AssignKeyEventData(*aEvent, false); keyEvent->mFlags.mIsSynthesizedForTests = aEvent->mFlags.mIsSynthesizedForTests; diff --git a/layout/forms/nsComboboxControlFrame.cpp b/layout/forms/nsComboboxControlFrame.cpp index df96fa565285..59b8705b27a7 100644 --- a/layout/forms/nsComboboxControlFrame.cpp +++ b/layout/forms/nsComboboxControlFrame.cpp @@ -1133,7 +1133,7 @@ nsComboboxControlFrame::HandleEvent(nsPresContext* aPresContext, } #if COMBOBOX_ROLLUP_CONSUME_EVENT == 0 - if (aEvent->message == NS_MOUSE_BUTTON_DOWN) { + if (aEvent->mMessage == NS_MOUSE_BUTTON_DOWN) { nsIWidget* widget = GetNearestWidget(); if (widget && GetContent() == widget->GetLastRollup()) { // This event did a Rollup on this control - prevent it from opening diff --git a/layout/forms/nsImageControlFrame.cpp b/layout/forms/nsImageControlFrame.cpp index bfecbbcebd8c..13bdf23a4eb6 100644 --- a/layout/forms/nsImageControlFrame.cpp +++ b/layout/forms/nsImageControlFrame.cpp @@ -162,7 +162,7 @@ nsImageControlFrame::HandleEvent(nsPresContext* aPresContext, *aEventStatus = nsEventStatus_eIgnore; - if (aEvent->message == NS_MOUSE_BUTTON_UP && + if (aEvent->mMessage == NS_MOUSE_BUTTON_UP && aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) { // Store click point for HTMLInputElement::SubmitNamesValues // Do this on MouseUp because the specs don't say and that's what IE does diff --git a/layout/forms/nsListControlFrame.cpp b/layout/forms/nsListControlFrame.cpp index a18689a9beb0..dbc4a631a339 100644 --- a/layout/forms/nsListControlFrame.cpp +++ b/layout/forms/nsListControlFrame.cpp @@ -898,11 +898,11 @@ nsListControlFrame::HandleEvent(nsPresContext* aPresContext, "NS_MOUSE_LEFT_CLICK", "NS_MOUSE_MIDDLE_CLICK", "NS_MOUSE_RIGHT_CLICK"}; - int inx = aEvent->message-NS_MOUSE_MESSAGE_START; + int inx = aEvent->mMessage-NS_MOUSE_MESSAGE_START; if (inx >= 0 && inx <= (NS_MOUSE_RIGHT_CLICK-NS_MOUSE_MESSAGE_START)) { - printf("Mouse in ListFrame %s [%d]\n", desc[inx], aEvent->message); + printf("Mouse in ListFrame %s [%d]\n", desc[inx], aEvent->mMessage); } else { - printf("Mouse in ListFrame [%d]\n", aEvent->message); + printf("Mouse in ListFrame [%d]\n", aEvent->mMessage); }*/ if (nsEventStatus_eConsumeNoDefault == *aEventStatus) diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index a9a8d901c7bb..2a5d90a252de 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -2558,7 +2558,7 @@ nsFrame::HandleEvent(nsPresContext* aPresContext, nsEventStatus* aEventStatus) { - if (aEvent->message == NS_MOUSE_MOVE) { + if (aEvent->mMessage == NS_MOUSE_MOVE) { // XXX If the second argument of HandleDrag() is WidgetMouseEvent, // the implementation becomes simpler. return HandleDrag(aPresContext, aEvent, aEventStatus); @@ -2567,9 +2567,11 @@ nsFrame::HandleEvent(nsPresContext* aPresContext, if ((aEvent->mClass == eMouseEventClass && aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) || aEvent->mClass == eTouchEventClass) { - if (aEvent->message == NS_MOUSE_BUTTON_DOWN || aEvent->message == NS_TOUCH_START) { + if (aEvent->mMessage == NS_MOUSE_BUTTON_DOWN || + aEvent->mMessage == NS_TOUCH_START) { HandlePress(aPresContext, aEvent, aEventStatus); - } else if (aEvent->message == NS_MOUSE_BUTTON_UP || aEvent->message == NS_TOUCH_END) { + } else if (aEvent->mMessage == NS_MOUSE_BUTTON_UP || + aEvent->mMessage == NS_TOUCH_END) { HandleRelease(aPresContext, aEvent, aEventStatus); } } @@ -2602,8 +2604,8 @@ nsFrame::GetDataForTableSelection(const nsFrameSelection* aFrameSelection, // (Mouse down does normal selection unless Ctrl/Cmd is pressed) bool doTableSelection = displaySelection == nsISelectionDisplay::DISPLAY_ALL && selectingTableCells && - (aMouseEvent->message == NS_MOUSE_MOVE || - (aMouseEvent->message == NS_MOUSE_BUTTON_UP && + (aMouseEvent->mMessage == NS_MOUSE_MOVE || + (aMouseEvent->mMessage == NS_MOUSE_BUTTON_UP && aMouseEvent->button == WidgetMouseEvent::eLeftButton) || aMouseEvent->IsShift()); diff --git a/layout/generic/nsFrameSetFrame.cpp b/layout/generic/nsFrameSetFrame.cpp index bd4c1839135d..b064376048a8 100644 --- a/layout/generic/nsFrameSetFrame.cpp +++ b/layout/generic/nsFrameSetFrame.cpp @@ -651,7 +651,7 @@ nsresult nsHTMLFramesetFrame::HandleEvent(nsPresContext* aPresContext, NS_ENSURE_ARG_POINTER(aEventStatus); if (mDragger) { // the nsFramesetBorderFrame has captured NS_MOUSE_DOWN - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_MOUSE_MOVE: MouseDrag(aPresContext, aEvent); break; @@ -1537,7 +1537,7 @@ nsHTMLFramesetBorderFrame::HandleEvent(nsPresContext* aPresContext, return NS_OK; } - if (aEvent->message == NS_MOUSE_BUTTON_DOWN && + if (aEvent->mMessage == NS_MOUSE_BUTTON_DOWN && aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) { nsHTMLFramesetFrame* parentFrame = do_QueryFrame(GetParent()); if (parentFrame) { diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index a720d422888d..bc32f79154ad 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -2010,9 +2010,9 @@ nsImageFrame::HandleEvent(nsPresContext* aPresContext, { NS_ENSURE_ARG_POINTER(aEventStatus); - if ((aEvent->message == NS_MOUSE_BUTTON_UP && + if ((aEvent->mMessage == NS_MOUSE_BUTTON_UP && aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) || - aEvent->message == NS_MOUSE_MOVE) { + aEvent->mMessage == NS_MOUSE_MOVE) { nsImageMap* map = GetImageMap(); bool isServerMap = IsServerImageMap(); if ((nullptr != map) || isServerMap) { @@ -2050,7 +2050,7 @@ nsImageFrame::HandleEvent(nsPresContext* aPresContext, uri->SetSpec(spec); bool clicked = false; - if (aEvent->message == NS_MOUSE_BUTTON_UP) { + if (aEvent->mMessage == NS_MOUSE_BUTTON_UP) { *aEventStatus = nsEventStatus_eConsumeDoDefault; clicked = true; } diff --git a/layout/generic/nsPluginFrame.cpp b/layout/generic/nsPluginFrame.cpp index 490bf22d0539..ff9702cc813c 100644 --- a/layout/generic/nsPluginFrame.cpp +++ b/layout/generic/nsPluginFrame.cpp @@ -1761,13 +1761,13 @@ nsPluginFrame::HandleEvent(nsPresContext* aPresContext, mInstanceOwner->ConsiderNewEventloopNestingLevel(); - if (anEvent->message == NS_PLUGIN_ACTIVATE) { + if (anEvent->mMessage == NS_PLUGIN_ACTIVATE) { nsIFocusManager* fm = nsFocusManager::GetFocusManager(); nsCOMPtr elem = do_QueryInterface(GetContent()); if (fm && elem) return fm->SetFocus(elem, 0); } - else if (anEvent->message == NS_PLUGIN_FOCUS) { + else if (anEvent->mMessage == NS_PLUGIN_FOCUS) { nsIFocusManager* fm = nsFocusManager::GetFocusManager(); if (fm) return fm->FocusPlugin(GetContent()); @@ -1788,8 +1788,8 @@ nsPluginFrame::HandleEvent(nsPresContext* aPresContext, #ifdef XP_MACOSX // we want to process some native mouse events in the cocoa event model - if ((anEvent->message == NS_MOUSE_ENTER_WIDGET || - anEvent->message == NS_WHEEL_WHEEL) && + if ((anEvent->mMessage == NS_MOUSE_ENTER_WIDGET || + anEvent->mMessage == NS_WHEEL_WHEEL) && mInstanceOwner->GetEventModel() == NPEventModelCocoa) { *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent); // Due to plugin code reentering Gecko, this frame may be dead at this @@ -1801,7 +1801,7 @@ nsPluginFrame::HandleEvent(nsPresContext* aPresContext, // and mouse-up) are needed to make the routing of mouse events while // dragging conform to standard OS X practice, and to the Cocoa NPAPI spec. // See bug 525078 and bug 909678. - if (anEvent->message == NS_MOUSE_BUTTON_DOWN) { + if (anEvent->mMessage == NS_MOUSE_BUTTON_DOWN) { nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED); } #endif @@ -1812,7 +1812,7 @@ nsPluginFrame::HandleEvent(nsPresContext* aPresContext, // nsPluginFrameSuper::HandleEvent() might have killed us. #ifdef XP_MACOSX - if (anEvent->message == NS_MOUSE_BUTTON_UP) { + if (anEvent->mMessage == NS_MOUSE_BUTTON_UP) { nsIPresShell::SetCapturingContent(nullptr, 0); } #endif diff --git a/layout/printing/nsPrintPreviewListener.cpp b/layout/printing/nsPrintPreviewListener.cpp index 5a4e7dae45e5..dca52906c906 100644 --- a/layout/printing/nsPrintPreviewListener.cpp +++ b/layout/printing/nsPrintPreviewListener.cpp @@ -118,7 +118,7 @@ GetActionForEvent(nsIDOMEvent* aEvent) } if (keyEvent->mFlags.mInSystemGroup) { - NS_ASSERTION(keyEvent->message == NS_KEY_DOWN, + NS_ASSERTION(keyEvent->mMessage == NS_KEY_DOWN, "Assuming we're listening only keydown event in system group"); return eEventAction_StopPropagation; } @@ -126,8 +126,8 @@ GetActionForEvent(nsIDOMEvent* aEvent) if (keyEvent->IsAlt() || keyEvent->IsControl() || keyEvent->IsMeta()) { // Don't consume keydown event because following keypress event may be // handled as access key or shortcut key. - return (keyEvent->message == NS_KEY_DOWN) ? eEventAction_StopPropagation : - eEventAction_Suppress; + return (keyEvent->mMessage == NS_KEY_DOWN) ? eEventAction_StopPropagation : + eEventAction_Suppress; } static const uint32_t kOKKeyCodes[] = { diff --git a/layout/style/nsAnimationManager.h b/layout/style/nsAnimationManager.h index 1dcd35eb5496..12db1d7ea442 100644 --- a/layout/style/nsAnimationManager.h +++ b/layout/style/nsAnimationManager.h @@ -44,7 +44,8 @@ struct AnimationEventInfo { // InternalAnimationEvent doesn't support copy-construction, so we need // to ourselves in order to work with nsTArray AnimationEventInfo(const AnimationEventInfo &aOther) - : mElement(aOther.mElement), mEvent(true, aOther.mEvent.message) + : mElement(aOther.mElement) + , mEvent(true, aOther.mEvent.mMessage) { mEvent.AssignAnimationEventData(aOther.mEvent, false); } diff --git a/layout/xul/nsButtonBoxFrame.cpp b/layout/xul/nsButtonBoxFrame.cpp index 3259e597f57e..bda9e52d7d47 100644 --- a/layout/xul/nsButtonBoxFrame.cpp +++ b/layout/xul/nsButtonBoxFrame.cpp @@ -110,7 +110,7 @@ nsButtonBoxFrame::HandleEvent(nsPresContext* aPresContext, return NS_OK; } - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_KEY_DOWN: { WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent(); if (!keyEvent) { diff --git a/layout/xul/nsMenuFrame.cpp b/layout/xul/nsMenuFrame.cpp index d498c66324df..22a363bcb981 100644 --- a/layout/xul/nsMenuFrame.cpp +++ b/layout/xul/nsMenuFrame.cpp @@ -394,7 +394,7 @@ nsMenuFrame::HandleEvent(nsPresContext* aPresContext, bool onmenu = IsOnMenu(); - if (aEvent->message == NS_KEY_PRESS && !IsDisabled()) { + if (aEvent->mMessage == NS_KEY_PRESS && !IsDisabled()) { WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent(); uint32_t keyCode = keyEvent->keyCode; #ifdef XP_MACOSX @@ -413,7 +413,7 @@ nsMenuFrame::HandleEvent(nsPresContext* aPresContext, } #endif } - else if (aEvent->message == NS_MOUSE_BUTTON_DOWN && + else if (aEvent->mMessage == NS_MOUSE_BUTTON_DOWN && aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton && !IsDisabled() && IsMenu()) { // The menu item was selected. Bring up the menu. @@ -431,10 +431,10 @@ nsMenuFrame::HandleEvent(nsPresContext* aPresContext, } else if ( #ifndef NSCONTEXTMENUISMOUSEUP - (aEvent->message == NS_MOUSE_BUTTON_UP && + (aEvent->mMessage == NS_MOUSE_BUTTON_UP && aEvent->AsMouseEvent()->button == WidgetMouseEvent::eRightButton) && #else - aEvent->message == NS_CONTEXTMENU && + aEvent->mMessage == NS_CONTEXTMENU && #endif onmenu && !IsMenu() && !IsDisabled()) { // if this menu is a context menu it accepts right-clicks...fire away! @@ -452,14 +452,14 @@ nsMenuFrame::HandleEvent(nsPresContext* aPresContext, Execute(aEvent); } } - else if (aEvent->message == NS_MOUSE_BUTTON_UP && + else if (aEvent->mMessage == NS_MOUSE_BUTTON_UP && aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton && !IsMenu() && !IsDisabled()) { // Execute the execute event handler. *aEventStatus = nsEventStatus_eConsumeNoDefault; Execute(aEvent); } - else if (aEvent->message == NS_MOUSE_OUT) { + else if (aEvent->mMessage == NS_MOUSE_OUT) { // Kill our timer if one is active. if (mOpenTimer) { mOpenTimer->Cancel(); @@ -479,7 +479,7 @@ nsMenuFrame::HandleEvent(nsPresContext* aPresContext, } } } - else if (aEvent->message == NS_MOUSE_MOVE && + else if (aEvent->mMessage == NS_MOUSE_MOVE && (onmenu || (menuParent && menuParent->IsMenuBar()))) { if (gEatMouseMove) { gEatMouseMove = false; diff --git a/layout/xul/nsResizerFrame.cpp b/layout/xul/nsResizerFrame.cpp index ea353a7be0f0..6e8f23c8fb65 100644 --- a/layout/xul/nsResizerFrame.cpp +++ b/layout/xul/nsResizerFrame.cpp @@ -61,7 +61,7 @@ nsResizerFrame::HandleEvent(nsPresContext* aPresContext, nsWeakFrame weakFrame(this); bool doDefault = true; - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_TOUCH_START: case NS_MOUSE_BUTTON_DOWN: { if (aEvent->mClass == eTouchEventClass || diff --git a/layout/xul/nsRootBoxFrame.cpp b/layout/xul/nsRootBoxFrame.cpp index 32ef238a7972..945c03f0bb4e 100644 --- a/layout/xul/nsRootBoxFrame.cpp +++ b/layout/xul/nsRootBoxFrame.cpp @@ -205,7 +205,7 @@ nsRootBoxFrame::HandleEvent(nsPresContext* aPresContext, return NS_OK; } - if (aEvent->message == NS_MOUSE_BUTTON_UP) { + if (aEvent->mMessage == NS_MOUSE_BUTTON_UP) { nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus); } diff --git a/layout/xul/nsScrollBoxFrame.cpp b/layout/xul/nsScrollBoxFrame.cpp index 8a9779a064b7..87f63a277def 100644 --- a/layout/xul/nsScrollBoxFrame.cpp +++ b/layout/xul/nsScrollBoxFrame.cpp @@ -83,8 +83,7 @@ nsAutoRepeatBoxFrame::HandleEvent(nsPresContext* aPresContext, return NS_OK; } - switch(aEvent->message) - { + switch(aEvent->mMessage) { // repeat mode may be "hover" for repeating while the mouse is hovering // over the element, otherwise repetition is done while the element is // active (pressed). diff --git a/layout/xul/nsScrollbarButtonFrame.cpp b/layout/xul/nsScrollbarButtonFrame.cpp index e135eccd01bb..1a40d84bb567 100644 --- a/layout/xul/nsScrollbarButtonFrame.cpp +++ b/layout/xul/nsScrollbarButtonFrame.cpp @@ -52,7 +52,7 @@ nsScrollbarButtonFrame::HandleEvent(nsPresContext* aPresContext, return NS_OK; } - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_MOUSE_BUTTON_DOWN: mCursorOnThis = true; // if we didn't handle the press ourselves, pass it on to the superclass diff --git a/layout/xul/nsSliderFrame.cpp b/layout/xul/nsSliderFrame.cpp index d774b693140b..c24a418b6268 100644 --- a/layout/xul/nsSliderFrame.cpp +++ b/layout/xul/nsSliderFrame.cpp @@ -477,7 +477,7 @@ nsSliderFrame::HandleEvent(nsPresContext* aPresContext, if (isDraggingThumb()) { - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_TOUCH_MOVE: case NS_MOUSE_MOVE: { nsPoint eventPoint; @@ -596,9 +596,9 @@ nsSliderFrame::HandleEvent(nsPresContext* aPresContext, aEvent->AsMouseEvent()->button == WidgetMouseEvent::eRightButton) { // HandlePress and HandleRelease are usually called via // nsFrame::HandleEvent, but only for the left mouse button. - if (aEvent->message == NS_MOUSE_BUTTON_DOWN) { + if (aEvent->mMessage == NS_MOUSE_BUTTON_DOWN) { HandlePress(aPresContext, aEvent, aEventStatus); - } else if (aEvent->message == NS_MOUSE_BUTTON_UP) { + } else if (aEvent->mMessage == NS_MOUSE_BUTTON_UP) { HandleRelease(aPresContext, aEvent, aEventStatus); } @@ -607,10 +607,13 @@ nsSliderFrame::HandleEvent(nsPresContext* aPresContext, #endif // XXX hack until handle release is actually called in nsframe. -// if (aEvent->message == NS_MOUSE_OUT || aEvent->message == NS_MOUSE_RIGHT_BUTTON_UP || aEvent->message == NS_MOUSE_LEFT_BUTTON_UP) - // HandleRelease(aPresContext, aEvent, aEventStatus); + // if (aEvent->mMessage == NS_MOUSE_OUT || + // aEvent->mMessage == NS_MOUSE_RIGHT_BUTTON_UP || + // aEvent->mMessage == NS_MOUSE_LEFT_BUTTON_UP) { + // HandleRelease(aPresContext, aEvent, aEventStatus); + // } - if (aEvent->message == NS_MOUSE_OUT && mChange) + if (aEvent->mMessage == NS_MOUSE_OUT && mChange) HandleRelease(aPresContext, aEvent, aEventStatus); return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus); @@ -1042,7 +1045,7 @@ nsSliderFrame::RemoveListener() bool nsSliderFrame::ShouldScrollForEvent(WidgetGUIEvent* aEvent) { - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_TOUCH_START: case NS_TOUCH_END: return true; @@ -1070,11 +1073,11 @@ nsSliderFrame::ShouldScrollToClickForEvent(WidgetGUIEvent* aEvent) return false; } - if (aEvent->message == NS_TOUCH_START) { + if (aEvent->mMessage == NS_TOUCH_START) { return GetScrollToClick(); } - if (aEvent->message != NS_MOUSE_BUTTON_DOWN) { + if (aEvent->mMessage != NS_MOUSE_BUTTON_DOWN) { return false; } diff --git a/layout/xul/nsSplitterFrame.cpp b/layout/xul/nsSplitterFrame.cpp index 20b44c0a49b9..c0b10cc9c429 100644 --- a/layout/xul/nsSplitterFrame.cpp +++ b/layout/xul/nsSplitterFrame.cpp @@ -388,7 +388,7 @@ nsSplitterFrame::HandleEvent(nsPresContext* aPresContext, nsWeakFrame weakFrame(this); nsRefPtr kungFuDeathGrip(mInner); - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_MOUSE_MOVE: mInner->MouseDrag(aPresContext, aEvent); break; diff --git a/layout/xul/nsTitleBarFrame.cpp b/layout/xul/nsTitleBarFrame.cpp index fea19176e150..f6e302e9dd7a 100644 --- a/layout/xul/nsTitleBarFrame.cpp +++ b/layout/xul/nsTitleBarFrame.cpp @@ -66,7 +66,7 @@ nsTitleBarFrame::HandleEvent(nsPresContext* aPresContext, bool doDefault = true; - switch (aEvent->message) { + switch (aEvent->mMessage) { case NS_MOUSE_BUTTON_DOWN: { if (aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) { diff --git a/layout/xul/tree/nsTreeBodyFrame.cpp b/layout/xul/tree/nsTreeBodyFrame.cpp index 556bd70a343c..76ebbe9bd5fa 100644 --- a/layout/xul/tree/nsTreeBodyFrame.cpp +++ b/layout/xul/tree/nsTreeBodyFrame.cpp @@ -2563,7 +2563,7 @@ nsTreeBodyFrame::HandleEvent(nsPresContext* aPresContext, WidgetGUIEvent* aEvent, nsEventStatus* aEventStatus) { - if (aEvent->message == NS_MOUSE_OVER || aEvent->message == NS_MOUSE_MOVE) { + if (aEvent->mMessage == NS_MOUSE_OVER || aEvent->mMessage == NS_MOUSE_MOVE) { nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this); int32_t xTwips = pt.x - mInnerBox.x; int32_t yTwips = pt.y - mInnerBox.y; @@ -2576,14 +2576,12 @@ nsTreeBodyFrame::HandleEvent(nsPresContext* aPresContext, if (mMouseOverRow != -1) InvalidateRow(mMouseOverRow); } - } - else if (aEvent->message == NS_MOUSE_OUT) { + } else if (aEvent->mMessage == NS_MOUSE_OUT) { if (mMouseOverRow != -1) { InvalidateRow(mMouseOverRow); mMouseOverRow = -1; } - } - else if (aEvent->message == NS_DRAGDROP_ENTER) { + } else if (aEvent->mMessage == NS_DRAGDROP_ENTER) { if (!mSlots) mSlots = new Slots(); @@ -2600,8 +2598,7 @@ nsTreeBodyFrame::HandleEvent(nsPresContext* aPresContext, mSlots->mDropRow = -1; mSlots->mDropOrient = -1; mSlots->mDragAction = GetDropEffect(aEvent); - } - else if (aEvent->message == NS_DRAGDROP_OVER) { + } else if (aEvent->mMessage == NS_DRAGDROP_OVER) { // The mouse is hovering over this tree. If we determine things are // different from the last time, invalidate the drop feedback at the old // position, query the view to see if the current location is droppable, @@ -2710,8 +2707,7 @@ nsTreeBodyFrame::HandleEvent(nsPresContext* aPresContext, // Indicate that the drop is allowed by preventing the default behaviour. if (mSlots->mDropAllowed) *aEventStatus = nsEventStatus_eConsumeNoDefault; - } - else if (aEvent->message == NS_DRAGDROP_DROP) { + } else if (aEvent->mMessage == NS_DRAGDROP_DROP) { // this event was meant for another frame, so ignore it if (!mSlots) return NS_OK; @@ -2735,8 +2731,7 @@ nsTreeBodyFrame::HandleEvent(nsPresContext* aPresContext, mSlots->mDropOrient = -1; mSlots->mIsDragging = false; *aEventStatus = nsEventStatus_eConsumeNoDefault; // already handled the drop - } - else if (aEvent->message == NS_DRAGDROP_EXIT) { + } else if (aEvent->mMessage == NS_DRAGDROP_EXIT) { // this event was meant for another frame, so ignore it if (!mSlots) return NS_OK; diff --git a/view/nsViewManager.cpp b/view/nsViewManager.cpp index 28997a793709..302b1a685ce0 100644 --- a/view/nsViewManager.cpp +++ b/view/nsViewManager.cpp @@ -753,11 +753,11 @@ nsViewManager::DispatchEvent(WidgetGUIEvent *aEvent, // Ignore mouse exit and enter (we'll get moves if the user // is really moving the mouse) since we get them when we // create and destroy widgets. - mouseEvent->message != NS_MOUSE_EXIT_WIDGET && - mouseEvent->message != NS_MOUSE_ENTER_WIDGET) || + mouseEvent->mMessage != NS_MOUSE_EXIT_WIDGET && + mouseEvent->mMessage != NS_MOUSE_ENTER_WIDGET) || aEvent->HasKeyEventMessage() || aEvent->HasIMEEventMessage() || - aEvent->message == NS_PLUGIN_INPUT_EVENT) { + aEvent->mMessage == NS_PLUGIN_INPUT_EVENT) { gLastUserEventTime = PR_IntervalToMicroseconds(PR_IntervalNow()); } diff --git a/widget/BasicEvents.h b/widget/BasicEvents.h index 26ba9ab60f25..71715dc76c08 100644 --- a/widget/BasicEvents.h +++ b/widget/BasicEvents.h @@ -599,7 +599,7 @@ class WidgetEvent protected: WidgetEvent(bool aIsTrusted, uint32_t aMessage, EventClassID aEventClassID) : mClass(aEventClassID) - , message(aMessage) + , mMessage(aMessage) , refPoint(0, 0) , lastRefPoint(0, 0) , time(0) @@ -621,7 +621,7 @@ class WidgetEvent public: WidgetEvent(bool aIsTrusted, uint32_t aMessage) : mClass(eBasicEventClass) - , message(aMessage) + , mMessage(aMessage) , refPoint(0, 0) , lastRefPoint(0, 0) , time(0) @@ -650,7 +650,7 @@ class WidgetEvent { MOZ_ASSERT(mClass == eBasicEventClass, "Duplicate() must be overridden by sub class"); - WidgetEvent* result = new WidgetEvent(false, message); + WidgetEvent* result = new WidgetEvent(false, mMessage); result->AssignEventData(*this, true); result->mFlags = mFlags; return result; @@ -658,7 +658,7 @@ class WidgetEvent EventClassID mClass; // See GUI MESSAGES, - uint32_t message; + uint32_t mMessage; // Relative to the widget of the event, or if there is no widget then it is // in screen coordinates. Not modified by layout code. LayoutDeviceIntPoint refPoint; @@ -686,7 +686,7 @@ class WidgetEvent void AssignEventData(const WidgetEvent& aEvent, bool aCopyTargets) { // mClass should be initialized with the constructor. - // message should be initialized with the constructor. + // mMessage should be initialized with the constructor. refPoint = aEvent.refPoint; // lastRefPoint doesn't need to be copied. time = aEvent.time; @@ -735,24 +735,24 @@ class WidgetEvent bool IsNativeEventDelivererForPlugin() const; /** - * Returns true if the event message is one of mouse events. + * Returns true if the event mMessage is one of mouse events. */ bool HasMouseEventMessage() const; /** - * Returns true if the event message is one of drag events. + * Returns true if the event mMessage is one of drag events. */ bool HasDragEventMessage() const; /** - * Returns true if the event message is one of key events. + * Returns true if the event mMessage is one of key events. */ bool HasKeyEventMessage() const; /** - * Returns true if the event message is one of composition events or text + * Returns true if the event mMessage is one of composition events or text * event. */ bool HasIMEEventMessage() const; /** - * Returns true if the event message is one of plugin activation events. + * Returns true if the event mMessage is one of plugin activation events. */ bool HasPluginActivationEventMessage() const; @@ -842,7 +842,7 @@ class WidgetGUIEvent : public WidgetEvent MOZ_ASSERT(mClass == eGUIEventClass, "Duplicate() must be overridden by sub class"); // Not copying widget, it is a weak reference. - WidgetGUIEvent* result = new WidgetGUIEvent(false, message, nullptr); + WidgetGUIEvent* result = new WidgetGUIEvent(false, mMessage, nullptr); result->AssignGUIEventData(*this, true); result->mFlags = mFlags; return result; @@ -1006,7 +1006,7 @@ class WidgetInputEvent : public WidgetGUIEvent MOZ_ASSERT(mClass == eInputEventClass, "Duplicate() must be overridden by sub class"); // Not copying widget, it is a weak reference. - WidgetInputEvent* result = new WidgetInputEvent(false, message, nullptr); + WidgetInputEvent* result = new WidgetInputEvent(false, mMessage, nullptr); result->AssignInputEventData(*this, true); result->mFlags = mFlags; return result; @@ -1175,7 +1175,7 @@ class InternalUIEvent : public WidgetGUIEvent { MOZ_ASSERT(mClass == eUIEventClass, "Duplicate() must be overridden by sub class"); - InternalUIEvent* result = new InternalUIEvent(false, message); + InternalUIEvent* result = new InternalUIEvent(false, mMessage); result->AssignUIEventData(*this, true); result->mFlags = mFlags; return result; diff --git a/widget/ContentCache.cpp b/widget/ContentCache.cpp index 368f7be1710b..8d74ab8c17b7 100644 --- a/widget/ContentCache.cpp +++ b/widget/ContentCache.cpp @@ -515,11 +515,11 @@ ContentCacheInParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent, aEvent.mSucceeded = false; aEvent.mReply.mFocusedWidget = aWidget; - switch (aEvent.message) { + switch (aEvent.mMessage) { case NS_QUERY_SELECTED_TEXT: MOZ_LOG(sContentCacheLog, LogLevel::Info, ("ContentCacheInParent: 0x%p HandleQueryContentEvent(" - "aEvent={ message=NS_QUERY_SELECTED_TEXT }, aWidget=0x%p)", + "aEvent={ mMessage=NS_QUERY_SELECTED_TEXT }, aWidget=0x%p)", this, aWidget)); if (NS_WARN_IF(!IsSelectionValid())) { // If content cache hasn't been initialized properly, make the query @@ -560,7 +560,7 @@ ContentCacheInParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent, case NS_QUERY_TEXT_CONTENT: { MOZ_LOG(sContentCacheLog, LogLevel::Info, ("ContentCacheInParent: 0x%p HandleQueryContentEvent(" - "aEvent={ message=NS_QUERY_TEXT_CONTENT, mInput={ mOffset=%u, " + "aEvent={ mMessage=NS_QUERY_TEXT_CONTENT, mInput={ mOffset=%u, " "mLength=%u } }, aWidget=0x%p), mText.Length()=%u", this, aEvent.mInput.mOffset, aEvent.mInput.mLength, aWidget, mText.Length())); @@ -586,7 +586,7 @@ ContentCacheInParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent, case NS_QUERY_TEXT_RECT: MOZ_LOG(sContentCacheLog, LogLevel::Info, ("ContentCacheInParent: 0x%p HandleQueryContentEvent(" - "aEvent={ message=NS_QUERY_TEXT_RECT, mInput={ mOffset=%u, " + "aEvent={ mMessage=NS_QUERY_TEXT_RECT, mInput={ mOffset=%u, " "mLength=%u } }, aWidget=0x%p), mText.Length()=%u", this, aEvent.mInput.mOffset, aEvent.mInput.mLength, aWidget, mText.Length())); @@ -641,7 +641,7 @@ ContentCacheInParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent, case NS_QUERY_CARET_RECT: MOZ_LOG(sContentCacheLog, LogLevel::Info, ("ContentCacheInParent: 0x%p HandleQueryContentEvent(" - "aEvent={ message=NS_QUERY_CARET_RECT, mInput={ mOffset=%u } }, " + "aEvent={ mMessage=NS_QUERY_CARET_RECT, mInput={ mOffset=%u } }, " "aWidget=0x%p), mText.Length()=%u", this, aEvent.mInput.mOffset, aWidget, mText.Length())); if (NS_WARN_IF(!IsSelectionValid())) { @@ -668,7 +668,7 @@ ContentCacheInParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent, case NS_QUERY_EDITOR_RECT: MOZ_LOG(sContentCacheLog, LogLevel::Info, ("ContentCacheInParent: 0x%p HandleQueryContentEvent(" - "aEvent={ message=NS_QUERY_EDITOR_RECT }, aWidget=0x%p)", + "aEvent={ mMessage=NS_QUERY_EDITOR_RECT }, aWidget=0x%p)", this, aWidget)); aEvent.mReply.mRect = mEditorRect; MOZ_LOG(sContentCacheLog, LogLevel::Info, @@ -846,17 +846,17 @@ ContentCacheInParent::OnCompositionEvent(const WidgetCompositionEvent& aEvent) { MOZ_LOG(sContentCacheLog, LogLevel::Info, ("ContentCacheInParent: 0x%p OnCompositionEvent(aEvent={ " - "message=%s, mData=\"%s\" (Length()=%u), mRanges->Length()=%u }), " + "mMessage=%s, mData=\"%s\" (Length()=%u), mRanges->Length()=%u }), " "mPendingEventsNeedingAck=%u, mIsComposing=%s, " "mRequestedToCommitOrCancelComposition=%s", - this, GetEventMessageName(aEvent.message), + this, GetEventMessageName(aEvent.mMessage), NS_ConvertUTF16toUTF8(aEvent.mData).get(), aEvent.mData.Length(), aEvent.mRanges ? aEvent.mRanges->Length() : 0, mPendingEventsNeedingAck, GetBoolName(mIsComposing), GetBoolName(mRequestedToCommitOrCancelComposition))); if (!aEvent.CausesDOMTextEvent()) { - MOZ_ASSERT(aEvent.message == NS_COMPOSITION_START); + MOZ_ASSERT(aEvent.mMessage == NS_COMPOSITION_START); mIsComposing = !aEvent.CausesDOMCompositionEndEvent(); mCompositionStart = mSelection.StartOffset(); // XXX What's this case?? @@ -900,10 +900,10 @@ ContentCacheInParent::OnSelectionEvent( { MOZ_LOG(sContentCacheLog, LogLevel::Info, ("ContentCacheInParent: 0x%p OnSelectionEvent(aEvent={ " - "message=%s, mOffset=%u, mLength=%u, mReversed=%s, " + "mMessage=%s, mOffset=%u, mLength=%u, mReversed=%s, " "mExpandToClusterBoundary=%s, mUseNativeLineBreak=%s }), " "mPendingEventsNeedingAck=%u, mIsComposing=%s", - this, GetEventMessageName(aSelectionEvent.message), + this, GetEventMessageName(aSelectionEvent.mMessage), aSelectionEvent.mOffset, aSelectionEvent.mLength, GetBoolName(aSelectionEvent.mReversed), GetBoolName(aSelectionEvent.mExpandToClusterBoundary), diff --git a/widget/ContentEvents.h b/widget/ContentEvents.h index 09d42a3fc2f8..2c299b9ed353 100644 --- a/widget/ContentEvents.h +++ b/widget/ContentEvents.h @@ -51,7 +51,7 @@ class InternalScrollPortEvent : public WidgetGUIEvent "Duplicate() must be overridden by sub class"); // Not copying widget, it is a weak reference. InternalScrollPortEvent* result = - new InternalScrollPortEvent(false, message, nullptr); + new InternalScrollPortEvent(false, mMessage, nullptr); result->AssignScrollPortEventData(*this, true); result->mFlags = mFlags; return result; @@ -92,7 +92,7 @@ class InternalScrollAreaEvent : public WidgetGUIEvent "Duplicate() must be overridden by sub class"); // Not copying widget, it is a weak reference. InternalScrollAreaEvent* result = - new InternalScrollAreaEvent(false, message, nullptr); + new InternalScrollAreaEvent(false, mMessage, nullptr); result->AssignScrollAreaEventData(*this, true); result->mFlags = mFlags; return result; @@ -131,7 +131,7 @@ class InternalFormEvent : public WidgetEvent { MOZ_ASSERT(mClass == eFormEventClass, "Duplicate() must be overridden by sub class"); - InternalFormEvent* result = new InternalFormEvent(false, message); + InternalFormEvent* result = new InternalFormEvent(false, mMessage); result->AssignFormEventData(*this, true); result->mFlags = mFlags; return result; @@ -168,7 +168,8 @@ class InternalClipboardEvent : public WidgetEvent { MOZ_ASSERT(mClass == eClipboardEventClass, "Duplicate() must be overridden by sub class"); - InternalClipboardEvent* result = new InternalClipboardEvent(false, message); + InternalClipboardEvent* result = + new InternalClipboardEvent(false, mMessage); result->AssignClipboardEventData(*this, true); result->mFlags = mFlags; return result; @@ -205,7 +206,7 @@ class InternalFocusEvent : public InternalUIEvent { MOZ_ASSERT(mClass == eFocusEventClass, "Duplicate() must be overridden by sub class"); - InternalFocusEvent* result = new InternalFocusEvent(false, message); + InternalFocusEvent* result = new InternalFocusEvent(false, mMessage); result->AssignFocusEventData(*this, true); result->mFlags = mFlags; return result; @@ -251,7 +252,7 @@ class InternalTransitionEvent : public WidgetEvent MOZ_ASSERT(mClass == eTransitionEventClass, "Duplicate() must be overridden by sub class"); InternalTransitionEvent* result = - new InternalTransitionEvent(false, message); + new InternalTransitionEvent(false, mMessage); result->AssignTransitionEventData(*this, true); result->mFlags = mFlags; return result; @@ -295,7 +296,8 @@ class InternalAnimationEvent : public WidgetEvent { MOZ_ASSERT(mClass == eAnimationEventClass, "Duplicate() must be overridden by sub class"); - InternalAnimationEvent* result = new InternalAnimationEvent(false, message); + InternalAnimationEvent* result = + new InternalAnimationEvent(false, mMessage); result->AssignAnimationEventData(*this, true); result->mFlags = mFlags; return result; @@ -336,7 +338,7 @@ class InternalSVGZoomEvent : public WidgetGUIEvent MOZ_ASSERT(mClass == eSVGZoomEventClass, "Duplicate() must be overridden by sub class"); // Not copying widget, it is a weak reference. - InternalSVGZoomEvent* result = new InternalSVGZoomEvent(false, message); + InternalSVGZoomEvent* result = new InternalSVGZoomEvent(false, mMessage); result->AssignSVGZoomEventData(*this, true); result->mFlags = mFlags; return result; @@ -372,7 +374,7 @@ class InternalSMILTimeEvent : public InternalUIEvent { MOZ_ASSERT(mClass == eSMILTimeEventClass, "Duplicate() must be overridden by sub class"); - InternalSMILTimeEvent* result = new InternalSMILTimeEvent(false, message); + InternalSMILTimeEvent* result = new InternalSMILTimeEvent(false, mMessage); result->AssignSMILTimeEventData(*this, true); result->mFlags = mFlags; return result; diff --git a/widget/InputData.cpp b/widget/InputData.cpp index cd73131a4d6e..17ad16138a2e 100644 --- a/widget/InputData.cpp +++ b/widget/InputData.cpp @@ -35,7 +35,7 @@ MultiTouchInput::MultiTouchInput(const WidgetTouchEvent& aTouchEvent) MOZ_ASSERT(NS_IsMainThread(), "Can only copy from WidgetTouchEvent on main thread"); - switch (aTouchEvent.message) { + switch (aTouchEvent.mMessage) { case NS_TOUCH_START: mType = MULTITOUCH_START; break; @@ -181,7 +181,7 @@ MultiTouchInput::MultiTouchInput(const WidgetMouseEvent& aMouseEvent) { MOZ_ASSERT(NS_IsMainThread(), "Can only copy from WidgetMouseEvent on main thread"); - switch (aMouseEvent.message) { + switch (aMouseEvent.mMessage) { case NS_MOUSE_BUTTON_DOWN: mType = MULTITOUCH_START; break; diff --git a/widget/MiscEvents.h b/widget/MiscEvents.h index d59027a25265..62fc5c2dc58e 100644 --- a/widget/MiscEvents.h +++ b/widget/MiscEvents.h @@ -158,7 +158,7 @@ class WidgetPluginEvent : public WidgetGUIEvent MOZ_ASSERT(mClass == ePluginEventClass, "Duplicate() must be overridden by sub class"); // Not copying widget, it is a weak reference. - WidgetPluginEvent* result = new WidgetPluginEvent(false, message, nullptr); + WidgetPluginEvent* result = new WidgetPluginEvent(false, mMessage, nullptr); result->AssignPluginEventData(*this, true); result->mFlags = mFlags; return result; diff --git a/widget/MouseEvents.h b/widget/MouseEvents.h index 23f1eb8e170b..10d66801b38a 100644 --- a/widget/MouseEvents.h +++ b/widget/MouseEvents.h @@ -155,7 +155,7 @@ class WidgetMouseEventBase : public WidgetInputEvent */ bool IsLeftClickEvent() const { - return message == NS_MOUSE_CLICK && button == eLeftButton; + return mMessage == NS_MOUSE_CLICK && button == eLeftButton; } }; @@ -240,7 +240,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, public WidgetPointerHelper #ifdef DEBUG virtual ~WidgetMouseEvent() { - NS_WARN_IF_FALSE(message != NS_CONTEXTMENU || + NS_WARN_IF_FALSE(mMessage != NS_CONTEXTMENU || button == ((context == eNormal) ? eRightButton : eLeftButton), "Wrong button set to NS_CONTEXTMENU event?"); @@ -253,7 +253,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, public WidgetPointerHelper "Duplicate() must be overridden by sub class"); // Not copying widget, it is a weak reference. WidgetMouseEvent* result = - new WidgetMouseEvent(false, message, nullptr, reason, context); + new WidgetMouseEvent(false, mMessage, nullptr, reason, context); result->AssignMouseEventData(*this, true); result->mFlags = mFlags; return result; @@ -287,7 +287,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, public WidgetPointerHelper */ bool IsContextMenuKeyEvent() const { - return message == NS_CONTEXTMENU && context == eContextMenuKey; + return mMessage == NS_CONTEXTMENU && context == eContextMenuKey; } /** @@ -332,7 +332,7 @@ class WidgetDragEvent : public WidgetMouseEvent MOZ_ASSERT(mClass == eDragEventClass, "Duplicate() must be overridden by sub class"); // Not copying widget, it is a weak reference. - WidgetDragEvent* result = new WidgetDragEvent(false, message, nullptr); + WidgetDragEvent* result = new WidgetDragEvent(false, mMessage, nullptr); result->AssignDragEventData(*this, true); result->mFlags = mFlags; return result; @@ -394,7 +394,7 @@ class WidgetMouseScrollEvent : public WidgetMouseEventBase "Duplicate() must be overridden by sub class"); // Not copying widget, it is a weak reference. WidgetMouseScrollEvent* result = - new WidgetMouseScrollEvent(false, message, nullptr); + new WidgetMouseScrollEvent(false, mMessage, nullptr); result->AssignMouseScrollEventData(*this, true); result->mFlags = mFlags; return result; @@ -462,7 +462,7 @@ class WidgetWheelEvent : public WidgetMouseEventBase MOZ_ASSERT(mClass == eWheelEventClass, "Duplicate() must be overridden by sub class"); // Not copying widget, it is a weak reference. - WidgetWheelEvent* result = new WidgetWheelEvent(false, message, nullptr); + WidgetWheelEvent* result = new WidgetWheelEvent(false, mMessage, nullptr); result->AssignWheelEventData(*this, true); result->mFlags = mFlags; return result; @@ -608,7 +608,7 @@ class WidgetPointerEvent : public WidgetMouseEvent void UpdateFlags() { - switch (message) { + switch (mMessage) { case NS_POINTER_ENTER: case NS_POINTER_LEAVE: mFlags.mBubbles = false; @@ -630,7 +630,7 @@ class WidgetPointerEvent : public WidgetMouseEvent "Duplicate() must be overridden by sub class"); // Not copying widget, it is a weak reference. WidgetPointerEvent* result = - new WidgetPointerEvent(false, message, nullptr); + new WidgetPointerEvent(false, mMessage, nullptr); result->AssignPointerEventData(*this, true); result->mFlags = mFlags; return result; diff --git a/widget/TextEvents.h b/widget/TextEvents.h index cd2717714362..8f5093b9cf90 100644 --- a/widget/TextEvents.h +++ b/widget/TextEvents.h @@ -113,7 +113,7 @@ class WidgetKeyboardEvent : public WidgetInputEvent "Duplicate() must be overridden by sub class"); // Not copying widget, it is a weak reference. WidgetKeyboardEvent* result = - new WidgetKeyboardEvent(false, message, nullptr); + new WidgetKeyboardEvent(false, mMessage, nullptr); result->AssignKeyEventData(*this, true); result->mFlags = mFlags; return result; @@ -281,10 +281,10 @@ class WidgetKeyboardEvent : public WidgetInputEvent * This is extended from WidgetKeyboardEvent and is mapped to DOM event * "BeforeAfterKeyboardEvent". * - * Event message: NS_KEY_BEFORE_DOWN - * NS_KEY_BEFORE_UP - * NS_KEY_AFTER_DOWN - * NS_KEY_AFTER_UP + * Event mMessage: NS_KEY_BEFORE_DOWN + * NS_KEY_BEFORE_UP + * NS_KEY_AFTER_DOWN + * NS_KEY_AFTER_UP ******************************************************************************/ class InternalBeforeAfterKeyboardEvent : public WidgetKeyboardEvent { @@ -318,7 +318,7 @@ class InternalBeforeAfterKeyboardEvent : public WidgetKeyboardEvent "Duplicate() must be overridden by sub class"); // Not copying widget, it is a weak reference. InternalBeforeAfterKeyboardEvent* result = - new InternalBeforeAfterKeyboardEvent(false, message, nullptr); + new InternalBeforeAfterKeyboardEvent(false, mMessage, nullptr); result->AssignBeforeAfterKeyEventData(*this, true); result->mFlags = mFlags; return result; @@ -376,7 +376,7 @@ class WidgetCompositionEvent : public WidgetGUIEvent "Duplicate() must be overridden by sub class"); // Not copying widget, it is a weak reference. WidgetCompositionEvent* result = - new WidgetCompositionEvent(false, message, nullptr); + new WidgetCompositionEvent(false, mMessage, nullptr); result->AssignCompositionEventData(*this, true); result->mFlags = mFlags; return result; @@ -426,16 +426,16 @@ class WidgetCompositionEvent : public WidgetGUIEvent bool CausesDOMTextEvent() const { - return message == NS_COMPOSITION_CHANGE || - message == NS_COMPOSITION_COMMIT || - message == NS_COMPOSITION_COMMIT_AS_IS; + return mMessage == NS_COMPOSITION_CHANGE || + mMessage == NS_COMPOSITION_COMMIT || + mMessage == NS_COMPOSITION_COMMIT_AS_IS; } bool CausesDOMCompositionEndEvent() const { - return message == NS_COMPOSITION_END || - message == NS_COMPOSITION_COMMIT || - message == NS_COMPOSITION_COMMIT_AS_IS; + return mMessage == NS_COMPOSITION_END || + mMessage == NS_COMPOSITION_COMMIT || + mMessage == NS_COMPOSITION_COMMIT_AS_IS; } }; @@ -481,7 +481,7 @@ class WidgetQueryContentEvent : public WidgetGUIEvent void InitForQueryTextContent(uint32_t aOffset, uint32_t aLength, bool aUseNativeLineBreak = true) { - NS_ASSERTION(message == NS_QUERY_TEXT_CONTENT, + NS_ASSERTION(mMessage == NS_QUERY_TEXT_CONTENT, "wrong initializer is called"); mInput.mOffset = aOffset; mInput.mLength = aLength; @@ -491,7 +491,7 @@ class WidgetQueryContentEvent : public WidgetGUIEvent void InitForQueryCaretRect(uint32_t aOffset, bool aUseNativeLineBreak = true) { - NS_ASSERTION(message == NS_QUERY_CARET_RECT, + NS_ASSERTION(mMessage == NS_QUERY_CARET_RECT, "wrong initializer is called"); mInput.mOffset = aOffset; mUseNativeLineBreak = aUseNativeLineBreak; @@ -500,7 +500,7 @@ class WidgetQueryContentEvent : public WidgetGUIEvent void InitForQueryTextRect(uint32_t aOffset, uint32_t aLength, bool aUseNativeLineBreak = true) { - NS_ASSERTION(message == NS_QUERY_TEXT_RECT, + NS_ASSERTION(mMessage == NS_QUERY_TEXT_RECT, "wrong initializer is called"); mInput.mOffset = aOffset; mInput.mLength = aLength; @@ -509,37 +509,37 @@ class WidgetQueryContentEvent : public WidgetGUIEvent void InitForQueryDOMWidgetHittest(const mozilla::LayoutDeviceIntPoint& aPoint) { - NS_ASSERTION(message == NS_QUERY_DOM_WIDGET_HITTEST, + NS_ASSERTION(mMessage == NS_QUERY_DOM_WIDGET_HITTEST, "wrong initializer is called"); refPoint = aPoint; } void RequestFontRanges() { - NS_ASSERTION(message == NS_QUERY_TEXT_CONTENT, + NS_ASSERTION(mMessage == NS_QUERY_TEXT_CONTENT, "not querying text content"); mWithFontRanges = true; } uint32_t GetSelectionStart(void) const { - NS_ASSERTION(message == NS_QUERY_SELECTED_TEXT, + NS_ASSERTION(mMessage == NS_QUERY_SELECTED_TEXT, "not querying selection"); return mReply.mOffset + (mReply.mReversed ? mReply.mString.Length() : 0); } uint32_t GetSelectionEnd(void) const { - NS_ASSERTION(message == NS_QUERY_SELECTED_TEXT, + NS_ASSERTION(mMessage == NS_QUERY_SELECTED_TEXT, "not querying selection"); return mReply.mOffset + (mReply.mReversed ? 0 : mReply.mString.Length()); } mozilla::WritingMode GetWritingMode(void) const { - NS_ASSERTION(message == NS_QUERY_SELECTED_TEXT || - message == NS_QUERY_CARET_RECT || - message == NS_QUERY_TEXT_RECT, + NS_ASSERTION(mMessage == NS_QUERY_SELECTED_TEXT || + mMessage == NS_QUERY_CARET_RECT || + mMessage == NS_QUERY_TEXT_RECT, "not querying selection or text rect"); return mReply.mWritingMode; } @@ -709,7 +709,7 @@ class InternalEditorInputEvent : public InternalUIEvent "Duplicate() must be overridden by sub class"); // Not copying widget, it is a weak reference. InternalEditorInputEvent* result = - new InternalEditorInputEvent(false, message, nullptr); + new InternalEditorInputEvent(false, mMessage, nullptr); result->AssignEditorInputEventData(*this, true); result->mFlags = mFlags; return result; diff --git a/widget/TouchEvents.h b/widget/TouchEvents.h index 33189375953b..81a06a3feda3 100644 --- a/widget/TouchEvents.h +++ b/widget/TouchEvents.h @@ -55,7 +55,7 @@ class WidgetGestureNotifyEvent : public WidgetGUIEvent "Duplicate() must be overridden by sub class"); // Not copying widget, it is a weak reference. WidgetGestureNotifyEvent* result = - new WidgetGestureNotifyEvent(false, message, nullptr); + new WidgetGestureNotifyEvent(false, mMessage, nullptr); result->AssignGestureNotifyEventData(*this, true); result->mFlags = mFlags; return result; @@ -106,7 +106,7 @@ class WidgetSimpleGestureEvent : public WidgetMouseEventBase } WidgetSimpleGestureEvent(const WidgetSimpleGestureEvent& aOther) - : WidgetMouseEventBase(aOther.mFlags.mIsTrusted, aOther.message, + : WidgetMouseEventBase(aOther.mFlags.mIsTrusted, aOther.mMessage, aOther.widget, eSimpleGestureEventClass) , allowedDirections(aOther.allowedDirections) , direction(aOther.direction) @@ -121,7 +121,7 @@ class WidgetSimpleGestureEvent : public WidgetMouseEventBase "Duplicate() must be overridden by sub class"); // Not copying widget, it is a weak reference. WidgetSimpleGestureEvent* result = - new WidgetSimpleGestureEvent(false, message, nullptr); + new WidgetSimpleGestureEvent(false, mMessage, nullptr); result->AssignSimpleGestureEventData(*this, true); result->mFlags = mFlags; return result; @@ -166,14 +166,14 @@ class WidgetTouchEvent : public WidgetInputEvent } WidgetTouchEvent(const WidgetTouchEvent& aOther) - : WidgetInputEvent(aOther.mFlags.mIsTrusted, aOther.message, aOther.widget, + : WidgetInputEvent(aOther.mFlags.mIsTrusted, aOther.mMessage, aOther.widget, eTouchEventClass) { modifiers = aOther.modifiers; time = aOther.time; timeStamp = aOther.timeStamp; touches.AppendElements(aOther.touches); - mFlags.mCancelable = message != NS_TOUCH_CANCEL; + mFlags.mCancelable = mMessage != NS_TOUCH_CANCEL; MOZ_COUNT_CTOR(WidgetTouchEvent); } @@ -181,7 +181,7 @@ class WidgetTouchEvent : public WidgetInputEvent : WidgetInputEvent(aIsTrusted, aMessage, aWidget, eTouchEventClass) { MOZ_COUNT_CTOR(WidgetTouchEvent); - mFlags.mCancelable = message != NS_TOUCH_CANCEL; + mFlags.mCancelable = mMessage != NS_TOUCH_CANCEL; } virtual ~WidgetTouchEvent() @@ -194,7 +194,7 @@ class WidgetTouchEvent : public WidgetInputEvent MOZ_ASSERT(mClass == eTouchEventClass, "Duplicate() must be overridden by sub class"); // Not copying widget, it is a weak reference. - WidgetTouchEvent* result = new WidgetTouchEvent(false, message, nullptr); + WidgetTouchEvent* result = new WidgetTouchEvent(false, mMessage, nullptr); result->AssignTouchEventData(*this, true); result->mFlags = mFlags; return result; diff --git a/widget/WidgetEventImpl.cpp b/widget/WidgetEventImpl.cpp index 300f5525a5e8..b7403df29a70 100644 --- a/widget/WidgetEventImpl.cpp +++ b/widget/WidgetEventImpl.cpp @@ -77,7 +77,7 @@ WidgetEvent::IsNativeEventDelivererForPlugin() const bool WidgetEvent::HasMouseEventMessage() const { - switch (message) { + switch (mMessage) { case NS_MOUSE_BUTTON_DOWN: case NS_MOUSE_BUTTON_UP: case NS_MOUSE_CLICK: @@ -98,7 +98,7 @@ WidgetEvent::HasMouseEventMessage() const bool WidgetEvent::HasDragEventMessage() const { - switch (message) { + switch (mMessage) { case NS_DRAGDROP_ENTER: case NS_DRAGDROP_OVER: case NS_DRAGDROP_EXIT: @@ -118,7 +118,7 @@ WidgetEvent::HasDragEventMessage() const bool WidgetEvent::HasKeyEventMessage() const { - switch (message) { + switch (mMessage) { case NS_KEY_DOWN: case NS_KEY_PRESS: case NS_KEY_UP: @@ -135,7 +135,7 @@ WidgetEvent::HasKeyEventMessage() const bool WidgetEvent::HasIMEEventMessage() const { - switch (message) { + switch (mMessage) { case NS_COMPOSITION_START: case NS_COMPOSITION_END: case NS_COMPOSITION_UPDATE: @@ -151,8 +151,8 @@ WidgetEvent::HasIMEEventMessage() const bool WidgetEvent::HasPluginActivationEventMessage() const { - return message == NS_PLUGIN_ACTIVATE || - message == NS_PLUGIN_FOCUS; + return mMessage == NS_PLUGIN_ACTIVATE || + mMessage == NS_PLUGIN_FOCUS; } /****************************************************************************** diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 0d41056215f3..1a8f41215303 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -966,7 +966,7 @@ nsWindow::OnMouseEvent(AndroidGeckoEvent *ae) nsRefPtr kungFuDeathGrip(this); WidgetMouseEvent event = ae->MakeMouseEvent(this); - if (event.message == NS_EVENT_NULL) { + if (event.mMessage == NS_EVENT_NULL) { // invalid event type, abort return; } @@ -1001,7 +1001,7 @@ nsWindow::OnContextmenuEvent(AndroidGeckoEvent *ae) // triggering further element behaviour such as link-clicks. if (contextMenuStatus == nsEventStatus_eConsumeNoDefault) { WidgetTouchEvent canceltouchEvent = ae->MakeTouchEvent(this); - canceltouchEvent.message = NS_TOUCH_CANCEL; + canceltouchEvent.mMessage = NS_TOUCH_CANCEL; DispatchEvent(&canceltouchEvent); return true; } @@ -1052,7 +1052,7 @@ bool nsWindow::OnMultitouchEvent(AndroidGeckoEvent *ae) bool isDownEvent = false; WidgetTouchEvent event = ae->MakeTouchEvent(this); - if (event.message != NS_EVENT_NULL) { + if (event.mMessage != NS_EVENT_NULL) { nsEventStatus status; DispatchEvent(&event, status); // We check mMultipleActionsPrevented because that's what @@ -1061,7 +1061,7 @@ bool nsWindow::OnMultitouchEvent(AndroidGeckoEvent *ae) // from running. preventDefaultActions = (status == nsEventStatus_eConsumeNoDefault || event.mFlags.mMultipleActionsPrevented); - isDownEvent = (event.message == NS_TOUCH_START); + isDownEvent = (event.mMessage == NS_TOUCH_START); } if (isDownEvent && event.touches.Length() == 1) { @@ -1461,7 +1461,7 @@ nsWindow::InitKeyEvent(WidgetKeyboardEvent& event, AndroidGeckoEvent& key, event.mCodeNameIndex = ConvertAndroidScanCodeToCodeNameIndex(key); uint32_t domKeyCode = ConvertAndroidKeyCodeToDOMKeyCode(key.KeyCode()); - if (event.message == NS_KEY_PRESS) { + if (event.mMessage == NS_KEY_PRESS) { // Android gives us \n, so filter out some control characters. int charCode = key.UnicodeChar(); if (!charCode) { @@ -1473,13 +1473,13 @@ nsWindow::InitKeyEvent(WidgetKeyboardEvent& event, AndroidGeckoEvent& key, event.mPluginEvent.Clear(); } else { #ifdef DEBUG - if (event.message != NS_KEY_DOWN && event.message != NS_KEY_UP) { - ALOG("InitKeyEvent: unexpected event.message %d", event.message); + if (event.mMessage != NS_KEY_DOWN && event.mMessage != NS_KEY_UP) { + ALOG("InitKeyEvent: unexpected event.mMessage %d", event.mMessage); } #endif // DEBUG // Flash will want a pluginEvent for keydown and keyup events. - ANPKeyActions action = event.message == NS_KEY_DOWN + ANPKeyActions action = event.mMessage == NS_KEY_DOWN ? kDown_ANPKeyAction : kUp_ANPKeyAction; InitPluginEvent(pluginEvent, action, key); @@ -1500,13 +1500,13 @@ nsWindow::InitKeyEvent(WidgetKeyboardEvent& event, AndroidGeckoEvent& key, // Note that on Android 4.x, Alt modifier isn't set when the key input // causes text input even while right Alt key is pressed. However, this // is necessary for Android 2.3 compatibility. - if (event.message == NS_KEY_PRESS && + if (event.mMessage == NS_KEY_PRESS && key.UnicodeChar() && key.UnicodeChar() != key.BaseUnicodeChar()) { event.modifiers &= ~(MODIFIER_ALT | MODIFIER_CONTROL | MODIFIER_META); } event.mIsRepeat = - (event.message == NS_KEY_DOWN || event.message == NS_KEY_PRESS) && + (event.mMessage == NS_KEY_DOWN || event.mMessage == NS_KEY_PRESS) && (!!(key.Flags() & AKEY_EVENT_FLAG_LONG_PRESS) || !!key.RepeatCount()); event.location = WidgetKeyboardEvent::ComputeLocationFromCodeValue(event.mCodeNameIndex); diff --git a/widget/cocoa/TextInputHandler.mm b/widget/cocoa/TextInputHandler.mm index b0a201899f3a..44e49ffc5720 100644 --- a/widget/cocoa/TextInputHandler.mm +++ b/widget/cocoa/TextInputHandler.mm @@ -225,7 +225,7 @@ static const char* GetGeckoKeyEventType(const WidgetEvent& aEvent) { - switch (aEvent.message) { + switch (aEvent.mMessage) { case NS_KEY_DOWN: return "NS_KEY_DOWN"; case NS_KEY_UP: return "NS_KEY_UP"; case NS_KEY_PRESS: return "NS_KEY_PRESS"; @@ -761,7 +761,7 @@ MOZ_LOG(gLog, LogLevel::Info, ("%p TISInputSourceWrapper::InitKeyEvent, aNativeKeyEvent=%p, " - "aKeyEvent.message=%s, aInsertString=%p, IsOpenedIMEMode()=%s", + "aKeyEvent.mMessage=%s, aInsertString=%p, IsOpenedIMEMode()=%s", this, aNativeKeyEvent, GetGeckoKeyEventType(aKeyEvent), aInsertString, TrueOrFalse(IsOpenedIMEMode()))); @@ -948,7 +948,7 @@ this, OnOrOff(aKeyEvent.IsShift()), OnOrOff(aKeyEvent.IsControl()), OnOrOff(aKeyEvent.IsAlt()), OnOrOff(aKeyEvent.IsMeta()))); - if (aKeyEvent.message == NS_KEY_PRESS && + if (aKeyEvent.mMessage == NS_KEY_PRESS && (isPrintableKey || !insertString.IsEmpty())) { InitKeyPressEvent(aNativeKeyEvent, insertString.IsEmpty() ? 0 : insertString[0], @@ -1038,7 +1038,7 @@ { NS_OBJC_BEGIN_TRY_ABORT_BLOCK; - NS_ASSERTION(aKeyEvent.message == NS_KEY_PRESS, + NS_ASSERTION(aKeyEvent.mMessage == NS_KEY_PRESS, "aKeyEvent must be NS_KEY_PRESS event"); if (MOZ_LOG_TEST(gLog, LogLevel::Info)) { @@ -1050,7 +1050,7 @@ MOZ_LOG(gLog, LogLevel::Info, ("%p TISInputSourceWrapper::InitKeyPressEvent, aNativeKeyEvent=%p, " "[aNativeKeyEvent characters]=\"%s\", aInsertChar=0x%X(%s), " - "aKeyEvent.message=%s, aKbType=0x%X, IsOpenedIMEMode()=%s", + "aKeyEvent.mMessage=%s, aKbType=0x%X, IsOpenedIMEMode()=%s", this, aNativeKeyEvent, utf8Chars.get(), aInsertChar, utf8ExpectedChar.get(), GetGeckoKeyEventType(aKeyEvent), aKbType, TrueOrFalse(IsOpenedIMEMode()))); @@ -3777,7 +3777,7 @@ WidgetCompositionEvent compositionChangeEvent(true, NS_COMPOSITION_CHANGE, bool TextInputHandlerBase::DispatchEvent(WidgetGUIEvent& aEvent) { - if (aEvent.message == NS_KEY_PRESS) { + if (aEvent.mMessage == NS_KEY_PRESS) { WidgetInputEvent& inputEvent = *aEvent.AsInputEvent(); if (!inputEvent.IsMeta()) { MOZ_LOG(gLog, LogLevel::Info, @@ -3919,7 +3919,7 @@ WidgetCompositionEvent compositionChangeEvent(true, NS_COMPOSITION_CHANGE, aKeyEvent.modifiers)); NSEventType eventType; - if (aKeyEvent.message == NS_KEY_UP) { + if (aKeyEvent.mMessage == NS_KEY_UP) { eventType = NSKeyUp; } else { eventType = NSKeyDown; diff --git a/widget/gtk/IMContextWrapper.cpp b/widget/gtk/IMContextWrapper.cpp index 162fa8f09cae..7962165fa29e 100644 --- a/widget/gtk/IMContextWrapper.cpp +++ b/widget/gtk/IMContextWrapper.cpp @@ -2201,7 +2201,7 @@ IMContextWrapper::Selection::Assign(const IMENotification& aIMENotification) void IMContextWrapper::Selection::Assign(const WidgetQueryContentEvent& aEvent) { - MOZ_ASSERT(aEvent.message == NS_QUERY_SELECTED_TEXT); + MOZ_ASSERT(aEvent.mMessage == NS_QUERY_SELECTED_TEXT); MOZ_ASSERT(aEvent.mSucceeded); mOffset = aEvent.mReply.mOffset; mLength = aEvent.mReply.mString.Length(); diff --git a/widget/gtk/nsGtkKeyUtils.cpp b/widget/gtk/nsGtkKeyUtils.cpp index cbbd1972dbd8..93903ad7b2e2 100644 --- a/widget/gtk/nsGtkKeyUtils.cpp +++ b/widget/gtk/nsGtkKeyUtils.cpp @@ -983,13 +983,13 @@ KeymapWrapper::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent, aGdkKeyEvent->keyval, aGdkKeyEvent->state, aGdkKeyEvent->hardware_keycode, GetBoolName(aGdkKeyEvent->is_modifier), - ((aKeyEvent.message == NS_KEY_DOWN) ? "NS_KEY_DOWN" : - (aKeyEvent.message == NS_KEY_PRESS) ? "NS_KEY_PRESS" : + ((aKeyEvent.mMessage == NS_KEY_DOWN) ? "NS_KEY_DOWN" : + (aKeyEvent.mMessage == NS_KEY_PRESS) ? "NS_KEY_PRESS" : "NS_KEY_UP"), GetBoolName(aKeyEvent.IsShift()), GetBoolName(aKeyEvent.IsControl()), GetBoolName(aKeyEvent.IsAlt()), GetBoolName(aKeyEvent.IsMeta()))); - if (aKeyEvent.message == NS_KEY_PRESS) { + if (aKeyEvent.mMessage == NS_KEY_PRESS) { keymapWrapper->InitKeypressEvent(aKeyEvent, aGdkKeyEvent); } @@ -1323,7 +1323,7 @@ void KeymapWrapper::InitKeypressEvent(WidgetKeyboardEvent& aKeyEvent, GdkEventKey* aGdkKeyEvent) { - NS_ENSURE_TRUE_VOID(aKeyEvent.message == NS_KEY_PRESS); + NS_ENSURE_TRUE_VOID(aKeyEvent.mMessage == NS_KEY_PRESS); aKeyEvent.charCode = GetCharCodeFor(aGdkKeyEvent); if (!aKeyEvent.charCode) { diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index 7fdbe04b7e66..2cb625855298 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -992,7 +992,7 @@ nsBaseWidget::ProcessUntransformedAPZEvent(WidgetInputEvent* aEvent, // TODO: Eventually we'll be able to move the SendSetTargetAPZCNotification // call into APZEventState::Process*Event() as well. if (WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent()) { - if (touchEvent->message == NS_TOUCH_START) { + if (touchEvent->mMessage == NS_TOUCH_START) { if (gfxPrefs::TouchActionEnabled()) { APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification(this, *touchEvent, aInputBlockId, mSetAllowedTouchBehaviorCallback); @@ -2628,7 +2628,7 @@ nsBaseWidget::debug_GuiEventToString(WidgetGUIEvent* aGuiEvent) #define _ASSIGN_eventName(_value,_name)\ case _value: eventName.AssignLiteral(_name) ; break - switch(aGuiEvent->message) + switch(aGuiEvent->mMessage) { _ASSIGN_eventName(NS_BLUR_CONTENT,"NS_BLUR_CONTENT"); _ASSIGN_eventName(NS_DRAGDROP_GESTURE,"NS_DND_GESTURE"); @@ -2670,7 +2670,7 @@ case _value: eventName.AssignLiteral(_name) ; break { char buf[32]; - snprintf_literal(buf,"UNKNOWN: %d",aGuiEvent->message); + snprintf_literal(buf,"UNKNOWN: %d",aGuiEvent->mMessage); CopyASCIItoUTF16(buf, eventName); } @@ -2802,15 +2802,13 @@ nsBaseWidget::debug_DumpEvent(FILE * aFileOut, const nsAutoCString & aWidgetName, int32_t aWindowID) { - if (aGuiEvent->message == NS_MOUSE_MOVE) - { + if (aGuiEvent->mMessage == NS_MOUSE_MOVE) { if (!debug_GetCachedBoolPref("nglayout.debug.motion_event_dumping")) return; } - if (aGuiEvent->message == NS_MOUSE_ENTER_WIDGET || - aGuiEvent->message == NS_MOUSE_EXIT_WIDGET) - { + if (aGuiEvent->mMessage == NS_MOUSE_ENTER_WIDGET || + aGuiEvent->mMessage == NS_MOUSE_EXIT_WIDGET) { if (!debug_GetCachedBoolPref("nglayout.debug.crossing_event_dumping")) return; } diff --git a/widget/nsGUIEventIPC.h b/widget/nsGUIEventIPC.h index 476f916121e2..c484c745e5e3 100644 --- a/widget/nsGUIEventIPC.h +++ b/widget/nsGUIEventIPC.h @@ -48,7 +48,7 @@ struct ParamTraits { WriteParam(aMsg, static_cast(aParam.mClass)); - WriteParam(aMsg, aParam.message); + WriteParam(aMsg, aParam.mMessage); WriteParam(aMsg, aParam.refPoint); WriteParam(aMsg, aParam.time); WriteParam(aMsg, aParam.timeStamp); @@ -59,7 +59,7 @@ struct ParamTraits { mozilla::EventClassIDType eventClassID = 0; bool ret = ReadParam(aMsg, aIter, &eventClassID) && - ReadParam(aMsg, aIter, &aResult->message) && + ReadParam(aMsg, aIter, &aResult->mMessage) && ReadParam(aMsg, aIter, &aResult->refPoint) && ReadParam(aMsg, aIter, &aResult->time) && ReadParam(aMsg, aIter, &aResult->timeStamp) && diff --git a/widget/qt/nsWindow.cpp b/widget/qt/nsWindow.cpp index 125904ba6382..64a1f999d1f7 100644 --- a/widget/qt/nsWindow.cpp +++ b/widget/qt/nsWindow.cpp @@ -1100,7 +1100,7 @@ InitKeyEvent(WidgetKeyboardEvent& aEvent, QKeyEvent* aQEvent) aQEvent->modifiers() & Qt::MetaModifier); aEvent.mIsRepeat = - (aEvent.message == NS_KEY_DOWN || aEvent.message == NS_KEY_PRESS) && + (aEvent.mMessage == NS_KEY_DOWN || aEvent.mMessage == NS_KEY_PRESS) && aQEvent->isAutoRepeat(); aEvent.time = 0; diff --git a/widget/windows/KeyboardLayout.cpp b/widget/windows/KeyboardLayout.cpp index 70d90d0cd55f..8aea777aa50b 100644 --- a/widget/windows/KeyboardLayout.cpp +++ b/widget/windows/KeyboardLayout.cpp @@ -1143,7 +1143,7 @@ NativeKey::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent, nsIntPoint point(0, 0); mWidget->InitEvent(aKeyEvent, &point); - switch (aKeyEvent.message) { + switch (aKeyEvent.mMessage) { case NS_KEY_DOWN: aKeyEvent.keyCode = mDOMKeyCode; // Unique id for this keydown event and its associated keypress. diff --git a/widget/windows/WinMouseScrollHandler.cpp b/widget/windows/WinMouseScrollHandler.cpp index d777313ed0cb..6dfcde7d6e0f 100644 --- a/widget/windows/WinMouseScrollHandler.cpp +++ b/widget/windows/WinMouseScrollHandler.cpp @@ -821,7 +821,7 @@ MouseScrollHandler::LastEventInfo::InitWheelEvent( WidgetWheelEvent& aWheelEvent, const ModifierKeyState& aModKeyState) { - MOZ_ASSERT(aWheelEvent.message == NS_WHEEL_WHEEL); + MOZ_ASSERT(aWheelEvent.mMessage == NS_WHEEL_WHEEL); // XXX Why don't we use lParam value? We should use lParam value because // our internal message is always posted by original message handler. diff --git a/widget/windows/nsWinGesture.cpp b/widget/windows/nsWinGesture.cpp index 3bd037d5e655..19ed83207a2b 100644 --- a/widget/windows/nsWinGesture.cpp +++ b/widget/windows/nsWinGesture.cpp @@ -334,13 +334,13 @@ nsWinGesture::ProcessGestureMessage(HWND hWnd, WPARAM wParam, LPARAM lParam, // The low 32 bits are the distance in pixels. mZoomIntermediate = (float)gi.ullArguments; - evt.message = NS_SIMPLE_GESTURE_MAGNIFY_START; + evt.mMessage = NS_SIMPLE_GESTURE_MAGNIFY_START; evt.delta = 0.0; } else if (gi.dwFlags & GF_END) { // Send a zoom end event, the delta is the change // in touch points. - evt.message = NS_SIMPLE_GESTURE_MAGNIFY; + evt.mMessage = NS_SIMPLE_GESTURE_MAGNIFY; // (positive for a "zoom in") evt.delta = -1.0 * (mZoomIntermediate - (float)gi.ullArguments); mZoomIntermediate = (float)gi.ullArguments; @@ -348,7 +348,7 @@ nsWinGesture::ProcessGestureMessage(HWND hWnd, WPARAM wParam, LPARAM lParam, else { // Send a zoom intermediate event, the delta is the change // in touch points. - evt.message = NS_SIMPLE_GESTURE_MAGNIFY_UPDATE; + evt.mMessage = NS_SIMPLE_GESTURE_MAGNIFY_UPDATE; // (positive for a "zoom in") evt.delta = -1.0 * (mZoomIntermediate - (float)gi.ullArguments); mZoomIntermediate = (float)gi.ullArguments; @@ -385,11 +385,11 @@ nsWinGesture::ProcessGestureMessage(HWND hWnd, WPARAM wParam, LPARAM lParam, evt.direction = nsIDOMSimpleGestureEvent::ROTATION_CLOCKWISE; if (gi.dwFlags & GF_BEGIN) - evt.message = NS_SIMPLE_GESTURE_ROTATE_START; + evt.mMessage = NS_SIMPLE_GESTURE_ROTATE_START; else if (gi.dwFlags & GF_END) - evt.message = NS_SIMPLE_GESTURE_ROTATE; + evt.mMessage = NS_SIMPLE_GESTURE_ROTATE; else - evt.message = NS_SIMPLE_GESTURE_ROTATE_UPDATE; + evt.mMessage = NS_SIMPLE_GESTURE_ROTATE_UPDATE; } break; @@ -397,7 +397,7 @@ nsWinGesture::ProcessGestureMessage(HWND hWnd, WPARAM wParam, LPARAM lParam, { // Normally maps to "restore" from whatever you may have recently changed. A simple // double click. - evt.message = NS_SIMPLE_GESTURE_TAP; + evt.mMessage = NS_SIMPLE_GESTURE_TAP; evt.clickCount = 1; } break; @@ -405,7 +405,7 @@ nsWinGesture::ProcessGestureMessage(HWND hWnd, WPARAM wParam, LPARAM lParam, case GID_PRESSANDTAP: { // Two finger right click. Defaults to right click if it falls through. - evt.message = NS_SIMPLE_GESTURE_PRESSTAP; + evt.mMessage = NS_SIMPLE_GESTURE_PRESSTAP; evt.clickCount = 1; } break; diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index 6441c84e4d93..b66f63c506b8 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -4080,7 +4080,7 @@ bool nsWindow::DispatchMouseEvent(uint32_t aEventType, WPARAM wParam, LONG curMsgTime = ::GetMessageTime(); if (aEventType == NS_MOUSE_DOUBLECLICK) { - event.message = NS_MOUSE_BUTTON_DOWN; + event.mMessage = NS_MOUSE_BUTTON_DOWN; event.button = aButton; sLastClickCount = 2; sLastMouseDownTime = curMsgTime; From 1373464578f32fbc936977e3a9900f387bd037b5 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 22 Aug 2015 10:34:51 +0900 Subject: [PATCH 174/208] Bug 895274 part.2 Define event messages as anonymous enum with EventMessageList.h r=smaug --- widget/BasicEvents.h | 426 -------------------------------------- widget/EventForwards.h | 21 ++ widget/EventMessageList.h | 426 ++++++++++++++++++++++++++++++++++++++ widget/moz.build | 1 + 4 files changed, 448 insertions(+), 426 deletions(-) create mode 100644 widget/EventMessageList.h diff --git a/widget/BasicEvents.h b/widget/BasicEvents.h index 71715dc76c08..47c407ce2f1a 100644 --- a/widget/BasicEvents.h +++ b/widget/BasicEvents.h @@ -18,432 +18,6 @@ #include "nsString.h" #include "Units.h" -/****************************************************************************** - * Messages - * - * TODO: Make them enum. - ******************************************************************************/ - -#define NS_EVENT_NULL 0 - -// This is a dummy event message for all event listener implementation in -// EventListenerManager. -#define NS_EVENT_ALL 1 - -#define NS_WINDOW_START 100 - -// Widget may be destroyed -#define NS_XUL_CLOSE (NS_WINDOW_START + 1) -// Key is pressed within a window -#define NS_KEY_PRESS (NS_WINDOW_START + 31) -// Key is released within a window -#define NS_KEY_UP (NS_WINDOW_START + 32) -// Key is pressed within a window -#define NS_KEY_DOWN (NS_WINDOW_START + 33) - -#define NS_KEY_BEFORE_DOWN (NS_WINDOW_START + 34) -#define NS_KEY_AFTER_DOWN (NS_WINDOW_START + 35) -#define NS_KEY_BEFORE_UP (NS_WINDOW_START + 36) -#define NS_KEY_AFTER_UP (NS_WINDOW_START + 37) - -#define NS_RESIZE_EVENT (NS_WINDOW_START + 60) -#define NS_SCROLL_EVENT (NS_WINDOW_START + 61) - -// A plugin was clicked or otherwise focused. NS_PLUGIN_ACTIVATE should be -// used when the window is not active. NS_PLUGIN_FOCUS should be used when -// the window is active. In the latter case, the dispatcher of the event -// is expected to ensure that the plugin's widget is focused beforehand. -#define NS_PLUGIN_ACTIVATE (NS_WINDOW_START + 62) -#define NS_PLUGIN_FOCUS (NS_WINDOW_START + 63) - -#define NS_OFFLINE (NS_WINDOW_START + 64) -#define NS_ONLINE (NS_WINDOW_START + 65) - -// NS_BEFORERESIZE_EVENT used to be here (NS_WINDOW_START + 66) - -// Indicates that the user is either idle or active -#define NS_MOZ_USER_IDLE (NS_WINDOW_START + 67) -#define NS_MOZ_USER_ACTIVE (NS_WINDOW_START + 68) - -#define NS_LANGUAGECHANGE (NS_WINDOW_START + 70) - -#define NS_MOUSE_MESSAGE_START 300 -#define NS_MOUSE_MOVE (NS_MOUSE_MESSAGE_START) -#define NS_MOUSE_BUTTON_UP (NS_MOUSE_MESSAGE_START + 1) -#define NS_MOUSE_BUTTON_DOWN (NS_MOUSE_MESSAGE_START + 2) -#define NS_MOUSE_ENTER_WIDGET (NS_MOUSE_MESSAGE_START + 22) -#define NS_MOUSE_EXIT_WIDGET (NS_MOUSE_MESSAGE_START + 23) -#define NS_MOUSE_DOUBLECLICK (NS_MOUSE_MESSAGE_START + 24) -#define NS_MOUSE_CLICK (NS_MOUSE_MESSAGE_START + 27) -#define NS_MOUSE_ACTIVATE (NS_MOUSE_MESSAGE_START + 30) -#define NS_MOUSE_OVER (NS_MOUSE_MESSAGE_START + 31) -#define NS_MOUSE_OUT (NS_MOUSE_MESSAGE_START + 32) -#define NS_MOUSE_MOZHITTEST (NS_MOUSE_MESSAGE_START + 33) -#define NS_MOUSEENTER (NS_MOUSE_MESSAGE_START + 34) -#define NS_MOUSELEAVE (NS_MOUSE_MESSAGE_START + 35) -#define NS_MOUSE_MOZLONGTAP (NS_MOUSE_MESSAGE_START + 36) - -// Pointer spec events -#define NS_POINTER_EVENT_START 4400 -#define NS_POINTER_MOVE (NS_POINTER_EVENT_START) -#define NS_POINTER_UP (NS_POINTER_EVENT_START + 1) -#define NS_POINTER_DOWN (NS_POINTER_EVENT_START + 2) -#define NS_POINTER_OVER (NS_POINTER_EVENT_START + 22) -#define NS_POINTER_OUT (NS_POINTER_EVENT_START + 23) -#define NS_POINTER_ENTER (NS_POINTER_EVENT_START + 24) -#define NS_POINTER_LEAVE (NS_POINTER_EVENT_START + 25) -#define NS_POINTER_CANCEL (NS_POINTER_EVENT_START + 26) -#define NS_POINTER_GOT_CAPTURE (NS_POINTER_EVENT_START + 27) -#define NS_POINTER_LOST_CAPTURE (NS_POINTER_EVENT_START + 28) - -#define NS_CONTEXTMENU_MESSAGE_START 500 -#define NS_CONTEXTMENU (NS_CONTEXTMENU_MESSAGE_START) - -#define NS_STREAM_EVENT_START 1100 -#define NS_LOAD (NS_STREAM_EVENT_START) -#define NS_PAGE_UNLOAD (NS_STREAM_EVENT_START + 1) -#define NS_HASHCHANGE (NS_STREAM_EVENT_START + 2) -#define NS_IMAGE_ABORT (NS_STREAM_EVENT_START + 3) -#define NS_LOAD_ERROR (NS_STREAM_EVENT_START + 4) -#define NS_POPSTATE (NS_STREAM_EVENT_START + 5) -#define NS_BEFORE_PAGE_UNLOAD (NS_STREAM_EVENT_START + 6) -#define NS_PAGE_RESTORE (NS_STREAM_EVENT_START + 7) -#define NS_READYSTATECHANGE (NS_STREAM_EVENT_START + 8) - -#define NS_FORM_EVENT_START 1200 -#define NS_FORM_SUBMIT (NS_FORM_EVENT_START) -#define NS_FORM_RESET (NS_FORM_EVENT_START + 1) -#define NS_FORM_CHANGE (NS_FORM_EVENT_START + 2) -#define NS_FORM_SELECTED (NS_FORM_EVENT_START + 3) -#define NS_FORM_INVALID (NS_FORM_EVENT_START + 4) - -//Need separate focus/blur notifications for non-native widgets -#define NS_FOCUS_EVENT_START 1300 -#define NS_FOCUS_CONTENT (NS_FOCUS_EVENT_START) -#define NS_BLUR_CONTENT (NS_FOCUS_EVENT_START + 1) - -#define NS_DRAGDROP_EVENT_START 1400 -#define NS_DRAGDROP_ENTER (NS_DRAGDROP_EVENT_START) -#define NS_DRAGDROP_OVER (NS_DRAGDROP_EVENT_START + 1) -#define NS_DRAGDROP_EXIT (NS_DRAGDROP_EVENT_START + 2) -#define NS_DRAGDROP_DRAGDROP (NS_DRAGDROP_EVENT_START + 3) -#define NS_DRAGDROP_GESTURE (NS_DRAGDROP_EVENT_START + 4) -#define NS_DRAGDROP_DRAG (NS_DRAGDROP_EVENT_START + 5) -#define NS_DRAGDROP_END (NS_DRAGDROP_EVENT_START + 6) -#define NS_DRAGDROP_START (NS_DRAGDROP_EVENT_START + 7) -#define NS_DRAGDROP_DROP (NS_DRAGDROP_EVENT_START + 8) -#define NS_DRAGDROP_LEAVE (NS_DRAGDROP_EVENT_START + 9) - -// Events for popups -#define NS_XUL_EVENT_START 1500 -#define NS_XUL_POPUP_SHOWING (NS_XUL_EVENT_START) -#define NS_XUL_POPUP_SHOWN (NS_XUL_EVENT_START+1) -#define NS_XUL_POPUP_HIDING (NS_XUL_EVENT_START+2) -#define NS_XUL_POPUP_HIDDEN (NS_XUL_EVENT_START+3) -// NS_XUL_COMMAND used to be here (NS_XUL_EVENT_START+4) -#define NS_XUL_BROADCAST (NS_XUL_EVENT_START+5) -#define NS_XUL_COMMAND_UPDATE (NS_XUL_EVENT_START+6) -//@} - -// Scroll events -#define NS_MOUSE_SCROLL_START 1600 -#define NS_MOUSE_SCROLL (NS_MOUSE_SCROLL_START) -#define NS_MOUSE_PIXEL_SCROLL (NS_MOUSE_SCROLL_START + 1) - -#define NS_SCROLLPORT_START 1700 -#define NS_SCROLLPORT_UNDERFLOW (NS_SCROLLPORT_START) -#define NS_SCROLLPORT_OVERFLOW (NS_SCROLLPORT_START+1) - -#define NS_MUTATION_START 1800 -#define NS_MUTATION_SUBTREEMODIFIED (NS_MUTATION_START) -#define NS_MUTATION_NODEINSERTED (NS_MUTATION_START+1) -#define NS_MUTATION_NODEREMOVED (NS_MUTATION_START+2) -#define NS_MUTATION_NODEREMOVEDFROMDOCUMENT (NS_MUTATION_START+3) -#define NS_MUTATION_NODEINSERTEDINTODOCUMENT (NS_MUTATION_START+4) -#define NS_MUTATION_ATTRMODIFIED (NS_MUTATION_START+5) -#define NS_MUTATION_CHARACTERDATAMODIFIED (NS_MUTATION_START+6) -#define NS_MUTATION_END (NS_MUTATION_START+6) - -#define NS_USER_DEFINED_EVENT 2000 - -// composition events -#define NS_COMPOSITION_EVENT_START 2200 -#define NS_COMPOSITION_START (NS_COMPOSITION_EVENT_START) -// NS_COMPOSITION_END is the message for DOM compositionend event. -// This event should NOT be dispatched from widget if NS_COMPOSITION_COMMIT -// is available. -#define NS_COMPOSITION_END (NS_COMPOSITION_EVENT_START + 1) -// NS_COMPOSITION_UPDATE is the message for DOM compositionupdate event. -// This event should NOT be dispatched from widget since it will be dispatched -// by mozilla::TextComposition automatically if NS_COMPOSITION_CHANGE event -// will change composition string. -#define NS_COMPOSITION_UPDATE (NS_COMPOSITION_EVENT_START + 2) -// NS_COMPOSITION_CHANGE is the message for representing a change of -// composition string. This should be dispatched from widget even if -// composition string isn't changed but the ranges are changed. This causes -// a DOM "text" event which is a non-standard DOM event. -#define NS_COMPOSITION_CHANGE (NS_COMPOSITION_EVENT_START + 3) -// NS_COMPOSITION_COMMIT_AS_IS is the message for representing a commit of -// composition string. TextComposition will commit composition with the -// last data. TextComposition will dispatch this event to the DOM tree as -// NS_COMPOSITION_CHANGE without clause information. After that, -// NS_COMPOSITION_END will be dispatched automatically. -// Its mData and mRanges should be empty and nullptr. -#define NS_COMPOSITION_COMMIT_AS_IS (NS_COMPOSITION_EVENT_START + 4) -// NS_COMPOSITION_COMMIT is the message for representing a commit of -// composition string with its mData value. TextComposition will dispatch this -// event to the DOM tree as NS_COMPOSITION_CHANGE without clause information. -// After that, NS_COMPOSITION_END will be dispatched automatically. -// Its mRanges should be nullptr. -#define NS_COMPOSITION_COMMIT (NS_COMPOSITION_EVENT_START + 5) - -// UI events -#define NS_UI_EVENT_START 2500 -// this is not to be confused with NS_ACTIVATE! -#define NS_UI_ACTIVATE (NS_UI_EVENT_START) -#define NS_UI_FOCUSIN (NS_UI_EVENT_START + 1) -#define NS_UI_FOCUSOUT (NS_UI_EVENT_START + 2) - -// pagetransition events -#define NS_PAGETRANSITION_START 2700 -#define NS_PAGE_SHOW (NS_PAGETRANSITION_START + 1) -#define NS_PAGE_HIDE (NS_PAGETRANSITION_START + 2) - -// SVG events -#define NS_SVG_EVENT_START 2800 -#define NS_SVG_LOAD (NS_SVG_EVENT_START) -#define NS_SVG_UNLOAD (NS_SVG_EVENT_START + 1) -#define NS_SVG_ABORT (NS_SVG_EVENT_START + 2) -#define NS_SVG_ERROR (NS_SVG_EVENT_START + 3) -#define NS_SVG_RESIZE (NS_SVG_EVENT_START + 4) -#define NS_SVG_SCROLL (NS_SVG_EVENT_START + 5) - -// SVG Zoom events -#define NS_SVGZOOM_EVENT_START 2900 -#define NS_SVG_ZOOM (NS_SVGZOOM_EVENT_START) - -// XUL command events -#define NS_XULCOMMAND_EVENT_START 3000 -#define NS_XUL_COMMAND (NS_XULCOMMAND_EVENT_START) - -// Cut, copy, paste events -#define NS_CUTCOPYPASTE_EVENT_START 3100 -#define NS_COPY (NS_CUTCOPYPASTE_EVENT_START) -#define NS_CUT (NS_CUTCOPYPASTE_EVENT_START + 1) -#define NS_PASTE (NS_CUTCOPYPASTE_EVENT_START + 2) - -// Query the content information -#define NS_QUERY_CONTENT_EVENT_START 3200 -// Query for the selected text information, it return the selection offset, -// selection length and selected text. -#define NS_QUERY_SELECTED_TEXT (NS_QUERY_CONTENT_EVENT_START) -// Query for the text content of specified range, it returns actual lengh (if -// the specified range is too long) and the text of the specified range. -// Returns the entire text if requested length > actual length. -#define NS_QUERY_TEXT_CONTENT (NS_QUERY_CONTENT_EVENT_START + 1) -// Query for the caret rect of nth insertion point. The offset of the result is -// relative position from the top level widget. -#define NS_QUERY_CARET_RECT (NS_QUERY_CONTENT_EVENT_START + 3) -// Query for the bounding rect of a range of characters. This works on any -// valid character range given offset and length. Result is relative to top -// level widget coordinates -#define NS_QUERY_TEXT_RECT (NS_QUERY_CONTENT_EVENT_START + 4) -// Query for the bounding rect of the current focused frame. Result is relative -// to top level widget coordinates -#define NS_QUERY_EDITOR_RECT (NS_QUERY_CONTENT_EVENT_START + 5) -// Query for the current state of the content. The particular members of -// mReply that are set for each query content event will be valid on success. -#define NS_QUERY_CONTENT_STATE (NS_QUERY_CONTENT_EVENT_START + 6) -// Query for the selection in the form of a nsITransferable. -#define NS_QUERY_SELECTION_AS_TRANSFERABLE (NS_QUERY_CONTENT_EVENT_START + 7) -// Query for character at a point. This returns the character offset, its -// rect and also tentative caret point if the point is clicked. The point is -// specified by Event::refPoint. -#define NS_QUERY_CHARACTER_AT_POINT (NS_QUERY_CONTENT_EVENT_START + 8) -// Query if the DOM element under Event::refPoint belongs to our widget -// or not. -#define NS_QUERY_DOM_WIDGET_HITTEST (NS_QUERY_CONTENT_EVENT_START + 9) - -// Video events -#define NS_MEDIA_EVENT_START 3300 -#define NS_LOADSTART (NS_MEDIA_EVENT_START) -#define NS_PROGRESS (NS_MEDIA_EVENT_START+1) -#define NS_SUSPEND (NS_MEDIA_EVENT_START+2) -#define NS_EMPTIED (NS_MEDIA_EVENT_START+3) -#define NS_STALLED (NS_MEDIA_EVENT_START+4) -#define NS_PLAY (NS_MEDIA_EVENT_START+5) -#define NS_PAUSE (NS_MEDIA_EVENT_START+6) -#define NS_LOADEDMETADATA (NS_MEDIA_EVENT_START+7) -#define NS_LOADEDDATA (NS_MEDIA_EVENT_START+8) -#define NS_WAITING (NS_MEDIA_EVENT_START+9) -#define NS_PLAYING (NS_MEDIA_EVENT_START+10) -#define NS_CANPLAY (NS_MEDIA_EVENT_START+11) -#define NS_CANPLAYTHROUGH (NS_MEDIA_EVENT_START+12) -#define NS_SEEKING (NS_MEDIA_EVENT_START+13) -#define NS_SEEKED (NS_MEDIA_EVENT_START+14) -#define NS_TIMEUPDATE (NS_MEDIA_EVENT_START+15) -#define NS_ENDED (NS_MEDIA_EVENT_START+16) -#define NS_RATECHANGE (NS_MEDIA_EVENT_START+17) -#define NS_DURATIONCHANGE (NS_MEDIA_EVENT_START+18) -#define NS_VOLUMECHANGE (NS_MEDIA_EVENT_START+19) -#define NS_NEED_KEY (NS_MEDIA_EVENT_START+20) - -// paint notification events -#define NS_NOTIFYPAINT_START 3400 -#define NS_AFTERPAINT (NS_NOTIFYPAINT_START) - -// Simple gesture events -#define NS_SIMPLE_GESTURE_EVENT_START 3500 -#define NS_SIMPLE_GESTURE_SWIPE_START (NS_SIMPLE_GESTURE_EVENT_START) -#define NS_SIMPLE_GESTURE_SWIPE_UPDATE (NS_SIMPLE_GESTURE_EVENT_START+1) -#define NS_SIMPLE_GESTURE_SWIPE_END (NS_SIMPLE_GESTURE_EVENT_START+2) -#define NS_SIMPLE_GESTURE_SWIPE (NS_SIMPLE_GESTURE_EVENT_START+3) -#define NS_SIMPLE_GESTURE_MAGNIFY_START (NS_SIMPLE_GESTURE_EVENT_START+4) -#define NS_SIMPLE_GESTURE_MAGNIFY_UPDATE (NS_SIMPLE_GESTURE_EVENT_START+5) -#define NS_SIMPLE_GESTURE_MAGNIFY (NS_SIMPLE_GESTURE_EVENT_START+6) -#define NS_SIMPLE_GESTURE_ROTATE_START (NS_SIMPLE_GESTURE_EVENT_START+7) -#define NS_SIMPLE_GESTURE_ROTATE_UPDATE (NS_SIMPLE_GESTURE_EVENT_START+8) -#define NS_SIMPLE_GESTURE_ROTATE (NS_SIMPLE_GESTURE_EVENT_START+9) -#define NS_SIMPLE_GESTURE_TAP (NS_SIMPLE_GESTURE_EVENT_START+10) -#define NS_SIMPLE_GESTURE_PRESSTAP (NS_SIMPLE_GESTURE_EVENT_START+11) -#define NS_SIMPLE_GESTURE_EDGE_STARTED (NS_SIMPLE_GESTURE_EVENT_START+12) -#define NS_SIMPLE_GESTURE_EDGE_CANCELED (NS_SIMPLE_GESTURE_EVENT_START+13) -#define NS_SIMPLE_GESTURE_EDGE_COMPLETED (NS_SIMPLE_GESTURE_EVENT_START+14) - -// These are used to send native events to plugins. -#define NS_PLUGIN_EVENT_START 3600 -#define NS_PLUGIN_INPUT_EVENT (NS_PLUGIN_EVENT_START) -#define NS_PLUGIN_FOCUS_EVENT (NS_PLUGIN_EVENT_START+1) - -// Events to manipulate selection (WidgetSelectionEvent) -#define NS_SELECTION_EVENT_START 3700 -// Clear any previous selection and set the given range as the selection -#define NS_SELECTION_SET (NS_SELECTION_EVENT_START) - -// Events of commands for the contents -#define NS_CONTENT_COMMAND_EVENT_START 3800 -#define NS_CONTENT_COMMAND_CUT (NS_CONTENT_COMMAND_EVENT_START) -#define NS_CONTENT_COMMAND_COPY (NS_CONTENT_COMMAND_EVENT_START+1) -#define NS_CONTENT_COMMAND_PASTE (NS_CONTENT_COMMAND_EVENT_START+2) -#define NS_CONTENT_COMMAND_DELETE (NS_CONTENT_COMMAND_EVENT_START+3) -#define NS_CONTENT_COMMAND_UNDO (NS_CONTENT_COMMAND_EVENT_START+4) -#define NS_CONTENT_COMMAND_REDO (NS_CONTENT_COMMAND_EVENT_START+5) -#define NS_CONTENT_COMMAND_PASTE_TRANSFERABLE (NS_CONTENT_COMMAND_EVENT_START+6) -// NS_CONTENT_COMMAND_SCROLL scrolls the nearest scrollable element to the -// currently focused content or latest DOM selection. This would normally be -// the same element scrolled by keyboard scroll commands, except that this event -// will scroll an element scrollable in either direction. I.e., if the nearest -// scrollable ancestor element can only be scrolled vertically, and horizontal -// scrolling is requested using this event, no scrolling will occur. -#define NS_CONTENT_COMMAND_SCROLL (NS_CONTENT_COMMAND_EVENT_START+7) - -// Event to gesture notification -#define NS_GESTURENOTIFY_EVENT_START 3900 - -#define NS_ORIENTATION_EVENT 4000 - -#define NS_SCROLLAREA_EVENT_START 4100 -#define NS_SCROLLEDAREACHANGED (NS_SCROLLAREA_EVENT_START) - -#define NS_TRANSITION_EVENT_START 4200 -#define NS_TRANSITION_END (NS_TRANSITION_EVENT_START) - -#define NS_ANIMATION_EVENT_START 4250 -#define NS_ANIMATION_START (NS_ANIMATION_EVENT_START) -#define NS_ANIMATION_END (NS_ANIMATION_EVENT_START + 1) -#define NS_ANIMATION_ITERATION (NS_ANIMATION_EVENT_START + 2) - -#define NS_SMIL_TIME_EVENT_START 4300 -#define NS_SMIL_BEGIN (NS_SMIL_TIME_EVENT_START) -#define NS_SMIL_END (NS_SMIL_TIME_EVENT_START + 1) -#define NS_SMIL_REPEAT (NS_SMIL_TIME_EVENT_START + 2) - -#define NS_WEBAUDIO_EVENT_START 4350 -#define NS_AUDIO_PROCESS (NS_WEBAUDIO_EVENT_START) -#define NS_AUDIO_COMPLETE (NS_WEBAUDIO_EVENT_START + 1) - -// script notification events -#define NS_NOTIFYSCRIPT_START 4500 -#define NS_BEFORE_SCRIPT_EXECUTE (NS_NOTIFYSCRIPT_START) -#define NS_AFTER_SCRIPT_EXECUTE (NS_NOTIFYSCRIPT_START+1) - -#define NS_PRINT_EVENT_START 4600 -#define NS_BEFOREPRINT (NS_PRINT_EVENT_START) -#define NS_AFTERPRINT (NS_PRINT_EVENT_START + 1) - -#define NS_MESSAGE_EVENT_START 4700 -#define NS_MESSAGE (NS_MESSAGE_EVENT_START) - -// Open and close events -#define NS_OPENCLOSE_EVENT_START 4800 -#define NS_OPEN (NS_OPENCLOSE_EVENT_START) -#define NS_CLOSE (NS_OPENCLOSE_EVENT_START+1) - -// Device motion and orientation -#define NS_DEVICE_ORIENTATION_START 4900 -#define NS_DEVICE_ORIENTATION (NS_DEVICE_ORIENTATION_START) -#define NS_DEVICE_MOTION (NS_DEVICE_ORIENTATION_START+1) -#define NS_DEVICE_PROXIMITY (NS_DEVICE_ORIENTATION_START+2) -#define NS_USER_PROXIMITY (NS_DEVICE_ORIENTATION_START+3) -#define NS_DEVICE_LIGHT (NS_DEVICE_ORIENTATION_START+4) - -#define NS_SHOW_EVENT 5000 - -// Fullscreen DOM API -#define NS_FULL_SCREEN_START 5100 -#define NS_FULLSCREENCHANGE (NS_FULL_SCREEN_START) -#define NS_FULLSCREENERROR (NS_FULL_SCREEN_START + 1) - -#define NS_TOUCH_EVENT_START 5200 -#define NS_TOUCH_START (NS_TOUCH_EVENT_START) -#define NS_TOUCH_MOVE (NS_TOUCH_EVENT_START+1) -#define NS_TOUCH_END (NS_TOUCH_EVENT_START+2) -#define NS_TOUCH_CANCEL (NS_TOUCH_EVENT_START+3) - -// Pointerlock DOM API -#define NS_POINTERLOCK_START 5300 -#define NS_POINTERLOCKCHANGE (NS_POINTERLOCK_START) -#define NS_POINTERLOCKERROR (NS_POINTERLOCK_START + 1) - -#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 - -// Network packet events. -#define NS_NETWORK_EVENT_START 5600 -#define NS_NETWORK_UPLOAD_EVENT (NS_NETWORK_EVENT_START + 1) -#define NS_NETWORK_DOWNLOAD_EVENT (NS_NETWORK_EVENT_START + 2) - -// MediaRecorder events. -#define NS_MEDIARECORDER_EVENT_START 5700 -#define NS_MEDIARECORDER_DATAAVAILABLE (NS_MEDIARECORDER_EVENT_START + 1) -#define NS_MEDIARECORDER_WARNING (NS_MEDIARECORDER_EVENT_START + 2) -#define NS_MEDIARECORDER_STOP (NS_MEDIARECORDER_EVENT_START + 3) - -// SpeakerManager events -#define NS_SPEAKERMANAGER_EVENT_START 5800 -#define NS_SPEAKERMANAGER_SPEAKERFORCEDCHANGE (NS_SPEAKERMANAGER_EVENT_START + 1) - -#ifdef MOZ_GAMEPAD -// Gamepad input events -#define NS_GAMEPAD_START 6000 -#define NS_GAMEPAD_BUTTONDOWN (NS_GAMEPAD_START) -#define NS_GAMEPAD_BUTTONUP (NS_GAMEPAD_START+1) -#define NS_GAMEPAD_AXISMOVE (NS_GAMEPAD_START+2) -#define NS_GAMEPAD_CONNECTED (NS_GAMEPAD_START+3) -#define NS_GAMEPAD_DISCONNECTED (NS_GAMEPAD_START+4) -// Keep this defined to the same value as the event above -#define NS_GAMEPAD_END (NS_GAMEPAD_START+4) -#endif - -// input and beforeinput events. -#define NS_EDITOR_EVENT_START 6100 -#define NS_EDITOR_INPUT (NS_EDITOR_EVENT_START) - namespace IPC { template struct ParamTraits; diff --git a/widget/EventForwards.h b/widget/EventForwards.h index 0df64f28b0bd..d899f2f97925 100644 --- a/widget/EventForwards.h +++ b/widget/EventForwards.h @@ -28,8 +28,29 @@ enum nsEventStatus nsEventStatus_eSentinel }; +/** + * Event messages + */ + +enum +{ + +#define NS_EVENT_MESSAGE(aMessage, aValue) aMessage = aValue, + +#include "mozilla/EventMessageList.h" + +#undef NS_EVENT_MESSAGE + + // For preventing bustage due to "," after the last item. + eEventMessage_MaxValue +}; + namespace mozilla { +/** + * Event class IDs + */ + typedef uint8_t EventClassIDType; enum EventClassID : EventClassIDType diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h new file mode 100644 index 000000000000..6db0afb9cdcf --- /dev/null +++ b/widget/EventMessageList.h @@ -0,0 +1,426 @@ +/* -*- 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/. */ + +/** + * This header file lists up all event messages and their values. + * Before including this header file, you should define + * NS_EVENT_MESSAGE(aMessage, aValue) + */ + +NS_EVENT_MESSAGE(NS_EVENT_NULL, 0) + +// This is a dummy event message for all event listener implementation in +// EventListenerManager. +NS_EVENT_MESSAGE(NS_EVENT_ALL, 1) + +NS_EVENT_MESSAGE(NS_WINDOW_START, 100) +// Widget may be destroyed +NS_EVENT_MESSAGE(NS_XUL_CLOSE, NS_WINDOW_START + 1) + +NS_EVENT_MESSAGE(NS_KEY_PRESS, NS_WINDOW_START + 31) +NS_EVENT_MESSAGE(NS_KEY_UP, NS_WINDOW_START + 32) +NS_EVENT_MESSAGE(NS_KEY_DOWN, NS_WINDOW_START + 33) + +NS_EVENT_MESSAGE(NS_KEY_BEFORE_DOWN, NS_WINDOW_START + 34) +NS_EVENT_MESSAGE(NS_KEY_AFTER_DOWN, NS_WINDOW_START + 35) +NS_EVENT_MESSAGE(NS_KEY_BEFORE_UP, NS_WINDOW_START + 36) +NS_EVENT_MESSAGE(NS_KEY_AFTER_UP, NS_WINDOW_START + 37) + +NS_EVENT_MESSAGE(NS_RESIZE_EVENT, NS_WINDOW_START + 60) +NS_EVENT_MESSAGE(NS_SCROLL_EVENT, NS_WINDOW_START + 61) + +// A plugin was clicked or otherwise focused. NS_PLUGIN_ACTIVATE should be +// used when the window is not active. NS_PLUGIN_FOCUS should be used when +// the window is active. In the latter case, the dispatcher of the event +// is expected to ensure that the plugin's widget is focused beforehand. +NS_EVENT_MESSAGE(NS_PLUGIN_ACTIVATE, NS_WINDOW_START + 62) +NS_EVENT_MESSAGE(NS_PLUGIN_FOCUS, NS_WINDOW_START + 63) + +NS_EVENT_MESSAGE(NS_OFFLINE, NS_WINDOW_START + 64) +NS_EVENT_MESSAGE(NS_ONLINE, NS_WINDOW_START + 65) + +// NS_BEFORERESIZE_EVENT used to be here (NS_WINDOW_START + 66) + +// Indicates that the user is either idle or active +NS_EVENT_MESSAGE(NS_MOZ_USER_IDLE, NS_WINDOW_START + 67) +NS_EVENT_MESSAGE(NS_MOZ_USER_ACTIVE, NS_WINDOW_START + 68) + +NS_EVENT_MESSAGE(NS_LANGUAGECHANGE, NS_WINDOW_START + 70) + +NS_EVENT_MESSAGE(NS_MOUSE_MESSAGE_START, 300) +NS_EVENT_MESSAGE(NS_MOUSE_MOVE, NS_MOUSE_MESSAGE_START) +NS_EVENT_MESSAGE(NS_MOUSE_BUTTON_UP, NS_MOUSE_MESSAGE_START + 1) +NS_EVENT_MESSAGE(NS_MOUSE_BUTTON_DOWN, NS_MOUSE_MESSAGE_START + 2) +NS_EVENT_MESSAGE(NS_MOUSE_ENTER_WIDGET, NS_MOUSE_MESSAGE_START + 22) +NS_EVENT_MESSAGE(NS_MOUSE_EXIT_WIDGET, NS_MOUSE_MESSAGE_START + 23) +NS_EVENT_MESSAGE(NS_MOUSE_DOUBLECLICK, NS_MOUSE_MESSAGE_START + 24) +NS_EVENT_MESSAGE(NS_MOUSE_CLICK, NS_MOUSE_MESSAGE_START + 27) +NS_EVENT_MESSAGE(NS_MOUSE_ACTIVATE, NS_MOUSE_MESSAGE_START + 30) +NS_EVENT_MESSAGE(NS_MOUSE_OVER, NS_MOUSE_MESSAGE_START + 31) +NS_EVENT_MESSAGE(NS_MOUSE_OUT, NS_MOUSE_MESSAGE_START + 32) +NS_EVENT_MESSAGE(NS_MOUSE_MOZHITTEST, NS_MOUSE_MESSAGE_START + 33) +NS_EVENT_MESSAGE(NS_MOUSEENTER, NS_MOUSE_MESSAGE_START + 34) +NS_EVENT_MESSAGE(NS_MOUSELEAVE, NS_MOUSE_MESSAGE_START + 35) +NS_EVENT_MESSAGE(NS_MOUSE_MOZLONGTAP, NS_MOUSE_MESSAGE_START + 36) + +// Pointer spec events +NS_EVENT_MESSAGE(NS_POINTER_EVENT_START, 4400) +NS_EVENT_MESSAGE(NS_POINTER_MOVE, NS_POINTER_EVENT_START) +NS_EVENT_MESSAGE(NS_POINTER_UP, NS_POINTER_EVENT_START + 1) +NS_EVENT_MESSAGE(NS_POINTER_DOWN, NS_POINTER_EVENT_START + 2) +NS_EVENT_MESSAGE(NS_POINTER_OVER, NS_POINTER_EVENT_START + 22) +NS_EVENT_MESSAGE(NS_POINTER_OUT, NS_POINTER_EVENT_START + 23) +NS_EVENT_MESSAGE(NS_POINTER_ENTER, NS_POINTER_EVENT_START + 24) +NS_EVENT_MESSAGE(NS_POINTER_LEAVE, NS_POINTER_EVENT_START + 25) +NS_EVENT_MESSAGE(NS_POINTER_CANCEL, NS_POINTER_EVENT_START + 26) +NS_EVENT_MESSAGE(NS_POINTER_GOT_CAPTURE, NS_POINTER_EVENT_START + 27) +NS_EVENT_MESSAGE(NS_POINTER_LOST_CAPTURE, NS_POINTER_EVENT_START + 28) + +NS_EVENT_MESSAGE(NS_CONTEXTMENU_MESSAGE_START, 500) +NS_EVENT_MESSAGE(NS_CONTEXTMENU, NS_CONTEXTMENU_MESSAGE_START) + +NS_EVENT_MESSAGE(NS_STREAM_EVENT_START, 1100) +NS_EVENT_MESSAGE(NS_LOAD, NS_STREAM_EVENT_START) +NS_EVENT_MESSAGE(NS_PAGE_UNLOAD, NS_STREAM_EVENT_START + 1) +NS_EVENT_MESSAGE(NS_HASHCHANGE, NS_STREAM_EVENT_START + 2) +NS_EVENT_MESSAGE(NS_IMAGE_ABORT, NS_STREAM_EVENT_START + 3) +NS_EVENT_MESSAGE(NS_LOAD_ERROR, NS_STREAM_EVENT_START + 4) +NS_EVENT_MESSAGE(NS_POPSTATE, NS_STREAM_EVENT_START + 5) +NS_EVENT_MESSAGE(NS_BEFORE_PAGE_UNLOAD, NS_STREAM_EVENT_START + 6) +NS_EVENT_MESSAGE(NS_PAGE_RESTORE, NS_STREAM_EVENT_START + 7) +NS_EVENT_MESSAGE(NS_READYSTATECHANGE, NS_STREAM_EVENT_START + 8) + +NS_EVENT_MESSAGE(NS_FORM_EVENT_START, 1200) +NS_EVENT_MESSAGE(NS_FORM_SUBMIT, NS_FORM_EVENT_START) +NS_EVENT_MESSAGE(NS_FORM_RESET, NS_FORM_EVENT_START + 1) +NS_EVENT_MESSAGE(NS_FORM_CHANGE, NS_FORM_EVENT_START + 2) +NS_EVENT_MESSAGE(NS_FORM_SELECTED, NS_FORM_EVENT_START + 3) +NS_EVENT_MESSAGE(NS_FORM_INVALID, NS_FORM_EVENT_START + 4) + +//Need separate focus/blur notifications for non-native widgets +NS_EVENT_MESSAGE(NS_FOCUS_EVENT_START, 1300) +NS_EVENT_MESSAGE(NS_FOCUS_CONTENT, NS_FOCUS_EVENT_START) +NS_EVENT_MESSAGE(NS_BLUR_CONTENT, NS_FOCUS_EVENT_START + 1) + +NS_EVENT_MESSAGE(NS_DRAGDROP_EVENT_START, 1400) +NS_EVENT_MESSAGE(NS_DRAGDROP_ENTER, NS_DRAGDROP_EVENT_START) +NS_EVENT_MESSAGE(NS_DRAGDROP_OVER, NS_DRAGDROP_EVENT_START + 1) +NS_EVENT_MESSAGE(NS_DRAGDROP_EXIT, NS_DRAGDROP_EVENT_START + 2) +NS_EVENT_MESSAGE(NS_DRAGDROP_DRAGDROP, NS_DRAGDROP_EVENT_START + 3) +NS_EVENT_MESSAGE(NS_DRAGDROP_GESTURE, NS_DRAGDROP_EVENT_START + 4) +NS_EVENT_MESSAGE(NS_DRAGDROP_DRAG, NS_DRAGDROP_EVENT_START + 5) +NS_EVENT_MESSAGE(NS_DRAGDROP_END, NS_DRAGDROP_EVENT_START + 6) +NS_EVENT_MESSAGE(NS_DRAGDROP_START, NS_DRAGDROP_EVENT_START + 7) +NS_EVENT_MESSAGE(NS_DRAGDROP_DROP, NS_DRAGDROP_EVENT_START + 8) +NS_EVENT_MESSAGE(NS_DRAGDROP_LEAVE, NS_DRAGDROP_EVENT_START + 9) + +// Events for popups +NS_EVENT_MESSAGE(NS_XUL_EVENT_START, 1500) +NS_EVENT_MESSAGE(NS_XUL_POPUP_SHOWING, NS_XUL_EVENT_START) +NS_EVENT_MESSAGE(NS_XUL_POPUP_SHOWN, NS_XUL_EVENT_START + 1) +NS_EVENT_MESSAGE(NS_XUL_POPUP_HIDING, NS_XUL_EVENT_START + 2) +NS_EVENT_MESSAGE(NS_XUL_POPUP_HIDDEN, NS_XUL_EVENT_START + 3) +// NS_XUL_COMMAND used to be here (NS_XUL_EVENT_START + 4) +NS_EVENT_MESSAGE(NS_XUL_BROADCAST, NS_XUL_EVENT_START + 5) +NS_EVENT_MESSAGE(NS_XUL_COMMAND_UPDATE, NS_XUL_EVENT_START + 6) + +// Scroll events +NS_EVENT_MESSAGE(NS_MOUSE_SCROLL_START, 1600) +NS_EVENT_MESSAGE(NS_MOUSE_SCROLL, NS_MOUSE_SCROLL_START) +NS_EVENT_MESSAGE(NS_MOUSE_PIXEL_SCROLL, NS_MOUSE_SCROLL_START + 1) + +NS_EVENT_MESSAGE(NS_SCROLLPORT_START, 1700) +NS_EVENT_MESSAGE(NS_SCROLLPORT_UNDERFLOW, NS_SCROLLPORT_START) +NS_EVENT_MESSAGE(NS_SCROLLPORT_OVERFLOW, NS_SCROLLPORT_START + 1) + +NS_EVENT_MESSAGE(NS_MUTATION_START, 1800) +NS_EVENT_MESSAGE(NS_MUTATION_SUBTREEMODIFIED, NS_MUTATION_START) +NS_EVENT_MESSAGE(NS_MUTATION_NODEINSERTED, NS_MUTATION_START + 1) +NS_EVENT_MESSAGE(NS_MUTATION_NODEREMOVED, NS_MUTATION_START + 2) +NS_EVENT_MESSAGE(NS_MUTATION_NODEREMOVEDFROMDOCUMENT, NS_MUTATION_START + 3) +NS_EVENT_MESSAGE(NS_MUTATION_NODEINSERTEDINTODOCUMENT, NS_MUTATION_START + 4) +NS_EVENT_MESSAGE(NS_MUTATION_ATTRMODIFIED, NS_MUTATION_START + 5) +NS_EVENT_MESSAGE(NS_MUTATION_CHARACTERDATAMODIFIED, NS_MUTATION_START + 6) +NS_EVENT_MESSAGE(NS_MUTATION_END, NS_MUTATION_START + 6) + +NS_EVENT_MESSAGE(NS_USER_DEFINED_EVENT, 2000) + +// composition events +NS_EVENT_MESSAGE(NS_COMPOSITION_EVENT_START, 2200) +NS_EVENT_MESSAGE(NS_COMPOSITION_START, NS_COMPOSITION_EVENT_START) +// NS_COMPOSITION_END is the message for DOM compositionend event. +// This event should NOT be dispatched from widget if NS_COMPOSITION_COMMIT +// is available. +NS_EVENT_MESSAGE(NS_COMPOSITION_END, NS_COMPOSITION_EVENT_START + 1) +// NS_COMPOSITION_UPDATE is the message for DOM compositionupdate event. +// This event should NOT be dispatched from widget since it will be dispatched +// by mozilla::TextComposition automatically if NS_COMPOSITION_CHANGE event +// will change composition string. +NS_EVENT_MESSAGE(NS_COMPOSITION_UPDATE, NS_COMPOSITION_EVENT_START + 2) +// NS_COMPOSITION_CHANGE is the message for representing a change of +// composition string. This should be dispatched from widget even if +// composition string isn't changed but the ranges are changed. This causes +// a DOM "text" event which is a non-standard DOM event. +NS_EVENT_MESSAGE(NS_COMPOSITION_CHANGE, NS_COMPOSITION_EVENT_START + 3) +// NS_COMPOSITION_COMMIT_AS_IS is the message for representing a commit of +// composition string. TextComposition will commit composition with the +// last data. TextComposition will dispatch this event to the DOM tree as +// NS_COMPOSITION_CHANGE without clause information. After that, +// NS_COMPOSITION_END will be dispatched automatically. +// Its mData and mRanges should be empty and nullptr. +NS_EVENT_MESSAGE(NS_COMPOSITION_COMMIT_AS_IS, NS_COMPOSITION_EVENT_START + 4) +// NS_COMPOSITION_COMMIT is the message for representing a commit of +// composition string with its mData value. TextComposition will dispatch this +// event to the DOM tree as NS_COMPOSITION_CHANGE without clause information. +// After that, NS_COMPOSITION_END will be dispatched automatically. +// Its mRanges should be nullptr. +NS_EVENT_MESSAGE(NS_COMPOSITION_COMMIT, NS_COMPOSITION_EVENT_START + 5) + +// UI events +NS_EVENT_MESSAGE(NS_UI_EVENT_START, 2500) +// this is not to be confused with NS_ACTIVATE! +NS_EVENT_MESSAGE(NS_UI_ACTIVATE, NS_UI_EVENT_START) +NS_EVENT_MESSAGE(NS_UI_FOCUSIN, NS_UI_EVENT_START + 1) +NS_EVENT_MESSAGE(NS_UI_FOCUSOUT, NS_UI_EVENT_START + 2) + +// pagetransition events +NS_EVENT_MESSAGE(NS_PAGETRANSITION_START, 2700) +NS_EVENT_MESSAGE(NS_PAGE_SHOW, NS_PAGETRANSITION_START + 1) +NS_EVENT_MESSAGE(NS_PAGE_HIDE, NS_PAGETRANSITION_START + 2) + +// SVG events +NS_EVENT_MESSAGE(NS_SVG_EVENT_START, 2800) +NS_EVENT_MESSAGE(NS_SVG_LOAD, NS_SVG_EVENT_START) +NS_EVENT_MESSAGE(NS_SVG_UNLOAD, NS_SVG_EVENT_START + 1) +NS_EVENT_MESSAGE(NS_SVG_ABORT, NS_SVG_EVENT_START + 2) +NS_EVENT_MESSAGE(NS_SVG_ERROR, NS_SVG_EVENT_START + 3) +NS_EVENT_MESSAGE(NS_SVG_RESIZE, NS_SVG_EVENT_START + 4) +NS_EVENT_MESSAGE(NS_SVG_SCROLL, NS_SVG_EVENT_START + 5) + +// SVG Zoom events +NS_EVENT_MESSAGE(NS_SVGZOOM_EVENT_START, 2900) +NS_EVENT_MESSAGE(NS_SVG_ZOOM, NS_SVGZOOM_EVENT_START) + +// XUL command events +NS_EVENT_MESSAGE(NS_XULCOMMAND_EVENT_START, 3000) +NS_EVENT_MESSAGE(NS_XUL_COMMAND, NS_XULCOMMAND_EVENT_START) + +// Cut, copy, paste events +NS_EVENT_MESSAGE(NS_CUTCOPYPASTE_EVENT_START, 3100) +NS_EVENT_MESSAGE(NS_COPY, NS_CUTCOPYPASTE_EVENT_START) +NS_EVENT_MESSAGE(NS_CUT, NS_CUTCOPYPASTE_EVENT_START + 1) +NS_EVENT_MESSAGE(NS_PASTE, NS_CUTCOPYPASTE_EVENT_START + 2) + +// Query the content information +NS_EVENT_MESSAGE(NS_QUERY_CONTENT_EVENT_START, 3200) +// Query for the selected text information, it return the selection offset, +// selection length and selected text. +NS_EVENT_MESSAGE(NS_QUERY_SELECTED_TEXT, NS_QUERY_CONTENT_EVENT_START) +// Query for the text content of specified range, it returns actual lengh (if +// the specified range is too long) and the text of the specified range. +// Returns the entire text if requested length > actual length. +NS_EVENT_MESSAGE(NS_QUERY_TEXT_CONTENT, NS_QUERY_CONTENT_EVENT_START + 1) +// Query for the caret rect of nth insertion point. The offset of the result is +// relative position from the top level widget. +NS_EVENT_MESSAGE(NS_QUERY_CARET_RECT, NS_QUERY_CONTENT_EVENT_START + 3) +// Query for the bounding rect of a range of characters. This works on any +// valid character range given offset and length. Result is relative to top +// level widget coordinates +NS_EVENT_MESSAGE(NS_QUERY_TEXT_RECT, NS_QUERY_CONTENT_EVENT_START + 4) +// Query for the bounding rect of the current focused frame. Result is relative +// to top level widget coordinates +NS_EVENT_MESSAGE(NS_QUERY_EDITOR_RECT, NS_QUERY_CONTENT_EVENT_START + 5) +// Query for the current state of the content. The particular members of +// mReply that are set for each query content event will be valid on success. +NS_EVENT_MESSAGE(NS_QUERY_CONTENT_STATE, NS_QUERY_CONTENT_EVENT_START + 6) +// Query for the selection in the form of a nsITransferable. +NS_EVENT_MESSAGE(NS_QUERY_SELECTION_AS_TRANSFERABLE, NS_QUERY_CONTENT_EVENT_START + 7) +// Query for character at a point. This returns the character offset, its +// rect and also tentative caret point if the point is clicked. The point is +// specified by Event::refPoint. +NS_EVENT_MESSAGE(NS_QUERY_CHARACTER_AT_POINT, NS_QUERY_CONTENT_EVENT_START + 8) +// Query if the DOM element under Event::refPoint belongs to our widget +// or not. +NS_EVENT_MESSAGE(NS_QUERY_DOM_WIDGET_HITTEST, NS_QUERY_CONTENT_EVENT_START + 9) + +// Video events +NS_EVENT_MESSAGE(NS_MEDIA_EVENT_START, 3300) +NS_EVENT_MESSAGE(NS_LOADSTART, NS_MEDIA_EVENT_START) +NS_EVENT_MESSAGE(NS_PROGRESS, NS_MEDIA_EVENT_START + 1) +NS_EVENT_MESSAGE(NS_SUSPEND, NS_MEDIA_EVENT_START + 2) +NS_EVENT_MESSAGE(NS_EMPTIED, NS_MEDIA_EVENT_START + 3) +NS_EVENT_MESSAGE(NS_STALLED, NS_MEDIA_EVENT_START + 4) +NS_EVENT_MESSAGE(NS_PLAY, NS_MEDIA_EVENT_START + 5) +NS_EVENT_MESSAGE(NS_PAUSE, NS_MEDIA_EVENT_START + 6) +NS_EVENT_MESSAGE(NS_LOADEDMETADATA, NS_MEDIA_EVENT_START + 7) +NS_EVENT_MESSAGE(NS_LOADEDDATA, NS_MEDIA_EVENT_START + 8) +NS_EVENT_MESSAGE(NS_WAITING, NS_MEDIA_EVENT_START + 9) +NS_EVENT_MESSAGE(NS_PLAYING, NS_MEDIA_EVENT_START + 10) +NS_EVENT_MESSAGE(NS_CANPLAY, NS_MEDIA_EVENT_START + 11) +NS_EVENT_MESSAGE(NS_CANPLAYTHROUGH, NS_MEDIA_EVENT_START + 12) +NS_EVENT_MESSAGE(NS_SEEKING, NS_MEDIA_EVENT_START + 13) +NS_EVENT_MESSAGE(NS_SEEKED, NS_MEDIA_EVENT_START + 14) +NS_EVENT_MESSAGE(NS_TIMEUPDATE, NS_MEDIA_EVENT_START + 15) +NS_EVENT_MESSAGE(NS_ENDED, NS_MEDIA_EVENT_START + 16) +NS_EVENT_MESSAGE(NS_RATECHANGE, NS_MEDIA_EVENT_START + 17) +NS_EVENT_MESSAGE(NS_DURATIONCHANGE, NS_MEDIA_EVENT_START + 18) +NS_EVENT_MESSAGE(NS_VOLUMECHANGE, NS_MEDIA_EVENT_START + 19) +NS_EVENT_MESSAGE(NS_NEED_KEY, NS_MEDIA_EVENT_START + 20) + +// paint notification events +NS_EVENT_MESSAGE(NS_NOTIFYPAINT_START, 3400) +NS_EVENT_MESSAGE(NS_AFTERPAINT, NS_NOTIFYPAINT_START) + +// Simple gesture events +NS_EVENT_MESSAGE(NS_SIMPLE_GESTURE_EVENT_START, 3500) +NS_EVENT_MESSAGE(NS_SIMPLE_GESTURE_SWIPE_START, NS_SIMPLE_GESTURE_EVENT_START) +NS_EVENT_MESSAGE(NS_SIMPLE_GESTURE_SWIPE_UPDATE, NS_SIMPLE_GESTURE_EVENT_START + 1) +NS_EVENT_MESSAGE(NS_SIMPLE_GESTURE_SWIPE_END, NS_SIMPLE_GESTURE_EVENT_START + 2) +NS_EVENT_MESSAGE(NS_SIMPLE_GESTURE_SWIPE, NS_SIMPLE_GESTURE_EVENT_START + 3) +NS_EVENT_MESSAGE(NS_SIMPLE_GESTURE_MAGNIFY_START, NS_SIMPLE_GESTURE_EVENT_START + 4) +NS_EVENT_MESSAGE(NS_SIMPLE_GESTURE_MAGNIFY_UPDATE, NS_SIMPLE_GESTURE_EVENT_START + 5) +NS_EVENT_MESSAGE(NS_SIMPLE_GESTURE_MAGNIFY, NS_SIMPLE_GESTURE_EVENT_START + 6) +NS_EVENT_MESSAGE(NS_SIMPLE_GESTURE_ROTATE_START, NS_SIMPLE_GESTURE_EVENT_START + 7) +NS_EVENT_MESSAGE(NS_SIMPLE_GESTURE_ROTATE_UPDATE, NS_SIMPLE_GESTURE_EVENT_START + 8) +NS_EVENT_MESSAGE(NS_SIMPLE_GESTURE_ROTATE, NS_SIMPLE_GESTURE_EVENT_START + 9) +NS_EVENT_MESSAGE(NS_SIMPLE_GESTURE_TAP, NS_SIMPLE_GESTURE_EVENT_START + 10) +NS_EVENT_MESSAGE(NS_SIMPLE_GESTURE_PRESSTAP, NS_SIMPLE_GESTURE_EVENT_START + 11) +NS_EVENT_MESSAGE(NS_SIMPLE_GESTURE_EDGE_STARTED, NS_SIMPLE_GESTURE_EVENT_START + 12) +NS_EVENT_MESSAGE(NS_SIMPLE_GESTURE_EDGE_CANCELED, NS_SIMPLE_GESTURE_EVENT_START + 13) +NS_EVENT_MESSAGE(NS_SIMPLE_GESTURE_EDGE_COMPLETED, NS_SIMPLE_GESTURE_EVENT_START + 14) + +// These are used to send native events to plugins. +NS_EVENT_MESSAGE(NS_PLUGIN_EVENT_START, 3600) +NS_EVENT_MESSAGE(NS_PLUGIN_INPUT_EVENT, NS_PLUGIN_EVENT_START) +NS_EVENT_MESSAGE(NS_PLUGIN_FOCUS_EVENT, NS_PLUGIN_EVENT_START + 1) + +// Events to manipulate selection (WidgetSelectionEvent) +NS_EVENT_MESSAGE(NS_SELECTION_EVENT_START, 3700) +// Clear any previous selection and set the given range as the selection +NS_EVENT_MESSAGE(NS_SELECTION_SET, NS_SELECTION_EVENT_START) + +// Events of commands for the contents +NS_EVENT_MESSAGE(NS_CONTENT_COMMAND_EVENT_START, 3800) +NS_EVENT_MESSAGE(NS_CONTENT_COMMAND_CUT, NS_CONTENT_COMMAND_EVENT_START) +NS_EVENT_MESSAGE(NS_CONTENT_COMMAND_COPY, NS_CONTENT_COMMAND_EVENT_START + 1) +NS_EVENT_MESSAGE(NS_CONTENT_COMMAND_PASTE, NS_CONTENT_COMMAND_EVENT_START + 2) +NS_EVENT_MESSAGE(NS_CONTENT_COMMAND_DELETE, NS_CONTENT_COMMAND_EVENT_START + 3) +NS_EVENT_MESSAGE(NS_CONTENT_COMMAND_UNDO, NS_CONTENT_COMMAND_EVENT_START + 4) +NS_EVENT_MESSAGE(NS_CONTENT_COMMAND_REDO, NS_CONTENT_COMMAND_EVENT_START + 5) +NS_EVENT_MESSAGE(NS_CONTENT_COMMAND_PASTE_TRANSFERABLE, NS_CONTENT_COMMAND_EVENT_START + 6) +// NS_CONTENT_COMMAND_SCROLL scrolls the nearest scrollable element to the +// currently focused content or latest DOM selection. This would normally be +// the same element scrolled by keyboard scroll commands, except that this event +// will scroll an element scrollable in either direction. I.e., if the nearest +// scrollable ancestor element can only be scrolled vertically, and horizontal +// scrolling is requested using this event, no scrolling will occur. +NS_EVENT_MESSAGE(NS_CONTENT_COMMAND_SCROLL, NS_CONTENT_COMMAND_EVENT_START+7) + +// Event to gesture notification +NS_EVENT_MESSAGE(NS_GESTURENOTIFY_EVENT_START, 3900) + +NS_EVENT_MESSAGE(NS_ORIENTATION_EVENT, 4000) + +NS_EVENT_MESSAGE(NS_SCROLLAREA_EVENT_START, 4100) +NS_EVENT_MESSAGE(NS_SCROLLEDAREACHANGED, NS_SCROLLAREA_EVENT_START) + +NS_EVENT_MESSAGE(NS_TRANSITION_EVENT_START, 4200) +NS_EVENT_MESSAGE(NS_TRANSITION_END, NS_TRANSITION_EVENT_START) + +NS_EVENT_MESSAGE(NS_ANIMATION_EVENT_START, 4250) +NS_EVENT_MESSAGE(NS_ANIMATION_START, NS_ANIMATION_EVENT_START) +NS_EVENT_MESSAGE(NS_ANIMATION_END, NS_ANIMATION_EVENT_START + 1) +NS_EVENT_MESSAGE(NS_ANIMATION_ITERATION, NS_ANIMATION_EVENT_START + 2) + +NS_EVENT_MESSAGE(NS_SMIL_TIME_EVENT_START, 4300) +NS_EVENT_MESSAGE(NS_SMIL_BEGIN, NS_SMIL_TIME_EVENT_START) +NS_EVENT_MESSAGE(NS_SMIL_END, NS_SMIL_TIME_EVENT_START + 1) +NS_EVENT_MESSAGE(NS_SMIL_REPEAT, NS_SMIL_TIME_EVENT_START + 2) + +NS_EVENT_MESSAGE(NS_WEBAUDIO_EVENT_START, 4350) +NS_EVENT_MESSAGE(NS_AUDIO_PROCESS, NS_WEBAUDIO_EVENT_START) +NS_EVENT_MESSAGE(NS_AUDIO_COMPLETE, NS_WEBAUDIO_EVENT_START + 1) + +// script notification events +NS_EVENT_MESSAGE(NS_NOTIFYSCRIPT_START, 4500) +NS_EVENT_MESSAGE(NS_BEFORE_SCRIPT_EXECUTE, NS_NOTIFYSCRIPT_START) +NS_EVENT_MESSAGE(NS_AFTER_SCRIPT_EXECUTE, NS_NOTIFYSCRIPT_START + 1) + +NS_EVENT_MESSAGE(NS_PRINT_EVENT_START, 4600) +NS_EVENT_MESSAGE(NS_BEFOREPRINT, NS_PRINT_EVENT_START) +NS_EVENT_MESSAGE(NS_AFTERPRINT, NS_PRINT_EVENT_START + 1) + +NS_EVENT_MESSAGE(NS_MESSAGE_EVENT_START, 4700) +NS_EVENT_MESSAGE(NS_MESSAGE, NS_MESSAGE_EVENT_START) + +// Open and close events +NS_EVENT_MESSAGE(NS_OPENCLOSE_EVENT_START, 4800) +NS_EVENT_MESSAGE(NS_OPEN, NS_OPENCLOSE_EVENT_START) +NS_EVENT_MESSAGE(NS_CLOSE, NS_OPENCLOSE_EVENT_START+1) + +// Device motion and orientation +NS_EVENT_MESSAGE(NS_DEVICE_ORIENTATION_START, 4900) +NS_EVENT_MESSAGE(NS_DEVICE_ORIENTATION, NS_DEVICE_ORIENTATION_START) +NS_EVENT_MESSAGE(NS_DEVICE_MOTION, NS_DEVICE_ORIENTATION_START + 1) +NS_EVENT_MESSAGE(NS_DEVICE_PROXIMITY, NS_DEVICE_ORIENTATION_START + 2) +NS_EVENT_MESSAGE(NS_USER_PROXIMITY, NS_DEVICE_ORIENTATION_START + 3) +NS_EVENT_MESSAGE(NS_DEVICE_LIGHT, NS_DEVICE_ORIENTATION_START + 4) + +NS_EVENT_MESSAGE(NS_SHOW_EVENT, 5000) + +// Fullscreen DOM API +NS_EVENT_MESSAGE(NS_FULL_SCREEN_START, 5100) +NS_EVENT_MESSAGE(NS_FULLSCREENCHANGE, NS_FULL_SCREEN_START) +NS_EVENT_MESSAGE(NS_FULLSCREENERROR, NS_FULL_SCREEN_START + 1) + +NS_EVENT_MESSAGE(NS_TOUCH_EVENT_START, 5200) +NS_EVENT_MESSAGE(NS_TOUCH_START, NS_TOUCH_EVENT_START) +NS_EVENT_MESSAGE(NS_TOUCH_MOVE, NS_TOUCH_EVENT_START + 1) +NS_EVENT_MESSAGE(NS_TOUCH_END, NS_TOUCH_EVENT_START + 2) +NS_EVENT_MESSAGE(NS_TOUCH_CANCEL, NS_TOUCH_EVENT_START + 3) + +// Pointerlock DOM API +NS_EVENT_MESSAGE(NS_POINTERLOCK_START, 5300) +NS_EVENT_MESSAGE(NS_POINTERLOCKCHANGE, NS_POINTERLOCK_START) +NS_EVENT_MESSAGE(NS_POINTERLOCKERROR, NS_POINTERLOCK_START + 1) + +NS_EVENT_MESSAGE(NS_WHEEL_EVENT_START, 5400) +NS_EVENT_MESSAGE(NS_WHEEL_WHEEL, NS_WHEEL_EVENT_START) +NS_EVENT_MESSAGE(NS_WHEEL_START, NS_WHEEL_EVENT_START + 1) +NS_EVENT_MESSAGE(NS_WHEEL_STOP, NS_WHEEL_EVENT_START + 2) + +//System time is changed +NS_EVENT_MESSAGE(NS_MOZ_TIME_CHANGE_EVENT, 5500) + +// Network packet events. +NS_EVENT_MESSAGE(NS_NETWORK_EVENT_START, 5600) +NS_EVENT_MESSAGE(NS_NETWORK_UPLOAD_EVENT, NS_NETWORK_EVENT_START + 1) +NS_EVENT_MESSAGE(NS_NETWORK_DOWNLOAD_EVENT, NS_NETWORK_EVENT_START + 2) + +// MediaRecorder events. +NS_EVENT_MESSAGE(NS_MEDIARECORDER_EVENT_START, 5700) +NS_EVENT_MESSAGE(NS_MEDIARECORDER_DATAAVAILABLE, NS_MEDIARECORDER_EVENT_START + 1) +NS_EVENT_MESSAGE(NS_MEDIARECORDER_WARNING, NS_MEDIARECORDER_EVENT_START + 2) +NS_EVENT_MESSAGE(NS_MEDIARECORDER_STOP, NS_MEDIARECORDER_EVENT_START + 3) + +// SpeakerManager events +NS_EVENT_MESSAGE(NS_SPEAKERMANAGER_EVENT_START, 5800) +NS_EVENT_MESSAGE(NS_SPEAKERMANAGER_SPEAKERFORCEDCHANGE, NS_SPEAKERMANAGER_EVENT_START + 1) + +#ifdef MOZ_GAMEPAD +// Gamepad input events +NS_EVENT_MESSAGE(NS_GAMEPAD_START, 6000) +NS_EVENT_MESSAGE(NS_GAMEPAD_BUTTONDOWN, NS_GAMEPAD_START) +NS_EVENT_MESSAGE(NS_GAMEPAD_BUTTONUP, NS_GAMEPAD_START + 1) +NS_EVENT_MESSAGE(NS_GAMEPAD_AXISMOVE, NS_GAMEPAD_START + 2) +NS_EVENT_MESSAGE(NS_GAMEPAD_CONNECTED, NS_GAMEPAD_START + 3) +NS_EVENT_MESSAGE(NS_GAMEPAD_DISCONNECTED, NS_GAMEPAD_START + 4) +// Keep this defined to the same value as the event above +NS_EVENT_MESSAGE(NS_GAMEPAD_END, NS_GAMEPAD_START + 4) +#endif + +// input and beforeinput events. +NS_EVENT_MESSAGE(NS_EDITOR_EVENT_START, 6100) +NS_EVENT_MESSAGE(NS_EDITOR_INPUT, NS_EDITOR_EVENT_START) diff --git a/widget/moz.build b/widget/moz.build index 706f8e4c55b0..81b383bf9dd4 100644 --- a/widget/moz.build +++ b/widget/moz.build @@ -113,6 +113,7 @@ EXPORTS.mozilla += [ 'ContentEvents.h', 'EventClassList.h', 'EventForwards.h', + 'EventMessageList.h', 'FontRange.h', 'LookAndFeel.h', 'MiscEvents.h', From 0e178c62f188ba4ec77790cb1b4ff7e212848c1b Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Wed, 19 Aug 2015 14:59:25 -0700 Subject: [PATCH 175/208] Bug 1168606 - Part 3: Allow multiple ObjectStoreCursorResponses in a CursorResponse. r=khuey For now, we assume that the array only ever contains a single response. --- dom/indexedDB/ActorsChild.cpp | 47 +++++++------ dom/indexedDB/ActorsChild.h | 2 +- dom/indexedDB/ActorsParent.cpp | 91 +++++++++++++++---------- dom/indexedDB/PBackgroundIDBCursor.ipdl | 2 +- 4 files changed, 84 insertions(+), 58 deletions(-) diff --git a/dom/indexedDB/ActorsChild.cpp b/dom/indexedDB/ActorsChild.cpp index 0445f1cefb77..b23299fedfff 100644 --- a/dom/indexedDB/ActorsChild.cpp +++ b/dom/indexedDB/ActorsChild.cpp @@ -2523,7 +2523,7 @@ BackgroundCursorChild::HandleResponse(const void_t& aResponse) void BackgroundCursorChild::HandleResponse( - const ObjectStoreCursorResponse& aResponse) + const nsTArray& aResponses) { AssertIsOnOwningThread(); MOZ_ASSERT(mRequest); @@ -2532,25 +2532,30 @@ BackgroundCursorChild::HandleResponse( MOZ_ASSERT(!mStrongRequest); MOZ_ASSERT(!mStrongCursor); - // XXX Fix this somehow... - auto& response = const_cast(aResponse); - - StructuredCloneReadInfo cloneReadInfo(Move(response.cloneInfo())); - cloneReadInfo.mDatabase = mTransaction->Database(); - - ConvertActorsToBlobs(mTransaction->Database(), - response.cloneInfo(), - cloneReadInfo.mFiles); - - nsRefPtr newCursor; + MOZ_ASSERT(aResponses.Length() == 1); - if (mCursor) { - mCursor->Reset(Move(response.key()), Move(cloneReadInfo)); - } else { - newCursor = IDBCursor::Create(this, - Move(response.key()), - Move(cloneReadInfo)); - mCursor = newCursor; + // XXX Fix this somehow... + auto& responses = + const_cast&>(aResponses); + + for (ObjectStoreCursorResponse& response : responses) { + StructuredCloneReadInfo cloneReadInfo(Move(response.cloneInfo())); + cloneReadInfo.mDatabase = mTransaction->Database(); + + ConvertActorsToBlobs(mTransaction->Database(), + response.cloneInfo(), + cloneReadInfo.mFiles); + + nsRefPtr newCursor; + + if (mCursor) { + mCursor->Reset(Move(response.key()), Move(cloneReadInfo)); + } else { + newCursor = IDBCursor::Create(this, + Move(response.key()), + Move(cloneReadInfo)); + mCursor = newCursor; + } } ResultHelper helper(mRequest, mTransaction, mCursor); @@ -2706,8 +2711,8 @@ BackgroundCursorChild::RecvResponse(const CursorResponse& aResponse) HandleResponse(aResponse.get_void_t()); break; - case CursorResponse::TObjectStoreCursorResponse: - HandleResponse(aResponse.get_ObjectStoreCursorResponse()); + case CursorResponse::TArrayOfObjectStoreCursorResponse: + HandleResponse(aResponse.get_ArrayOfObjectStoreCursorResponse()); break; case CursorResponse::TObjectStoreKeyCursorResponse: diff --git a/dom/indexedDB/ActorsChild.h b/dom/indexedDB/ActorsChild.h index dfe976d0b30b..23d234c14a1a 100644 --- a/dom/indexedDB/ActorsChild.h +++ b/dom/indexedDB/ActorsChild.h @@ -709,7 +709,7 @@ class BackgroundCursorChild final HandleResponse(const void_t& aResponse); void - HandleResponse(const ObjectStoreCursorResponse& aResponse); + HandleResponse(const nsTArray& aResponse); void HandleResponse(const ObjectStoreKeyCursorResponse& aResponse); diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp index de6733962ca2..950b4de0c455 100644 --- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -7597,8 +7597,9 @@ class Cursor final : Start(const OpenCursorParams& aParams); void - SendResponseInternal(CursorResponse& aResponse, - const nsTArray& aFiles); + SendResponseInternal( + CursorResponse& aResponse, + const nsTArray>& aFiles); // Must call SendResponseInternal! bool @@ -7620,7 +7621,7 @@ class Cursor::CursorOpBase { protected: nsRefPtr mCursor; - FallibleTArray mFiles; + nsTArray> mFiles; CursorResponse mResponse; @@ -7647,7 +7648,8 @@ class Cursor::CursorOpBase Cleanup() override; nsresult - PopulateResponseFromStatement(DatabaseConnection::CachedStatement& aStmt); + PopulateResponseFromStatement(DatabaseConnection::CachedStatement& aStmt, + bool aInitializeResponse); }; class Cursor::OpenOp final @@ -14638,8 +14640,9 @@ Cursor::Start(const OpenCursorParams& aParams) } void -Cursor::SendResponseInternal(CursorResponse& aResponse, - const nsTArray& aFiles) +Cursor::SendResponseInternal( + CursorResponse& aResponse, + const nsTArray>& aFiles) { AssertIsOnBackgroundThread(); MOZ_ASSERT(aResponse.type() != CursorResponse::T__None); @@ -14662,30 +14665,38 @@ Cursor::SendResponseInternal(CursorResponse& aResponse, MOZ_ASSERT(!mActorDestroyed); MOZ_ASSERT(mCurrentlyRunningOp); - if (!aFiles.IsEmpty()) { - MOZ_ASSERT(aResponse.type() == CursorResponse::TObjectStoreCursorResponse || - aResponse.type() == CursorResponse::TIndexCursorResponse); - MOZ_ASSERT(mFileManager); - MOZ_ASSERT(mBackgroundParent); + for (size_t i = 0; i < aFiles.Length(); ++i) { + const auto& files = aFiles[i]; + if (!files.IsEmpty()) { + MOZ_ASSERT(aResponse.type() == + CursorResponse::TArrayOfObjectStoreCursorResponse || + aResponse.type() == CursorResponse::TIndexCursorResponse); + MOZ_ASSERT(mFileManager); + MOZ_ASSERT(mBackgroundParent); + + FallibleTArray actors; + FallibleTArray fileInfos; + nsresult rv = ConvertBlobsToActors(mBackgroundParent, + mFileManager, + files, + actors, + fileInfos); + if (NS_WARN_IF(NS_FAILED(rv))) { + aResponse = ClampResultCode(rv); + break; + } - FallibleTArray actors; - FallibleTArray fileInfos; - nsresult rv = ConvertBlobsToActors(mBackgroundParent, - mFileManager, - aFiles, - actors, - fileInfos); - if (NS_WARN_IF(NS_FAILED(rv))) { - aResponse = ClampResultCode(rv); - } else { SerializedStructuredCloneReadInfo* serializedInfo = nullptr; switch (aResponse.type()) { - case CursorResponse::TObjectStoreCursorResponse: - serializedInfo = - &aResponse.get_ObjectStoreCursorResponse().cloneInfo(); + case CursorResponse::TArrayOfObjectStoreCursorResponse: { + auto& responses = aResponse.get_ArrayOfObjectStoreCursorResponse(); + MOZ_ASSERT(i < responses.Length()); + serializedInfo = &responses[i].cloneInfo(); break; + } case CursorResponse::TIndexCursorResponse: + MOZ_ASSERT(i == 0); serializedInfo = &aResponse.get_IndexCursorResponse().cloneInfo(); break; @@ -24308,11 +24319,12 @@ CursorOpBase::Cleanup() nsresult Cursor:: CursorOpBase::PopulateResponseFromStatement( - DatabaseConnection::CachedStatement& aStmt) + DatabaseConnection::CachedStatement& aStmt, + bool aInitializeResponse) { Transaction()->AssertIsOnConnectionThread(); MOZ_ASSERT(mResponse.type() == CursorResponse::T__None); - MOZ_ASSERT(mFiles.IsEmpty()); + MOZ_ASSERT_IF(mFiles.IsEmpty(), aInitializeResponse); nsresult rv = mCursor->mKey.SetFromStatement(aStmt, 0); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -24331,17 +24343,24 @@ CursorOpBase::PopulateResponseFromStatement( return rv; } - mResponse = ObjectStoreCursorResponse(); + if (aInitializeResponse) { + mResponse = nsTArray(); + } else { + MOZ_ASSERT(mResponse.type() == + CursorResponse::TArrayOfObjectStoreCursorResponse); + } - auto& response = mResponse.get_ObjectStoreCursorResponse(); + auto& responses = mResponse.get_ArrayOfObjectStoreCursorResponse(); + auto& response = *responses.AppendElement(); response.cloneInfo().data().SwapElements(cloneInfo.mData); response.key() = mCursor->mKey; - mFiles.SwapElements(cloneInfo.mFiles); + mFiles.AppendElement(Move(cloneInfo.mFiles)); break; } case OpenCursorParams::TObjectStoreOpenKeyCursorParams: { + MOZ_ASSERT(aInitializeResponse); mResponse = ObjectStoreKeyCursorResponse(mCursor->mKey); break; } @@ -24362,6 +24381,7 @@ CursorOpBase::PopulateResponseFromStatement( return rv; } + MOZ_ASSERT(aInitializeResponse); mResponse = IndexCursorResponse(); auto& response = mResponse.get_IndexCursorResponse(); @@ -24369,7 +24389,7 @@ CursorOpBase::PopulateResponseFromStatement( response.key() = mCursor->mKey; response.objectKey() = mCursor->mObjectKey; - mFiles.SwapElements(cloneInfo.mFiles); + mFiles.AppendElement(Move(cloneInfo.mFiles)); break; } @@ -24379,6 +24399,7 @@ CursorOpBase::PopulateResponseFromStatement( return rv; } + MOZ_ASSERT(aInitializeResponse); mResponse = IndexKeyCursorResponse(mCursor->mKey, mCursor->mObjectKey); break; } @@ -24506,7 +24527,7 @@ OpenOp::DoObjectStoreDatabaseWork(DatabaseConnection* aConnection) return NS_OK; } - rv = PopulateResponseFromStatement(stmt); + rv = PopulateResponseFromStatement(stmt, true); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -24665,7 +24686,7 @@ OpenOp::DoObjectStoreKeyDatabaseWork(DatabaseConnection* aConnection) return NS_OK; } - rv = PopulateResponseFromStatement(stmt); + rv = PopulateResponseFromStatement(stmt, true); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -24842,7 +24863,7 @@ OpenOp::DoIndexDatabaseWork(DatabaseConnection* aConnection) return NS_OK; } - rv = PopulateResponseFromStatement(stmt); + rv = PopulateResponseFromStatement(stmt, true); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -25049,7 +25070,7 @@ OpenOp::DoIndexKeyDatabaseWork(DatabaseConnection* aConnection) return NS_OK; } - rv = PopulateResponseFromStatement(stmt); + rv = PopulateResponseFromStatement(stmt, true); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -25348,7 +25369,7 @@ ContinueOp::DoDatabaseWork(DatabaseConnection* aConnection) } } - rv = PopulateResponseFromStatement(stmt); + rv = PopulateResponseFromStatement(stmt, true); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } diff --git a/dom/indexedDB/PBackgroundIDBCursor.ipdl b/dom/indexedDB/PBackgroundIDBCursor.ipdl index 3c755e903f26..1d20e91f4a98 100644 --- a/dom/indexedDB/PBackgroundIDBCursor.ipdl +++ b/dom/indexedDB/PBackgroundIDBCursor.ipdl @@ -64,7 +64,7 @@ union CursorResponse { void_t; nsresult; - ObjectStoreCursorResponse; + ObjectStoreCursorResponse[]; ObjectStoreKeyCursorResponse; IndexCursorResponse; IndexKeyCursorResponse; From 408edaab197778e4a36b6ac3b7d80a7aeebd3c77 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Wed, 19 Aug 2015 14:59:28 -0700 Subject: [PATCH 176/208] Bug 1168606 - Part 4: Allow current key to be provided with PBackgroundIDBCursor::Continue. r=khuey The key is assumed to be unset for now. --- dom/indexedDB/ActorsChild.cpp | 5 +++-- dom/indexedDB/ActorsChild.h | 4 ++-- dom/indexedDB/ActorsParent.cpp | 14 ++++++++++---- dom/indexedDB/IDBCursor.cpp | 4 ++-- dom/indexedDB/PBackgroundIDBCursor.ipdl | 2 +- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/dom/indexedDB/ActorsChild.cpp b/dom/indexedDB/ActorsChild.cpp index b23299fedfff..04d8d0beea40 100644 --- a/dom/indexedDB/ActorsChild.cpp +++ b/dom/indexedDB/ActorsChild.cpp @@ -2444,7 +2444,8 @@ BackgroundCursorChild::AssertIsOnOwningThread() const #endif // DEBUG void -BackgroundCursorChild::SendContinueInternal(const CursorRequestParams& aParams) +BackgroundCursorChild::SendContinueInternal(const CursorRequestParams& aParams, + const Key& aKey) { AssertIsOnOwningThread(); MOZ_ASSERT(mRequest); @@ -2461,7 +2462,7 @@ BackgroundCursorChild::SendContinueInternal(const CursorRequestParams& aParams) mTransaction->OnNewRequest(); - MOZ_ALWAYS_TRUE(PBackgroundIDBCursorChild::SendContinue(aParams)); + MOZ_ALWAYS_TRUE(PBackgroundIDBCursorChild::SendContinue(aParams, aKey)); } void diff --git a/dom/indexedDB/ActorsChild.h b/dom/indexedDB/ActorsChild.h index 23d234c14a1a..5f4c3fde273b 100644 --- a/dom/indexedDB/ActorsChild.h +++ b/dom/indexedDB/ActorsChild.h @@ -660,7 +660,7 @@ class BackgroundCursorChild final #endif void - SendContinueInternal(const CursorRequestParams& aParams); + SendContinueInternal(const CursorRequestParams& aParams, const Key& aKey); void SendDeleteMeInternal(); @@ -729,7 +729,7 @@ class BackgroundCursorChild final // Force callers to use SendContinueInternal. bool - SendContinue(const CursorRequestParams& aParams) = delete; + SendContinue(const CursorRequestParams& aParams, const Key& aKey) = delete; bool SendDeleteMe() = delete; diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp index 950b4de0c455..10e70bbca43b 100644 --- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -7613,7 +7613,7 @@ class Cursor final : RecvDeleteMe() override; virtual bool - RecvContinue(const CursorRequestParams& aParams) override; + RecvContinue(const CursorRequestParams& aParams, const Key& key) override; }; class Cursor::CursorOpBase @@ -7699,12 +7699,16 @@ class Cursor::ContinueOp final friend class Cursor; const CursorRequestParams mParams; + const Key mKey; private: // Only created by Cursor. - ContinueOp(Cursor* aCursor, const CursorRequestParams& aParams) + ContinueOp(Cursor* aCursor, + const CursorRequestParams& aParams, + const Key& aKey) : CursorOpBase(aCursor) , mParams(aParams) + , mKey(aKey) { MOZ_ASSERT(aParams.type() != CursorRequestParams::T__None); } @@ -14755,7 +14759,7 @@ Cursor::RecvDeleteMe() } bool -Cursor::RecvContinue(const CursorRequestParams& aParams) +Cursor::RecvContinue(const CursorRequestParams& aParams, const Key& aKey) { AssertIsOnBackgroundThread(); MOZ_ASSERT(aParams.type() != CursorRequestParams::T__None); @@ -14774,6 +14778,8 @@ Cursor::RecvContinue(const CursorRequestParams& aParams) #endif ; + MOZ_ASSERT(aKey.IsUnset()); + if (!trustParams && !VerifyRequestParams(aParams)) { ASSERT_UNLESS_FUZZING(); return false; @@ -14793,7 +14799,7 @@ Cursor::RecvContinue(const CursorRequestParams& aParams) return true; } - nsRefPtr continueOp = new ContinueOp(this, aParams); + nsRefPtr continueOp = new ContinueOp(this, aParams, aKey); if (NS_WARN_IF(!continueOp->Init(mTransaction))) { continueOp->Cleanup(); return false; diff --git a/dom/indexedDB/IDBCursor.cpp b/dom/indexedDB/IDBCursor.cpp index 3aae7a2793bf..1a3bec288e6a 100644 --- a/dom/indexedDB/IDBCursor.cpp +++ b/dom/indexedDB/IDBCursor.cpp @@ -483,7 +483,7 @@ IDBCursor::Continue(JSContext* aCx, IDB_LOG_STRINGIFY(key)); } - mBackgroundActor->SendContinueInternal(ContinueParams(key)); + mBackgroundActor->SendContinueInternal(ContinueParams(key), Key()); mContinueCalled = true; } @@ -541,7 +541,7 @@ IDBCursor::Advance(uint32_t aCount, ErrorResult &aRv) aCount); } - mBackgroundActor->SendContinueInternal(AdvanceParams(aCount)); + mBackgroundActor->SendContinueInternal(AdvanceParams(aCount), Key()); mContinueCalled = true; } diff --git a/dom/indexedDB/PBackgroundIDBCursor.ipdl b/dom/indexedDB/PBackgroundIDBCursor.ipdl index 1d20e91f4a98..311abde744d6 100644 --- a/dom/indexedDB/PBackgroundIDBCursor.ipdl +++ b/dom/indexedDB/PBackgroundIDBCursor.ipdl @@ -77,7 +77,7 @@ protocol PBackgroundIDBCursor parent: DeleteMe(); - Continue(CursorRequestParams params); + Continue(CursorRequestParams params, Key key); child: __delete__(); From e8c70d7822beb2aef85395a710f62cd704894f47 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Wed, 19 Aug 2015 14:59:29 -0700 Subject: [PATCH 177/208] Bug 1168606 - Part 5: Send two records with every ObjectStoreCursorResponse. r=khuey --- dom/indexedDB/ActorsChild.cpp | 88 +++++++++++++++++++++++++++++++++- dom/indexedDB/ActorsChild.h | 19 ++++++++ dom/indexedDB/ActorsParent.cpp | 42 ++++++++++------ dom/indexedDB/IDBCursor.cpp | 8 +++- dom/indexedDB/IDBCursor.h | 2 + 5 files changed, 140 insertions(+), 19 deletions(-) diff --git a/dom/indexedDB/ActorsChild.cpp b/dom/indexedDB/ActorsChild.cpp index 04d8d0beea40..17884a268ae4 100644 --- a/dom/indexedDB/ActorsChild.cpp +++ b/dom/indexedDB/ActorsChild.cpp @@ -2462,7 +2462,66 @@ BackgroundCursorChild::SendContinueInternal(const CursorRequestParams& aParams, mTransaction->OnNewRequest(); - MOZ_ALWAYS_TRUE(PBackgroundIDBCursorChild::SendContinue(aParams, aKey)); + CursorRequestParams params = aParams; + Key key = aKey; + + switch (params.type()) { + case CursorRequestParams::TContinueParams: { + if (key.IsUnset()) { + break; + } + while (!mCachedResponses.IsEmpty()) { + if (mCachedResponses[0].mKey == key) { + break; + } + mCachedResponses.RemoveElementAt(0); + } + break; + } + + case CursorRequestParams::TAdvanceParams: { + uint32_t& advanceCount = params.get_AdvanceParams().count(); + while (advanceCount > 1 && !mCachedResponses.IsEmpty()) { + key = mCachedResponses[0].mKey; + mCachedResponses.RemoveElementAt(0); + --advanceCount; + } + break; + } + + default: + MOZ_CRASH("Should never get here!"); + } + + if (!mCachedResponses.IsEmpty()) { + nsCOMPtr continueRunnable = new DelayedActionRunnable( + this, &BackgroundCursorChild::SendDelayedContinueInternal); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(continueRunnable))); + } else { + MOZ_ALWAYS_TRUE(PBackgroundIDBCursorChild::SendContinue(params, key)); + } +} + +void +BackgroundCursorChild::SendDelayedContinueInternal() +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(mTransaction); + MOZ_ASSERT(mCursor); + MOZ_ASSERT(mStrongCursor); + MOZ_ASSERT(!mCachedResponses.IsEmpty()); + + nsRefPtr cursor; + mStrongCursor.swap(cursor); + + auto& item = mCachedResponses[0]; + mCursor->Reset(Move(item.mKey), Move(item.mCloneInfo)); + mCachedResponses.RemoveElementAt(0); + + ResultHelper helper(mRequest, mTransaction, mCursor); + DispatchSuccessEvent(&helper); + + mTransaction->OnRequestFinished(/* aActorDestroyedNormally */ true); } void @@ -2485,6 +2544,14 @@ BackgroundCursorChild::SendDeleteMeInternal() } } +void +BackgroundCursorChild::InvalidateCachedResponses() +{ + AssertIsOnOwningThread(); + + mCachedResponses.Clear(); +} + void BackgroundCursorChild::HandleResponse(nsresult aResponse) { @@ -2550,7 +2617,14 @@ BackgroundCursorChild::HandleResponse( nsRefPtr newCursor; if (mCursor) { - mCursor->Reset(Move(response.key()), Move(cloneReadInfo)); + if (mCursor->IsContinueCalled()) { + mCursor->Reset(Move(response.key()), Move(cloneReadInfo)); + } else { + CachedResponse cachedResponse; + cachedResponse.mKey = Move(response.key()); + cachedResponse.mCloneInfo = Move(cloneReadInfo); + mCachedResponses.AppendElement(Move(cachedResponse)); + } } else { newCursor = IDBCursor::Create(this, Move(response.key()), @@ -2792,6 +2866,16 @@ DelayedActionRunnable::Cancel() return NS_OK; } +BackgroundCursorChild::CachedResponse::CachedResponse() +{ +} + +BackgroundCursorChild::CachedResponse::CachedResponse(CachedResponse&& aOther) + : mKey(Move(aOther.mKey)) +{ + mCloneInfo = Move(aOther.mCloneInfo); +} + } // namespace indexedDB } // namespace dom } // namespace mozilla diff --git a/dom/indexedDB/ActorsChild.h b/dom/indexedDB/ActorsChild.h index 5f4c3fde273b..25bba42726db 100644 --- a/dom/indexedDB/ActorsChild.h +++ b/dom/indexedDB/ActorsChild.h @@ -626,6 +626,17 @@ class BackgroundCursorChild final class DelayedActionRunnable; + struct CachedResponse + { + CachedResponse(); + + explicit CachedResponse(CachedResponse&& aOther); + + Key mKey; + Key mObjectKey; + StructuredCloneReadInfo mCloneInfo; + }; + IDBRequest* mRequest; IDBTransaction* mTransaction; IDBObjectStore* mObjectStore; @@ -642,6 +653,8 @@ class BackgroundCursorChild final PRThread* mOwningThread; #endif + nsTArray mCachedResponses; + public: BackgroundCursorChild(IDBRequest* aRequest, IDBObjectStore* aObjectStore, @@ -665,6 +678,9 @@ class BackgroundCursorChild final void SendDeleteMeInternal(); + void + InvalidateCachedResponses(); + IDBRequest* GetRequest() const { @@ -702,6 +718,9 @@ class BackgroundCursorChild final // BackgroundVersionChangeTransactionChild. ~BackgroundCursorChild(); + void + SendDelayedContinueInternal(); + void HandleResponse(nsresult aResponse); diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp index 10e70bbca43b..8e96517e8b85 100644 --- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -14778,8 +14778,6 @@ Cursor::RecvContinue(const CursorRequestParams& aParams, const Key& aKey) #endif ; - MOZ_ASSERT(aKey.IsUnset()); - if (!trustParams && !VerifyRequestParams(aParams)) { ASSERT_UNLESS_FUZZING(); return false; @@ -25284,33 +25282,30 @@ ContinueOp::DoDatabaseWork(DatabaseConnection* aConnection) // Note: Changing the number or order of SELECT columns in the query will // require changes to CursorOpBase::PopulateResponseFromStatement. - nsCString query; - nsAutoCString countString; - bool hasContinueKey = false; - uint32_t advanceCount; + uint32_t advanceCount = 1; if (mParams.type() == CursorRequestParams::TContinueParams) { // Always go to the next result. - advanceCount = 1; - countString.AppendLiteral("1"); - if (mParams.get_ContinueParams().key().IsUnset()) { - query = mCursor->mContinueQuery + countString; hasContinueKey = false; } else { - query = mCursor->mContinueToQuery + countString; hasContinueKey = true; } } else { advanceCount = mParams.get_AdvanceParams().count(); - MOZ_ASSERT(advanceCount > 0); - countString.AppendInt(advanceCount); - - query = mCursor->mContinueQuery + countString; hasContinueKey = false; } + const nsCString& continueQuery = + hasContinueKey ? mCursor->mContinueToQuery : mCursor->mContinueQuery; + + MOZ_ASSERT(advanceCount > 0); + nsAutoCString countString; + countString.AppendInt(advanceCount); + + nsCString query = continueQuery + countString; + NS_NAMED_LITERAL_CSTRING(currentKeyName, "current_key"); NS_NAMED_LITERAL_CSTRING(rangeKeyName, "range_key"); NS_NAMED_LITERAL_CSTRING(objectKeyName, "object_key"); @@ -25380,6 +25375,23 @@ ContinueOp::DoDatabaseWork(DatabaseConnection* aConnection) return rv; } + uint32_t extraCount = 1; + for (uint32_t i = 0; i < extraCount; i++) { + rv = stmt->ExecuteStep(&hasResult); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!hasResult) { + break; + } + + rv = PopulateResponseFromStatement(stmt, false); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + return NS_OK; } diff --git a/dom/indexedDB/IDBCursor.cpp b/dom/indexedDB/IDBCursor.cpp index 1a3bec288e6a..52bbcab3031f 100644 --- a/dom/indexedDB/IDBCursor.cpp +++ b/dom/indexedDB/IDBCursor.cpp @@ -483,7 +483,7 @@ IDBCursor::Continue(JSContext* aCx, IDB_LOG_STRINGIFY(key)); } - mBackgroundActor->SendContinueInternal(ContinueParams(key), Key()); + mBackgroundActor->SendContinueInternal(ContinueParams(key), mKey); mContinueCalled = true; } @@ -541,7 +541,7 @@ IDBCursor::Advance(uint32_t aCount, ErrorResult &aRv) aCount); } - mBackgroundActor->SendContinueInternal(AdvanceParams(aCount), Key()); + mBackgroundActor->SendContinueInternal(AdvanceParams(aCount), mKey); mContinueCalled = true; } @@ -574,6 +574,8 @@ IDBCursor::Update(JSContext* aCx, JS::Handle aValue, MOZ_ASSERT(!mKey.IsUnset()); MOZ_ASSERT_IF(mType == Type_Index, !mPrimaryKey.IsUnset()); + mBackgroundActor->InvalidateCachedResponses(); + IDBObjectStore* objectStore; if (mType == Type_ObjectStore) { objectStore = mSourceObjectStore; @@ -691,6 +693,8 @@ IDBCursor::Delete(JSContext* aCx, ErrorResult& aRv) MOZ_ASSERT(mType == Type_ObjectStore || mType == Type_Index); MOZ_ASSERT(!mKey.IsUnset()); + mBackgroundActor->InvalidateCachedResponses(); + IDBObjectStore* objectStore; if (mType == Type_ObjectStore) { objectStore = mSourceObjectStore; diff --git a/dom/indexedDB/IDBCursor.h b/dom/indexedDB/IDBCursor.h index fd68366fbb3e..b7dff8318392 100644 --- a/dom/indexedDB/IDBCursor.h +++ b/dom/indexedDB/IDBCursor.h @@ -130,6 +130,8 @@ class IDBCursor final IDBCursorDirection GetDirection() const; + bool IsContinueCalled() const { return mContinueCalled; } + void GetKey(JSContext* aCx, JS::MutableHandle aResult, From 452068192088251581e24d5007db3196d524ce11 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Fri, 21 Aug 2015 19:53:29 -0700 Subject: [PATCH 178/208] Bug 1105827 - Part 6: Add PermissionUtils.h for helper functions. r=baku --- dom/permission/PermissionUtils.cpp | 29 +++++++++++++++++++++++++++++ dom/permission/PermissionUtils.h | 20 ++++++++++++++++++++ dom/permission/Permissions.cpp | 18 +----------------- dom/permission/moz.build | 1 + 4 files changed, 51 insertions(+), 17 deletions(-) create mode 100644 dom/permission/PermissionUtils.cpp create mode 100644 dom/permission/PermissionUtils.h diff --git a/dom/permission/PermissionUtils.cpp b/dom/permission/PermissionUtils.cpp new file mode 100644 index 000000000000..70a478b4305d --- /dev/null +++ b/dom/permission/PermissionUtils.cpp @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#include "PermissionUtils.h" + +namespace mozilla { +namespace dom { + +PermissionState +ActionToPermissionState(uint32_t aAction) +{ + switch (aAction) { + case nsIPermissionManager::ALLOW_ACTION: + return PermissionState::Granted; + + case nsIPermissionManager::DENY_ACTION: + return PermissionState::Denied; + + default: + case nsIPermissionManager::PROMPT_ACTION: + return PermissionState::Prompt; + } +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/permission/PermissionUtils.h b/dom/permission/PermissionUtils.h new file mode 100644 index 000000000000..ebf6a43c435b --- /dev/null +++ b/dom/permission/PermissionUtils.h @@ -0,0 +1,20 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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_PermissionUtils_h_ +#define mozilla_dom_PermissionUtils_h_ + +#include "mozilla/dom/PermissionsBinding.h" + +namespace mozilla { +namespace dom { + +PermissionState ActionToPermissionState(uint32_t aAction); + +} // namespace dom +} // namespace mozilla + +#endif diff --git a/dom/permission/Permissions.cpp b/dom/permission/Permissions.cpp index c7518f9983f2..36e046dd587e 100644 --- a/dom/permission/Permissions.cpp +++ b/dom/permission/Permissions.cpp @@ -9,8 +9,8 @@ #include "mozilla/dom/PermissionsBinding.h" #include "mozilla/dom/Promise.h" #include "mozilla/Services.h" - #include "nsIPermissionManager.h" +#include "PermissionUtils.h" namespace mozilla { namespace dom { @@ -42,22 +42,6 @@ Permissions::WrapObject(JSContext* aCx, JS::Handle aGivenProto) namespace { -PermissionState -ActionToPermissionState(uint32_t aAction) -{ - switch (aAction) { - case nsIPermissionManager::ALLOW_ACTION: - return PermissionState::Granted; - - case nsIPermissionManager::DENY_ACTION: - return PermissionState::Denied; - - default: - case nsIPermissionManager::PROMPT_ACTION: - return PermissionState::Prompt; - } -} - nsresult CheckPermission(const char* aName, nsPIDOMWindow* aWindow, diff --git a/dom/permission/moz.build b/dom/permission/moz.build index b027459d55f2..34e599b2efd0 100644 --- a/dom/permission/moz.build +++ b/dom/permission/moz.build @@ -12,6 +12,7 @@ EXPORTS.mozilla.dom += [ UNIFIED_SOURCES += [ 'Permissions.cpp', 'PermissionStatus.cpp', + 'PermissionUtils.cpp', ] EXTRA_COMPONENTS += [ From 8288ba6f9bc585ef1a049b009e11e0d138b9635d Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Fri, 21 Aug 2015 19:53:29 -0700 Subject: [PATCH 179/208] Bug 1105827 - Part 7: Add helpers to convert between PermissionName and permission type. r=baku --- dom/permission/PermissionUtils.cpp | 33 ++++++++++++++++++++++++++++++ dom/permission/PermissionUtils.h | 5 +++++ dom/permission/Permissions.cpp | 13 ++++++------ 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/dom/permission/PermissionUtils.cpp b/dom/permission/PermissionUtils.cpp index 70a478b4305d..c873f154127a 100644 --- a/dom/permission/PermissionUtils.cpp +++ b/dom/permission/PermissionUtils.cpp @@ -9,6 +9,39 @@ namespace mozilla { namespace dom { +const char* kPermissionTypes[] = { + "geo", + "desktop-notification", + "push", + "midi" +}; + +// `-1` for the last null entry. +const size_t kPermissionNameCount = + MOZ_ARRAY_LENGTH(PermissionNameValues::strings) - 1; + +static_assert(MOZ_ARRAY_LENGTH(kPermissionTypes) == kPermissionNameCount, + "kPermissionTypes and PermissionName count should match"); + +const char* +PermissionNameToType(PermissionName aName) +{ + MOZ_ASSERT((size_t)aName < ArrayLength(kPermissionTypes)); + return kPermissionTypes[static_cast(aName)]; +} + +Maybe +TypeToPermissionName(const char* aType) +{ + for (size_t i = 0; i < ArrayLength(kPermissionTypes); ++i) { + if (!strcmp(aType, kPermissionTypes[i])) { + return Some(static_cast(i)); + } + } + + return Nothing(); +} + PermissionState ActionToPermissionState(uint32_t aAction) { diff --git a/dom/permission/PermissionUtils.h b/dom/permission/PermissionUtils.h index ebf6a43c435b..34bf7573d876 100644 --- a/dom/permission/PermissionUtils.h +++ b/dom/permission/PermissionUtils.h @@ -8,10 +8,15 @@ #define mozilla_dom_PermissionUtils_h_ #include "mozilla/dom/PermissionsBinding.h" +#include "mozilla/dom/PermissionStatusBinding.h" +#include "mozilla/Maybe.h" namespace mozilla { namespace dom { +const char* PermissionNameToType(PermissionName aName); +Maybe TypeToPermissionName(const char* aType); + PermissionState ActionToPermissionState(uint32_t aAction); } // namespace dom diff --git a/dom/permission/Permissions.cpp b/dom/permission/Permissions.cpp index 36e046dd587e..acb7be81abc1 100644 --- a/dom/permission/Permissions.cpp +++ b/dom/permission/Permissions.cpp @@ -43,11 +43,10 @@ Permissions::WrapObject(JSContext* aCx, JS::Handle aGivenProto) namespace { nsresult -CheckPermission(const char* aName, +CheckPermission(PermissionName aName, nsPIDOMWindow* aWindow, PermissionState& aResult) { - MOZ_ASSERT(aName); MOZ_ASSERT(aWindow); nsCOMPtr permMgr = services::GetPermissionManager(); @@ -56,7 +55,9 @@ CheckPermission(const char* aName, } uint32_t action = nsIPermissionManager::DENY_ACTION; - nsresult rv = permMgr->TestPermissionFromWindow(aWindow, aName, &action); + nsresult rv = permMgr->TestPermissionFromWindow(aWindow, + PermissionNameToType(aName), + &action); if (NS_WARN_IF(NS_FAILED(rv))) { return NS_ERROR_FAILURE; } @@ -81,7 +82,7 @@ CheckPushPermission(JSContext* aCx, return NS_ERROR_NOT_IMPLEMENTED; } - return CheckPermission("push", aWindow, aResult); + return CheckPermission(permission.mName, aWindow, aResult); } nsresult @@ -98,10 +99,8 @@ CheckPermission(JSContext* aCx, switch (permission.mName) { case PermissionName::Geolocation: - return CheckPermission("geo", aWindow, aResult); - case PermissionName::Notifications: - return CheckPermission("desktop-notification", aWindow, aResult); + return CheckPermission(permission.mName, aWindow, aResult); case PermissionName::Push: return CheckPushPermission(aCx, aPermission, aWindow, aResult); From e2c8857d62658360de448700b4be375e36652b34 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Fri, 21 Aug 2015 19:53:29 -0700 Subject: [PATCH 180/208] Bug 1105827 - Part 8: Move permission checking into PermissionStatus. r=baku --- dom/permission/PermissionStatus.cpp | 52 +++++++++++++++++++++++++-- dom/permission/PermissionStatus.h | 12 +++++-- dom/permission/Permissions.cpp | 54 +++++++++-------------------- 3 files changed, 75 insertions(+), 43 deletions(-) diff --git a/dom/permission/PermissionStatus.cpp b/dom/permission/PermissionStatus.cpp index 862e9be5b5fa..efce7d8ac650 100644 --- a/dom/permission/PermissionStatus.cpp +++ b/dom/permission/PermissionStatus.cpp @@ -5,17 +5,38 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/PermissionStatus.h" -#include "mozilla/Services.h" +#include "mozilla/Services.h" +#include "mozilla/UniquePtr.h" #include "nsIPermissionManager.h" +#include "PermissionUtils.h" namespace mozilla { namespace dom { +/* static */ nsresult +PermissionStatus::Create(nsPIDOMWindow* aWindow, + PermissionName aName, + PermissionStatus** aStatus) +{ + MOZ_ASSERT(aStatus); + *aStatus = nullptr; + + UniquePtr status(new PermissionStatus(aWindow, aName)); + nsresult rv = status->UpdateState(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + *aStatus = status.release(); + return NS_OK; +} + PermissionStatus::PermissionStatus(nsPIDOMWindow* aWindow, - PermissionState aState) + PermissionName aName) : DOMEventTargetHelper(aWindow) - , mState(aState) + , mName(aName) + , mState(PermissionState::Denied) { } @@ -29,5 +50,30 @@ PermissionStatus::WrapObject(JSContext* aCx, JS::Handle aGivenProto) return PermissionStatusBinding::Wrap(aCx, this, aGivenProto); } +nsresult +PermissionStatus::UpdateState() +{ + nsCOMPtr permMgr = services::GetPermissionManager(); + if (NS_WARN_IF(!permMgr)) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr window = do_QueryInterface(GetOwner()); + if (NS_WARN_IF(!window)) { + return NS_ERROR_FAILURE; + } + + uint32_t action = nsIPermissionManager::DENY_ACTION; + nsresult rv = permMgr->TestPermissionFromWindow(window, + PermissionNameToType(mName), + &action); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + mState = ActionToPermissionState(action); + return NS_OK; +} + } // namespace dom } // namespace mozilla diff --git a/dom/permission/PermissionStatus.h b/dom/permission/PermissionStatus.h index b4c0e1a73e79..ca15d562cd2a 100644 --- a/dom/permission/PermissionStatus.h +++ b/dom/permission/PermissionStatus.h @@ -7,6 +7,7 @@ #ifndef mozilla_dom_PermissionStatus_h_ #define mozilla_dom_PermissionStatus_h_ +#include "mozilla/dom/PermissionsBinding.h" #include "mozilla/dom/PermissionStatusBinding.h" #include "mozilla/DOMEventTargetHelper.h" @@ -17,7 +18,11 @@ class PermissionStatus final : public DOMEventTargetHelper { public: - explicit PermissionStatus(nsPIDOMWindow* aWindow, PermissionState aState); + ~PermissionStatus(); + + static nsresult Create(nsPIDOMWindow* aWindow, + PermissionName aName, + PermissionStatus** aStatus); JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; @@ -27,8 +32,11 @@ class PermissionStatus final IMPL_EVENT_HANDLER(change) private: - ~PermissionStatus(); + PermissionStatus(nsPIDOMWindow* aWindow, PermissionName aName); + + nsresult UpdateState(); + PermissionName mName; PermissionState mState; }; diff --git a/dom/permission/Permissions.cpp b/dom/permission/Permissions.cpp index acb7be81abc1..cec3fe9c590d 100644 --- a/dom/permission/Permissions.cpp +++ b/dom/permission/Permissions.cpp @@ -43,34 +43,10 @@ Permissions::WrapObject(JSContext* aCx, JS::Handle aGivenProto) namespace { nsresult -CheckPermission(PermissionName aName, - nsPIDOMWindow* aWindow, - PermissionState& aResult) -{ - MOZ_ASSERT(aWindow); - - nsCOMPtr permMgr = services::GetPermissionManager(); - if (NS_WARN_IF(!permMgr)) { - return NS_ERROR_FAILURE; - } - - uint32_t action = nsIPermissionManager::DENY_ACTION; - nsresult rv = permMgr->TestPermissionFromWindow(aWindow, - PermissionNameToType(aName), - &action); - if (NS_WARN_IF(NS_FAILED(rv))) { - return NS_ERROR_FAILURE; - } - - aResult = ActionToPermissionState(action); - return NS_OK; -} - -nsresult -CheckPushPermission(JSContext* aCx, - JS::Handle aPermission, - nsPIDOMWindow* aWindow, - PermissionState& aResult) +CreatePushPermissionStatus(JSContext* aCx, + JS::Handle aPermission, + nsPIDOMWindow* aWindow, + PermissionStatus** aResult) { PushPermissionDescriptor permission; JS::Rooted value(aCx, JS::ObjectOrNullValue(aPermission)); @@ -82,14 +58,14 @@ CheckPushPermission(JSContext* aCx, return NS_ERROR_NOT_IMPLEMENTED; } - return CheckPermission(permission.mName, aWindow, aResult); + return PermissionStatus::Create(aWindow, permission.mName, aResult); } nsresult -CheckPermission(JSContext* aCx, - JS::Handle aPermission, - nsPIDOMWindow* aWindow, - PermissionState& aResult) +CreatePermissionStatus(JSContext* aCx, + JS::Handle aPermission, + nsPIDOMWindow* aWindow, + PermissionStatus** aResult) { PermissionDescriptor permission; JS::Rooted value(aCx, JS::ObjectOrNullValue(aPermission)); @@ -100,10 +76,10 @@ CheckPermission(JSContext* aCx, switch (permission.mName) { case PermissionName::Geolocation: case PermissionName::Notifications: - return CheckPermission(permission.mName, aWindow, aResult); + return PermissionStatus::Create(aWindow, permission.mName, aResult); case PermissionName::Push: - return CheckPushPermission(aCx, aPermission, aWindow, aResult); + return CreatePushPermissionStatus(aCx, aPermission, aWindow, aResult); case PermissionName::Midi: default: @@ -129,12 +105,14 @@ Permissions::Query(JSContext* aCx, return nullptr; } - PermissionState state = PermissionState::Denied; - nsresult rv = CheckPermission(aCx, aPermission, mWindow, state); + PermissionStatus* status = nullptr; + nsresult rv = CreatePermissionStatus(aCx, aPermission, mWindow, &status); if (NS_WARN_IF(NS_FAILED(rv))) { + MOZ_ASSERT(!status); promise->MaybeReject(rv); } else { - promise->MaybeResolve(new PermissionStatus(mWindow, state)); + MOZ_ASSERT(status); + promise->MaybeResolve(status); } return promise.forget(); } From db79369b9ffd88823d29ef812652e7b7c8819b27 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Fri, 21 Aug 2015 19:53:29 -0700 Subject: [PATCH 181/208] Bug 1105827 - Part 9: Add PermissionObserver to watch for perm-changed notifications. r=baku --- dom/permission/PermissionObserver.cpp | 131 ++++++++++++++++++++++++++ dom/permission/PermissionObserver.h | 49 ++++++++++ dom/permission/PermissionStatus.cpp | 40 +++++++- dom/permission/PermissionStatus.h | 12 +++ dom/permission/moz.build | 1 + 5 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 dom/permission/PermissionObserver.cpp create mode 100644 dom/permission/PermissionObserver.h diff --git a/dom/permission/PermissionObserver.cpp b/dom/permission/PermissionObserver.cpp new file mode 100644 index 000000000000..65b7bc303add --- /dev/null +++ b/dom/permission/PermissionObserver.cpp @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#include "PermissionObserver.h" + +#include "mozilla/dom/PermissionStatus.h" +#include "mozilla/Services.h" +#include "mozilla/UniquePtr.h" +#include "nsIObserverService.h" +#include "nsIPermission.h" +#include "PermissionUtils.h" + +namespace mozilla { +namespace dom { + +namespace { +PermissionObserver* gInstance = nullptr; +} // namespace + +NS_IMPL_ISUPPORTS(PermissionObserver, + nsIObserver, + nsISupportsWeakReference) + +PermissionObserver::PermissionObserver() +{ + MOZ_ASSERT(!gInstance); +} + +PermissionObserver::~PermissionObserver() +{ + MOZ_ASSERT(mSinks.IsEmpty()); + MOZ_ASSERT(gInstance == this); + + gInstance = nullptr; +} + +/* static */ already_AddRefed +PermissionObserver::GetInstance() +{ + nsRefPtr instance = gInstance; + if (!instance) { + instance = new PermissionObserver(); + + nsCOMPtr obs = services::GetObserverService(); + if (NS_WARN_IF(!obs)) { + return nullptr; + } + + nsresult rv = obs->AddObserver(instance, "perm-changed", true); + if (NS_WARN_IF(NS_FAILED(rv))) { + return nullptr; + } + + gInstance = instance; + } + + return instance.forget(); +} + +void +PermissionObserver::AddSink(PermissionStatus* aSink) +{ + MOZ_ASSERT(aSink); + MOZ_ASSERT(!mSinks.Contains(aSink)); + + mSinks.AppendElement(aSink); +} + +void +PermissionObserver::RemoveSink(PermissionStatus* aSink) +{ + MOZ_ASSERT(aSink); + MOZ_ASSERT(mSinks.Contains(aSink)); + + mSinks.RemoveElement(aSink); +} + +void +PermissionObserver::Notify(PermissionName aName, nsIPrincipal& aPrincipal) +{ + for (auto* sink : mSinks) { + if (sink->mName != aName) { + continue; + } + + nsIPrincipal* sinkPrincipal = sink->GetPrincipal(); + if (NS_WARN_IF(!sinkPrincipal) || !aPrincipal.Equals(sinkPrincipal)) { + continue; + } + + sink->PermissionChanged(); + } +} + +NS_IMETHODIMP +PermissionObserver::Observe(nsISupports* aSubject, + const char* aTopic, + const char16_t* aData) +{ + MOZ_ASSERT(!strcmp(aTopic, "perm-changed")); + + if (mSinks.IsEmpty()) { + return NS_OK; + } + + nsCOMPtr perm = do_QueryInterface(aSubject); + if (!perm) { + return NS_OK; + } + + nsCOMPtr principal; + perm->GetPrincipal(getter_AddRefs(principal)); + if (!principal) { + return NS_OK; + } + + nsAutoCString type; + perm->GetType(type); + Maybe permission = TypeToPermissionName(type.get()); + if (permission) { + Notify(permission.value(), *principal); + } + + return NS_OK; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/permission/PermissionObserver.h b/dom/permission/PermissionObserver.h new file mode 100644 index 000000000000..e92452b8d03d --- /dev/null +++ b/dom/permission/PermissionObserver.h @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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_PermissionObserver_h_ +#define mozilla_dom_PermissionObserver_h_ + +#include "mozilla/dom/PermissionsBinding.h" + +#include "nsIObserver.h" +#include "nsIPrincipal.h" +#include "nsTArray.h" +#include "nsWeakReference.h" + +namespace mozilla { +namespace dom { + +class PermissionStatus; + +// Singleton that watches for perm-changed notifications in order to notify +// PermissionStatus objects. +class PermissionObserver final + : public nsIObserver + , public nsSupportsWeakReference +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + + static already_AddRefed GetInstance(); + + void AddSink(PermissionStatus* aObs); + void RemoveSink(PermissionStatus* aObs); + +private: + PermissionObserver(); + virtual ~PermissionObserver(); + + void Notify(PermissionName aName, nsIPrincipal& aPrincipal); + + nsTArray mSinks; +}; + +} // namespace dom +} // namespace mozilla + +#endif diff --git a/dom/permission/PermissionStatus.cpp b/dom/permission/PermissionStatus.cpp index efce7d8ac650..f9662ac814f2 100644 --- a/dom/permission/PermissionStatus.cpp +++ b/dom/permission/PermissionStatus.cpp @@ -9,6 +9,7 @@ #include "mozilla/Services.h" #include "mozilla/UniquePtr.h" #include "nsIPermissionManager.h" +#include "PermissionObserver.h" #include "PermissionUtils.h" namespace mozilla { @@ -23,7 +24,7 @@ PermissionStatus::Create(nsPIDOMWindow* aWindow, *aStatus = nullptr; UniquePtr status(new PermissionStatus(aWindow, aName)); - nsresult rv = status->UpdateState(); + nsresult rv = status->Init(); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -40,8 +41,29 @@ PermissionStatus::PermissionStatus(nsPIDOMWindow* aWindow, { } +nsresult +PermissionStatus::Init() +{ + mObserver = PermissionObserver::GetInstance(); + if (NS_WARN_IF(!mObserver)) { + return NS_ERROR_FAILURE; + } + + mObserver->AddSink(this); + + nsresult rv = UpdateState(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + PermissionStatus::~PermissionStatus() { + if (mObserver) { + mObserver->RemoveSink(this); + } } JSObject* @@ -75,5 +97,21 @@ PermissionStatus::UpdateState() return NS_OK; } +nsIPrincipal* +PermissionStatus::GetPrincipal() const +{ + nsCOMPtr window = do_QueryInterface(GetOwner()); + if (NS_WARN_IF(!window)) { + return nullptr; + } + + nsIDocument* doc = window->GetExtantDoc(); + if (NS_WARN_IF(!doc)) { + return nullptr; + } + + return doc->NodePrincipal(); +} + } // namespace dom } // namespace mozilla diff --git a/dom/permission/PermissionStatus.h b/dom/permission/PermissionStatus.h index ca15d562cd2a..605d99d65052 100644 --- a/dom/permission/PermissionStatus.h +++ b/dom/permission/PermissionStatus.h @@ -14,9 +14,13 @@ namespace mozilla { namespace dom { +class PermissionObserver; + class PermissionStatus final : public DOMEventTargetHelper { + friend class PermissionObserver; + public: ~PermissionStatus(); @@ -34,10 +38,18 @@ class PermissionStatus final private: PermissionStatus(nsPIDOMWindow* aWindow, PermissionName aName); + nsresult Init(); + nsresult UpdateState(); + nsIPrincipal* GetPrincipal() const; + + void PermissionChanged() {} + PermissionName mName; PermissionState mState; + + nsRefPtr mObserver; }; } // namespace dom diff --git a/dom/permission/moz.build b/dom/permission/moz.build index 34e599b2efd0..b64d199238a9 100644 --- a/dom/permission/moz.build +++ b/dom/permission/moz.build @@ -10,6 +10,7 @@ EXPORTS.mozilla.dom += [ ] UNIFIED_SOURCES += [ + 'PermissionObserver.cpp', 'Permissions.cpp', 'PermissionStatus.cpp', 'PermissionUtils.cpp', From ef715c7098f6f1b94fc1c28691c0f4349be1c73e Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Fri, 21 Aug 2015 19:53:29 -0700 Subject: [PATCH 182/208] Bug 1105827 - Part 10: Fire change event for PermissionStatus objects. r=baku --- dom/permission/PermissionStatus.cpp | 13 ++++++ dom/permission/PermissionStatus.h | 2 +- .../tests/test_permissions_api.html | 44 ++++++++++++++++--- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/dom/permission/PermissionStatus.cpp b/dom/permission/PermissionStatus.cpp index f9662ac814f2..e966b18c835b 100644 --- a/dom/permission/PermissionStatus.cpp +++ b/dom/permission/PermissionStatus.cpp @@ -6,6 +6,7 @@ #include "mozilla/dom/PermissionStatus.h" +#include "mozilla/AsyncEventDispatcher.h" #include "mozilla/Services.h" #include "mozilla/UniquePtr.h" #include "nsIPermissionManager.h" @@ -113,5 +114,17 @@ PermissionStatus::GetPrincipal() const return doc->NodePrincipal(); } +void +PermissionStatus::PermissionChanged() +{ + auto oldState = mState; + UpdateState(); + if (mState != oldState) { + nsRefPtr eventDispatcher = + new AsyncEventDispatcher(this, NS_LITERAL_STRING("change"), false); + eventDispatcher->PostDOMEvent(); + } +} + } // namespace dom } // namespace mozilla diff --git a/dom/permission/PermissionStatus.h b/dom/permission/PermissionStatus.h index 605d99d65052..61e3df739808 100644 --- a/dom/permission/PermissionStatus.h +++ b/dom/permission/PermissionStatus.h @@ -44,7 +44,7 @@ class PermissionStatus final nsIPrincipal* GetPrincipal() const; - void PermissionChanged() {} + void PermissionChanged(); PermissionName mName; PermissionState mState; diff --git a/dom/permission/tests/test_permissions_api.html b/dom/permission/tests/test_permissions_api.html index bf122631e5e8..d05c021976b1 100644 --- a/dom/permission/tests/test_permissions_api.html +++ b/dom/permission/tests/test_permissions_api.html @@ -15,6 +15,9 @@ + + + + +

+link + + + + + + +

+ +
+
+
+ + From b873e054a4f150ebe1bae1de580e9416aaac694b Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 22 Aug 2015 13:02:39 +0900 Subject: [PATCH 190/208] Bug 930843 part.2 NS_UI_ACTIVATE event should be trusted event even if it's caused by an untrusted event r=smaug --- dom/base/Element.cpp | 9 ++++++--- dom/events/UIEvent.cpp | 2 +- dom/html/HTMLButtonElement.cpp | 7 +++---- dom/html/HTMLInputElement.cpp | 7 +++---- widget/BasicEvents.h | 25 +++++++++++++++++++++++-- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 462a7857f691..a010c2f2bee5 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -2983,7 +2983,9 @@ Element::PostHandleEventForLinks(EventChainPostVisitor& aVisitor) if (shell) { // single-click nsEventStatus status = nsEventStatus_eIgnore; - InternalUIEvent actEvent(mouseEvent->mFlags.mIsTrusted, NS_UI_ACTIVATE); + // DOMActive event should be trusted since the activation is actually + // occurred even if the cause is an untrusted click event. + InternalUIEvent actEvent(true, NS_UI_ACTIVATE, mouseEvent); actEvent.detail = 1; rv = shell->HandleDOMEventWithTarget(this, &actEvent, &status); @@ -2999,9 +3001,10 @@ Element::PostHandleEventForLinks(EventChainPostVisitor& aVisitor) if (aVisitor.mEvent->originalTarget == this) { nsAutoString target; GetLinkTarget(target); + const InternalUIEvent* activeEvent = aVisitor.mEvent->AsUIEvent(); + MOZ_ASSERT(activeEvent); nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target, - true, true, - aVisitor.mEvent->mFlags.mIsTrusted); + true, true, activeEvent->IsTrustable()); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } } diff --git a/dom/events/UIEvent.cpp b/dom/events/UIEvent.cpp index 5cc516e497af..3ce69a6455e9 100644 --- a/dom/events/UIEvent.cpp +++ b/dom/events/UIEvent.cpp @@ -29,7 +29,7 @@ UIEvent::UIEvent(EventTarget* aOwner, nsPresContext* aPresContext, WidgetGUIEvent* aEvent) : Event(aOwner, aPresContext, - aEvent ? aEvent : new InternalUIEvent(false, 0)) + aEvent ? aEvent : new InternalUIEvent(false, 0, nullptr)) , mClientPoint(0, 0) , mLayerPoint(0, 0) , mPagePoint(0, 0) diff --git a/dom/html/HTMLButtonElement.cpp b/dom/html/HTMLButtonElement.cpp index 04d86dadaec6..1b0f74b215b8 100644 --- a/dom/html/HTMLButtonElement.cpp +++ b/dom/html/HTMLButtonElement.cpp @@ -250,10 +250,9 @@ HTMLButtonElement::PostHandleEvent(EventChainPostVisitor& aVisitor) if (aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) { WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); if (mouseEvent && mouseEvent->IsLeftClickEvent()) { - // XXX Activating actually occurs even if it's caused by untrusted event. - // Therefore, shouldn't this be always trusted event? - InternalUIEvent actEvent(aVisitor.mEvent->mFlags.mIsTrusted, - NS_UI_ACTIVATE); + // DOMActive event should be trusted since the activation is actually + // occurred even if the cause is an untrusted click event. + InternalUIEvent actEvent(true, NS_UI_ACTIVATE, mouseEvent); actEvent.detail = 1; nsCOMPtr shell = aVisitor.mPresContext->GetPresShell(); diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index cb697cbcb71c..e1e8265397d7 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -3629,10 +3629,9 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); if (mouseEvent && mouseEvent->IsLeftClickEvent() && !ShouldPreventDOMActivateDispatch(aVisitor.mEvent->originalTarget)) { - // XXX Activating actually occurs even if it's caused by untrusted event. - // Therefore, shouldn't this be always trusted event? - InternalUIEvent actEvent(aVisitor.mEvent->mFlags.mIsTrusted, - NS_UI_ACTIVATE); + // DOMActive event should be trusted since the activation is actually + // occurred even if the cause is an untrusted click event. + InternalUIEvent actEvent(true, NS_UI_ACTIVATE, mouseEvent); actEvent.detail = 1; nsCOMPtr shell = aVisitor.mPresContext->GetPresShell(); diff --git a/widget/BasicEvents.h b/widget/BasicEvents.h index 47c407ce2f1a..21ed254c7046 100644 --- a/widget/BasicEvents.h +++ b/widget/BasicEvents.h @@ -719,6 +719,7 @@ class InternalUIEvent : public WidgetGUIEvent protected: InternalUIEvent() : detail(0) + , mCausedByUntrustedEvent(false) { } @@ -726,6 +727,7 @@ class InternalUIEvent : public WidgetGUIEvent EventClassID aEventClassID) : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, aEventClassID) , detail(0) + , mCausedByUntrustedEvent(false) { } @@ -733,15 +735,24 @@ class InternalUIEvent : public WidgetGUIEvent EventClassID aEventClassID) : WidgetGUIEvent(aIsTrusted, aMessage, nullptr, aEventClassID) , detail(0) + , mCausedByUntrustedEvent(false) { } public: virtual InternalUIEvent* AsUIEvent() override { return this; } - InternalUIEvent(bool aIsTrusted, uint32_t aMessage) + /** + * If the UIEvent is caused by another event (e.g., click event), + * aEventCausesThisEvent should be the event. If there is no such event, + * this should be nullptr. + */ + InternalUIEvent(bool aIsTrusted, uint32_t aMessage, + const WidgetEvent* aEventCausesThisEvent) : WidgetGUIEvent(aIsTrusted, aMessage, nullptr, eUIEventClass) , detail(0) + , mCausedByUntrustedEvent( + aEventCausesThisEvent && !aEventCausesThisEvent->mFlags.mIsTrusted) { } @@ -749,19 +760,29 @@ class InternalUIEvent : public WidgetGUIEvent { MOZ_ASSERT(mClass == eUIEventClass, "Duplicate() must be overridden by sub class"); - InternalUIEvent* result = new InternalUIEvent(false, mMessage); + InternalUIEvent* result = new InternalUIEvent(false, mMessage, nullptr); result->AssignUIEventData(*this, true); result->mFlags = mFlags; return result; } int32_t detail; + // mCausedByUntrustedEvent is true if the event is caused by untrusted event. + bool mCausedByUntrustedEvent; + + // If you check the event is a trusted event and NOT caused by an untrusted + // event, IsTrustable() returns what you expected. + bool IsTrustable() const + { + return mFlags.mIsTrusted && !mCausedByUntrustedEvent; + } void AssignUIEventData(const InternalUIEvent& aEvent, bool aCopyTargets) { AssignGUIEventData(aEvent, aCopyTargets); detail = aEvent.detail; + mCausedByUntrustedEvent = aEvent.mCausedByUntrustedEvent; } }; From f727c3af53df7cd64f51295cc43c9e5bb53d9874 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Sat, 22 Aug 2015 13:49:11 +0200 Subject: [PATCH 191/208] Bug 889158 part 1 - Fix chrome and tests to not use arrow functions with arguments. r=Waldo --- addon-sdk/source/test/context-menu/test-helper.js | 2 +- addon-sdk/source/test/event/helpers.js | 4 ++-- browser/base/content/test/general/head.js | 8 ++++---- .../places/tests/browser/browser_library_commands.js | 4 ++-- browser/components/places/tests/browser/head.js | 10 +++++----- .../tests/bookmarks/test_bookmarks_notifications.js | 4 ++-- .../components/places/tests/bookmarks/test_keywords.js | 2 +- toolkit/components/places/tests/unit/test_keywords.js | 2 +- toolkit/devtools/event-emitter.js | 4 ++-- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/addon-sdk/source/test/context-menu/test-helper.js b/addon-sdk/source/test/context-menu/test-helper.js index 14180249e0ea..97948098505d 100644 --- a/addon-sdk/source/test/context-menu/test-helper.js +++ b/addon-sdk/source/test/context-menu/test-helper.js @@ -30,7 +30,7 @@ const TEST_DOC_URL = module.uri.replace(/context-menu\/test-helper\.js$/, "test- function TestHelper(assert, done) { // Methods on the wrapped test can be called on this object. for (var prop in assert) - this[prop] = () => assert[prop].apply(assert, arguments); + this[prop] = (...args) => assert[prop].apply(assert, args); this.assert = assert; this.end = done; this.loaders = []; diff --git a/addon-sdk/source/test/event/helpers.js b/addon-sdk/source/test/event/helpers.js index ec120b79dd9a..35833b35f372 100644 --- a/addon-sdk/source/test/event/helpers.js +++ b/addon-sdk/source/test/event/helpers.js @@ -26,7 +26,7 @@ const { defer } = require("sdk/core/promise"); * A promise resolved once the delay given is passed, or the object * receives the event specified */ -const wait = (target, type, capture) => { +const wait = function(target, type, capture) { let { promise, resolve, reject } = defer(); if (!arguments.length) { @@ -105,4 +105,4 @@ exports.FIFO = scenario(function(target, expected, actual) { return expected.reduce(function(result, value) { return result.concat(value + "#1", value + "#2", value + "#3"); }, []); -}); \ No newline at end of file +}); diff --git a/browser/base/content/test/general/head.js b/browser/base/content/test/general/head.js index 654fee2c4ed5..9cd58ade0cc5 100644 --- a/browser/base/content/test/general/head.js +++ b/browser/base/content/test/general/head.js @@ -558,8 +558,8 @@ let FullZoomHelper = { let didPs = false; let didZoom = false; - gBrowser.addEventListener("pageshow", function (event) { - gBrowser.removeEventListener("pageshow", arguments.callee, true); + gBrowser.addEventListener("pageshow", function listener(event) { + gBrowser.removeEventListener("pageshow", listener, true); didPs = true; if (didZoom) resolve(); @@ -718,9 +718,9 @@ function assertWebRTCIndicatorStatus(expected) { let win = Services.wm.getMostRecentWindow("Browser:WebRTCGlobalIndicator"); if (win) { yield new Promise((resolve, reject) => { - win.addEventListener("unload", (e) => { + win.addEventListener("unload", function listener(e) { if (e.target == win.document) { - win.removeEventListener("unload", arguments.callee); + win.removeEventListener("unload", listener); resolve(); } }, false); diff --git a/browser/components/places/tests/browser/browser_library_commands.js b/browser/components/places/tests/browser/browser_library_commands.js index 891a1f4a3057..5775990df15a 100644 --- a/browser/components/places/tests/browser/browser_library_commands.js +++ b/browser/components/places/tests/browser/browser_library_commands.js @@ -60,7 +60,7 @@ add_task(function* test_date_container() { // Execute the delete command and check visit has been removed. let promiseURIRemoved = promiseHistoryNotification("onDeleteURI", - () => TEST_URI.equals(arguments[0])); + v => TEST_URI.equals(v)); PO._places.controller.doCommand("cmd_delete"); yield promiseURIRemoved; @@ -125,7 +125,7 @@ add_task(function* test_query_on_toolbar() { // Execute the delete command and check bookmark has been removed. let promiseItemRemoved = promiseBookmarksNotification("onItemRemoved", - () => query.guid == arguments[5]); + (...args) => query.guid == args[5]); PO._places.controller.doCommand("cmd_delete"); yield promiseItemRemoved; diff --git a/browser/components/places/tests/browser/head.js b/browser/components/places/tests/browser/head.js index e5722d653722..f1800b33912e 100644 --- a/browser/components/places/tests/browser/head.js +++ b/browser/components/places/tests/browser/head.js @@ -170,13 +170,13 @@ function promiseBookmarksNotification(notification, conditionFn) { return XPCOMUtils.generateQI([ Ci.nsINavBookmarkObserver ]); info(`promiseBookmarksNotification: got ${name} notification`); if (name == notification) - return () => { - if (conditionFn.apply(this, arguments)) { + return (...args) => { + if (conditionFn.apply(this, args)) { clearTimeout(timeout); PlacesUtils.bookmarks.removeObserver(proxifiedObserver, false); executeSoon(resolve); } else { - info(`promiseBookmarksNotification: skip cause condition doesn't apply to ${JSON.stringify(arguments)}`); + info(`promiseBookmarksNotification: skip cause condition doesn't apply to ${JSON.stringify(args)}`); } } return () => {}; @@ -198,8 +198,8 @@ function promiseHistoryNotification(notification, conditionFn) { if (name == "QueryInterface") return XPCOMUtils.generateQI([ Ci.nsINavHistoryObserver ]); if (name == notification) - return () => { - if (conditionFn.apply(this, arguments)) { + return (...args) => { + if (conditionFn.apply(this, args)) { clearTimeout(timeout); PlacesUtils.history.removeObserver(proxifiedObserver, false); executeSoon(resolve); diff --git a/toolkit/components/places/tests/bookmarks/test_bookmarks_notifications.js b/toolkit/components/places/tests/bookmarks/test_bookmarks_notifications.js index 12d001d6e320..7f1edb76afd7 100644 --- a/toolkit/components/places/tests/bookmarks/test_bookmarks_notifications.js +++ b/toolkit/components/places/tests/bookmarks/test_bookmarks_notifications.js @@ -430,8 +430,8 @@ function expectNotifications() { } if (name.startsWith("onItem")) { - return () => { - let args = Array.from(arguments, arg => { + return (...origArgs) => { + let args = Array.from(origArgs, arg => { if (arg && arg instanceof Ci.nsIURI) return new URL(arg.spec); if (arg && typeof(arg) == "number" && arg >= Date.now() * 1000) diff --git a/toolkit/components/places/tests/bookmarks/test_keywords.js b/toolkit/components/places/tests/bookmarks/test_keywords.js index fa7c44702c96..d8574611f4eb 100644 --- a/toolkit/components/places/tests/bookmarks/test_keywords.js +++ b/toolkit/components/places/tests/bookmarks/test_keywords.js @@ -44,7 +44,7 @@ function expectNotifications() { } if (name.startsWith("onItemChanged")) { - return (id, prop, isAnno, val, lastMod, itemType, parentId, guid, parentGuid, oldVal) => { + return function(id, prop, isAnno, val, lastMod, itemType, parentId, guid, parentGuid, oldVal) { if (prop != "keyword") return; let args = Array.from(arguments, arg => { diff --git a/toolkit/components/places/tests/unit/test_keywords.js b/toolkit/components/places/tests/unit/test_keywords.js index 55a726f12b7d..9e3d181a93eb 100644 --- a/toolkit/components/places/tests/unit/test_keywords.js +++ b/toolkit/components/places/tests/unit/test_keywords.js @@ -56,7 +56,7 @@ function expectBookmarkNotifications() { } if (name.startsWith("onItemChanged")) { - return (itemId, property) => { + return function(itemId, property) { if (property != "keyword") return; let args = Array.from(arguments, arg => { diff --git a/toolkit/devtools/event-emitter.js b/toolkit/devtools/event-emitter.js index 458a14f9de49..d3031e6841ef 100644 --- a/toolkit/devtools/event-emitter.js +++ b/toolkit/devtools/event-emitter.js @@ -86,10 +86,10 @@ EventEmitter.prototype = { once: function EventEmitter_once(aEvent, aListener) { let deferred = promise.defer(); - let handler = (aEvent, aFirstArg) => { + let handler = (aEvent, aFirstArg, ...aRest) => { this.off(aEvent, handler); if (aListener) { - aListener.apply(null, arguments); + aListener.apply(null, [aEvent, aFirstArg, ...aRest]); } deferred.resolve(aFirstArg); }; From c4b86c2c84d6e1bd671cb47151e6b7d1ba643813 Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Sat, 22 Aug 2015 12:03:17 -0400 Subject: [PATCH 192/208] Bug 1197483 - update talos.json to pick up the latest changes. r=parkouss --- testing/talos/talos.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/talos/talos.json b/testing/talos/talos.json index 25cb0e909bdc..a75597972d34 100644 --- a/testing/talos/talos.json +++ b/testing/talos/talos.json @@ -5,7 +5,7 @@ }, "global": { "talos_repo": "https://hg.mozilla.org/build/talos", - "talos_revision": "c0039de7a1c6" + "talos_revision": "762f27d9a07b" }, "extra_options": { "android": [ "--apkPath=%(apk_path)s" ] From 4549d86b3abf92f77c6fe9cc105baca907864cb1 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Wed, 19 Aug 2015 22:45:21 -0700 Subject: [PATCH 193/208] Bug 1196638 - Infer the proper button for synthesized mouse clicks on all callsites. r=jmaher --- layout/base/tests/chrome/test_bug370436.html | 19 ++++++++++++------- .../mochitest/tests/SimpleTest/EventUtils.js | 15 +++++++++++---- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/layout/base/tests/chrome/test_bug370436.html b/layout/base/tests/chrome/test_bug370436.html index 49e0934b26d0..9ad8511aba29 100644 --- a/layout/base/tests/chrome/test_bug370436.html +++ b/layout/base/tests/chrome/test_bug370436.html @@ -42,27 +42,32 @@ ta.focus(); ta.selectionStart = ta.selectionEnd = ta.value.length; +// Note: This test, intentionally or by accident, relies on sending button '0' +// with contextMenu, which triggers some key-equiv stuff in +// PresShell::AdjustContextMenuKeyEvent. +var mouseParams = { type: 'contextmenu', button: 0 }; + /* Put cursor at start and middle of "sheep" */ synthesizeKey("VK_UP", {}) - synthesizeMouse(ta, 0, 0, { type : "contextmenu" }); + synthesizeMouse(ta, 0, 0, mouseParams); synthesizeKey("VK_RIGHT", {}) - synthesizeMouse(ta, 0, 0, { type : "contextmenu" }); + synthesizeMouse(ta, 0, 0, mouseParams); synthesizeKey("VK_RIGHT", {}) - synthesizeMouse(ta, 0, 0, { type : "contextmenu" }); + synthesizeMouse(ta, 0, 0, mouseParams); /* Put cursor at the end of "hello" */ synthesizeKey("VK_UP", {}) - synthesizeMouse(ta, 0, 0, { type : "contextmenu" }); + synthesizeMouse(ta, 0, 0, mouseParams); synthesizeKey("VK_RIGHT", {}) synthesizeKey("VK_RIGHT", {}) synthesizeKey("VK_RIGHT", {}) - synthesizeMouse(ta, 0, 0, { type : "contextmenu" }); + synthesizeMouse(ta, 0, 0, mouseParams); synthesizeKey("VK_RIGHT", {}) - synthesizeMouse(ta, 0, 0, { type : "contextmenu" }); + synthesizeMouse(ta, 0, 0, mouseParams); /* Put cursor on "welcome" */ synthesizeKey("VK_UP", {}) - synthesizeMouse(ta, 0, 0, { type : "contextmenu" }); + synthesizeMouse(ta, 0, 0, mouseParams); is(words.pop(), "welcome", "Word 1 selected correctly"); is(words.pop(), "world" , "Word 2 selected correctly"); diff --git a/testing/mochitest/tests/SimpleTest/EventUtils.js b/testing/mochitest/tests/SimpleTest/EventUtils.js index 257ec2fdac33..206af6a57f3b 100644 --- a/testing/mochitest/tests/SimpleTest/EventUtils.js +++ b/testing/mochitest/tests/SimpleTest/EventUtils.js @@ -52,6 +52,13 @@ function getElement(id) { this.$ = this.getElement; +function computeButton(aEvent) { + if (typeof aEvent.button != 'undefined') { + return aEvent.button; + } + return aEvent.type == 'contextmenu' ? 2 : 0; +} + function sendMouseEvent(aEvent, aTarget, aWindow) { if (['click', 'contextmenu', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout'].indexOf(aEvent.type) == -1) { throw new Error("sendMouseEvent doesn't know about event type '" + aEvent.type + "'"); @@ -83,7 +90,7 @@ function sendMouseEvent(aEvent, aTarget, aWindow) { var altKeyArg = aEvent.altKey || false; var shiftKeyArg = aEvent.shiftKey || false; var metaKeyArg = aEvent.metaKey || false; - var buttonArg = aEvent.button || (aEvent.type == 'contextmenu' ? 2 : 0); + var buttonArg = computeButton(aEvent); var relatedTargetArg = aEvent.relatedTarget || null; event.initMouseEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg, @@ -124,7 +131,7 @@ function sendDragEvent(aEvent, aTarget, aWindow=window) { var altKeyArg = aEvent.altKey || false; var shiftKeyArg = aEvent.shiftKey || false; var metaKeyArg = aEvent.metaKey || false; - var buttonArg = aEvent.button || 0; + var buttonArg = computeButton(aEvent); var relatedTargetArg = aEvent.relatedTarget || null; var dataTransfer = aEvent.dataTransfer || null; @@ -307,7 +314,7 @@ function synthesizeMouseAtPoint(left, top, aEvent, aWindow) var defaultPrevented = false; if (utils) { - var button = aEvent.button || 0; + var button = computeButton(aEvent); var clickCount = aEvent.clickCount || 1; var modifiers = _parseModifiers(aEvent); var pressure = ("pressure" in aEvent) ? aEvent.pressure : 0; @@ -355,7 +362,7 @@ function synthesizePointerAtPoint(left, top, aEvent, aWindow) var defaultPrevented = false; if (utils) { - var button = aEvent.button || 0; + var button = computeButton(aEvent); var clickCount = aEvent.clickCount || 1; var modifiers = _parseModifiers(aEvent); var pressure = ("pressure" in aEvent) ? aEvent.pressure : 0; From 6e506c4095e6b79324d4d83c26bff6050df4516e Mon Sep 17 00:00:00 2001 From: Chris Lord Date: Thu, 20 Aug 2015 12:07:54 +0100 Subject: [PATCH 194/208] Bug 1181555 - Add 'moz-extremely-unstable-and-will-change-webcomponents' permission. r=fabrice --- dom/apps/PermissionsTable.jsm | 6 ++++++ dom/base/nsDocument.cpp | 29 ++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/dom/apps/PermissionsTable.jsm b/dom/apps/PermissionsTable.jsm index ca7b4a2694f0..ed4abd20f822 100644 --- a/dom/apps/PermissionsTable.jsm +++ b/dom/apps/PermissionsTable.jsm @@ -579,6 +579,12 @@ this.PermissionsTable = { geolocation: { privileged: DENY_ACTION, certified: ALLOW_ACTION }, + "moz-extremely-unstable-and-will-change-webcomponents": { + app: DENY_ACTION, + trusted: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + } }; /** diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 60c7ba424f9e..c85d9cc8d528 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -92,6 +92,7 @@ #include "nsIAuthPrompt2.h" #include "nsIScriptSecurityManager.h" +#include "nsIPermissionManager.h" #include "nsIPrincipal.h" #include "nsIDOMWindow.h" @@ -5831,9 +5832,31 @@ nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* bool nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject) { - JS::Rooted obj(aCx, aObject); - return Preferences::GetBool("dom.webcomponents.enabled") || - IsInCertifiedApp(aCx, obj); + if (Preferences::GetBool("dom.webcomponents.enabled")) { + return true; + } + + // Check for the webcomponents permission. See Bug 1181555. + JSAutoCompartment ac(aCx, aObject); + JS::Rooted global(aCx, JS_GetGlobalForObject(aCx, aObject)); + nsCOMPtr window = + do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(global)); + + if (window) { + nsresult rv; + nsCOMPtr permMgr = + do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, false); + + uint32_t perm; + rv = permMgr->TestPermissionFromWindow( + window, "moz-extremely-unstable-and-will-change-webcomponents", &perm); + NS_ENSURE_SUCCESS(rv, false); + + return perm == nsIPermissionManager::ALLOW_ACTION; + } + + return false; } nsresult From a5f66d7da78c7992c8a8fc019b1bc1ba2b1a5660 Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Sat, 22 Aug 2015 21:53:48 +0200 Subject: [PATCH 195/208] Backed out changeset e9d838084096 (bug 1181555) for Linux x64 opt and B2G Desktop Linux x64 opt Hazard analysis fail. r=backout --- dom/apps/PermissionsTable.jsm | 6 ------ dom/base/nsDocument.cpp | 29 +++-------------------------- 2 files changed, 3 insertions(+), 32 deletions(-) diff --git a/dom/apps/PermissionsTable.jsm b/dom/apps/PermissionsTable.jsm index ed4abd20f822..ca7b4a2694f0 100644 --- a/dom/apps/PermissionsTable.jsm +++ b/dom/apps/PermissionsTable.jsm @@ -579,12 +579,6 @@ this.PermissionsTable = { geolocation: { privileged: DENY_ACTION, certified: ALLOW_ACTION }, - "moz-extremely-unstable-and-will-change-webcomponents": { - app: DENY_ACTION, - trusted: DENY_ACTION, - privileged: ALLOW_ACTION, - certified: ALLOW_ACTION - } }; /** diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index c85d9cc8d528..60c7ba424f9e 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -92,7 +92,6 @@ #include "nsIAuthPrompt2.h" #include "nsIScriptSecurityManager.h" -#include "nsIPermissionManager.h" #include "nsIPrincipal.h" #include "nsIDOMWindow.h" @@ -5832,31 +5831,9 @@ nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* bool nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject) { - if (Preferences::GetBool("dom.webcomponents.enabled")) { - return true; - } - - // Check for the webcomponents permission. See Bug 1181555. - JSAutoCompartment ac(aCx, aObject); - JS::Rooted global(aCx, JS_GetGlobalForObject(aCx, aObject)); - nsCOMPtr window = - do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(global)); - - if (window) { - nsresult rv; - nsCOMPtr permMgr = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, false); - - uint32_t perm; - rv = permMgr->TestPermissionFromWindow( - window, "moz-extremely-unstable-and-will-change-webcomponents", &perm); - NS_ENSURE_SUCCESS(rv, false); - - return perm == nsIPermissionManager::ALLOW_ACTION; - } - - return false; + JS::Rooted obj(aCx, aObject); + return Preferences::GetBool("dom.webcomponents.enabled") || + IsInCertifiedApp(aCx, obj); } nsresult From a13994e7b0c89ec15d391174e9b56c9adccf9796 Mon Sep 17 00:00:00 2001 From: Yura Zenevich Date: Wed, 5 Aug 2015 14:40:18 -0400 Subject: [PATCH 196/208] Bug 1191432 - improving coverage for marionette accessibility checks. r=automatedtester --- .../tests/unit/test_accessibility.py | 66 ++++++++++++-- .../marionette/www/test_accessibility.html | 15 ++++ testing/marionette/elements.js | 2 + testing/marionette/listener.js | 85 +++++++++++++++---- 4 files changed, 144 insertions(+), 24 deletions(-) diff --git a/testing/marionette/client/marionette/tests/unit/test_accessibility.py b/testing/marionette/client/marionette/tests/unit/test_accessibility.py index 0863aeacf739..ebd5c154418d 100644 --- a/testing/marionette/client/marionette/tests/unit/test_accessibility.py +++ b/testing/marionette/client/marionette/tests/unit/test_accessibility.py @@ -4,7 +4,7 @@ from marionette import MarionetteTestCase from marionette_driver.errors import (ElementNotAccessibleException, - ElementNotVisibleException) + ElementNotVisibleException) class TestAccessibility(MarionetteTestCase): @@ -16,7 +16,13 @@ class TestAccessibility(MarionetteTestCase): "button1", # Button2 is an accessible button with a valid accessible name # computed from aria-label - "button2" + "button2", + # Button13 is an accessible button that is implemented via role="button" + # and is explorable using tabindex="0" + "button13", + # button17 is an accessible button that overrides parent's + # pointer-events:none; property with its own pointer-events:all; + "button17" ] # Elements that are not accessible with the accessibility API @@ -35,7 +41,10 @@ class TestAccessibility(MarionetteTestCase): "button7", # Button8 is not currently visible via the accessibility API and may # not be manipulated by it (in hidden subtree) - "button8" + "button8", + # Button14 is accessible button but is not explorable because of lack + # of tabindex that would make it focusable. + "button14" ] # Elements that are either accessible to accessibility API or not accessible @@ -57,6 +66,12 @@ class TestAccessibility(MarionetteTestCase): disabled_elementIDs = ["button11", "no_accessible_but_disabled"] + # Elements that are enabled but otherwise disabled or not explorable via the accessibility API + disabled_accessibility_elementIDs = ["button12", "button15", "button16"] + + # Elements that are reporting selected state + valid_option_elementIDs = ["option1", "option2"] + def run_element_test(self, ids, testFn): for id in ids: element = self.marionette.find_element("id", id) @@ -129,13 +144,50 @@ def test_element_is_visible_to_accessibility(self): # No exception should be raised self.run_element_test(self.displayed_elementIDs, lambda element: element.is_displayed()) - def test_is_element_is_not_enabled_to_accessbility(self): + def test_element_is_not_enabled_to_accessbility(self): self.setup_accessibility() - # Button is enabled but disabled via the accessibility API - self.assertRaises(ElementNotAccessibleException, - self.marionette.find_element("id", "button12").is_enabled) + # Buttons are enabled but disabled/not-explorable via the accessibility API + self.run_element_test(self.disabled_accessibility_elementIDs, + lambda element: self.assertRaises(ElementNotAccessibleException, + element.is_enabled)) + + # Buttons are enabled but disabled/not-explorable via the accessibility API and thus are not + # clickable via the accessibility API + self.run_element_test(self.disabled_accessibility_elementIDs, + lambda element: self.assertRaises(ElementNotAccessibleException, + element.click)) + + self.setup_accessibility(False, False) + self.run_element_test(self.disabled_accessibility_elementIDs, + lambda element: element.is_enabled()) + self.run_element_test(self.disabled_accessibility_elementIDs, + lambda element: element.click()) def test_element_is_enabled_to_accessibility(self): self.setup_accessibility() # No exception should be raised self.run_element_test(self.disabled_elementIDs, lambda element: element.is_enabled()) + + def test_send_keys_raises_no_exception(self): + self.setup_accessibility() + # Sending keys to valid input should not raise any exceptions + self.run_element_test(['input1'], lambda element: element.send_keys("a")) + + self.setup_accessibility(False, False) + # Sending keys to invalid element should not raise any exceptions when raising accessibility + # exceptions is disabled + self.run_element_test(['button5'], lambda element: element.send_keys("abc")) + + def test_send_keys_raises_element_not_accessible(self): + self.setup_accessibility() + # Sending keys to invalid element should raise an exception + self.run_element_test(['button5'], + lambda element: self.assertRaises(ElementNotAccessibleException, + element.send_keys)) + + def test_is_selected_raises_no_exception(self): + self.setup_accessibility() + # No exception should be raised for valid options + self.run_element_test(self.valid_option_elementIDs, lambda element: element.is_selected()) + # No exception should be raised for non-selectable elements + self.run_element_test(self.valid_elementIDs, lambda element: element.is_selected()) diff --git a/testing/marionette/client/marionette/www/test_accessibility.html b/testing/marionette/client/marionette/www/test_accessibility.html index 8838ce869974..8cc9fd64930c 100644 --- a/testing/marionette/client/marionette/www/test_accessibility.html +++ b/testing/marionette/client/marionette/www/test_accessibility.html @@ -32,7 +32,22 @@

I have no accessible object + Span button + Unexplorable Span button + +
+ +
+
+ +
+ + + + + + diff --git a/browser/modules/PluginContent.jsm b/browser/modules/PluginContent.jsm index 18881d3daff1..670728df0c3d 100644 --- a/browser/modules/PluginContent.jsm +++ b/browser/modules/PluginContent.jsm @@ -311,6 +311,8 @@ PluginContent.prototype = { return "PluginVulnerableUpdatable"; case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE: return "PluginVulnerableNoUpdate"; + case Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW: + return "PluginPlayPreview"; default: // Not all states map to a handler return null; @@ -415,6 +417,10 @@ PluginContent.prototype = { shouldShowNotification = true; break; + case "PluginPlayPreview": + this._handlePlayPreviewEvent(plugin); + break; + case "PluginDisabled": let manageLink = this.getPluginUI(plugin, "managePluginsLink"); this.addLinkClickCallback(manageLink, "forwardCallback", "managePlugins"); @@ -525,6 +531,12 @@ PluginContent.prototype = { objLoadingContent.pluginFallbackType >= Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY && objLoadingContent.pluginFallbackType <= Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE; + if (objLoadingContent.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW) { + // checking if play preview is subject to CTP rules + let playPreviewInfo = pluginHost.getPlayPreviewInfo(objLoadingContent.actualType); + isFallbackTypeValid = !playPreviewInfo.ignoreCTP; + } + return !objLoadingContent.activated && pluginPermission != Ci.nsIPermissionManager.DENY_ACTION && isFallbackTypeValid; @@ -537,6 +549,17 @@ PluginContent.prototype = { } }, + stopPlayPreview: function (plugin, playPlugin) { + let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent); + if (objLoadingContent.activated) + return; + + if (playPlugin) + objLoadingContent.playPlugin(); + else + objLoadingContent.cancelPlayPreview(); + }, + // Forward a link click callback to the chrome process. forwardCallback: function (name) { this.global.sendAsyncMessage("PluginContent:LinkClickCallback", { name: name }); @@ -618,6 +641,49 @@ PluginContent.prototype = { } }, + _handlePlayPreviewEvent: function (plugin) { + let doc = plugin.ownerDocument; + let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); + let pluginInfo = this._getPluginInfo(plugin); + let playPreviewInfo = pluginHost.getPlayPreviewInfo(pluginInfo.mimetype); + + let previewContent = this.getPluginUI(plugin, "previewPluginContent"); + let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0]; + if (!iframe) { + // lazy initialization of the iframe + iframe = doc.createElementNS("http://www.w3.org/1999/xhtml", "iframe"); + iframe.className = "previewPluginContentFrame"; + previewContent.appendChild(iframe); + + // Force a style flush, so that we ensure our binding is attached. + plugin.clientTop; + } + iframe.src = playPreviewInfo.redirectURL; + + // MozPlayPlugin event can be dispatched from the extension chrome + // code to replace the preview content with the native plugin + let playPluginHandler = (event) => { + if (!event.isTrusted) + return; + + previewContent.removeEventListener("MozPlayPlugin", playPluginHandler, true); + + let playPlugin = !event.detail; + this.stopPlayPreview(plugin, playPlugin); + + // cleaning up: removes overlay iframe from the DOM + let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0]; + if (iframe) + previewContent.removeChild(iframe); + }; + + previewContent.addEventListener("MozPlayPlugin", playPluginHandler, true); + + if (!playPreviewInfo.ignoreCTP) { + this._showClickToPlayNotification(plugin, false); + } + }, + reshowClickToPlayNotification: function () { let contentWindow = this.global.content; let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor) diff --git a/dom/base/nsIObjectLoadingContent.idl b/dom/base/nsIObjectLoadingContent.idl index 953a2591187c..6cf0c535f10b 100644 --- a/dom/base/nsIObjectLoadingContent.idl +++ b/dom/base/nsIObjectLoadingContent.idl @@ -25,7 +25,7 @@ class nsNPAPIPluginInstance; * interface to mirror this interface when changing it. */ -[scriptable, uuid(2eb3195e-3eea-4083-bb1d-d2d70fa35ccb)] +[scriptable, uuid(5efbd411-5bbe-4de1-9f3a-1c3459696eb2)] interface nsIObjectLoadingContent : nsISupports { /** @@ -65,6 +65,8 @@ interface nsIObjectLoadingContent : nsISupports const unsigned long PLUGIN_VULNERABLE_UPDATABLE = 9; // The plugin is vulnerable (no update available) const unsigned long PLUGIN_VULNERABLE_NO_UPDATE = 10; + // The plugin is in play preview mode + const unsigned long PLUGIN_PLAY_PREVIEW = 11; /** * The actual mime type (the one we got back from the network @@ -126,7 +128,8 @@ interface nsIObjectLoadingContent : nsISupports in boolean submittedCrashReport); /** - * This method will play a plugin that has been stopped by click-to-play. + * This method will play a plugin that has been stopped by the + * click-to-play plugins or play-preview features. */ void playPlugin(); @@ -141,7 +144,7 @@ interface nsIObjectLoadingContent : nsISupports /** * This attribute will return true if the current content type has been * activated, either explicitly or by passing checks that would have it be - * click-to-play. + * click-to-play or play-preview. */ readonly attribute boolean activated; @@ -181,6 +184,11 @@ interface nsIObjectLoadingContent : nsISupports */ readonly attribute bool hasRunningPlugin; + /** + * This method will disable the play-preview plugin state. + */ + void cancelPlayPreview(); + /** * If this plugin runs out-of-process, it has a runID to differentiate * between different times the plugin process has been instantiated. diff --git a/dom/base/nsObjectLoadingContent.cpp b/dom/base/nsObjectLoadingContent.cpp index 7e805a68b7dc..1f0dad3a856e 100644 --- a/dom/base/nsObjectLoadingContent.cpp +++ b/dom/base/nsObjectLoadingContent.cpp @@ -715,6 +715,7 @@ nsObjectLoadingContent::nsObjectLoadingContent() , mInstantiating(false) , mNetworkCreated(true) , mActivated(false) + , mPlayPreviewCanceled(false) , mIsStopping(false) , mIsLoading(false) , mScriptRequested(false) {} @@ -1405,6 +1406,8 @@ nsObjectLoadingContent::ObjectState() const return NS_EVENT_STATE_USERDISABLED; case eFallbackClickToPlay: return NS_EVENT_STATE_TYPE_CLICK_TO_PLAY; + case eFallbackPlayPreview: + return NS_EVENT_STATE_TYPE_PLAY_PREVIEW; case eFallbackDisabled: return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_DISABLED; case eFallbackBlocklisted: @@ -3119,7 +3122,7 @@ nsObjectLoadingContent::PlayPlugin() LOG(("OBJLC [%p]: Activated by user", this)); } - // If we're in a click-to-play state, reload. + // If we're in a click-to-play or play preview state, we need to reload // Fallback types >= eFallbackClickToPlay are plugin-replacement types, see // header if (mType == eType_Null && mFallbackType >= eFallbackClickToPlay) { @@ -3134,6 +3137,7 @@ nsObjectLoadingContent::Reload(bool aClearActivation) { if (aClearActivation) { mActivated = false; + mPlayPreviewCanceled = false; } return LoadObject(true, true); @@ -3173,6 +3177,22 @@ nsObjectLoadingContent::GetHasRunningPlugin(bool *aHasPlugin) return NS_OK; } +NS_IMETHODIMP +nsObjectLoadingContent::CancelPlayPreview() +{ + if (!nsContentUtils::IsCallerChrome()) + return NS_ERROR_NOT_AVAILABLE; + + mPlayPreviewCanceled = true; + + // If we're in play preview state already, reload + if (mType == eType_Null && mFallbackType == eFallbackPlayPreview) { + return LoadObject(true, true); + } + + return NS_OK; +} + NS_IMETHODIMP nsObjectLoadingContent::GetRunID(uint32_t* aRunID) { @@ -3218,6 +3238,31 @@ nsObjectLoadingContent::ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentTyp nsRefPtr pluginHost = nsPluginHost::GetInst(); + nsCOMPtr playPreviewInfo; + bool isPlayPreviewSpecified = NS_SUCCEEDED(pluginHost->GetPlayPreviewInfo( + mContentType, getter_AddRefs(playPreviewInfo))); + if (isPlayPreviewSpecified) { + // Checking PlayPreview whitelist as well. + nsCString uriSpec, baseSpec; + if (mURI) { + mURI->GetSpec(uriSpec); + } + if (mBaseURI) { + mBaseURI->GetSpec(baseSpec); + } + playPreviewInfo->CheckWhitelist(baseSpec, uriSpec, &isPlayPreviewSpecified); + } + bool ignoreCTP = false; + if (isPlayPreviewSpecified) { + playPreviewInfo->GetIgnoreCTP(&ignoreCTP); + } + if (isPlayPreviewSpecified && !mPlayPreviewCanceled && + ignoreCTP) { + // play preview in ignoreCTP mode is shown even if the native plugin + // is not present/installed + aReason = eFallbackPlayPreview; + return false; + } // at this point if it's not a plugin, we let it play/fallback if (!aIgnoreCurrentType && mType != eType_Plugin) { return true; @@ -3227,6 +3272,8 @@ nsObjectLoadingContent::ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentTyp // * Assume a default of click-to-play // * If globally disabled, per-site permissions cannot override. // * If blocklisted, override the reason with the blocklist reason + // * If not blocklisted but playPreview, override the reason with the + // playPreview reason. // * Check per-site permissions and follow those if specified. // * Honor per-plugin disabled permission // * Blocklisted plugins are forced to CtP @@ -3262,6 +3309,12 @@ nsObjectLoadingContent::ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentTyp aReason = eFallbackVulnerableNoUpdate; } + if (aReason == eFallbackClickToPlay && isPlayPreviewSpecified && + !mPlayPreviewCanceled && !ignoreCTP) { + // play preview in click-to-play mode is shown instead of standard CTP UI + aReason = eFallbackPlayPreview; + } + // Check the permission manager for permission based on the principal of // the toplevel content. diff --git a/dom/base/nsObjectLoadingContent.h b/dom/base/nsObjectLoadingContent.h index d12c1fa01677..d246eac042cb 100644 --- a/dom/base/nsObjectLoadingContent.h +++ b/dom/base/nsObjectLoadingContent.h @@ -94,6 +94,9 @@ class nsObjectLoadingContent : public nsImageLoadingContent eFallbackVulnerableUpdatable = nsIObjectLoadingContent::PLUGIN_VULNERABLE_UPDATABLE, // The plugin is vulnerable (no update available) eFallbackVulnerableNoUpdate = nsIObjectLoadingContent::PLUGIN_VULNERABLE_NO_UPDATE, + // The plugin is disabled and play preview content is displayed until + // the extension code enables it by sending the MozPlayPlugin event + eFallbackPlayPreview = nsIObjectLoadingContent::PLUGIN_PLAY_PREVIEW }; nsObjectLoadingContent(); @@ -222,6 +225,10 @@ class nsObjectLoadingContent : public nsImageLoadingContent { return !!mInstanceOwner; } + void CancelPlayPreview(mozilla::ErrorResult& aRv) + { + aRv = CancelPlayPreview(); + } void SwapFrameLoaders(nsXULElement& aOtherOwner, mozilla::ErrorResult& aRv) { aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); @@ -615,13 +622,16 @@ class nsObjectLoadingContent : public nsImageLoadingContent // activated by PlayPlugin(). (see ShouldPlay()) bool mActivated : 1; + // Used to keep track of whether or not a plugin is blocked by play-preview. + bool mPlayPreviewCanceled : 1; + // Protects DoStopPlugin from reentry (bug 724781). bool mIsStopping : 1; // Protects LoadObject from re-entry bool mIsLoading : 1; - // For plugin stand-in types (click-to-play) tracks + // For plugin stand-in types (click-to-play, play preview, ...) tracks // whether content js has tried to access the plugin script object. bool mScriptRequested : 1; diff --git a/dom/events/EventStates.h b/dom/events/EventStates.h index 3fc72cd34e98..e6a3854cc8b5 100644 --- a/dom/events/EventStates.h +++ b/dom/events/EventStates.h @@ -262,6 +262,8 @@ class EventStates #define NS_EVENT_STATE_LTR NS_DEFINE_EVENT_STATE_MACRO(42) // Element is rtl (for :dir pseudo-class) #define NS_EVENT_STATE_RTL NS_DEFINE_EVENT_STATE_MACRO(43) +// Handler for play preview plugin +#define NS_EVENT_STATE_TYPE_PLAY_PREVIEW NS_DEFINE_EVENT_STATE_MACRO(44) // Element is highlighted (devtools inspector) #define NS_EVENT_STATE_DEVTOOLS_HIGHLIGHTED NS_DEFINE_EVENT_STATE_MACRO(45) // Element is an unresolved custom element candidate diff --git a/dom/plugins/base/moz.build b/dom/plugins/base/moz.build index e971eeb43f98..7528b45ae618 100644 --- a/dom/plugins/base/moz.build +++ b/dom/plugins/base/moz.build @@ -32,6 +32,7 @@ EXPORTS += [ 'nsPluginLogging.h', 'nsPluginNativeWindow.h', 'nsPluginNativeWindowGtk.h', + 'nsPluginPlayPreviewInfo.h', 'nsPluginsCID.h', 'nsPluginsDir.h', 'nsPluginTags.h', @@ -47,6 +48,7 @@ UNIFIED_SOURCES += [ 'nsNPAPIPluginStreamListener.cpp', 'nsPluginInstanceOwner.cpp', 'nsPluginModule.cpp', + 'nsPluginPlayPreviewInfo.cpp', 'nsPluginStreamListenerPeer.cpp', 'nsPluginTags.cpp', 'PluginPRLibrary.cpp', diff --git a/dom/plugins/base/nsIPluginHost.idl b/dom/plugins/base/nsIPluginHost.idl index ae349bea2a26..d6b01f6bc5c9 100644 --- a/dom/plugins/base/nsIPluginHost.idl +++ b/dom/plugins/base/nsIPluginHost.idl @@ -12,6 +12,21 @@ "@mozilla.org/plugin/host;1" %} +[scriptable, uuid(57069ada-2845-46ef-b57f-233596d1c02c)] +interface nsIPluginPlayPreviewInfo : nsISupports +{ + readonly attribute AUTF8String mimeType; + readonly attribute boolean ignoreCTP; + readonly attribute AUTF8String redirectURL; + readonly attribute AUTF8String whitelist; + + /** + * Checks if pageURI and objectURI matches once of the entries in + * the whitelist. If whitelist is empty, returns true. + */ + boolean checkWhitelist(in AUTF8String pageURI, in AUTF8String objectURI); +}; + [scriptable, function, uuid(9c311778-7c2c-4ad8-b439-b8a2786a20dd)] interface nsIClearSiteDataCallback : nsISupports { @@ -21,7 +36,7 @@ interface nsIClearSiteDataCallback : nsISupports void callback(in nsresult rv); }; -[scriptable, uuid(f938f5ba-7093-42cd-a559-af8039d99204)] +[scriptable, uuid(0f73bbd2-fc89-41df-b31b-38c09903d187)] interface nsIPluginHost : nsISupports { /** @@ -87,6 +102,27 @@ interface nsIPluginHost : nsISupports */ boolean siteHasData(in nsIPluginTag plugin, in AUTF8String domain); + /** + * Registers the play preview plugin mode for specific mime type + * + * @param mimeType: specifies plugin mime type. + * @param ignoreCTP: if true, the play preview ignores CTP rules, e.g. + whitelisted websites, will not notify about plugin + presence in the address bar. + * @param redirectURL: specifies url for the overlay iframe + * @param whitelist: specifies plugin whitelist in form of comma separated + * "[@page_url object_url|@page_url|object_url]" entries, + * e.g. @http://example.org/* http://example.org/t.swf + */ + void registerPlayPreviewMimeType(in AUTF8String mimeType, + [optional] in boolean ignoreCTP, + [optional] in AUTF8String redirectURL, + [optional] in AUTF8String whitelist); + + void unregisterPlayPreviewMimeType(in AUTF8String mimeType); + + nsIPluginPlayPreviewInfo getPlayPreviewInfo(in AUTF8String mimeType); + /** * Get the "permission string" for the plugin. This is a string that can be * passed to the permission manager to see whether the plugin is allowed to diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index 96347e29b577..24114cae4e66 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -1598,6 +1598,58 @@ nsPluginHost::UnregisterFakePlugin(const nsACString& aHandlerURI) return NS_OK; } +NS_IMETHODIMP +nsPluginHost::RegisterPlayPreviewMimeType(const nsACString& mimeType, + bool ignoreCTP, + const nsACString& redirectURL, + const nsACString& whitelist) +{ + nsAutoCString mt(mimeType); + nsAutoCString url(redirectURL); + if (url.Length() == 0) { + // using default play preview iframe URL, if redirectURL is not specified + url.AssignLiteral("data:application/x-moz-playpreview;,"); + url.Append(mimeType); + } + nsAutoCString wl(whitelist); + + nsRefPtr playPreview = + new nsPluginPlayPreviewInfo(mt.get(), ignoreCTP, url.get(), wl.get()); + mPlayPreviewMimeTypes.AppendElement(playPreview); + return NS_OK; +} + +NS_IMETHODIMP +nsPluginHost::UnregisterPlayPreviewMimeType(const nsACString& mimeType) +{ + nsAutoCString mimeTypeToRemove(mimeType); + for (uint32_t i = mPlayPreviewMimeTypes.Length(); i > 0; i--) { + nsRefPtr pp = mPlayPreviewMimeTypes[i - 1]; + if (PL_strcasecmp(pp.get()->mMimeType.get(), mimeTypeToRemove.get()) == 0) { + mPlayPreviewMimeTypes.RemoveElementAt(i - 1); + break; + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsPluginHost::GetPlayPreviewInfo(const nsACString& mimeType, + nsIPluginPlayPreviewInfo** aResult) +{ + nsAutoCString mimeTypeToFind(mimeType); + for (uint32_t i = 0; i < mPlayPreviewMimeTypes.Length(); i++) { + nsRefPtr pp = mPlayPreviewMimeTypes[i]; + if (PL_strcasecmp(pp.get()->mMimeType.get(), mimeTypeToFind.get()) == 0) { + *aResult = new nsPluginPlayPreviewInfo(pp.get()); + NS_ADDREF(*aResult); + return NS_OK; + } + } + *aResult = nullptr; + return NS_ERROR_NOT_AVAILABLE; +} + // FIXME-jsplugins Is this method actually needed? NS_IMETHODIMP nsPluginHost::GetFakePlugin(const nsACString & aMimeType, diff --git a/dom/plugins/base/nsPluginHost.h b/dom/plugins/base/nsPluginHost.h index 9d30c147c49b..7fe797054eea 100644 --- a/dom/plugins/base/nsPluginHost.h +++ b/dom/plugins/base/nsPluginHost.h @@ -12,6 +12,7 @@ #include "prlink.h" #include "prclist.h" #include "nsIPluginTag.h" +#include "nsPluginPlayPreviewInfo.h" #include "nsPluginsDir.h" #include "nsPluginDirServiceProvider.h" #include "nsAutoPtr.h" @@ -368,6 +369,7 @@ class nsPluginHost final : public nsIPluginHost, nsRefPtr mPlugins; nsRefPtr mCachedPlugins; nsRefPtr mInvalidPlugins; + nsTArray< nsRefPtr > mPlayPreviewMimeTypes; nsTArray< nsRefPtr > mFakePlugins; diff --git a/dom/plugins/base/nsPluginPlayPreviewInfo.cpp b/dom/plugins/base/nsPluginPlayPreviewInfo.cpp new file mode 100644 index 000000000000..c2a4ae18ed79 --- /dev/null +++ b/dom/plugins/base/nsPluginPlayPreviewInfo.cpp @@ -0,0 +1,154 @@ +/* -*- 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/. */ + +#include "nsPluginPlayPreviewInfo.h" +#include "nsWildCard.h" + +using namespace mozilla; + +nsPluginPlayPreviewInfo::nsPluginPlayPreviewInfo(const char* aMimeType, + bool aIgnoreCTP, + const char* aRedirectURL, + const char* aWhitelist) + : mMimeType(aMimeType), mIgnoreCTP(aIgnoreCTP), mRedirectURL(aRedirectURL), + mWhitelist(aWhitelist) {} + +nsPluginPlayPreviewInfo::nsPluginPlayPreviewInfo( + const nsPluginPlayPreviewInfo* aSource) +{ + MOZ_ASSERT(aSource); + + mMimeType = aSource->mMimeType; + mIgnoreCTP = aSource->mIgnoreCTP; + mRedirectURL = aSource->mRedirectURL; + mWhitelist = aSource->mWhitelist; +} + +nsPluginPlayPreviewInfo::~nsPluginPlayPreviewInfo() +{ +} + +NS_IMPL_ISUPPORTS(nsPluginPlayPreviewInfo, nsIPluginPlayPreviewInfo) + +NS_IMETHODIMP +nsPluginPlayPreviewInfo::GetMimeType(nsACString& aMimeType) +{ + aMimeType = mMimeType; + return NS_OK; +} + +NS_IMETHODIMP +nsPluginPlayPreviewInfo::GetIgnoreCTP(bool* aIgnoreCTP) +{ + *aIgnoreCTP = mIgnoreCTP; + return NS_OK; +} + +NS_IMETHODIMP +nsPluginPlayPreviewInfo::GetRedirectURL(nsACString& aRedirectURL) +{ + aRedirectURL = mRedirectURL; + return NS_OK; +} + +NS_IMETHODIMP +nsPluginPlayPreviewInfo::GetWhitelist(nsACString& aWhitelist) +{ + aWhitelist = mWhitelist; + return NS_OK; +} + +/* static */ nsresult +nsPluginPlayPreviewInfo::CheckWhitelist(const nsACString& aPageURI, + const nsACString& aObjectURI, + const nsACString& aWhitelist, + bool *_retval) +{ + if (aWhitelist.Length() == 0) { + // Considering empty whitelist as '*' entry. + *_retval = true; + return NS_OK; + } + + // Parses whitelist as comma separated entries of + // [@page_url object_url|@page_url|object_url] + // where page_url and object_url pattern matches for aPageURI + // and aObjectURI, and performs matching as the same time. + nsACString::const_iterator start, end; + aWhitelist.BeginReading(start); + aWhitelist.EndReading(end); + + nsAutoCString pageURI(aPageURI); + nsAutoCString objectURI(aObjectURI); + nsACString::const_iterator pos = start, entryStart, entryEnd; + nsACString::const_iterator pagePatternStart, pagePatternEnd; + nsACString::const_iterator objectPatternStart, objectPatternEnd; + int matchResult; + bool matched, didMatching; + while (pos != end) { + matched = true; + didMatching = false; + entryStart = pos; + // Looking for end of the entry. + while (pos != end && *pos != ',') { + pos++; + } + entryEnd = pos; + if (entryStart != entryEnd && *entryStart == '@') { + // Pattern for aPageURL is found, finding a space or end of the entry. + pagePatternStart = entryStart; + pagePatternStart++; + pagePatternEnd = pagePatternStart; + while (pagePatternEnd != entryEnd && *pagePatternEnd != ' ') { + pagePatternEnd++; + } + nsAutoCString pagePattern(Substring(pagePatternStart, pagePatternEnd)); + matchResult = NS_WildCardMatch(pageURI.get(), pagePattern.get(), true); + matched &= matchResult == MATCH; + didMatching = true; + objectPatternStart = pagePatternEnd; + } else { + objectPatternStart = entryStart; + } + while (objectPatternStart != entryEnd && *objectPatternStart == ' ') { + objectPatternStart++; + } + if (objectPatternStart != entryEnd) { + // Pattern for aObjectURL is found, removing trailing spaces. + objectPatternEnd = entryEnd; + --objectPatternEnd; + while (objectPatternStart != objectPatternEnd && + *objectPatternEnd == ' ') { + objectPatternEnd--; + }; + objectPatternEnd++; + nsAutoCString objectPattern(Substring(objectPatternStart, + objectPatternEnd)); + matchResult = NS_WildCardMatch(objectURI.get(), objectPattern.get(), true); + matched &= matchResult == MATCH; + didMatching = true; + } + // Ignoring match result for empty entries. + if (didMatching && matched) { + *_retval = true; + return NS_OK; + } + if (pos == end) { + break; + } + pos++; + } + + *_retval = false; + return NS_OK; +} + +NS_IMETHODIMP +nsPluginPlayPreviewInfo::CheckWhitelist(const nsACString& aPageURI, + const nsACString& aObjectURI, + bool *_retval) +{ + return CheckWhitelist(aPageURI, aObjectURI, mWhitelist, _retval); +} diff --git a/dom/plugins/base/nsPluginPlayPreviewInfo.h b/dom/plugins/base/nsPluginPlayPreviewInfo.h new file mode 100644 index 000000000000..a28bba593a7b --- /dev/null +++ b/dom/plugins/base/nsPluginPlayPreviewInfo.h @@ -0,0 +1,45 @@ +/* -*- 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 nsPluginPlayPreviewInfo_h_ +#define nsPluginPlayPreviewInfo_h_ + +#include "nsString.h" +#include "nsIPluginHost.h" + +class nsPluginPlayPreviewInfo : public nsIPluginPlayPreviewInfo +{ + virtual ~nsPluginPlayPreviewInfo(); + +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPLUGINPLAYPREVIEWINFO + + nsPluginPlayPreviewInfo(const char* aMimeType, + bool aIgnoreCTP, + const char* aRedirectURL, + const char* aWhitelist); + explicit nsPluginPlayPreviewInfo(const nsPluginPlayPreviewInfo* aSource); + + /** This function checks aPageURI and aObjectURI against the whitelist + * specified in aWhitelist. This is public static function because this + * whitelist checking code needs to be accessed without any instances of + * nsIPluginPlayPreviewInfo. In particular, the Shumway whitelist is + * obtained directly from prefs and compared using this code for telemetry + * purposes. + */ + static nsresult CheckWhitelist(const nsACString& aPageURI, + const nsACString& aObjectURI, + const nsACString& aWhitelist, + bool *_retval); + + nsCString mMimeType; + bool mIgnoreCTP; + nsCString mRedirectURL; + nsCString mWhitelist; +}; + + +#endif // nsPluginPlayPreviewInfo_h_ diff --git a/dom/plugins/ipc/PluginInstanceParent.cpp b/dom/plugins/ipc/PluginInstanceParent.cpp index 5bb6a827e299..afb2c3535e90 100644 --- a/dom/plugins/ipc/PluginInstanceParent.cpp +++ b/dom/plugins/ipc/PluginInstanceParent.cpp @@ -167,7 +167,26 @@ PluginInstanceParent::InitMetadata(const nsACString& aMimeType, return false; } nsCOMPtr baseUri(owner->GetBaseURI()); - return NS_SUCCEEDED(NS_MakeAbsoluteURI(mSrcAttribute, aSrcAttribute, baseUri)); + nsresult rv = NS_MakeAbsoluteURI(mSrcAttribute, aSrcAttribute, baseUri); + if (NS_FAILED(rv)) { + return false; + } + // Check the whitelist + nsAutoCString baseUrlSpec; + rv = baseUri->GetSpec(baseUrlSpec); + if (NS_FAILED(rv)) { + return false; + } + auto whitelist = Preferences::GetCString(kShumwayWhitelistPref); + // Empty whitelist is interpreted by CheckWhitelist as "allow everything," + // which is not valid for our use case and should be treated as a failure. + if (whitelist.IsEmpty()) { + return false; + } + rv = nsPluginPlayPreviewInfo::CheckWhitelist(baseUrlSpec, mSrcAttribute, + whitelist, + &mIsWhitelistedForShumway); + return NS_SUCCEEDED(rv); } void diff --git a/dom/webidl/HTMLObjectElement.webidl b/dom/webidl/HTMLObjectElement.webidl index 4bfa1a80352d..43aaa0dd4009 100644 --- a/dom/webidl/HTMLObjectElement.webidl +++ b/dom/webidl/HTMLObjectElement.webidl @@ -129,6 +129,9 @@ interface MozObjectLoadingContent { // The plugin is vulnerable (no update available) [ChromeOnly] const unsigned long PLUGIN_VULNERABLE_NO_UPDATE = 10; + // The plugin is in play preview mode + [ChromeOnly] + const unsigned long PLUGIN_PLAY_PREVIEW = 11; /** * The actual mime type (the one we got back from the network @@ -160,8 +163,8 @@ interface MozObjectLoadingContent { sequence getPluginParameters(); /** - * This method will play a plugin that has been stopped by the click-to-play - * feature. + * This method will play a plugin that has been stopped by the + * click-to-play plugins or play-preview features. */ [ChromeOnly, Throws] void playPlugin(); @@ -178,7 +181,7 @@ interface MozObjectLoadingContent { /** * This attribute will return true if the current content type has been * activated, either explicitly or by passing checks that would have it be - * click-to-play. + * click-to-play or play-preview. */ [ChromeOnly] readonly attribute boolean activated; @@ -203,6 +206,12 @@ interface MozObjectLoadingContent { [ChromeOnly] readonly attribute boolean hasRunningPlugin; + /** + * This method will disable the play-preview plugin state. + */ + [ChromeOnly, Throws] + void cancelPlayPreview(); + [ChromeOnly, Throws] readonly attribute unsigned long runID; }; diff --git a/layout/style/nsCSSPseudoClassList.h b/layout/style/nsCSSPseudoClassList.h index 45947cd63356..913dd2f5eaf8 100644 --- a/layout/style/nsCSSPseudoClassList.h +++ b/layout/style/nsCSSPseudoClassList.h @@ -179,6 +179,8 @@ CSS_STATE_PSEUDO_CLASS(mozTypeUnsupportedPlatform, ":-moz-type-unsupported-platf NS_EVENT_STATE_TYPE_UNSUPPORTED_PLATFORM) CSS_STATE_PSEUDO_CLASS(mozHandlerClickToPlay, ":-moz-handler-clicktoplay", 0, "", NS_EVENT_STATE_TYPE_CLICK_TO_PLAY) +CSS_STATE_PSEUDO_CLASS(mozHandlerPlayPreview, ":-moz-handler-playpreview", 0, "", + NS_EVENT_STATE_TYPE_PLAY_PREVIEW) CSS_STATE_PSEUDO_CLASS(mozHandlerVulnerableUpdatable, ":-moz-handler-vulnerable-updatable", 0, "", NS_EVENT_STATE_VULNERABLE_UPDATABLE) CSS_STATE_PSEUDO_CLASS(mozHandlerVulnerableNoUpdate, ":-moz-handler-vulnerable-no-update", 0, "", diff --git a/mobile/android/chrome/content/PluginHelper.js b/mobile/android/chrome/content/PluginHelper.js index b684a74555cf..4c4a81198fb3 100644 --- a/mobile/android/chrome/content/PluginHelper.js +++ b/mobile/android/chrome/content/PluginHelper.js @@ -87,6 +87,17 @@ var PluginHelper = { objLoadingContent.playPlugin(); }, + stopPlayPreview: function(plugin, playPlugin) { + let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent); + if (objLoadingContent.activated) + return; + + if (playPlugin) + objLoadingContent.playPlugin(); + else + objLoadingContent.cancelPlayPreview(); + }, + getPluginPreference: function getPluginPreference() { let pluginDisable = Services.prefs.getBoolPref("plugin.disable"); if (pluginDisable) @@ -201,6 +212,54 @@ var PluginHelper = { break; } + case "PluginPlayPreview": { + let previewContent = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent"); + let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); + let mimeType = PluginHelper.getPluginMimeType(plugin); + let playPreviewInfo = pluginHost.getPlayPreviewInfo(mimeType); + + if (!playPreviewInfo.ignoreCTP) { + // Check if plugins have already been activated for this page, or if + // the user has set a permission to always play plugins on the site + if (aTab.clickToPlayPluginsActivated || + Services.perms.testPermission(aTab.browser.currentURI, "plugins") == + Services.perms.ALLOW_ACTION) { + PluginHelper.playPlugin(plugin); + return; + } + + // Always show door hanger for play preview plugins + PluginHelper.delayAndShowDoorHanger(aTab); + } + + let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0]; + if (!iframe) { + // lazy initialization of the iframe + iframe = doc.createElementNS("http://www.w3.org/1999/xhtml", "iframe"); + iframe.className = "previewPluginContentFrame"; + previewContent.appendChild(iframe); + } + iframe.src = playPreviewInfo.redirectURL; + + // MozPlayPlugin event can be dispatched from the extension chrome + // code to replace the preview content with the native plugin + previewContent.addEventListener("MozPlayPlugin", function playPluginHandler(e) { + if (!e.isTrusted) + return; + + previewContent.removeEventListener("MozPlayPlugin", playPluginHandler, true); + + let playPlugin = !aEvent.detail; + PluginHelper.stopPlayPreview(plugin, playPlugin); + + // cleaning up: removes overlay iframe from the DOM + let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0]; + if (iframe) + previewContent.removeChild(iframe); + }, true); + break; + } + case "PluginNotFound": { // On devices where we don't support Flash, there will be a // "Learn More..." link in the missing plugin error message. @@ -224,6 +283,8 @@ var PluginHelper = { return "PluginNotFound"; case Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY: return "PluginClickToPlay"; + case Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW: + return "PluginPlayPreview"; default: // Not all states map to a handler return null; diff --git a/toolkit/mozapps/plugins/content/pluginProblem.xml b/toolkit/mozapps/plugins/content/pluginProblem.xml index 5b3c9f99f956..e20ae3c83069 100644 --- a/toolkit/mozapps/plugins/content/pluginProblem.xml +++ b/toolkit/mozapps/plugins/content/pluginProblem.xml @@ -67,6 +67,7 @@ + diff --git a/toolkit/mozapps/plugins/content/pluginProblemBinding.css b/toolkit/mozapps/plugins/content/pluginProblemBinding.css index bf9f1c222483..abf4b00a0204 100644 --- a/toolkit/mozapps/plugins/content/pluginProblemBinding.css +++ b/toolkit/mozapps/plugins/content/pluginProblemBinding.css @@ -8,18 +8,21 @@ embed:-moz-handler-disabled, embed:-moz-handler-blocked, embed:-moz-handler-crashed, embed:-moz-handler-clicktoplay, +embed:-moz-handler-playpreview, embed:-moz-handler-vulnerable-updatable, embed:-moz-handler-vulnerable-no-update, applet:-moz-handler-disabled, applet:-moz-handler-blocked, applet:-moz-handler-crashed, applet:-moz-handler-clicktoplay, +applet:-moz-handler-playpreview, applet:-moz-handler-vulnerable-updatable, applet:-moz-handler-vulnerable-no-update, object:-moz-handler-disabled, object:-moz-handler-blocked, object:-moz-handler-crashed, object:-moz-handler-clicktoplay, +object:-moz-handler-playpreview, object:-moz-handler-vulnerable-updatable, object:-moz-handler-vulnerable-no-update { display: inline-block; diff --git a/toolkit/mozapps/plugins/content/pluginProblemContent.css b/toolkit/mozapps/plugins/content/pluginProblemContent.css index 0f7c7d39a709..91bcda016c1d 100644 --- a/toolkit/mozapps/plugins/content/pluginProblemContent.css +++ b/toolkit/mozapps/plugins/content/pluginProblemContent.css @@ -71,6 +71,10 @@ html|applet:not([height]), html|applet[height=""] { direction: rtl; } +:-moz-handler-playpreview .mainBox { + display: none; +} + :-moz-handler-clicktoplay .hoverBox, :-moz-handler-vulnerable-updatable .hoverBox, :-moz-handler-vulnerable-no-update .hoverBox { @@ -84,6 +88,23 @@ html|applet:not([height]), html|applet[height=""] { cursor: inherit; } +.previewPluginContent { + display: none; +} + +.previewPluginContent > iframe { + width: inherit; + height: inherit; + border: none; +} + +:-moz-handler-playpreview .previewPluginContent { + display: block; + width: inherit; + height: inherit; + overflow: hidden; +} + .msg { display: none; }