mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
Merge inbound to m-c. a=merge
This commit is contained in:
commit
8b5cd2c641
@ -29,22 +29,27 @@ endif
|
||||
|
||||
AB_CD = $(MOZ_UI_LOCALE)
|
||||
|
||||
AB := $(firstword $(subst -, ,$(AB_CD)))
|
||||
ifeq (zh-TW,$(AB_CD))
|
||||
LPROJ_ROOT := $(subst -,_,$(AB_CD))
|
||||
else
|
||||
LPROJ_ROOT := $(firstword $(subst -, ,$(AB_CD)))
|
||||
endif
|
||||
LPROJ := Contents/Resources/$(LPROJ_ROOT).lproj
|
||||
|
||||
clean clobber repackage::
|
||||
rm -rf $(DIST)/$(APP_NAME).app
|
||||
|
||||
libs-preqs = \
|
||||
$(call mkdir_deps,$(DIST)/$(APP_NAME).app/Contents/MacOS) \
|
||||
$(call mkdir_deps,$(DIST)/$(APP_NAME).app/Contents/Resources/$(AB).lproj) \
|
||||
$(call mkdir_deps,$(DIST)/$(APP_NAME).app/$(LPROJ)) \
|
||||
$(NULL)
|
||||
|
||||
.PHONY: repackage
|
||||
tools repackage:: $(libs-preqs)
|
||||
rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents $(DIST)/$(APP_NAME).app --exclude English.lproj
|
||||
rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(DIST)/$(APP_NAME).app/Contents/Resources/$(AB).lproj
|
||||
rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(DIST)/$(APP_NAME).app/$(LPROJ)
|
||||
sed -e 's/%MOZ_APP_VERSION%/$(MOZ_APP_VERSION)/' -e 's/%MOZ_APP_NAME%/$(MOZ_APP_NAME)/' -e 's/%APP_VERSION%/$(APP_VERSION)/' -e 's/%APP_NAME%/$(APP_NAME)/' -e 's/%APP_BINARY%/$(APP_BINARY)/' $(srcdir)/macbuild/Contents/Info.plist.in > $(DIST)/$(APP_NAME).app/Contents/Info.plist
|
||||
sed -e 's/%APP_VERSION%/$(APP_VERSION)/' -e 's/%APP_NAME%/$(APP_NAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(DIST)/$(APP_NAME).app/Contents/Resources/$(AB).lproj/InfoPlist.strings
|
||||
sed -e 's/%APP_VERSION%/$(APP_VERSION)/' -e 's/%APP_NAME%/$(APP_NAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(DIST)/$(APP_NAME).app/$(LPROJ)/InfoPlist.strings
|
||||
rsync -a --exclude 'mangle' --exclude 'shlibsign' --exclude-from='$(srcdir)/macbuild/Contents/MacOS-files.in' $(DIST)/bin/ $(DIST)/$(APP_NAME).app/Contents/Resources
|
||||
rsync -a --include-from='$(srcdir)/macbuild/Contents/MacOS-files.in' --exclude '*' $(DIST)/bin/ $(DIST)/$(APP_NAME).app/Contents/MacOS
|
||||
ifdef LIBXUL_SDK
|
||||
|
@ -1,44 +0,0 @@
|
||||
{
|
||||
"config_version": 2,
|
||||
"tooltool_manifest": "releng-hamachi.tt",
|
||||
"mock_target": "mozilla-centos6-x86_64",
|
||||
"mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "java-1.6.0-openjdk-devel", "git", "glibc-devel.i686", "libstdc++.i686", "zlib-devel.i686", "ncurses-devel.i686", "libX11-devel.i686", "mesa-libGL-devel.i686", "mesa-libGL-devel", "libX11-devel"],
|
||||
"mock_files": [
|
||||
["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"],
|
||||
["/builds/crash-stats-api.token", "/builds/crash-stats-api.token"]
|
||||
],
|
||||
"build_targets": [],
|
||||
"upload_files": [
|
||||
"{objdir}/dist/b2g-*.crashreporter-symbols.zip",
|
||||
"{objdir}/dist/b2g-*.tar.gz",
|
||||
"{workdir}/sources.xml"
|
||||
],
|
||||
"public_upload_files": [
|
||||
"{objdir}/dist/b2g-*.crashreporter-symbols.zip",
|
||||
"{objdir}/dist/b2g-*.tar.gz",
|
||||
"{workdir}/sources.xml",
|
||||
"{workdir}/out/target/product/hamachi/*.mar"
|
||||
],
|
||||
"zip_files": [
|
||||
"{workdir}/profile.sh",
|
||||
["{workdir}/gecko/tools/profiler/merge-profiles.py", "gecko/tools/profiler/"],
|
||||
["{workdir}/scripts/profile-symbolicate.py", "scripts/"],
|
||||
["{workdir}/gecko/tools/rb/fix_stack_using_bpsyms.py", "gecko/tools/rb/"]
|
||||
],
|
||||
"env": {
|
||||
"VARIANT": "user",
|
||||
"MOZILLA_OFFICIAL": "1",
|
||||
"MOZ_TELEMETRY_REPORTING": "1",
|
||||
"B2G_UPDATE_CHANNEL": "nightly"
|
||||
},
|
||||
"b2g_manifest": "hamachi.xml",
|
||||
"b2g_manifest_intree": true,
|
||||
"additional_source_tarballs": ["backup-hamachi.tar.xz"],
|
||||
"gecko_l10n_root": "https://hg.mozilla.org/l10n-central",
|
||||
"gaia": {
|
||||
"l10n": {
|
||||
"vcs": "hgtool",
|
||||
"root": "https://hg.mozilla.org/gaia-l10n"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
{
|
||||
"config_version": 2,
|
||||
"tooltool_manifest": "releng-limited-memory.tt",
|
||||
"tooltool_bootstrap_cmd": ["bash", "-xe", "tt_setup.sh"],
|
||||
"mock_target": "mozilla-centos6-x86_64",
|
||||
"mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "java-1.6.0-openjdk-devel", "git", "glibc-devel.i686", "libstdc++.i686", "zlib-devel.i686", "ncurses-devel.i686", "libX11-devel.i686", "mesa-libGL-devel.i686", "mesa-libGL-devel", "libX11-devel"],
|
||||
"mock_files": [["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"]],
|
||||
"build_targets": [],
|
||||
"upload_files": [
|
||||
"{objdir}/dist/b2g-*.crashreporter-symbols.zip",
|
||||
"{objdir}/dist/b2g-*.tar.gz",
|
||||
"{workdir}/sources.xml"
|
||||
],
|
||||
"zip_files": [
|
||||
["{workdir}/out/target/product/hamachi/*.img", "out/target/product/hamachi/"],
|
||||
["{workdir}/boot.2knand.img", "out/target/product/hamachi/boot.img"],
|
||||
"{workdir}/flash.sh",
|
||||
"{workdir}/load-config.sh",
|
||||
"{workdir}/.config",
|
||||
"{workdir}/sources.xml"
|
||||
],
|
||||
"env": {
|
||||
"VARIANT": "user",
|
||||
"MOZILLA_OFFICIAL": "1",
|
||||
"MOZ_TELEMETRY_REPORTING": "1"
|
||||
},
|
||||
"b2g_manifest": "hamachi.xml",
|
||||
"b2g_manifest_branch": "master",
|
||||
"additional_source_tarballs": ["backup-hamachi.tar.xz"],
|
||||
"gecko_l10n_root": "https://hg.mozilla.org/l10n-central",
|
||||
"gaia": {
|
||||
"l10n": {
|
||||
"vcs": "hgtool",
|
||||
"root": "https://hg.mozilla.org/gaia-l10n"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
[
|
||||
{
|
||||
"size": 55276112,
|
||||
"digest": "035efc2064a88bdb6f60fd126f17ee0e35de708f4666837cbeb0f3381024044a6ec3a05c244c553f9c2d852d94706f5263edde3d7dbff33872bd05db0215f5e6",
|
||||
"algorithm": "sha512",
|
||||
"filename": "backup-hamachi.tar.xz"
|
||||
},
|
||||
{
|
||||
"size": 1570553,
|
||||
"digest": "ea03de74df73b05e939c314cd15c54aac7b5488a407b7cc4f5f263f3049a1f69642c567dd35c43d0bc3f0d599d0385a26ab2dd947a6b18f9044e4918b382eea7",
|
||||
"algorithm": "sha512",
|
||||
"filename": "Adreno200-AU_LINUX_ANDROID_ICS_CHOCO_CS.04.00.03.06.001.zip"
|
||||
},
|
||||
{
|
||||
"size": 80458572,
|
||||
"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gcc.tar.xz",
|
||||
"unpack": "True"
|
||||
}
|
||||
]
|
@ -1,39 +0,0 @@
|
||||
[
|
||||
{
|
||||
"size": 55276112,
|
||||
"digest": "035efc2064a88bdb6f60fd126f17ee0e35de708f4666837cbeb0f3381024044a6ec3a05c244c553f9c2d852d94706f5263edde3d7dbff33872bd05db0215f5e6",
|
||||
"algorithm": "sha512",
|
||||
"filename": "backup-hamachi.tar.xz"
|
||||
},
|
||||
{
|
||||
"size": 1570553,
|
||||
"digest": "ea03de74df73b05e939c314cd15c54aac7b5488a407b7cc4f5f263f3049a1f69642c567dd35c43d0bc3f0d599d0385a26ab2dd947a6b18f9044e4918b382eea7",
|
||||
"algorithm": "sha512",
|
||||
"filename": "Adreno200-AU_LINUX_ANDROID_ICS_CHOCO_CS.04.00.03.06.001.zip"
|
||||
},
|
||||
{
|
||||
"size": 4632576,
|
||||
"digest": "27d149a804d6cfaf387d7cced7078b5fe5227681d407f9258cf07ac61fcb35ee17a414b3c108eee6720293bd3e1d9e9c911eaf57059ad7d2361f9b93e9ee815b",
|
||||
"algorithm": "sha512",
|
||||
"filename": "boot.2knand.img"
|
||||
},
|
||||
{
|
||||
"size": 9452,
|
||||
"digest": "d4b919947dfb3f90d6645df31c92d795d6cf68e67f3679bbd80f8bb1920310dd69c8f6d3c0dcd697000b4691cbfddd17d60667a5a9ef933ba78d9a54a86503f0",
|
||||
"algorithm": "sha512",
|
||||
"filename": "patches.tgz"
|
||||
},
|
||||
{
|
||||
"size": 302,
|
||||
"digest": "d6a969fad4e53b617a21026062767f4b89d301464c38e9c9d04ba7dc7dcad72f1b337c284243a81e74de713171af5dd9a13aaaa7efd10109a0847ed23bf6e539",
|
||||
"algorithm": "sha512",
|
||||
"filename": "tt_setup.sh"
|
||||
},
|
||||
{
|
||||
"size": 80458572,
|
||||
"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gcc.tar.xz",
|
||||
"unpack": "True"
|
||||
}
|
||||
]
|
@ -1,112 +0,0 @@
|
||||
<?xml version="1.0" ?><manifest>
|
||||
<!--original fetch url was https://android.googlesource.com/-->
|
||||
<remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
|
||||
<!--original fetch url was git://github.com/mozilla-b2g/-->
|
||||
<remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
|
||||
<!--original fetch url was git://github.com/mozilla/-->
|
||||
<remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
|
||||
<!--original fetch url was git://codeaurora.org/-->
|
||||
<remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
|
||||
<!--original fetch url was https://git.mozilla.org/releases-->
|
||||
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
|
||||
<!--original fetch url was git://github.com/apitrace/-->
|
||||
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
|
||||
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
|
||||
<!-- Gonk specific things and forks -->
|
||||
<project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7205eca829290a2b5c312ddade7416dff41051cd"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a536a1fec54b9e2a9ae4fd2e69c2336f12559730"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
<project name="platform_bionic" path="bionic" remote="b2g" revision="1a2a32eda22ef2cd18f57f423a5e7b22a105a6f8"/>
|
||||
<project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
|
||||
<project name="platform/development" path="development" revision="2460485184bc8535440bb63876d4e63ec1b4770c"/>
|
||||
<project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
|
||||
<project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
|
||||
<project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
|
||||
<project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="eb469e89d6ec6ec7ff1633a7f1b567a3787888f8"/>
|
||||
<project name="platform/external/bluetooth/glib" path="external/bluetooth/glib" revision="c6b49241cc1a8950723a5f74f8f4b4f4c3fa970e"/>
|
||||
<project name="platform/external/bluetooth/hcidump" path="external/bluetooth/hcidump" revision="05c760f3cca674e868cd35fefbacfb8d67745ce8"/>
|
||||
<project name="platform/external/bsdiff" path="external/bsdiff" revision="81872540236d9bb15cccf963d05b9de48baa5375"/>
|
||||
<project name="platform/external/bzip2" path="external/bzip2" revision="048dacdca43eed1534689ececcf2781c63e1e4ba"/>
|
||||
<project name="platform/external/dbus" path="external/dbus" revision="878ed6cf21207e36956253a9013932c819053ee4"/>
|
||||
<project name="platform/external/dhcpcd" path="external/dhcpcd" revision="638e6ed58cb734c178f1dfb251d3769e1b8ef410"/>
|
||||
<project name="platform/external/dnsmasq" path="external/dnsmasq" revision="f621afad94df46204c25fc2593a19d704d2637f5"/>
|
||||
<project name="platform_external_elfcopy" path="external/elfcopy" remote="b2g" revision="62c1bed1c4505369cac2e72fbe30452a598fb690"/>
|
||||
<project name="platform_external_elfutils" path="external/elfutils" remote="b2g" revision="72940dec691fa3255e13df01f8c53b620e446066"/>
|
||||
<project name="platform/external/e2fsprogs" path="external/e2fsprogs" revision="d5f550bb2f556c5d287f7c8d2b77223654bcec37"/>
|
||||
<project name="platform/external/expat" path="external/expat" revision="6df134250feab71edb5915ecaa6268210bca76c5"/>
|
||||
<project name="platform/external/fdlibm" path="external/fdlibm" revision="988ffeb12a6e044ae3504838ef1fee3fe0716934"/>
|
||||
<project name="platform/external/flac" path="external/flac" revision="5893fbe890f5dab8e4146d2baa4bd2691c0739e0"/>
|
||||
<project name="platform/external/freetype" path="external/freetype" revision="aeb407daf3711a10a27f3bc2223c5eb05158076e"/>
|
||||
<project name="platform/external/giflib" path="external/giflib" revision="b2597268aef084202a8c349d1cc072c03c6e22eb"/>
|
||||
<project name="platform/external/gtest" path="external/gtest" revision="8c212ebe53bb2baab3575f03069016f1fb11e449"/>
|
||||
<project name="platform/external/harfbuzz" path="external/harfbuzz" revision="116610d63a859521dacf00fb6818ee9ab2e666f6"/>
|
||||
<project name="platform/external/icu4c" path="external/icu4c" revision="0fa67b93b831c6636ca18b152a1b1b14cc99b034"/>
|
||||
<project name="platform/external/iptables" path="external/iptables" revision="3b2deb17f065c5664bb25e1a28489e5792eb63ff"/>
|
||||
<project name="platform/external/jpeg" path="external/jpeg" revision="ef8288e4a75360236d69c5860b0d18ea101f0c1d"/>
|
||||
<project name="platform/external/libgsm" path="external/libgsm" revision="5e4516958690b9a1b2c98f88eeecba3edd2dbda4"/>
|
||||
<project name="platform/external/liblzf" path="external/liblzf" revision="6946aa575b0949d045722794850896099d937cbb"/>
|
||||
<project name="platform/external/libnfc-nxp" path="external/libnfc-nxp" revision="3a912b065a31a72c63ad56ac224cfeaa933423b6"/>
|
||||
<project name="platform/external/libnl-headers" path="external/libnl-headers" revision="6ccf7349d61f73ac26a0675d735d903ab919c658"/>
|
||||
<project name="platform/external/libpng" path="external/libpng" revision="1353a869289ec205209e594c5804e17fa4787e04"/>
|
||||
<project name="platform/external/libvpx" path="external/libvpx" revision="2618c324e2ecd1fa5dbfb8cc0ba0911f4fd255d9"/>
|
||||
<project name="platform/external/llvm" path="external/llvm" revision="d9527968ba7078ee6ce99dda8d8f555342032b91"/>
|
||||
<project name="platform/external/mksh" path="external/mksh" revision="8380dd0a75783fc5e4a3e3b0f07f7e25bade3c8c"/>
|
||||
<project name="platform/external/openssl" path="external/openssl" revision="c63c712a6a20e2c1b6085601c2d48e3f3ef32f73"/>
|
||||
<project name="platform/external/protobuf" path="external/protobuf" revision="e217977611c52bccde7f7c78e1d3c790c6357431"/>
|
||||
<project name="platform/external/safe-iop" path="external/safe-iop" revision="07073634e2e3aa4f518e36ed5dec3aabc549d5fb"/>
|
||||
<project name="screencap-gonk" path="external/screencap-gonk" remote="b2g" revision="e6403c71e9eca8cb943739d5a0a192deac60fc51"/>
|
||||
<project name="platform/external/skia" path="external/skia" revision="098dff2ef5d35b30bc79fdfdeae74e186919dcfe"/>
|
||||
<project name="platform/external/sonivox" path="external/sonivox" revision="f5f46e68585c690436956f552994910f5e33bef5"/>
|
||||
<project name="platform/external/speex" path="external/speex" revision="ebe6230a7f7c69f5a4389f2b09b7b19ef9e94f32"/>
|
||||
<project name="platform/external/sqlite" path="external/sqlite" revision="fb30e613139b8836fdc8e81e166cf3a76e5fa17f"/>
|
||||
<project name="platform/external/stlport" path="external/stlport" revision="a6734e0645fce81c9610de0488b729207bfa576e"/>
|
||||
<project name="platform/external/strace" path="external/strace" revision="c9fd2e5ef7d002e12e7cf2512506c84a9414b0fd"/>
|
||||
<project name="platform/external/svox" path="external/svox" revision="02dadb2ae0a5c31b9451ab169f1383dd0ff0948f"/>
|
||||
<project name="platform/external/tagsoup" path="external/tagsoup" revision="68c2ec9e0acdb3214b7fb91dbab8c9fab8736817"/>
|
||||
<project name="platform/external/tinyalsa" path="external/tinyalsa" revision="b3a40ef1402b782553e1f3798d17e75636f16e3b"/>
|
||||
<project name="platform/external/tremolo" path="external/tremolo" revision="25bd78d2392dbdc879ae53382cde9d019f79cf6f"/>
|
||||
<project name="unbootimg" path="external/unbootimg" remote="b2g" revision="9464623d92eb8668544916dc5a8f4f6337d0bc08"/>
|
||||
<project name="platform/external/webp" path="external/webp" revision="88fe2b83c4b9232cd08729556fd0485d6a6a92cd"/>
|
||||
<project name="platform/external/webrtc" path="external/webrtc" revision="137024dc8a2e9251a471e20518a9c3ae06f81f23"/>
|
||||
<project name="platform/external/wpa_supplicant" path="external/wpa_supplicant" revision="a01d37870bbf9892d43e792e5de0683ca41c5497"/>
|
||||
<project name="platform/external/hostap" path="external/hostap" revision="611194f9ea6a2851171663dd59fae2fbfb39e246"/>
|
||||
<project name="platform/external/zlib" path="external/zlib" revision="cb8dbfb25f8f0b111d0c8270ac49455cac4fd5b3"/>
|
||||
<project name="platform/external/yaffs2" path="external/yaffs2" revision="0afa916204c664b3114429637b63af1321a0aeca"/>
|
||||
<project name="platform/frameworks/base" path="frameworks/base" revision="e353565bea6e7c8382219190afefcced4b50b7d0"/>
|
||||
<project name="platform/frameworks/opt/emoji" path="frameworks/opt/emoji" revision="a95d8db002770469d72dfaf59ff37ac96db29a87"/>
|
||||
<project name="platform/frameworks/support" path="frameworks/support" revision="90ffd236fe7f1e2bec74bd8624284ea017b41e64"/>
|
||||
<project name="platform/hardware/libhardware" path="hardware/libhardware" revision="300ccfa39e003383d746d6a404be48c9194b19e1"/>
|
||||
<project name="platform/hardware/libhardware_legacy" path="hardware/libhardware_legacy" revision="f197f55362dea6b9fc338a4f6d89bc009900f41f"/>
|
||||
<project name="platform/libcore" path="libcore" revision="6d924abb26a30abb24d98378fac6bdc405f2a398"/>
|
||||
<project name="platform/ndk" path="ndk" revision="9f555971e1481854d5b4dc11b3e6af9fff4f241f"/>
|
||||
<project name="platform/prebuilt" path="prebuilt" revision="248d92592df169569c387a91db56b1fedd6e5d29"/>
|
||||
<project name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" revision="d9735fc81434f2af2c44d86ca57740c673c8d9bc"/>
|
||||
<project name="platform/system/bluetooth" path="system/bluetooth" revision="395aff045276107a285daf0392d0884a98b9f538"/>
|
||||
<project name="platform/system/core" path="system/core" revision="70229cf62037cfb70ec2257f7c78b5550628fb53"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="a5dd0ea60ce973c2c762b41835a43316fb4ff9e3"/>
|
||||
<project name="platform/system/media" path="system/media" revision="fbb3d9b4c5bf59071424e820e872e3f64f0a244a"/>
|
||||
<project name="platform/system/netd" path="system/netd" revision="2e226e6e636ca0a8cc4c51093e46f4baba1ffcce"/>
|
||||
<project name="platform/system/vold" path="system/vold" revision="8ac5eef8ea3a456b96d52ce2091bf6d814782d8c"/>
|
||||
<!-- hamachi specific things -->
|
||||
<project name="quic/lf/b2g/build" path="device/qcom/b2g_common" revision="ccd8b858242c099cb4bc725daf22896ab4a4b325"/>
|
||||
<project name="quic/lf/b2g/external/jsmin" path="external/jsmin" revision="cec896f0affaa0226c02605ad28d42df1bc0e393"/>
|
||||
<project name="device/qcom/common" path="device/qcom/common" revision="d13aaf080177b7c48f243d51827db5c7a7873cd0"/>
|
||||
<project name="platform/vendor/qcom/msm7627a" path="device/qcom/msm7627a" revision="f06bcacc6f13cec895dc5d4c2385c076396194ec"/>
|
||||
<project name="android-device-hamachi" path="device/qcom/hamachi" remote="b2g" revision="7a67afcef2846ad7938059111e1d0bc4de9f0445"/>
|
||||
<project name="kernel/msm" path="kernel" revision="a6578b9cacf9079f2dcf5bfe77c31b1be18809e3"/>
|
||||
<project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="19933e5d182a4799c6217b19a18562193a419298"/>
|
||||
<project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="5a58382180c70d0c446badc9c9837918ab69ec60"/>
|
||||
<project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="20d83ab382a1f813702421e76c2f9f994585990e"/>
|
||||
<project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="1698e6e9ed7cf1d543508845fa05ed86c7e5e241"/>
|
||||
<project name="platform/hardware/msm7k" path="hardware/msm7k" revision="693e65da9905d88c23653b45800e6509143f6a78"/>
|
||||
<project name="platform/vendor/qcom-opensource/omx/mm-core" path="vendor/qcom/opensource/omx/mm-core" revision="0365db6af2d4df11184a421f97c5043db47a0c0d"/>
|
||||
<project name="platform/hardware/ril" path="hardware/ril" revision="ec40c0aee736052fc4fe01c1b8dc16929da5dc45"/>
|
||||
</manifest>
|
@ -1,50 +0,0 @@
|
||||
{
|
||||
"config_version": 2,
|
||||
"tooltool_manifest": "releng-helix.tt",
|
||||
"mock_target": "mozilla-centos6-x86_64",
|
||||
"mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "java-1.6.0-openjdk-devel", "git", "glibc-devel.i686", "libstdc++.i686", "zlib-devel.i686", "ncurses-devel.i686", "libX11-devel.i686", "mesa-libGL-devel.i686", "mesa-libGL-devel", "libX11-devel"],
|
||||
"mock_files": [
|
||||
["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"],
|
||||
["/builds/crash-stats-api.token", "/builds/crash-stats-api.token"]
|
||||
],
|
||||
"build_targets": [],
|
||||
"upload_files": [
|
||||
"{objdir}/dist/b2g-*.crashreporter-symbols.zip",
|
||||
"{objdir}/dist/b2g-*.tar.gz",
|
||||
"{workdir}/sources.xml"
|
||||
],
|
||||
"public_upload_files": [
|
||||
"{objdir}/dist/b2g-*.crashreporter-symbols.zip",
|
||||
"{objdir}/dist/b2g-*.tar.gz",
|
||||
"{workdir}/sources.xml",
|
||||
"{objdir}/dist/b2g-update/*.mar"
|
||||
],
|
||||
"zip_files": [
|
||||
["{workdir}/out/target/product/helix/*.img", "out/target/product/helix/"],
|
||||
"{workdir}/flash.sh",
|
||||
"{workdir}/load-config.sh",
|
||||
"{workdir}/.config",
|
||||
"{workdir}/sources.xml",
|
||||
"{workdir}/profile.sh",
|
||||
["{workdir}/gecko/tools/profiler/merge-profiles.py", "gecko/tools/profiler/"],
|
||||
["{workdir}/scripts/profile-symbolicate.py", "scripts/"],
|
||||
["{workdir}/gecko/tools/rb/fix_stack_using_bpsyms.py", "gecko/tools/rb/"]
|
||||
],
|
||||
"env": {
|
||||
"VARIANT": "user",
|
||||
"MOZILLA_OFFICIAL": "1",
|
||||
"MOZ_TELEMETRY_REPORTING": "1",
|
||||
"ANDROIDFS_DIR": "{workdir}/helix-ics",
|
||||
"B2G_UPDATE_CHANNEL": "nightly"
|
||||
},
|
||||
"b2g_manifest": "helix.xml",
|
||||
"b2g_manifest_intree": true,
|
||||
"additional_source_tarballs": ["helix-ics.tar.xz"],
|
||||
"gecko_l10n_root": "https://hg.mozilla.org/l10n-central",
|
||||
"gaia": {
|
||||
"l10n": {
|
||||
"vcs": "hgtool",
|
||||
"root": "https://hg.mozilla.org/gaia-l10n"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
[
|
||||
{
|
||||
"size": 58958768,
|
||||
"digest": "a1c7727075b481259ee1835d0f016834f52b8a20dd18be6e0dbf265421671e2fc5203ff01891588ab712f5033103350574528dae866ea795460518afa78b0c4b",
|
||||
"algorithm": "sha512",
|
||||
"filename": "helix-ics.tar.xz"
|
||||
},
|
||||
{
|
||||
"size": 1570553,
|
||||
"digest": "ea03de74df73b05e939c314cd15c54aac7b5488a407b7cc4f5f263f3049a1f69642c567dd35c43d0bc3f0d599d0385a26ab2dd947a6b18f9044e4918b382eea7",
|
||||
"algorithm": "sha512",
|
||||
"filename": "Adreno200-AU_LINUX_ANDROID_ICS_CHOCO_CS.04.00.03.06.001.zip"
|
||||
},
|
||||
{
|
||||
"size": 80458572,
|
||||
"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gcc.tar.xz",
|
||||
"unpack": "True"
|
||||
}
|
||||
]
|
@ -1,109 +0,0 @@
|
||||
<?xml version="1.0" ?><manifest>
|
||||
<!--original fetch url was https://android.googlesource.com/-->
|
||||
<remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
|
||||
<!--original fetch url was git://github.com/mozilla-b2g/-->
|
||||
<remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
|
||||
<!--original fetch url was git://github.com/mozilla/-->
|
||||
<remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
|
||||
<!--original fetch url was git://codeaurora.org/-->
|
||||
<remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
|
||||
<!--original fetch url was https://git.mozilla.org/releases-->
|
||||
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
|
||||
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
|
||||
<!-- Gonk specific things and forks -->
|
||||
<project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="b33a1afb538e8c7e12f6fb792c454da34f9f5b76"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
<project name="platform_bionic" path="bionic" remote="b2g" revision="1a2a32eda22ef2cd18f57f423a5e7b22a105a6f8"/>
|
||||
<project name="platform/bootable/recovery" path="bootable/recovery" revision="575fdbf046e966a5915b1f1e800e5d6ad0ea14c0"/>
|
||||
<project name="platform/development" path="development" revision="b1025ec93beeb480caaf3049d171283c3846461d"/>
|
||||
<project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
|
||||
<project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
|
||||
<project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
|
||||
<project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="eb469e89d6ec6ec7ff1633a7f1b567a3787888f8"/>
|
||||
<project name="platform/external/bluetooth/glib" path="external/bluetooth/glib" revision="c6b49241cc1a8950723a5f74f8f4b4f4c3fa970e"/>
|
||||
<project name="platform/external/bluetooth/hcidump" path="external/bluetooth/hcidump" revision="05c760f3cca674e868cd35fefbacfb8d67745ce8"/>
|
||||
<project name="platform/external/bsdiff" path="external/bsdiff" revision="81872540236d9bb15cccf963d05b9de48baa5375"/>
|
||||
<project name="platform/external/bzip2" path="external/bzip2" revision="048dacdca43eed1534689ececcf2781c63e1e4ba"/>
|
||||
<project name="platform/external/dbus" path="external/dbus" revision="878ed6cf21207e36956253a9013932c819053ee4"/>
|
||||
<project name="platform/external/dhcpcd" path="external/dhcpcd" revision="638e6ed58cb734c178f1dfb251d3769e1b8ef410"/>
|
||||
<project name="platform/external/dnsmasq" path="external/dnsmasq" revision="f621afad94df46204c25fc2593a19d704d2637f5"/>
|
||||
<project name="platform_external_elfcopy" path="external/elfcopy" remote="b2g" revision="62c1bed1c4505369cac2e72fbe30452a598fb690"/>
|
||||
<project name="platform_external_elfutils" path="external/elfutils" remote="b2g" revision="72940dec691fa3255e13df01f8c53b620e446066"/>
|
||||
<project name="platform/external/e2fsprogs" path="external/e2fsprogs" revision="d5f550bb2f556c5d287f7c8d2b77223654bcec37"/>
|
||||
<project name="platform/external/expat" path="external/expat" revision="6df134250feab71edb5915ecaa6268210bca76c5"/>
|
||||
<project name="platform/external/fdlibm" path="external/fdlibm" revision="988ffeb12a6e044ae3504838ef1fee3fe0716934"/>
|
||||
<project name="platform/external/flac" path="external/flac" revision="5893fbe890f5dab8e4146d2baa4bd2691c0739e0"/>
|
||||
<project name="platform/external/freetype" path="external/freetype" revision="aeb407daf3711a10a27f3bc2223c5eb05158076e"/>
|
||||
<project name="platform/external/giflib" path="external/giflib" revision="b2597268aef084202a8c349d1cc072c03c6e22eb"/>
|
||||
<project name="platform/external/gtest" path="external/gtest" revision="8c212ebe53bb2baab3575f03069016f1fb11e449" upstream="aosp-new/master"/>
|
||||
<project name="platform/external/harfbuzz" path="external/harfbuzz" revision="116610d63a859521dacf00fb6818ee9ab2e666f6"/>
|
||||
<project name="platform/external/icu4c" path="external/icu4c" revision="0fa67b93b831c6636ca18b152a1b1b14cc99b034"/>
|
||||
<project name="platform/external/iptables" path="external/iptables" revision="3b2deb17f065c5664bb25e1a28489e5792eb63ff"/>
|
||||
<project name="platform/external/jpeg" path="external/jpeg" revision="ef8288e4a75360236d69c5860b0d18ea101f0c1d"/>
|
||||
<project name="platform/external/libgsm" path="external/libgsm" revision="5e4516958690b9a1b2c98f88eeecba3edd2dbda4"/>
|
||||
<project name="platform/external/liblzf" path="external/liblzf" revision="6946aa575b0949d045722794850896099d937cbb"/>
|
||||
<project name="platform/external/libnfc-nxp" path="external/libnfc-nxp" revision="3a912b065a31a72c63ad56ac224cfeaa933423b6"/>
|
||||
<project name="platform/external/libnl-headers" path="external/libnl-headers" revision="6ccf7349d61f73ac26a0675d735d903ab919c658"/>
|
||||
<project name="platform/external/libpng" path="external/libpng" revision="1353a869289ec205209e594c5804e17fa4787e04"/>
|
||||
<project name="platform/external/libvpx" path="external/libvpx" revision="2618c324e2ecd1fa5dbfb8cc0ba0911f4fd255d9"/>
|
||||
<project name="platform/external/llvm" path="external/llvm" revision="d9527968ba7078ee6ce99dda8d8f555342032b91"/>
|
||||
<project name="platform/external/mksh" path="external/mksh" revision="8380dd0a75783fc5e4a3e3b0f07f7e25bade3c8c"/>
|
||||
<project name="platform/external/openssl" path="external/openssl" revision="c63c712a6a20e2c1b6085601c2d48e3f3ef32f73"/>
|
||||
<project name="platform/external/protobuf" path="external/protobuf" revision="e217977611c52bccde7f7c78e1d3c790c6357431"/>
|
||||
<project name="platform/external/safe-iop" path="external/safe-iop" revision="07073634e2e3aa4f518e36ed5dec3aabc549d5fb"/>
|
||||
<project name="screencap-gonk" path="external/screencap-gonk" remote="b2g" revision="e6403c71e9eca8cb943739d5a0a192deac60fc51"/>
|
||||
<project name="platform/external/skia" path="external/skia" revision="098dff2ef5d35b30bc79fdfdeae74e186919dcfe"/>
|
||||
<project name="platform/external/sonivox" path="external/sonivox" revision="f5f46e68585c690436956f552994910f5e33bef5"/>
|
||||
<project name="platform/external/speex" path="external/speex" revision="ebe6230a7f7c69f5a4389f2b09b7b19ef9e94f32"/>
|
||||
<project name="platform/external/sqlite" path="external/sqlite" revision="537b409287fe6c28b71c5500a42f5fd7724f900d"/>
|
||||
<project name="platform/external/stlport" path="external/stlport" revision="a6734e0645fce81c9610de0488b729207bfa576e"/>
|
||||
<project name="platform/external/strace" path="external/strace" revision="c9fd2e5ef7d002e12e7cf2512506c84a9414b0fd"/>
|
||||
<project name="platform/external/svox" path="external/svox" revision="02dadb2ae0a5c31b9451ab169f1383dd0ff0948f"/>
|
||||
<project name="platform/external/tagsoup" path="external/tagsoup" revision="68c2ec9e0acdb3214b7fb91dbab8c9fab8736817"/>
|
||||
<project name="platform/external/tinyalsa" path="external/tinyalsa" revision="b3a40ef1402b782553e1f3798d17e75636f16e3b"/>
|
||||
<project name="platform/external/tremolo" path="external/tremolo" revision="25bd78d2392dbdc879ae53382cde9d019f79cf6f"/>
|
||||
<project name="unbootimg" path="external/unbootimg" remote="b2g" revision="9464623d92eb8668544916dc5a8f4f6337d0bc08"/>
|
||||
<project name="platform/external/webp" path="external/webp" revision="88fe2b83c4b9232cd08729556fd0485d6a6a92cd"/>
|
||||
<project name="platform/external/webrtc" path="external/webrtc" revision="137024dc8a2e9251a471e20518a9c3ae06f81f23"/>
|
||||
<project name="platform/external/wpa_supplicant" path="external/wpa_supplicant" revision="a01d37870bbf9892d43e792e5de0683ca41c5497"/>
|
||||
<project name="platform/external/hostap" path="external/hostap" revision="611194f9ea6a2851171663dd59fae2fbfb39e246"/>
|
||||
<project name="platform/external/zlib" path="external/zlib" revision="cb8dbfb25f8f0b111d0c8270ac49455cac4fd5b3"/>
|
||||
<project name="platform/external/yaffs2" path="external/yaffs2" revision="0afa916204c664b3114429637b63af1321a0aeca"/>
|
||||
<project name="platform/frameworks/base" path="frameworks/base" revision="bb9f8618ff7a1dfb5627b3c13219f6583a16e470"/>
|
||||
<project name="platform/frameworks/opt/emoji" path="frameworks/opt/emoji" revision="a95d8db002770469d72dfaf59ff37ac96db29a87"/>
|
||||
<project name="platform/frameworks/support" path="frameworks/support" revision="90ffd236fe7f1e2bec74bd8624284ea017b41e64"/>
|
||||
<project name="platform/hardware/libhardware" path="hardware/libhardware" revision="93226241c35eea5ae139c8370a6d8ad837c8106e"/>
|
||||
<project name="platform/hardware/libhardware_legacy" path="hardware/libhardware_legacy" revision="f197f55362dea6b9fc338a4f6d89bc009900f41f"/>
|
||||
<project name="platform/hardware/ril" path="hardware/ril" revision="7dc9ff3e8de3fbf36fa89bf2909959a0070fc75d"/>
|
||||
<project name="platform/libcore" path="libcore" revision="6d924abb26a30abb24d98378fac6bdc405f2a398"/>
|
||||
<project name="platform/ndk" path="ndk" revision="9f555971e1481854d5b4dc11b3e6af9fff4f241f"/>
|
||||
<project name="platform/prebuilt" path="prebuilt" revision="248d92592df169569c387a91db56b1fedd6e5d29"/>
|
||||
<project name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" revision="d9735fc81434f2af2c44d86ca57740c673c8d9bc"/>
|
||||
<project name="platform/system/bluetooth" path="system/bluetooth" revision="395aff045276107a285daf0392d0884a98b9f538"/>
|
||||
<project name="platform/system/core" path="system/core" revision="e4e910457913d521e1773e059a94891bde2cfeeb"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="a5dd0ea60ce973c2c762b41835a43316fb4ff9e3"/>
|
||||
<project name="platform/system/media" path="system/media" revision="fbb3d9b4c5bf59071424e820e872e3f64f0a244a"/>
|
||||
<project name="platform/system/netd" path="system/netd" revision="a947ed754bb0cd0db992579d9a3a00ae4484c59c"/>
|
||||
<project name="platform/system/vold" path="system/vold" revision="3f87f19bf8bdf3a7cb3c01ef2b2c5810633e78ef"/>
|
||||
<!-- helix specific things -->
|
||||
<project name="device/qcom/common" path="device/qcom/common" revision="d13aaf080177b7c48f243d51827db5c7a7873cd0"/>
|
||||
<project name="platform/vendor/qcom/msm7627a" path="device/qcom/msm7627a" revision="9019e1c750f427785148c7512a183531f7675679"/>
|
||||
<project name="device-helix" path="device/qcom/helix" remote="b2g" revision="47f22c59edb13379a6995554cb4a473558929653"/>
|
||||
<project name="kernel/msm" path="kernel" revision="e9c1e0c6a0ca33f5741a48288de4b46453031210"/>
|
||||
<project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="c4e3e6cf938f1bdde78bc39f38350f72b6fc3a21"/>
|
||||
<project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="32905dde6a66296c7e5843e9664c5c6444deb38c"/>
|
||||
<project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="b2ac43193f3d3a44171bdb50ea3c2aeb558511d3"/>
|
||||
<project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="1698e6e9ed7cf1d543508845fa05ed86c7e5e241"/>
|
||||
<project name="platform/hardware/msm7k" path="hardware/msm7k" revision="669815aaca47afee95b4a95908dc87bff267a815"/>
|
||||
<project name="platform/vendor/qcom-opensource/omx/mm-core" path="vendor/qcom/opensource/omx/mm-core" revision="0365db6af2d4df11184a421f97c5043db47a0c0d"/>
|
||||
</manifest>
|
@ -1,43 +0,0 @@
|
||||
{
|
||||
"config_version": 2,
|
||||
"tooltool_manifest": "releng-wasabi.tt",
|
||||
"mock_target": "mozilla-centos6-x86_64",
|
||||
"mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "java-1.6.0-openjdk-devel", "git", "glibc-devel.i686", "libstdc++.i686", "zlib-devel.i686", "ncurses-devel.i686", "libX11-devel.i686", "mesa-libGL-devel.i686", "mesa-libGL-devel", "libX11-devel"],
|
||||
"mock_files": [
|
||||
["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"],
|
||||
["/builds/crash-stats-api.token", "/builds/crash-stats-api.token"]
|
||||
],
|
||||
"build_targets": [],
|
||||
"upload_files": [
|
||||
"{objdir}/dist/b2g-*.crashreporter-symbols.zip",
|
||||
"{objdir}/dist/b2g-*.tar.gz",
|
||||
"{workdir}/sources.xml"
|
||||
],
|
||||
"zip_files": [
|
||||
["{workdir}/out/target/product/wasabi/*.img", "out/target/product/wasabi/"],
|
||||
["{workdir}/boot.img", "out/target/product/wasabi/"],
|
||||
"{workdir}/flash.sh",
|
||||
"{workdir}/load-config.sh",
|
||||
"{workdir}/.config",
|
||||
"{workdir}/sources.xml",
|
||||
"{workdir}/profile.sh",
|
||||
["{workdir}/gecko/tools/profiler/merge-profiles.py", "gecko/tools/profiler/"],
|
||||
["{workdir}/scripts/profile-symbolicate.py", "scripts/"],
|
||||
["{workdir}/gecko/tools/rb/fix_stack_using_bpsyms.py", "gecko/tools/rb/"]
|
||||
],
|
||||
"env": {
|
||||
"VARIANT": "user",
|
||||
"MOZILLA_OFFICIAL": "1",
|
||||
"MOZ_TELEMETRY_REPORTING": "1"
|
||||
},
|
||||
"b2g_manifest": "wasabi.xml",
|
||||
"b2g_manifest_intree": true,
|
||||
"additional_source_tarballs": ["backup-wasabi.tar.gz"],
|
||||
"gecko_l10n_root": "https://hg.mozilla.org/l10n-central",
|
||||
"gaia": {
|
||||
"l10n": {
|
||||
"vcs": "hgtool",
|
||||
"root": "https://hg.mozilla.org/gaia-l10n"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
[
|
||||
{
|
||||
"size": 311696844,
|
||||
"digest": "110d6a8a275fb8427816e748448930bb5e6fc45eaba88ac5be824d2873d2d41e1b5c0252d68a1d3b197ec209a7d6dcd1b5e83322702667c8e1b89f3db2ff0bc6",
|
||||
"algorithm": "sha512",
|
||||
"filename": "backup-wasabi.tar.gz"
|
||||
},
|
||||
{
|
||||
"size": 1570553,
|
||||
"digest": "ea03de74df73b05e939c314cd15c54aac7b5488a407b7cc4f5f263f3049a1f69642c567dd35c43d0bc3f0d599d0385a26ab2dd947a6b18f9044e4918b382eea7",
|
||||
"algorithm": "sha512",
|
||||
"filename": "Adreno200-AU_LINUX_ANDROID_ICS_CHOCO_CS.04.00.03.06.001.zip"
|
||||
},
|
||||
{
|
||||
"size": 5730304,
|
||||
"digest": "709a281438607f10c9f55683303d5cc1d8720520e26a8ae45f48b7ccb9265ba8939c4a077ae3368afc891bbd7426013edfbbbb3dbdeab5b1f06e60901b141de6",
|
||||
"algorithm": "sha512",
|
||||
"filename": "boot.img"
|
||||
},
|
||||
{
|
||||
"size": 80458572,
|
||||
"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gcc.tar.xz",
|
||||
"unpack": "True"
|
||||
}
|
||||
]
|
@ -1,112 +0,0 @@
|
||||
<?xml version="1.0" ?><manifest>
|
||||
<!--original fetch url was https://android.googlesource.com/-->
|
||||
<remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
|
||||
<!--original fetch url was git://github.com/mozilla-b2g/-->
|
||||
<remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
|
||||
<!--original fetch url was git://github.com/mozilla/-->
|
||||
<remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
|
||||
<!--original fetch url was git://codeaurora.org/-->
|
||||
<remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
|
||||
<!--original fetch url was https://git.mozilla.org/releases-->
|
||||
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
|
||||
<!--original fetch url was git://github.com/apitrace/-->
|
||||
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
|
||||
<default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
|
||||
<!-- Gonk specific things and forks -->
|
||||
<project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="b33a1afb538e8c7e12f6fb792c454da34f9f5b76"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="5d482e320548e7ef0a44f62fd7ad51778cca4b3a"/>
|
||||
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
<project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
|
||||
<project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
|
||||
<project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
|
||||
<project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
|
||||
<project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
|
||||
<project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
|
||||
<project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="1023c91c66e9c3bd1132480051993bf7827770f6"/>
|
||||
<project name="platform/external/bluetooth/glib" path="external/bluetooth/glib" revision="c6b49241cc1a8950723a5f74f8f4b4f4c3fa970e"/>
|
||||
<project name="platform/external/bluetooth/hcidump" path="external/bluetooth/hcidump" revision="02b1eb24fbb3d0135a81edb4a2175b1397308d7d"/>
|
||||
<project name="platform/external/bsdiff" path="external/bsdiff" revision="81872540236d9bb15cccf963d05b9de48baa5375"/>
|
||||
<project name="platform/external/bzip2" path="external/bzip2" revision="048dacdca43eed1534689ececcf2781c63e1e4ba"/>
|
||||
<project name="platform/external/dbus" path="external/dbus" revision="c7517b6195dc6926728352113e6cc335da3f9c9e"/>
|
||||
<project name="platform/external/dhcpcd" path="external/dhcpcd" revision="1e00fb67022d0921af0fead263f81762781b9ffa"/>
|
||||
<project name="platform/external/dnsmasq" path="external/dnsmasq" revision="f621afad94df46204c25fc2593a19d704d2637f5"/>
|
||||
<project name="platform_external_elfcopy" path="external/elfcopy" remote="b2g" revision="62c1bed1c4505369cac2e72fbe30452a598fb690"/>
|
||||
<project name="platform_external_elfutils" path="external/elfutils" remote="b2g" revision="72940dec691fa3255e13df01f8c53b620e446066"/>
|
||||
<project name="platform/external/e2fsprogs" path="external/e2fsprogs" revision="d5f550bb2f556c5d287f7c8d2b77223654bcec37"/>
|
||||
<project name="platform/external/expat" path="external/expat" revision="6df134250feab71edb5915ecaa6268210bca76c5"/>
|
||||
<project name="platform/external/fdlibm" path="external/fdlibm" revision="988ffeb12a6e044ae3504838ef1fee3fe0716934"/>
|
||||
<project name="platform/external/flac" path="external/flac" revision="5893fbe890f5dab8e4146d2baa4bd2691c0739e0"/>
|
||||
<project name="platform/external/freetype" path="external/freetype" revision="aeb407daf3711a10a27f3bc2223c5eb05158076e"/>
|
||||
<project name="platform/external/giflib" path="external/giflib" revision="b2597268aef084202a8c349d1cc072c03c6e22eb"/>
|
||||
<project name="platform/external/gtest" path="external/gtest" revision="8c212ebe53bb2baab3575f03069016f1fb11e449"/>
|
||||
<project name="platform/external/harfbuzz" path="external/harfbuzz" revision="116610d63a859521dacf00fb6818ee9ab2e666f6"/>
|
||||
<project name="platform/external/icu4c" path="external/icu4c" revision="0fa67b93b831c6636ca18b152a1b1b14cc99b034"/>
|
||||
<project name="platform/external/iptables" path="external/iptables" revision="3b2deb17f065c5664bb25e1a28489e5792eb63ff"/>
|
||||
<project name="platform/external/jpeg" path="external/jpeg" revision="a62e464d672a4623233180e4023034bf825f066e"/>
|
||||
<project name="platform/external/libgsm" path="external/libgsm" revision="5e4516958690b9a1b2c98f88eeecba3edd2dbda4"/>
|
||||
<project name="platform/external/liblzf" path="external/liblzf" revision="6946aa575b0949d045722794850896099d937cbb"/>
|
||||
<project name="platform/external/libnfc-nxp" path="external/libnfc-nxp" revision="3a912b065a31a72c63ad56ac224cfeaa933423b6"/>
|
||||
<project name="platform/external/libnl-headers" path="external/libnl-headers" revision="6ccf7349d61f73ac26a0675d735d903ab919c658"/>
|
||||
<project name="platform/external/libpng" path="external/libpng" revision="9c3730f0efa69f580f03463c237cd928f3196404"/>
|
||||
<project name="platform/external/libvpx" path="external/libvpx" revision="3a40da0d96da5c520e7707aa14f48a80956e20d7"/>
|
||||
<project name="platform/external/llvm" path="external/llvm" revision="bff5923831940309f7d8ddbff5826ca6ed2dc050"/>
|
||||
<project name="platform/external/mksh" path="external/mksh" revision="ec646e8f5e7dac9a77d1de549c6ed92c04d0cd4b"/>
|
||||
<project name="platform_external_opensans" path="external/opensans" remote="b2g" revision="b5b4c226ca1d71e936153cf679dda6d3d60e2354"/>
|
||||
<project name="platform/external/openssl" path="external/openssl" revision="27d333cce9a31c806b4bfa042925f045c727aecd"/>
|
||||
<project name="platform/external/protobuf" path="external/protobuf" revision="e217977611c52bccde7f7c78e1d3c790c6357431"/>
|
||||
<project name="platform/external/safe-iop" path="external/safe-iop" revision="07073634e2e3aa4f518e36ed5dec3aabc549d5fb"/>
|
||||
<project name="screencap-gonk" path="external/screencap-gonk" remote="b2g" revision="e6403c71e9eca8cb943739d5a0a192deac60fc51"/>
|
||||
<project name="platform/external/skia" path="external/skia" revision="7d90c85f2c0e3b747f7c7eff8bc9253b0063b439"/>
|
||||
<project name="platform/external/sonivox" path="external/sonivox" revision="7c967779dfc61ac1f346e972de91d4bfce7dccbb"/>
|
||||
<project name="platform/external/speex" path="external/speex" revision="ebe6230a7f7c69f5a4389f2b09b7b19ef9e94f32"/>
|
||||
<project name="platform/external/sqlite" path="external/sqlite" revision="fb30e613139b8836fdc8e81e166cf3a76e5fa17f"/>
|
||||
<project name="platform/external/stlport" path="external/stlport" revision="a6734e0645fce81c9610de0488b729207bfa576e"/>
|
||||
<project name="platform/external/strace" path="external/strace" revision="c9fd2e5ef7d002e12e7cf2512506c84a9414b0fd"/>
|
||||
<project name="platform/external/svox" path="external/svox" revision="bd1c06681030164268172ead2eb39b86425624bf"/>
|
||||
<project name="platform/external/tagsoup" path="external/tagsoup" revision="68c2ec9e0acdb3214b7fb91dbab8c9fab8736817"/>
|
||||
<project name="platform/external/tinyalsa" path="external/tinyalsa" revision="06cc244ee512c1352215e543615738bc8ac82814"/>
|
||||
<project name="platform/external/tremolo" path="external/tremolo" revision="25bd78d2392dbdc879ae53382cde9d019f79cf6f"/>
|
||||
<project name="unbootimg" path="external/unbootimg" remote="b2g" revision="9464623d92eb8668544916dc5a8f4f6337d0bc08"/>
|
||||
<project name="platform/external/webp" path="external/webp" revision="88fe2b83c4b9232cd08729556fd0485d6a6a92cd"/>
|
||||
<project name="platform/external/webrtc" path="external/webrtc" revision="137024dc8a2e9251a471e20518a9c3ae06f81f23"/>
|
||||
<project name="platform/external/wpa_supplicant" path="external/wpa_supplicant" revision="a01d37870bbf9892d43e792e5de0683ca41c5497"/>
|
||||
<project name="platform/external/hostap" path="external/hostap" revision="bf04b0faadbdeb4b7943f2e2c4c5aa59df872bb1"/>
|
||||
<project name="platform/external/zlib" path="external/zlib" revision="f96a1d1ebfdf1cd582210fd09c23d8f59e0ae094"/>
|
||||
<project name="platform/external/yaffs2" path="external/yaffs2" revision="0afa916204c664b3114429637b63af1321a0aeca"/>
|
||||
<project name="platform/frameworks/base" path="frameworks/base" revision="eb2bc75803ca179353c24c364a9c8a8ce23e8b78"/>
|
||||
<project name="platform/frameworks/opt/emoji" path="frameworks/opt/emoji" revision="a95d8db002770469d72dfaf59ff37ac96db29a87"/>
|
||||
<project name="platform/frameworks/support" path="frameworks/support" revision="27208692b001981f1806f4f396434f4eac78b909"/>
|
||||
<project name="platform/hardware/libhardware" path="hardware/libhardware" revision="4a619901847621f8a7305edf42dd07347a140484"/>
|
||||
<project name="platform/hardware/libhardware_legacy" path="hardware/libhardware_legacy" revision="87b4d7afa8f854b445e2d0d95091f6f6069f2b30"/>
|
||||
<project name="platform/hardware/ril" path="hardware/ril" revision="d65f556f96bf5421f1f8db36b81706c8c3cb53c3"/>
|
||||
<project name="platform/libcore" path="libcore" revision="30841f9fba9ccd5c54f4f079f495994db97f283e"/>
|
||||
<project name="platform/ndk" path="ndk" revision="9f555971e1481854d5b4dc11b3e6af9fff4f241f"/>
|
||||
<project name="platform/prebuilt" path="prebuilt" revision="447ea790fcc957dde59730ecc2a65ca263bdc733"/>
|
||||
<project name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" revision="d9735fc81434f2af2c44d86ca57740c673c8d9bc"/>
|
||||
<project name="platform/system/bluetooth" path="system/bluetooth" revision="7772cad4823f1f427ce1d4df84a55982386d6d18"/>
|
||||
<project name="platform/system/core" path="system/core" revision="bf1970408676ce570b8f4dc3efa038e47552137f"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="01db6c1254e1407740a543f24317fc540fc4c049"/>
|
||||
<project name="platform/system/media" path="system/media" revision="7f71c7fd362bbd992ff2e0e80f7af5859ad116ad"/>
|
||||
<project name="platform/system/netd" path="system/netd" revision="306e765248e3900041bf2737e9f57b1b5694a4ce"/>
|
||||
<project name="platform/system/vold" path="system/vold" revision="99fff257d53cc045d1460841edca5d901dacfcf5"/>
|
||||
<!-- Wasabi specific things -->
|
||||
<project name="device/qcom/common" path="device/qcom/common" revision="b9cdab8e1e1a215a8c65b8d5816f666bec7be205"/>
|
||||
<project name="platform/vendor/qcom/msm8960" path="device/qcom/msm8960" revision="58786a6a6f16384a7770f92081a5d8f7b1a067ae"/>
|
||||
<project name="device-wasabi" path="device/qcom/wasabi" remote="b2g" revision="75c4cf201326edcd909502aa52febc96bf553104"/>
|
||||
<project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="0a01247e4b0880f93424b27251cd3a1f6b19dbb2"/>
|
||||
<project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="1acf77a75e30f3fc8b1eed2057c97adf1cb1633f"/>
|
||||
<project name="hardware_qcom_display" path="hardware/qcom/display" remote="b2g" revision="6405d30f2fac7d8a1f2cb17b99fb7dd0a8bcfdac"/>
|
||||
<project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="552c3ddb7174a01f3508782d40c4d8c845ab441a"/>
|
||||
<project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="23d5707b320d7fc69f8ba3b7d84d78a1c5681708"/>
|
||||
<project name="platform/vendor/qcom-opensource/omx/mm-core" path="vendor/qcom/opensource/omx/mm-core" revision="ab17ac9a074b4bb69986a8436336bdfbbaf9cd39"/>
|
||||
</manifest>
|
@ -79,7 +79,12 @@ endif
|
||||
|
||||
AB_CD = $(MOZ_UI_LOCALE)
|
||||
|
||||
AB := $(firstword $(subst -, ,$(AB_CD)))
|
||||
ifeq (zh-TW,$(AB_CD))
|
||||
LPROJ_ROOT := $(subst -,_,$(AB_CD))
|
||||
else
|
||||
LPROJ_ROOT := $(firstword $(subst -, ,$(AB_CD)))
|
||||
endif
|
||||
LPROJ := Contents/Resources/$(LPROJ_ROOT).lproj
|
||||
|
||||
clean clobber repackage::
|
||||
$(RM) -r $(dist_dest)
|
||||
@ -89,11 +94,11 @@ MAC_BUNDLE_VERSION = $(shell $(PYTHON) $(srcdir)/macversion.py --version=$(MOZ_A
|
||||
.PHONY: repackage
|
||||
tools repackage:: $(PROGRAM)
|
||||
$(MKDIR) -p $(dist_dest)/Contents/MacOS
|
||||
$(MKDIR) -p $(dist_dest)/Contents/Resources/$(AB).lproj
|
||||
$(MKDIR) -p $(dist_dest)/$(LPROJ)
|
||||
rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents $(dist_dest) --exclude English.lproj
|
||||
rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(dist_dest)/Contents/Resources/$(AB).lproj
|
||||
rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(dist_dest)/$(LPROJ)
|
||||
sed -e 's/%APP_VERSION%/$(MOZ_APP_VERSION)/' -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' -e 's/%MOZ_MACBUNDLE_ID%/$(MOZ_MACBUNDLE_ID)/' -e 's/%MAC_BUNDLE_VERSION%/$(MAC_BUNDLE_VERSION)/' $(srcdir)/macbuild/Contents/Info.plist.in > $(dist_dest)/Contents/Info.plist
|
||||
sed -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(dist_dest)/Contents/Resources/$(AB).lproj/InfoPlist.strings
|
||||
sed -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(dist_dest)/$(LPROJ)/InfoPlist.strings
|
||||
rsync -a --exclude-from='$(srcdir)/macbuild/Contents/MacOS-files.in' $(DIST)/bin/ $(dist_dest)/Contents/Resources
|
||||
rsync -a --include-from='$(srcdir)/macbuild/Contents/MacOS-files.in' --exclude '*' $(DIST)/bin/ $(dist_dest)/Contents/MacOS
|
||||
$(RM) $(dist_dest)/Contents/MacOS/$(PROGRAM)
|
||||
|
@ -295,6 +295,7 @@ skip-if = true # browser_drag.js is disabled, as it needs to be updated for the
|
||||
[browser_favicon_change.js]
|
||||
[browser_favicon_change_not_in_document.js]
|
||||
[browser_findbarClose.js]
|
||||
[browser_focusonkeydown.js]
|
||||
[browser_fullscreen-window-open.js]
|
||||
skip-if = buildapp == 'mulet' || e10s || os == "linux" # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly. Linux: Intermittent failures - bug 941575.
|
||||
[browser_fxa_migrate.js]
|
||||
|
26
browser/base/content/test/general/browser_focusonkeydown.js
Normal file
26
browser/base/content/test/general/browser_focusonkeydown.js
Normal file
@ -0,0 +1,26 @@
|
||||
add_task(function *()
|
||||
{
|
||||
let keyUps = 0;
|
||||
|
||||
yield BrowserTestUtils.openNewForegroundTab(gBrowser, "data:text/html,<body>");
|
||||
|
||||
gURLBar.focus();
|
||||
|
||||
window.addEventListener("keyup", function countKeyUps(event) {
|
||||
window.removeEventListener("keyup", countKeyUps, true);
|
||||
if (event.originalTarget == gURLBar.inputField) {
|
||||
keyUps++;
|
||||
}
|
||||
}, true);
|
||||
|
||||
gURLBar.addEventListener("keydown", function redirectFocus(event) {
|
||||
gURLBar.removeEventListener("keydown", redirectFocus, true);
|
||||
gBrowser.selectedBrowser.focus();
|
||||
}, true);
|
||||
|
||||
EventUtils.synthesizeKey("v", { });
|
||||
|
||||
is(keyUps, 1, "Key up fired at url bar");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
@ -1,220 +1,200 @@
|
||||
Cu.import("resource://gre/modules/CrashSubmit.jsm", this);
|
||||
|
||||
const CRASH_URL = "http://example.com/browser/browser/base/content/test/plugins/plugin_crashCommentAndURL.html";
|
||||
const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
|
||||
|
||||
/**
|
||||
* Frame script that will be injected into the test browser
|
||||
* to cause plugin crashes, and then manipulate the crashed plugin
|
||||
* UI. The specific actions and checks that occur in the frame
|
||||
* script for the crashed plugin UI are set in the
|
||||
* test:crash-plugin message object sent from the parent. The actions
|
||||
* and checks that the parent can specify are:
|
||||
*
|
||||
* pleaseSubmitStyle: the display style that the pleaseSubmit anonymous element
|
||||
* should have - example "block", "none".
|
||||
* submitComment: the comment that should be put into the crash report
|
||||
* urlOptIn: true if the submitURLOptIn element should be checked.
|
||||
* sendCrashMessage: if true, the frame script will send a
|
||||
* test:crash-plugin:crashed message when the plugin has
|
||||
* crashed. This is used for the last test case, and
|
||||
* causes the frame script to skip any of the crashed
|
||||
* plugin UI manipulation, since the last test shows
|
||||
* no crashed plugin UI.
|
||||
*/
|
||||
function frameScript() {
|
||||
function fail(reason) {
|
||||
sendAsyncMessage("test:crash-plugin:fail", {
|
||||
reason: `Failure from frameScript: ${reason}`,
|
||||
});
|
||||
}
|
||||
|
||||
addMessageListener("test:crash-plugin", (message) => {
|
||||
addEventListener("PluginCrashed", function onPluginCrashed(event) {
|
||||
removeEventListener("PluginCrashed", onPluginCrashed);
|
||||
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("plugin");
|
||||
if (!plugin) {
|
||||
fail("Could not find plugin element");
|
||||
return;
|
||||
}
|
||||
|
||||
let getUI = (anonid) => {
|
||||
return doc.getAnonymousElementByAttribute(plugin, "anonid", anonid);
|
||||
};
|
||||
|
||||
let style = content.getComputedStyle(getUI("pleaseSubmit"));
|
||||
if (style.display != message.data.pleaseSubmitStyle) {
|
||||
fail("Submission UI visibility is not correct. Expected " +
|
||||
`${message.data.pleaseSubmitStyle} and got ${style.display}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.data.sendCrashMessage) {
|
||||
sendAsyncMessage("test:crash-plugin:crashed", {
|
||||
crashID: event.pluginDumpID,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.data.submitComment) {
|
||||
getUI("submitComment").value = message.data.submitComment;
|
||||
}
|
||||
getUI("submitURLOptIn").checked = message.data.urlOptIn;
|
||||
getUI("submitButton").click();
|
||||
});
|
||||
|
||||
let plugin = content.document.getElementById("test");
|
||||
try {
|
||||
plugin.crash()
|
||||
} catch(e) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test() {
|
||||
// Crashing the plugin takes up a lot of time, so extend the test timeout.
|
||||
requestLongerTimeout(runs.length);
|
||||
waitForExplicitFinish();
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
|
||||
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||
let gTestBrowser = null;
|
||||
let config = {};
|
||||
|
||||
add_task(function* () {
|
||||
// The test harness sets MOZ_CRASHREPORTER_NO_REPORT, which disables plugin
|
||||
// crash reports. This test needs them enabled. The test also needs a mock
|
||||
// report server, and fortunately one is already set up by toolkit/
|
||||
// crashreporter/test/Makefile.in. Assign its URL to MOZ_CRASHREPORTER_URL,
|
||||
// which CrashSubmit.jsm uses as a server override.
|
||||
let env = Cc["@mozilla.org/process/environment;1"].
|
||||
getService(Components.interfaces.nsIEnvironment);
|
||||
let env = Components.classes["@mozilla.org/process/environment;1"]
|
||||
.getService(Components.interfaces.nsIEnvironment);
|
||||
let noReport = env.get("MOZ_CRASHREPORTER_NO_REPORT");
|
||||
let serverURL = env.get("MOZ_CRASHREPORTER_URL");
|
||||
let serverUrl = env.get("MOZ_CRASHREPORTER_URL");
|
||||
env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
|
||||
env.set("MOZ_CRASHREPORTER_URL", SERVER_URL);
|
||||
|
||||
let tab = gBrowser.loadOneTab("about:blank", { inBackground: false });
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
let mm = browser.messageManager;
|
||||
mm.loadFrameScript("data:,(" + frameScript.toString() + ")();", true);
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gTestBrowser = gBrowser.selectedBrowser;
|
||||
|
||||
mm.addMessageListener("test:crash-plugin:fail", (message) => {
|
||||
ok(false, message.data.reason);
|
||||
});
|
||||
// Crash immediately
|
||||
Services.prefs.setIntPref("dom.ipc.plugins.timeoutSecs", 0);
|
||||
|
||||
Services.obs.addObserver(onSubmitStatus, "crash-report-status", false);
|
||||
|
||||
registerCleanupFunction(function cleanUp() {
|
||||
registerCleanupFunction(Task.async(function*() {
|
||||
Services.prefs.clearUserPref("dom.ipc.plugins.timeoutSecs");
|
||||
env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport);
|
||||
env.set("MOZ_CRASHREPORTER_URL", serverURL);
|
||||
Services.obs.removeObserver(onSubmitStatus, "crash-report-status");
|
||||
env.set("MOZ_CRASHREPORTER_URL", serverUrl);
|
||||
env = null;
|
||||
config = null;
|
||||
gTestBrowser = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
window.focus();
|
||||
}));
|
||||
});
|
||||
|
||||
doNextRun();
|
||||
}
|
||||
|
||||
let runs = [
|
||||
{
|
||||
add_task(function* () {
|
||||
config = {
|
||||
shouldSubmissionUIBeVisible: true,
|
||||
comment: "",
|
||||
urlOptIn: false,
|
||||
},
|
||||
{
|
||||
urlOptIn: false
|
||||
};
|
||||
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
|
||||
|
||||
let pluginCrashed = promisePluginCrashed();
|
||||
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_crashCommentAndURL.html");
|
||||
|
||||
// Work around for delayed PluginBindingAttached
|
||||
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||
|
||||
// Wait for the plugin to crash
|
||||
yield pluginCrashed;
|
||||
|
||||
let crashReportStatus = TestUtils.topicObserved("crash-report-status", onSubmitStatus);
|
||||
|
||||
// Test that the crash submission UI is actually visible and submit the crash report.
|
||||
let crashUiVisible = yield ContentTask.spawn(gTestBrowser, config, function* (aConfig) {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("plugin");
|
||||
let pleaseSubmit = doc.getAnonymousElementByAttribute(plugin, "anonid", "pleaseSubmit");
|
||||
let submitButton = doc.getAnonymousElementByAttribute(plugin, "anonid", "submitButton");
|
||||
// Test that we don't send the URL when urlOptIn is false.
|
||||
doc.getAnonymousElementByAttribute(plugin, "anonid", "submitURLOptIn").checked = aConfig.urlOptIn;
|
||||
submitButton.click();
|
||||
return content.getComputedStyle(pleaseSubmit).display == "block";
|
||||
});
|
||||
|
||||
yield crashReportStatus;
|
||||
|
||||
is(crashUiVisible, config.shouldSubmissionUIBeVisible, "The crash UI should be visible");
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
config = {
|
||||
shouldSubmissionUIBeVisible: true,
|
||||
comment: "a test comment",
|
||||
urlOptIn: true,
|
||||
},
|
||||
{
|
||||
width: 300,
|
||||
height: 300,
|
||||
urlOptIn: true
|
||||
};
|
||||
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
|
||||
|
||||
let pluginCrashed = promisePluginCrashed();
|
||||
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_crashCommentAndURL.html");
|
||||
|
||||
// Work around for delayed PluginBindingAttached
|
||||
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||
|
||||
// Wait for the plugin to crash
|
||||
yield pluginCrashed;
|
||||
|
||||
let crashReportStatus = TestUtils.topicObserved("crash-report-status", onSubmitStatus);
|
||||
|
||||
// Test that the crash submission UI is actually visible and submit the crash report.
|
||||
let crashUiVisible = yield ContentTask.spawn(gTestBrowser, config, function* (aConfig) {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("plugin");
|
||||
let pleaseSubmit = doc.getAnonymousElementByAttribute(plugin, "anonid", "pleaseSubmit");
|
||||
let submitButton = doc.getAnonymousElementByAttribute(plugin, "anonid", "submitButton");
|
||||
// Test that we send the URL when urlOptIn is true.
|
||||
doc.getAnonymousElementByAttribute(plugin, "anonid", "submitURLOptIn").checked = aConfig.urlOptIn;
|
||||
doc.getAnonymousElementByAttribute(plugin, "anonid", "submitComment").value = aConfig.comment;
|
||||
submitButton.click();
|
||||
return content.getComputedStyle(pleaseSubmit).display == "block";
|
||||
});
|
||||
|
||||
yield crashReportStatus;
|
||||
|
||||
is(crashUiVisible, config.shouldSubmissionUIBeVisible, "The crash UI should be visible");
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
config = {
|
||||
shouldSubmissionUIBeVisible: false,
|
||||
},
|
||||
];
|
||||
comment: "",
|
||||
urlOptIn: true
|
||||
};
|
||||
|
||||
let currentRun = null;
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
|
||||
|
||||
function doNextRun() {
|
||||
try {
|
||||
if (!runs.length) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
currentRun = runs.shift();
|
||||
let args = ["width", "height"].reduce(function (memo, arg) {
|
||||
if (arg in currentRun)
|
||||
memo[arg] = currentRun[arg];
|
||||
return memo;
|
||||
}, {});
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
let pluginCrashed = promisePluginCrashed();
|
||||
|
||||
if (!currentRun.shouldSubmittionUIBeVisible) {
|
||||
mm.addMessageListener("test:crash-plugin:crash", function onCrash(message) {
|
||||
mm.removeMessageListener("test:crash-plugin:crash", onCrash);
|
||||
// Make sure that the plugin container is too small to display the crash submission UI
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_crashCommentAndURL.html?" +
|
||||
encodeURIComponent(JSON.stringify({width: 300, height: 300})));
|
||||
|
||||
ok(!!message.data.crashID, "pluginDumpID should be set");
|
||||
CrashSubmit.delete(message.data.crashID);
|
||||
doNextRun();
|
||||
// Work around for delayed PluginBindingAttached
|
||||
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||
|
||||
// Wait for the plugin to crash
|
||||
yield pluginCrashed;
|
||||
|
||||
// Test that the crash submission UI is not visible and do not submit a crash report.
|
||||
let crashUiVisible = yield ContentTask.spawn(gTestBrowser, {}, function* () {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("plugin");
|
||||
let pleaseSubmit = doc.getAnonymousElementByAttribute(plugin, "anonid", "pleaseSubmit");
|
||||
return !!pleaseSubmit && content.getComputedStyle(pleaseSubmit).display == "block";
|
||||
});
|
||||
|
||||
is(crashUiVisible, config.shouldSubmissionUIBeVisible, "Plugin crash UI should not be visible");
|
||||
});
|
||||
|
||||
function promisePluginCrashed() {
|
||||
return new ContentTask.spawn(gTestBrowser, {}, function* () {
|
||||
yield new Promise((resolve) => {
|
||||
addEventListener("PluginCrashed", function onPluginCrashed() {
|
||||
removeEventListener("PluginCrashed", onPluginCrashed);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
mm.sendAsyncMessage("test:crash-plugin", {
|
||||
pleaseSubmitStyle: currentRun.shouldSubmissionUIBeVisible ? "block" : "none",
|
||||
submitComment: currentRun.comment,
|
||||
urlOptIn: currentRun.urlOptIn,
|
||||
sendOnCrashMessage: !currentRun.shouldSubmissionUIBeVisible,
|
||||
});
|
||||
gBrowser.loadURI(CRASH_URL + "?" +
|
||||
encodeURIComponent(JSON.stringify(args)));
|
||||
// And now wait for the crash.
|
||||
}
|
||||
catch (err) {
|
||||
failWithException(err);
|
||||
finish();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function onSubmitStatus(subj, topic, data) {
|
||||
try {
|
||||
// Wait for success or failed, doesn't matter which.
|
||||
if (data != "success" && data != "failed")
|
||||
return;
|
||||
function onSubmitStatus(aSubject, aData) {
|
||||
// Wait for success or failed, doesn't matter which.
|
||||
if (aData != "success" && aData != "failed")
|
||||
return false;
|
||||
|
||||
let propBag = subj.QueryInterface(Ci.nsIPropertyBag);
|
||||
if (data == "success") {
|
||||
let remoteID = getPropertyBagValue(propBag, "serverCrashID");
|
||||
ok(!!remoteID, "serverCrashID should be set");
|
||||
let propBag = aSubject.QueryInterface(Ci.nsIPropertyBag);
|
||||
if (aData == "success") {
|
||||
let remoteID = getPropertyBagValue(propBag, "serverCrashID");
|
||||
ok(!!remoteID, "serverCrashID should be set");
|
||||
|
||||
// Remove the submitted report file.
|
||||
let file = Cc["@mozilla.org/file/local;1"]
|
||||
.createInstance(Ci.nsILocalFile);
|
||||
file.initWithPath(Services.crashmanager._submittedDumpsDir);
|
||||
file.append(remoteID + ".txt");
|
||||
ok(file.exists(), "Submitted report file should exist");
|
||||
file.remove(false);
|
||||
}
|
||||
|
||||
let extra = getPropertyBagValue(propBag, "extra");
|
||||
ok(extra instanceof Ci.nsIPropertyBag, "Extra data should be property bag");
|
||||
|
||||
let val = getPropertyBagValue(extra, "PluginUserComment");
|
||||
if (currentRun.comment)
|
||||
is(val, currentRun.comment,
|
||||
"Comment in extra data should match comment in textbox");
|
||||
else
|
||||
ok(val === undefined,
|
||||
"Comment should be absent from extra data when textbox is empty");
|
||||
|
||||
val = getPropertyBagValue(extra, "PluginContentURL");
|
||||
if (currentRun.urlOptIn)
|
||||
is(val, gBrowser.currentURI.spec,
|
||||
"URL in extra data should match browser URL when opt-in checked");
|
||||
else
|
||||
ok(val === undefined,
|
||||
"URL should be absent from extra data when opt-in not checked");
|
||||
// Remove the submitted report file.
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
file.initWithPath(Services.crashmanager._submittedDumpsDir);
|
||||
file.append(remoteID + ".txt");
|
||||
ok(file.exists(), "Submitted report file should exist");
|
||||
file.remove(false);
|
||||
}
|
||||
catch (err) {
|
||||
failWithException(err);
|
||||
}
|
||||
doNextRun();
|
||||
|
||||
let extra = getPropertyBagValue(propBag, "extra");
|
||||
ok(extra instanceof Ci.nsIPropertyBag, "Extra data should be property bag");
|
||||
|
||||
let val = getPropertyBagValue(extra, "PluginUserComment");
|
||||
if (config.comment)
|
||||
is(val, config.comment,
|
||||
"Comment in extra data should match comment in textbox");
|
||||
else
|
||||
ok(val === undefined,
|
||||
"Comment should be absent from extra data when textbox is empty");
|
||||
|
||||
val = getPropertyBagValue(extra, "PluginContentURL");
|
||||
if (config.urlOptIn)
|
||||
is(val, gBrowser.currentURI.spec,
|
||||
"URL in extra data should match browser URL when opt-in checked");
|
||||
else
|
||||
ok(val === undefined,
|
||||
"URL should be absent from extra data when opt-in not checked");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getPropertyBagValue(bag, key) {
|
||||
@ -224,7 +204,3 @@ function getPropertyBagValue(bag, key) {
|
||||
catch (e if e.result == Cr.NS_ERROR_FAILURE) {}
|
||||
return val;
|
||||
}
|
||||
|
||||
function failWithException(err) {
|
||||
ok(false, "Uncaught exception: " + err + "\n" + err.stack);
|
||||
}
|
||||
|
@ -126,8 +126,13 @@ RESPATH = $(BINPATH)
|
||||
endif
|
||||
DEFINES += -DRESPATH=$(RESPATH)
|
||||
|
||||
AB = $(firstword $(subst -, ,$(AB_CD)))
|
||||
DEFINES += -DAB=$(AB)
|
||||
LPROJ_ROOT = $(firstword $(subst -, ,$(AB_CD)))
|
||||
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
|
||||
ifeq (zh-TW,$(AB_CD))
|
||||
LPROJ_ROOT := $(subst -,_,$(AB_CD))
|
||||
endif
|
||||
endif
|
||||
DEFINES += -DLPROJ_ROOT=$(LPROJ_ROOT)
|
||||
|
||||
DEFINES += -DMOZ_ICU_VERSION=$(MOZ_ICU_VERSION)
|
||||
ifdef MOZ_NATIVE_ICU
|
||||
|
@ -38,7 +38,7 @@
|
||||
@APPNAME@/Contents/PkgInfo
|
||||
@RESPATH@/firefox.icns
|
||||
@RESPATH@/document.icns
|
||||
@RESPATH@/@AB@.lproj/*
|
||||
@RESPATH@/@LPROJ_ROOT@.lproj/*
|
||||
#endif
|
||||
|
||||
[@AB_CD@]
|
||||
|
@ -349,6 +349,7 @@ CFLAGS += $(MOZ_OPTIMIZE_FLAGS)
|
||||
CXXFLAGS += $(MOZ_OPTIMIZE_FLAGS)
|
||||
endif # MOZ_OPTIMIZE == 1
|
||||
LDFLAGS += $(MOZ_OPTIMIZE_LDFLAGS)
|
||||
RUSTFLAGS += $(MOZ_OPTIMIZE_RUSTFLAGS)
|
||||
endif # MOZ_OPTIMIZE
|
||||
|
||||
ifdef CROSS_COMPILE
|
||||
|
@ -888,7 +888,8 @@ $(basename $2$(notdir $1)).$(OBJ_SUFFIX): $1 $$(call mkdir_deps,$$(MDDEPDIR))
|
||||
endef
|
||||
$(foreach f,$(CSRCS) $(SSRCS) $(CPPSRCS) $(CMSRCS) $(CMMSRCS) $(ASFILES),$(eval $(call src_objdep,$(f))))
|
||||
$(foreach f,$(HOST_CSRCS) $(HOST_CPPSRCS) $(HOST_CMSRCS) $(HOST_CMMSRCS),$(eval $(call src_objdep,$(f),host_)))
|
||||
# The rust compiler only outputs library objects, and so we need different
|
||||
|
||||
# The Rust compiler only outputs library objects, and so we need different
|
||||
# mangling to generate dependency rules for it.
|
||||
mk_libname = $(basename lib$(notdir $1)).$(LIB_SUFFIX)
|
||||
src_libdep = $(call mk_libname,$1): $1 $$(call mkdir_deps,$$(MDDEPDIR))
|
||||
@ -946,7 +947,7 @@ ifdef MOZ_RUST
|
||||
# in the target's LIBS.
|
||||
$(RSOBJS):
|
||||
$(REPORT_BUILD)
|
||||
$(RUSTC) --crate-type staticlib -o $(call mk_libname,$<) $(_VPATH_SRCS)
|
||||
$(RUSTC) $(RUSTFLAGS) --crate-type staticlib -o $(call mk_libname,$<) $(_VPATH_SRCS)
|
||||
endif
|
||||
|
||||
$(SOBJS):
|
||||
|
16
configure.in
16
configure.in
@ -29,6 +29,7 @@ LDFLAGS="${LDFLAGS=}"
|
||||
HOST_CFLAGS="${HOST_CFLAGS=}"
|
||||
HOST_CXXFLAGS="${HOST_CXXFLAGS=}"
|
||||
HOST_LDFLAGS="${HOST_LDFLAGS=}"
|
||||
RUSTFLAGS="${RUSTFLAGS=}"
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Preserve certain environment flags passed to configure
|
||||
@ -429,7 +430,7 @@ if test -n "$RUSTC"; then
|
||||
AC_MSG_RESULT([$RUSTC_VERSION (v${_RUSTC_MAJOR_VERSION}.${_RUSTC_MINOR_VERSION}.${_RUSTC_PATCH_VERSION})])
|
||||
fi
|
||||
MOZ_ARG_ENABLE_BOOL([rust],
|
||||
[ --enable-rust Include rust language sources],
|
||||
[ --enable-rust Include Rust language sources],
|
||||
[MOZ_RUST=1],
|
||||
[MOZ_RUST= ])
|
||||
if test -z "$RUSTC" -a -n "$MOZ_RUST"; then
|
||||
@ -440,7 +441,7 @@ fi
|
||||
if test -n "$MOZ_RUST" && test -z "$_RUSTC_MAJOR_VERSION" -o \
|
||||
"$_RUSTC_MAJOR_VERSION" -lt 1; then
|
||||
AC_MSG_ERROR([Rust compiler ${RUSTC_VERSION} is too old.
|
||||
To compile rust language sources please install at least
|
||||
To compile Rust language sources please install at least
|
||||
version 1.0 of the 'rustc' toolchain and make sure it is
|
||||
first in your path.
|
||||
You can verify this by typing 'rustc --version'.])
|
||||
@ -505,7 +506,7 @@ EOF
|
||||
if test -z "$MOZ_RUST"; then
|
||||
AC_MSG_ERROR([rustc does not support MacOS X $MACOSX_DEPLOYMENT_TARGET
|
||||
Add 'ac_add_options --enable-macos-target=10.7' (or later)
|
||||
to mozconfig, disable rust support, or use an alternate toolchain.])
|
||||
to mozconfig, disable Rust support, or use an alternate toolchain.])
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -7054,6 +7055,10 @@ if test -z "$MOZ_OPTIMIZE_FLAGS"; then
|
||||
MOZ_OPTIMIZE_FLAGS="-O"
|
||||
fi
|
||||
|
||||
if test -z "$MOZ_OPTIMIZE_RUSTFLAGS"; then
|
||||
MOZ_OPTIMIZE_RUSTFLAGS="-O"
|
||||
fi
|
||||
|
||||
MOZ_ARG_ENABLE_STRING(optimize,
|
||||
[ --disable-optimize Disable compiler optimization
|
||||
--enable-optimize=[OPT] Specify compiler optimization flags [OPT=-O]],
|
||||
@ -7071,7 +7076,7 @@ MOZ_SET_FRAMEPTR_FLAGS
|
||||
|
||||
if test "$COMPILE_ENVIRONMENT"; then
|
||||
if test -n "$MOZ_OPTIMIZE"; then
|
||||
AC_MSG_CHECKING([for valid optimization flags])
|
||||
AC_MSG_CHECKING([for valid C compiler optimization flags])
|
||||
_SAVE_CFLAGS=$CFLAGS
|
||||
CFLAGS="$CFLAGS $MOZ_OPTIMIZE_FLAGS"
|
||||
AC_TRY_COMPILE([#include <stdio.h>],
|
||||
@ -7080,7 +7085,7 @@ if test -n "$MOZ_OPTIMIZE"; then
|
||||
_results=no)
|
||||
AC_MSG_RESULT([$_results])
|
||||
if test "$_results" = "no"; then
|
||||
AC_MSG_ERROR([These compiler flags are invalid: $MOZ_OPTIMIZE_FLAGS])
|
||||
AC_MSG_ERROR([These compiler flags for C are invalid: $MOZ_OPTIMIZE_FLAGS])
|
||||
fi
|
||||
CFLAGS=$_SAVE_CFLAGS
|
||||
fi
|
||||
@ -7089,6 +7094,7 @@ fi # COMPILE_ENVIRONMENT
|
||||
AC_SUBST(MOZ_OPTIMIZE)
|
||||
AC_SUBST(MOZ_FRAMEPTR_FLAGS)
|
||||
AC_SUBST(MOZ_OPTIMIZE_FLAGS)
|
||||
AC_SUBST(MOZ_OPTIMIZE_RUSTFLAGS)
|
||||
AC_SUBST(MOZ_OPTIMIZE_LDFLAGS)
|
||||
AC_SUBST(MOZ_ALLOW_HEAP_EXECUTE_FLAGS)
|
||||
AC_SUBST(MOZ_PGO)
|
||||
|
@ -158,9 +158,7 @@ Animation::SetPlaybackRate(double aPlaybackRate)
|
||||
Nullable<TimeDuration> previousTime = GetCurrentTime();
|
||||
mPlaybackRate = aPlaybackRate;
|
||||
if (!previousTime.IsNull()) {
|
||||
ErrorResult rv;
|
||||
SetCurrentTime(previousTime.Value());
|
||||
MOZ_ASSERT(!rv.Failed(), "Should not assert for non-null time");
|
||||
}
|
||||
}
|
||||
|
||||
@ -449,9 +447,7 @@ Animation::SilentlySetPlaybackRate(double aPlaybackRate)
|
||||
Nullable<TimeDuration> previousTime = GetCurrentTime();
|
||||
mPlaybackRate = aPlaybackRate;
|
||||
if (!previousTime.IsNull()) {
|
||||
ErrorResult rv;
|
||||
SilentlySetCurrentTime(previousTime.Value());
|
||||
MOZ_ASSERT(!rv.Failed(), "Should not assert for non-null time");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -348,6 +348,12 @@ this.PermissionsTable = { geolocation: {
|
||||
privileged: ALLOW_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"audio-channel-system": {
|
||||
app: DENY_ACTION,
|
||||
trusted: DENY_ACTION,
|
||||
privileged: ALLOW_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"audio-channel-telephony": {
|
||||
app: DENY_ACTION,
|
||||
trusted: DENY_ACTION,
|
||||
|
@ -93,6 +93,7 @@ AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType,
|
||||
int(AUDIO_AGENT_CHANNEL_ALARM) == int(AudioChannel::Alarm) &&
|
||||
int(AUDIO_AGENT_CHANNEL_TELEPHONY) == int(AudioChannel::Telephony) &&
|
||||
int(AUDIO_AGENT_CHANNEL_RINGER) == int(AudioChannel::Ringer) &&
|
||||
int(AUDIO_AGENT_CHANNEL_SYSTEM) == int(AudioChannel::System) &&
|
||||
int(AUDIO_AGENT_CHANNEL_PUBLICNOTIFICATION) == int(AudioChannel::Publicnotification),
|
||||
"Enum of channel on nsIAudioChannelAgent.idl should be the same with AudioChannelBinding.h");
|
||||
|
||||
|
@ -29,7 +29,7 @@ interface nsIAudioChannelAgentCallback : nsISupports
|
||||
* 1. Changes to the playable status of this channel.
|
||||
*/
|
||||
|
||||
[uuid(e28e1569-2a44-4f71-9cd0-216874b05d57)]
|
||||
[uuid(ee39a34b-a5c7-4b30-b1ac-cd64ceedef67)]
|
||||
interface nsIAudioChannelAgent : nsISupports
|
||||
{
|
||||
const long AUDIO_AGENT_CHANNEL_NORMAL = 0;
|
||||
@ -39,6 +39,7 @@ interface nsIAudioChannelAgent : nsISupports
|
||||
const long AUDIO_AGENT_CHANNEL_TELEPHONY = 4;
|
||||
const long AUDIO_AGENT_CHANNEL_RINGER = 5;
|
||||
const long AUDIO_AGENT_CHANNEL_PUBLICNOTIFICATION = 6;
|
||||
const long AUDIO_AGENT_CHANNEL_SYSTEM = 7;
|
||||
|
||||
const long AUDIO_AGENT_CHANNEL_ERROR = 1000;
|
||||
|
||||
|
@ -3619,7 +3619,7 @@ nsDOMWindowUtils::GetOMTAStyle(nsIDOMElement* aElement,
|
||||
forwarder->GetShadowManager()->SendGetAnimationTransform(
|
||||
layer->AsShadowableLayer()->GetShadow(), &transform);
|
||||
if (transform.type() == MaybeTransform::TMatrix4x4) {
|
||||
gfx3DMatrix matrix = To3DMatrix(transform.get_Matrix4x4());
|
||||
Matrix4x4 matrix = transform.get_Matrix4x4();
|
||||
cssValue = nsComputedDOMStyle::MatrixToCSSValue(matrix);
|
||||
}
|
||||
}
|
||||
|
@ -2983,20 +2983,20 @@ nsFocusManager::GetNextTabbableContent(nsIPresShell* aPresShell,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If this is a remote child browser, call NavigateDocument to have
|
||||
// the child process continue the navigation. Return a special error
|
||||
// code to have the caller return early. If the child ends up not
|
||||
// being focusable in some way, the child process will call back
|
||||
// into document navigation again by calling MoveFocus.
|
||||
TabParent* remote = TabParent::GetFrom(currentContent);
|
||||
if (remote) {
|
||||
remote->NavigateByKey(aForward, aForDocumentNavigation);
|
||||
return NS_SUCCESS_DOM_NO_OPERATION;
|
||||
}
|
||||
|
||||
// Next, for document navigation, check if this a non-remote child document.
|
||||
bool checkSubDocument = true;
|
||||
if (aForDocumentNavigation) {
|
||||
// If this is a remote child browser, call NavigateDocument to have
|
||||
// the child process continue the navigation. Return a special error
|
||||
// code to have the caller return early. If the child ends up not
|
||||
// being focusable in some way, the child process will call back
|
||||
// into document navigation again by calling MoveFocus.
|
||||
TabParent* remote = TabParent::GetFrom(currentContent);
|
||||
if (remote) {
|
||||
remote->NavigateDocument(aForward);
|
||||
return NS_SUCCESS_DOM_NO_OPERATION;
|
||||
}
|
||||
|
||||
// Next, check if this a non-remote child document.
|
||||
nsIContent* docRoot = GetRootForChildDocument(currentContent);
|
||||
if (docRoot) {
|
||||
// If GetRootForChildDocument returned something then call
|
||||
|
@ -2079,6 +2079,7 @@ GK_ATOM(labelMouseDownPtProperty, "LabelMouseDownPtProperty")
|
||||
GK_ATOM(baseURIProperty, "baseURIProperty")
|
||||
GK_ATOM(lockedStyleStates, "lockedStyleStates")
|
||||
GK_ATOM(apzCallbackTransform, "apzCallbackTransform")
|
||||
GK_ATOM(restylableAnonymousNode, "restylableAnonymousNode")
|
||||
|
||||
// Languages for lang-specific transforms
|
||||
GK_ATOM(Japanese, "ja")
|
||||
|
@ -759,6 +759,9 @@ nsOuterWindowProxy::getOwnPropertyDescriptor(JSContext* cx,
|
||||
}
|
||||
// else fall through to js::Wrapper
|
||||
|
||||
// When we change this to always claim the property is configurable (bug
|
||||
// 1178639), update the comments in nsOuterWindowProxy::defineProperty
|
||||
// accordingly.
|
||||
return js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc);
|
||||
}
|
||||
|
||||
@ -777,14 +780,29 @@ nsOuterWindowProxy::defineProperty(JSContext* cx,
|
||||
return result.failCantDefineWindowElement();
|
||||
}
|
||||
|
||||
#ifndef RELEASE_BUILD // To be turned on in bug 1178638.
|
||||
// For now, allow chrome code to define non-configurable properties
|
||||
// on windows, until we sort out what exactly the addon SDK is
|
||||
// doing. In the meantime, this still allows us to test web compat
|
||||
// behavior.
|
||||
if (false && !desc.configurable() && !nsContentUtils::IsCallerChrome()) {
|
||||
if (desc.hasConfigurable() && !desc.configurable() &&
|
||||
!nsContentUtils::IsCallerChrome()) {
|
||||
return ThrowErrorMessage(cx, MSG_DEFINE_NON_CONFIGURABLE_PROP_ON_WINDOW);
|
||||
}
|
||||
|
||||
// Note that if hasConfigurable() is false we do NOT want to
|
||||
// setConfigurable(true). That would make this code:
|
||||
//
|
||||
// var x;
|
||||
// window.x = 5;
|
||||
//
|
||||
// fail, because the JS engine ends up converting the assignment into a define
|
||||
// with !hasConfigurable(), but the var actually declared a non-configurable
|
||||
// property on our underlying Window object, so the set would fail if we
|
||||
// forced setConfigurable(true) here. What we want to do instead is change
|
||||
// getOwnPropertyDescriptor to always claim configurable. See bug 1178639.
|
||||
#endif
|
||||
|
||||
return js::Wrapper::defineProperty(cx, proxy, id, desc, result);
|
||||
}
|
||||
|
||||
|
@ -790,7 +790,6 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android'
|
||||
[test_bug1081686.html]
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s
|
||||
[test_window_define_nonconfigurable.html]
|
||||
skip-if = true # bug 1107443 - code for newly-added test was disabled
|
||||
[test_root_iframe.html]
|
||||
[test_performance_user_timing.html]
|
||||
[test_bug1126851.html]
|
||||
|
@ -12,7 +12,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1107443
|
||||
|
||||
/** Test for Bug 1107443 **/
|
||||
try {
|
||||
Object.defineProperty(window, "nosuchprop", { value: 5 });
|
||||
Object.defineProperty(window, "nosuchprop", { value: 5, configurable: false });
|
||||
throw "didn't throw";
|
||||
} catch (e) {
|
||||
is(e instanceof TypeError, true,
|
||||
@ -22,9 +22,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1107443
|
||||
'Window should not have property after an attempt to define it failed');
|
||||
}
|
||||
|
||||
Object.defineProperty(window, "nosuchprop", { value: 7, configurable: true });
|
||||
Object.defineProperty(window, "nosuchprop", { value: 6 });
|
||||
var desc = Object.getOwnPropertyDescriptor(window, "nosuchprop");
|
||||
is(typeof(desc), "object", "Should have a property now");
|
||||
todo_is(desc.configurable, true, "Property should be configurable");
|
||||
is(desc.writable, false, "Property should be readonly");
|
||||
is(desc.value, 6, "Property should have the right value");
|
||||
|
||||
Object.defineProperty(window, "nosuchprop2", { value: 7, configurable: true });
|
||||
desc = Object.getOwnPropertyDescriptor(window, "nosuchprop2");
|
||||
is(typeof(desc), "object", "Should have a property now");
|
||||
is(desc.configurable, true, "Property should be configurable");
|
||||
is(desc.writable, false, "Property should be readonly");
|
||||
is(desc.value, 7, "Property should have the right value");
|
||||
|
@ -23,11 +23,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=607464
|
||||
* Pixel scrolling shouldn't scroll smoothly, even if general.smoothScroll is on.
|
||||
**/
|
||||
|
||||
function scrollDown15PxWithPixelScrolling(scrollbox) {
|
||||
function scrollDown150PxWithPixelScrolling(scrollbox) {
|
||||
var win = scrollbox.ownerDocument.defaultView;
|
||||
let event = {
|
||||
deltaMode: WheelEvent.DOM_DELTA_PIXEL,
|
||||
deltaY: 3.0,
|
||||
deltaY: 30.0,
|
||||
lineOrPageDeltaY: 1
|
||||
};
|
||||
// A pixel scroll with lineOrPageDeltaY.
|
||||
@ -52,20 +52,18 @@ function runTest() {
|
||||
var scrollbox = win.document.getElementById("scrollbox");
|
||||
let scrollTopBefore = scrollbox.scrollTop;
|
||||
|
||||
scrollDown15PxWithPixelScrolling(scrollbox);
|
||||
|
||||
// wait for the next refresh driver run
|
||||
win.requestAnimationFrame(function() {
|
||||
// actually, wait for the next one before checking results, since
|
||||
// scrolling might not be flushed until after this code has run
|
||||
win.requestAnimationFrame(function() {
|
||||
is(scrollbox.scrollTop, scrollTopBefore + 15,
|
||||
"Pixel scrolling should have finished after one refresh driver iteration. " +
|
||||
"We shouldn't be scrolling smoothly, even though the pref is set.");
|
||||
win.addEventListener("scroll", function(e) {
|
||||
is(scrollbox.scrollTop % 30, 0,
|
||||
"Pixel scrolling should happen instantly, not smoothly. The " +
|
||||
"scroll position " + scrollbox.scrollTop + " in this sequence of wheel " +
|
||||
"events should be a multiple of 30.");
|
||||
if (scrollbox.scrollTop == 150) {
|
||||
win.close();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
}
|
||||
}, true);
|
||||
|
||||
scrollDown150PxWithPixelScrolling(scrollbox);
|
||||
}, win);
|
||||
}
|
||||
|
||||
@ -77,6 +75,7 @@ window.onload = function() {
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.testInChaosMode();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -1211,6 +1211,7 @@ nsresult HTMLMediaElement::LoadResource()
|
||||
// TODO: Handle failure: run "If the media data cannot be fetched at
|
||||
// all, due to network errors, causing the user agent to give up
|
||||
// trying to fetch the resource" section of resource fetch algorithm.
|
||||
decoder->Shutdown();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsRefPtr<MediaResource> resource =
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include "domstubs.idl"
|
||||
|
||||
[scriptable, uuid(A10D887D-7FC2-48A2-ABC6-A2027423860C)]
|
||||
[scriptable, uuid(CE6F563B-BD77-4EF2-9D7C-A94C587353E4)]
|
||||
interface nsITabParent : nsISupports
|
||||
{
|
||||
void injectTouchEvent(in AString aType,
|
||||
@ -28,10 +28,13 @@ interface nsITabParent : nsISupports
|
||||
readonly attribute uint64_t tabId;
|
||||
|
||||
/**
|
||||
* If aForward is true, navigate to the first focusable document.
|
||||
* If aForward is false, navigate to the last focusable document.
|
||||
* Navigate by key. If aForDocumentNavigation is true, navigate by document.
|
||||
* If aForDocumentNavigation is false, navigate by element.
|
||||
*
|
||||
* If aForward is true, navigate to the first focusable element or document.
|
||||
* If aForward is false, navigate to the last focusable element or document.
|
||||
*/
|
||||
void navigateDocument(in bool aForward);
|
||||
void navigateByKey(in bool aForward, in bool aForDocumentNavigation);
|
||||
|
||||
readonly attribute boolean hasContentOpener;
|
||||
};
|
||||
|
@ -698,9 +698,9 @@ child:
|
||||
SetIsDocShellActive(bool aIsActive);
|
||||
|
||||
/**
|
||||
* Navigate by document.
|
||||
* Navigate by key (Tab/Shift+Tab/F6/Shift+f6).
|
||||
*/
|
||||
NavigateDocument(bool aForward);
|
||||
NavigateByKey(bool aForward, bool aForDocumentNavigation);
|
||||
|
||||
/**
|
||||
* The parent (chrome thread) requests that the child inform it when
|
||||
|
@ -2512,7 +2512,7 @@ TabChild::RecvSetIsDocShellActive(const bool& aIsActive)
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvNavigateDocument(const bool& aForward)
|
||||
TabChild::RecvNavigateByKey(const bool& aForward, const bool& aForDocumentNavigation)
|
||||
{
|
||||
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||
if (fm) {
|
||||
@ -2520,9 +2520,20 @@ TabChild::RecvNavigateDocument(const bool& aForward)
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(WebNavigation());
|
||||
|
||||
// Move to the first or last document.
|
||||
fm->MoveFocus(window, nullptr, aForward ? nsIFocusManager::MOVEFOCUS_FIRSTDOC :
|
||||
nsIFocusManager::MOVEFOCUS_LASTDOC,
|
||||
uint32_t type = aForward ?
|
||||
(aForDocumentNavigation ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FIRSTDOC) :
|
||||
static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_ROOT)) :
|
||||
(aForDocumentNavigation ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_LASTDOC) :
|
||||
static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_LAST));
|
||||
fm->MoveFocus(window, nullptr, type,
|
||||
nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result));
|
||||
|
||||
// No valid root element was found, so move to the first focusable element.
|
||||
if (!result && aForward && !aForDocumentNavigation) {
|
||||
fm->MoveFocus(window, nullptr, nsIFocusManager::MOVEFOCUS_FIRST,
|
||||
nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result));
|
||||
}
|
||||
|
||||
SendRequestFocus(false);
|
||||
}
|
||||
|
||||
|
@ -502,7 +502,7 @@ protected:
|
||||
virtual bool RecvDestroy() override;
|
||||
virtual bool RecvSetUpdateHitRegion(const bool& aEnabled) override;
|
||||
virtual bool RecvSetIsDocShellActive(const bool& aIsActive) override;
|
||||
virtual bool RecvNavigateDocument(const bool& aForward) override;
|
||||
virtual bool RecvNavigateByKey(const bool& aForward, const bool& aForDocumentNavigation) override;
|
||||
|
||||
virtual bool RecvRequestNotifyAfterRemotePaint() override;
|
||||
|
||||
|
@ -2950,9 +2950,9 @@ TabParent::SetHasContentOpener(bool aHasContentOpener)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TabParent::NavigateDocument(bool aForward)
|
||||
TabParent::NavigateByKey(bool aForward, bool aForDocumentNavigation)
|
||||
{
|
||||
unused << SendNavigateDocument(aForward);
|
||||
unused << SendNavigateByKey(aForward, aForDocumentNavigation);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -3,10 +3,13 @@
|
||||
/* 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 "AudioSink.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "AudioStream.h"
|
||||
#include "prenv.h"
|
||||
#include "MediaQueue.h"
|
||||
#include "VideoUtils.h"
|
||||
|
||||
#include "mozilla/CheckedInt.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -19,9 +22,13 @@ extern PRLogModuleInfo* gMediaDecoderLog;
|
||||
// The amount of audio frames that is used to fuzz rounding errors.
|
||||
static const int64_t AUDIO_FUZZ_FRAMES = 1;
|
||||
|
||||
AudioSink::AudioSink(MediaDecoderStateMachine* aStateMachine,
|
||||
int64_t aStartTime, AudioInfo aInfo, dom::AudioChannel aChannel)
|
||||
: mStateMachine(aStateMachine)
|
||||
AudioSink::AudioSink(MediaQueue<AudioData>& aAudioQueue,
|
||||
ReentrantMonitor& aMonitor,
|
||||
int64_t aStartTime,
|
||||
const AudioInfo& aInfo,
|
||||
dom::AudioChannel aChannel)
|
||||
: mAudioQueue(aAudioQueue)
|
||||
, mDecoderMonitor(aMonitor)
|
||||
, mStartTime(aStartTime)
|
||||
, mWritten(0)
|
||||
, mLastGoodPosition(0)
|
||||
@ -318,9 +325,6 @@ AudioSink::PlayFromAudioQueue()
|
||||
|
||||
StartAudioStreamPlaybackIfNeeded();
|
||||
|
||||
if (audio->mOffset != -1) {
|
||||
mStateMachine->DispatchOnPlaybackOffsetUpdate(audio->mOffset);
|
||||
}
|
||||
return audio->mFrames;
|
||||
}
|
||||
|
||||
@ -394,28 +398,10 @@ AudioSink::GetEndTime() const
|
||||
return playedUsecs.value();
|
||||
}
|
||||
|
||||
MediaQueue<AudioData>&
|
||||
AudioSink::AudioQueue()
|
||||
{
|
||||
return mStateMachine->AudioQueue();
|
||||
}
|
||||
|
||||
ReentrantMonitor&
|
||||
AudioSink::GetReentrantMonitor()
|
||||
{
|
||||
return mStateMachine->mDecoder->GetReentrantMonitor();
|
||||
}
|
||||
|
||||
void
|
||||
AudioSink::AssertCurrentThreadInMonitor()
|
||||
{
|
||||
return mStateMachine->AssertCurrentThreadInMonitor();
|
||||
}
|
||||
|
||||
void
|
||||
AudioSink::AssertOnAudioThread()
|
||||
{
|
||||
MOZ_ASSERT(IsCurrentThread(mThread));
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mThread);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -6,23 +6,30 @@
|
||||
#if !defined(AudioSink_h__)
|
||||
#define AudioSink_h__
|
||||
|
||||
#include "MediaInfo.h"
|
||||
#include "nsRefPtr.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "MediaDecoderReader.h"
|
||||
|
||||
#include "mozilla/dom/AudioChannelBinding.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class AudioData;
|
||||
class AudioStream;
|
||||
class MediaDecoderStateMachine;
|
||||
template <class T> class MediaQueue;
|
||||
|
||||
class AudioSink {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioSink)
|
||||
|
||||
AudioSink(MediaDecoderStateMachine* aStateMachine,
|
||||
int64_t aStartTime, AudioInfo aInfo, dom::AudioChannel aChannel);
|
||||
AudioSink(MediaQueue<AudioData>& aAudioQueue,
|
||||
ReentrantMonitor& aMonitor,
|
||||
int64_t aStartTime,
|
||||
const AudioInfo& aInfo,
|
||||
dom::AudioChannel aChannel);
|
||||
|
||||
// Return a promise which will be resolved when AudioSink finishes playing,
|
||||
// or rejected if any error.
|
||||
@ -92,13 +99,22 @@ private:
|
||||
void StartAudioStreamPlaybackIfNeeded();
|
||||
void WriteSilence(uint32_t aFrames);
|
||||
|
||||
MediaQueue<AudioData>& AudioQueue();
|
||||
MediaQueue<AudioData>& AudioQueue() const {
|
||||
return mAudioQueue;
|
||||
}
|
||||
|
||||
ReentrantMonitor& GetReentrantMonitor() const {
|
||||
return mDecoderMonitor;
|
||||
}
|
||||
|
||||
void AssertCurrentThreadInMonitor() const {
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
}
|
||||
|
||||
ReentrantMonitor& GetReentrantMonitor();
|
||||
void AssertCurrentThreadInMonitor();
|
||||
void AssertOnAudioThread();
|
||||
|
||||
nsRefPtr<MediaDecoderStateMachine> mStateMachine;
|
||||
MediaQueue<AudioData>& mAudioQueue;
|
||||
ReentrantMonitor& mDecoderMonitor;
|
||||
|
||||
// Thread for pushing audio onto the audio hardware.
|
||||
// The "audio push thread".
|
||||
|
@ -181,6 +181,8 @@ cubeb_stream_type ConvertChannelToCubebType(dom::AudioChannel aChannel)
|
||||
return CUBEB_STREAM_TYPE_VOICE_CALL;
|
||||
case dom::AudioChannel::Ringer:
|
||||
return CUBEB_STREAM_TYPE_RING;
|
||||
case dom::AudioChannel::System:
|
||||
return CUBEB_STREAM_TYPE_SYSTEM;
|
||||
case dom::AudioChannel::Publicnotification:
|
||||
return CUBEB_STREAM_TYPE_SYSTEM_ENFORCED;
|
||||
default:
|
||||
|
@ -558,12 +558,11 @@ void MediaDecoder::SetMinimizePrerollUntilPlaybackStarts()
|
||||
nsresult MediaDecoder::ScheduleStateMachine()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ASSERTION(mDecoderStateMachine,
|
||||
"Must have state machine to start state machine thread");
|
||||
NS_ENSURE_STATE(mDecoderStateMachine);
|
||||
|
||||
if (mShuttingDown)
|
||||
return NS_OK;
|
||||
|
||||
MOZ_ASSERT(mDecoderStateMachine);
|
||||
NS_ENSURE_STATE(mDecoderStateMachine);
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
mDecoderStateMachine->ScheduleStateMachineCrossThread();
|
||||
return NS_OK;
|
||||
|
@ -283,13 +283,17 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
||||
timeBeginPeriod(1);
|
||||
#endif
|
||||
|
||||
nsRefPtr<MediaDecoderStateMachine> self = this;
|
||||
|
||||
AudioQueue().AddPopListener(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::OnAudioPopped),
|
||||
mTaskQueue);
|
||||
[self] (const AudioData* aSample) {
|
||||
self->OnAudioPopped(aSample);
|
||||
}, mTaskQueue);
|
||||
|
||||
VideoQueue().AddPopListener(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::OnVideoPopped),
|
||||
mTaskQueue);
|
||||
[self] (const VideoData* aSample) {
|
||||
self->OnVideoPopped(aSample);
|
||||
}, mTaskQueue);
|
||||
}
|
||||
|
||||
MediaDecoderStateMachine::~MediaDecoderStateMachine()
|
||||
@ -681,19 +685,21 @@ MediaDecoderStateMachine::PushFront(VideoData* aSample)
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::OnAudioPopped()
|
||||
MediaDecoderStateMachine::OnAudioPopped(const AudioData* aSample)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mDecoder->UpdatePlaybackOffset(std::max<int64_t>(0, aSample->mOffset));
|
||||
UpdateNextFrameStatus();
|
||||
DispatchAudioDecodeTaskIfNeeded();
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::OnVideoPopped()
|
||||
MediaDecoderStateMachine::OnVideoPopped(const VideoData* aSample)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mDecoder->UpdatePlaybackOffset(aSample->mOffset);
|
||||
UpdateNextFrameStatus();
|
||||
DispatchVideoDecodeTaskIfNeeded();
|
||||
// Notify the decode thread that the video queue's buffers may have
|
||||
@ -1788,8 +1794,9 @@ MediaDecoderStateMachine::StartAudioThread()
|
||||
|
||||
if (HasAudio() && !mAudioSink) {
|
||||
mAudioCompleted = false;
|
||||
mAudioSink = new AudioSink(this, GetMediaTime(),
|
||||
mInfo.mAudio, mDecoder->GetAudioChannel());
|
||||
mAudioSink = new AudioSink(mAudioQueue, mDecoder->GetReentrantMonitor(),
|
||||
GetMediaTime(), mInfo.mAudio,
|
||||
mDecoder->GetAudioChannel());
|
||||
|
||||
mAudioSinkPromise.Begin(
|
||||
mAudioSink->Init()->Then(
|
||||
@ -2714,7 +2721,6 @@ void MediaDecoderStateMachine::UpdateRenderedVideoFrames()
|
||||
}
|
||||
VideoQueue().PushFront(currentFrame);
|
||||
if (framesRemoved > 0) {
|
||||
OnPlaybackOffsetUpdate(currentFrame->mOffset);
|
||||
mVideoFrameEndTime = currentFrame->GetEndTime();
|
||||
MediaDecoder::FrameStatistics& frameStats = mDecoder->GetFrameStatistics();
|
||||
frameStats.NotifyPresentedFrame();
|
||||
@ -3104,13 +3110,6 @@ MediaDecoderStateMachine::AudioEndTime() const
|
||||
return -1;
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::OnPlaybackOffsetUpdate(int64_t aPlaybackOffset)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mDecoder->UpdatePlaybackOffset(aPlaybackOffset);
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::OnAudioSinkComplete()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
@ -119,7 +119,6 @@ extern PRLogModuleInfo* gMediaSampleLog;
|
||||
*/
|
||||
class MediaDecoderStateMachine
|
||||
{
|
||||
friend class AudioSink;
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderStateMachine)
|
||||
public:
|
||||
typedef MediaDecoderReader::AudioDataPromise AudioDataPromise;
|
||||
@ -398,8 +397,8 @@ protected:
|
||||
void PushFront(AudioData* aSample);
|
||||
void PushFront(VideoData* aSample);
|
||||
|
||||
void OnAudioPopped();
|
||||
void OnVideoPopped();
|
||||
void OnAudioPopped(const AudioData* aSample);
|
||||
void OnVideoPopped(const VideoData* aSample);
|
||||
|
||||
void VolumeChanged();
|
||||
void LogicalPlaybackRateChanged();
|
||||
@ -667,17 +666,6 @@ protected:
|
||||
// Can only be called on the state machine thread.
|
||||
void SetPlayStartTime(const TimeStamp& aTimeStamp);
|
||||
|
||||
private:
|
||||
// Update mDecoder's playback offset.
|
||||
void OnPlaybackOffsetUpdate(int64_t aPlaybackOffset);
|
||||
public:
|
||||
void DispatchOnPlaybackOffsetUpdate(int64_t aPlaybackOffset)
|
||||
{
|
||||
RefPtr<nsRunnable> r =
|
||||
NS_NewRunnableMethodWithArg<int64_t>(this, &MediaDecoderStateMachine::OnPlaybackOffsetUpdate, aPlaybackOffset);
|
||||
OwnerThread()->Dispatch(r.forget());
|
||||
}
|
||||
|
||||
private:
|
||||
// Resolved by the AudioSink to signal that all outstanding work is complete
|
||||
// and the sink is shutting down.
|
||||
|
@ -52,31 +52,34 @@ public:
|
||||
OnSuccess(nsIVariant* aDevices) override
|
||||
{
|
||||
// Cribbed from MediaPermissionGonk.cpp
|
||||
nsIID elementIID;
|
||||
uint16_t elementType;
|
||||
|
||||
// Create array for nsIMediaDevice
|
||||
nsTArray<nsCOMPtr<nsIMediaDevice>> devices;
|
||||
// Contain the fumes
|
||||
{
|
||||
void* rawArray;
|
||||
uint32_t arrayLen;
|
||||
nsresult rv;
|
||||
rv = aDevices->GetAsArray(&elementType, &elementIID, &arrayLen, &rawArray);
|
||||
uint16_t vtype;
|
||||
nsresult rv = aDevices->GetDataType(&vtype);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (vtype != nsIDataType::VTYPE_EMPTY_ARRAY) {
|
||||
nsIID elementIID;
|
||||
uint16_t elementType;
|
||||
void* rawArray;
|
||||
uint32_t arrayLen;
|
||||
rv = aDevices->GetAsArray(&elementType, &elementIID, &arrayLen, &rawArray);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (elementType != nsIDataType::VTYPE_INTERFACE) {
|
||||
free(rawArray);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (elementType != nsIDataType::VTYPE_INTERFACE) {
|
||||
free(rawArray);
|
||||
return NS_ERROR_FAILURE;
|
||||
nsISupports **supportsArray = reinterpret_cast<nsISupports **>(rawArray);
|
||||
for (uint32_t i = 0; i < arrayLen; ++i) {
|
||||
nsCOMPtr<nsIMediaDevice> device(do_QueryInterface(supportsArray[i]));
|
||||
devices.AppendElement(device);
|
||||
NS_IF_RELEASE(supportsArray[i]); // explicitly decrease refcount for rawptr
|
||||
}
|
||||
free(rawArray); // explicitly free memory from nsIVariant::GetAsArray
|
||||
}
|
||||
|
||||
nsISupports **supportsArray = reinterpret_cast<nsISupports **>(rawArray);
|
||||
for (uint32_t i = 0; i < arrayLen; ++i) {
|
||||
nsCOMPtr<nsIMediaDevice> device(do_QueryInterface(supportsArray[i]));
|
||||
devices.AppendElement(device);
|
||||
NS_IF_RELEASE(supportsArray[i]); // explicitly decrease refcount for rawptr
|
||||
}
|
||||
free(rawArray); // explicitly free memory from nsIVariant::GetAsArray
|
||||
}
|
||||
nsTArray<nsRefPtr<MediaDeviceInfo>> infos;
|
||||
for (auto& device : devices) {
|
||||
|
@ -1683,12 +1683,12 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow,
|
||||
if (!privileged) {
|
||||
// only allow privileged content to set the window id
|
||||
if (vc.mBrowserWindow.WasPassed()) {
|
||||
vc.mBrowserWindow.Construct(-1);
|
||||
vc.mBrowserWindow.Value() = -1;
|
||||
}
|
||||
if (vc.mAdvanced.WasPassed()) {
|
||||
for (MediaTrackConstraintSet& cs : vc.mAdvanced.Value()) {
|
||||
if (cs.mBrowserWindow.WasPassed()) {
|
||||
cs.mBrowserWindow.Construct(-1);
|
||||
cs.mBrowserWindow.Value() = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,8 @@
|
||||
#define MediaQueue_h_
|
||||
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/TaskQueue.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#include "nsDeque.h"
|
||||
#include "nsTArray.h"
|
||||
@ -24,14 +24,44 @@ class MediaQueueDeallocator : public nsDequeFunctor {
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> class MediaQueue : private nsDeque {
|
||||
public:
|
||||
template <class T>
|
||||
class MediaQueue : private nsDeque {
|
||||
struct Listener {
|
||||
virtual ~Listener() {}
|
||||
virtual void Dispatch(T* aItem) = 0;
|
||||
};
|
||||
|
||||
MediaQueue()
|
||||
: nsDeque(new MediaQueueDeallocator<T>()),
|
||||
mReentrantMonitor("mediaqueue"),
|
||||
mEndOfStream(false)
|
||||
{}
|
||||
template<typename Function>
|
||||
class PopListener : public Listener {
|
||||
public:
|
||||
explicit PopListener(const Function& aFunction, TaskQueue* aTarget)
|
||||
: mFunction(aFunction), mTarget(aTarget) {}
|
||||
|
||||
void Dispatch(T* aItem) override {
|
||||
nsRefPtr<T> item = aItem;
|
||||
Function function = mFunction;
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
|
||||
function(item);
|
||||
});
|
||||
mTarget->Dispatch(r.forget());
|
||||
}
|
||||
private:
|
||||
Function mFunction;
|
||||
nsRefPtr<TaskQueue> mTarget;
|
||||
};
|
||||
|
||||
void NotifyPopListeners(T* aItem) {
|
||||
for (auto&& l : mPopListeners) {
|
||||
l->Dispatch(aItem);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
MediaQueue()
|
||||
: nsDeque(new MediaQueueDeallocator<T>()),
|
||||
mReentrantMonitor("mediaqueue"),
|
||||
mEndOfStream(false)
|
||||
{}
|
||||
|
||||
~MediaQueue() {
|
||||
Reset();
|
||||
@ -60,7 +90,7 @@ template <class T> class MediaQueue : private nsDeque {
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
nsRefPtr<T> rv = dont_AddRef(static_cast<T*>(nsDeque::PopFront()));
|
||||
if (rv) {
|
||||
NotifyPopListeners();
|
||||
NotifyPopListeners(rv);
|
||||
}
|
||||
return rv.forget();
|
||||
}
|
||||
@ -160,39 +190,16 @@ template <class T> class MediaQueue : private nsDeque {
|
||||
mPopListeners.Clear();
|
||||
}
|
||||
|
||||
void AddPopListener(nsIRunnable* aRunnable, TaskQueue* aTarget) {
|
||||
template<typename Function>
|
||||
void AddPopListener(const Function& aFunction, TaskQueue* aTarget) {
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
mPopListeners.AppendElement(Listener(aRunnable, aTarget));
|
||||
mPopListeners.AppendElement()->reset(
|
||||
new PopListener<Function>(aFunction, aTarget));
|
||||
}
|
||||
|
||||
private:
|
||||
mutable ReentrantMonitor mReentrantMonitor;
|
||||
|
||||
struct Listener {
|
||||
Listener(nsIRunnable* aRunnable, TaskQueue* aTarget)
|
||||
: mRunnable(aRunnable)
|
||||
, mTarget(aTarget)
|
||||
{
|
||||
}
|
||||
Listener(const Listener& aOther)
|
||||
: mRunnable(aOther.mRunnable)
|
||||
, mTarget(aOther.mTarget)
|
||||
{
|
||||
}
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
RefPtr<TaskQueue> mTarget;
|
||||
};
|
||||
|
||||
nsTArray<Listener> mPopListeners;
|
||||
|
||||
void NotifyPopListeners() {
|
||||
for (uint32_t i = 0; i < mPopListeners.Length(); i++) {
|
||||
Listener& l = mPopListeners[i];
|
||||
nsCOMPtr<nsIRunnable> r = l.mRunnable;
|
||||
l.mTarget->Dispatch(r.forget());
|
||||
}
|
||||
}
|
||||
|
||||
nsTArray<UniquePtr<Listener>> mPopListeners;
|
||||
// True when we've decoded the last frame of data in the
|
||||
// bitstream for which we're queueing frame data.
|
||||
bool mEndOfStream;
|
||||
|
@ -21,10 +21,10 @@ function mustFailWith(msg, reason, f) {
|
||||
e => is(e.name, reason, msg + " must fail: " + e.message));
|
||||
}
|
||||
|
||||
var pushPrefs = dict => new Promise(res => SpecialPowers.pushPrefEnv(dict, res));
|
||||
var pushPrefs = (...p) => new Promise(r => SpecialPowers.pushPrefEnv({set: p}, r));
|
||||
|
||||
runTest(() =>
|
||||
pushPrefs({ set : [["media.navigator.streams.fake", true]] })
|
||||
pushPrefs(["media.navigator.streams.fake", true])
|
||||
.then(() => navigator.mediaDevices.enumerateDevices())
|
||||
.then(devices => {
|
||||
ok(devices.length > 0, "At least one device found");
|
||||
@ -58,7 +58,12 @@ runTest(() =>
|
||||
() => navigator.mediaDevices.getUserMedia({
|
||||
audio: { deviceId: { exact: "unknown9qHr8B0JIbcHlbl9xR+jMbZZ8WyoPfpCXPfc=" } },
|
||||
fake: true,
|
||||
}))));
|
||||
})))
|
||||
// Check the special case of no devices found (these prefs override fake).
|
||||
.then(() => pushPrefs(["media.audio_loopback_dev", "none"],
|
||||
["media.video_loopback_dev", "none"]))
|
||||
.then(() => navigator.mediaDevices.enumerateDevices())
|
||||
.then(devices => ok(devices.length === 0, "No devices found")));
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -95,7 +95,7 @@ runTest(function() {
|
||||
|
||||
var unexpected = supported.filter(key => !mustSupport.includes(key));
|
||||
is(unexpected.length, 0,
|
||||
"Unexpected support (please update test): " + unexpected);
|
||||
"Unanticipated support (please update test): " + unexpected);
|
||||
|
||||
// Run constraint tests
|
||||
|
||||
|
@ -41,7 +41,9 @@ if CONFIG['MOZ_WEBSPEECH']:
|
||||
'test/nsFakeSynthServices.cpp'
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_SYNTH_PICO']:
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
DIRS = ['windows']
|
||||
elif CONFIG['MOZ_SYNTH_PICO']:
|
||||
DIRS = ['pico']
|
||||
|
||||
IPDL_SOURCES += [
|
||||
|
57
dom/media/webspeech/synth/windows/SapiModule.cpp
Normal file
57
dom/media/webspeech/synth/windows/SapiModule.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
/* -*- 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 "mozilla/ModuleUtils.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
|
||||
#include "SapiService.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
#define SAPISERVICE_CID \
|
||||
{0x21b4a45b, 0x9806, 0x4021, {0xa7, 0x06, 0xd7, 0x68, 0xab, 0x05, 0x48, 0xf9}}
|
||||
|
||||
#define SAPISERVICE_CONTRACTID "@mozilla.org/synthsapi;1"
|
||||
|
||||
// Defines SapiServiceConstructor
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(SapiService,
|
||||
SapiService::GetInstanceForService)
|
||||
|
||||
// Defines kSAPISERVICE_CID
|
||||
NS_DEFINE_NAMED_CID(SAPISERVICE_CID);
|
||||
|
||||
static const mozilla::Module::CIDEntry kCIDs[] = {
|
||||
{ &kSAPISERVICE_CID, true, nullptr, SapiServiceConstructor },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module::ContractIDEntry kContracts[] = {
|
||||
{ SAPISERVICE_CONTRACTID, &kSAPISERVICE_CID },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module::CategoryEntry kCategories[] = {
|
||||
{ "profile-after-change", "Sapi Speech Synth", SAPISERVICE_CONTRACTID },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static void
|
||||
UnloadSapiModule()
|
||||
{
|
||||
SapiService::Shutdown();
|
||||
}
|
||||
|
||||
static const mozilla::Module kModule = {
|
||||
mozilla::Module::kVersion,
|
||||
kCIDs,
|
||||
kContracts,
|
||||
kCategories,
|
||||
nullptr,
|
||||
nullptr,
|
||||
UnloadSapiModule
|
||||
};
|
||||
|
||||
NSMODULE_DEFN(synthsapi) = &kModule;
|
381
dom/media/webspeech/synth/windows/SapiService.cpp
Normal file
381
dom/media/webspeech/synth/windows/SapiService.cpp
Normal file
@ -0,0 +1,381 @@
|
||||
/* -*- 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 "nsISupports.h"
|
||||
#include "SapiService.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsWin32Locale.h"
|
||||
|
||||
#include "mozilla/dom/nsSynthVoiceRegistry.h"
|
||||
#include "mozilla/dom/nsSpeechTask.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#include <sphelper.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
StaticRefPtr<SapiService> SapiService::sSingleton;
|
||||
|
||||
class SapiCallback final : public nsISpeechTaskCallback
|
||||
{
|
||||
public:
|
||||
SapiCallback(nsISpeechTask* aTask, ISpVoice* aSapiClient,
|
||||
uint32_t aTextOffset, uint32_t aSpeakTextLen)
|
||||
: mTask(aTask)
|
||||
, mSapiClient(aSapiClient)
|
||||
, mTextOffset(aTextOffset)
|
||||
, mSpeakTextLen(aSpeakTextLen)
|
||||
, mCurrentIndex(0)
|
||||
, mStreamNum(0)
|
||||
{
|
||||
mStartingTime = GetTickCount();
|
||||
}
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(SapiCallback, nsISpeechTaskCallback)
|
||||
|
||||
NS_DECL_NSISPEECHTASKCALLBACK
|
||||
|
||||
ULONG GetStreamNum() const { return mStreamNum; }
|
||||
void SetStreamNum(ULONG aValue) { mStreamNum = aValue; }
|
||||
|
||||
void OnSpeechEvent(const SPEVENT& speechEvent);
|
||||
|
||||
private:
|
||||
~SapiCallback() { }
|
||||
|
||||
// This pointer is used to dispatch events
|
||||
nsCOMPtr<nsISpeechTask> mTask;
|
||||
nsRefPtr<ISpVoice> mSapiClient;
|
||||
|
||||
uint32_t mTextOffset;
|
||||
uint32_t mSpeakTextLen;
|
||||
|
||||
// Used for calculating the time taken to speak the utterance
|
||||
double mStartingTime;
|
||||
uint32_t mCurrentIndex;
|
||||
|
||||
ULONG mStreamNum;
|
||||
};
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(SapiCallback, mTask);
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SapiCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISpeechTaskCallback)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechTaskCallback)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(SapiCallback)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(SapiCallback)
|
||||
|
||||
NS_IMETHODIMP
|
||||
SapiCallback::OnPause()
|
||||
{
|
||||
if (FAILED(mSapiClient->Pause())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mTask->DispatchPause(GetTickCount() - mStartingTime, mCurrentIndex);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SapiCallback::OnResume()
|
||||
{
|
||||
if (FAILED(mSapiClient->Resume())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mTask->DispatchResume(GetTickCount() - mStartingTime, mCurrentIndex);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SapiCallback::OnCancel()
|
||||
{
|
||||
// After cancel, mCurrentIndex may be updated.
|
||||
// At cancel case, use mCurrentIndex for DispatchEnd.
|
||||
mSpeakTextLen = 0;
|
||||
// Purge all the previous utterances and speak an empty string
|
||||
if (FAILED(mSapiClient->Speak(nullptr, SPF_PURGEBEFORESPEAK, nullptr))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
SapiCallback::OnSpeechEvent(const SPEVENT& speechEvent)
|
||||
{
|
||||
switch (speechEvent.eEventId) {
|
||||
case SPEI_START_INPUT_STREAM:
|
||||
mTask->DispatchStart();
|
||||
break;
|
||||
case SPEI_END_INPUT_STREAM:
|
||||
if (mSpeakTextLen) {
|
||||
mCurrentIndex = mSpeakTextLen;
|
||||
}
|
||||
mTask->DispatchEnd(GetTickCount() - mStartingTime, mCurrentIndex);
|
||||
mTask = nullptr;
|
||||
break;
|
||||
case SPEI_TTS_BOOKMARK:
|
||||
mCurrentIndex = static_cast<ULONG>(speechEvent.lParam) - mTextOffset;
|
||||
mTask->DispatchBoundary(NS_LITERAL_STRING("mark"),
|
||||
GetTickCount() - mStartingTime, mCurrentIndex);
|
||||
break;
|
||||
case SPEI_WORD_BOUNDARY:
|
||||
mCurrentIndex = static_cast<ULONG>(speechEvent.lParam) - mTextOffset;
|
||||
mTask->DispatchBoundary(NS_LITERAL_STRING("word"),
|
||||
GetTickCount() - mStartingTime, mCurrentIndex);
|
||||
break;
|
||||
case SPEI_SENTENCE_BOUNDARY:
|
||||
mCurrentIndex = static_cast<ULONG>(speechEvent.lParam) - mTextOffset;
|
||||
mTask->DispatchBoundary(NS_LITERAL_STRING("sentence"),
|
||||
GetTickCount() - mStartingTime, mCurrentIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void __stdcall
|
||||
SapiService::SpeechEventCallback(WPARAM aWParam, LPARAM aLParam)
|
||||
{
|
||||
nsRefPtr<SapiService> service = (SapiService*) aWParam;
|
||||
|
||||
SPEVENT speechEvent;
|
||||
while (service->mSapiClient->GetEvents(1, &speechEvent, nullptr) == S_OK) {
|
||||
for (size_t i = 0; i < service->mCallbacks.Length(); i++) {
|
||||
nsRefPtr<SapiCallback> callback = service->mCallbacks[i];
|
||||
if (callback->GetStreamNum() == speechEvent.ulStreamNum) {
|
||||
callback->OnSpeechEvent(speechEvent);
|
||||
if (speechEvent.eEventId == SPEI_END_INPUT_STREAM) {
|
||||
service->mCallbacks.RemoveElementAt(i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(SapiService)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISpeechService)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechService)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_ADDREF(SapiService)
|
||||
NS_IMPL_RELEASE(SapiService)
|
||||
|
||||
SapiService::SapiService()
|
||||
: mInitialized(false)
|
||||
{
|
||||
}
|
||||
|
||||
SapiService::~SapiService()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
SapiService::Init()
|
||||
{
|
||||
MOZ_ASSERT(!mInitialized);
|
||||
|
||||
if (Preferences::GetBool("media.webspeech.synth.test")) {
|
||||
// When enabled, we shouldn't add OS backend (Bug 1160844)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (FAILED(CoCreateInstance(CLSID_SpVoice, nullptr, CLSCTX_ALL, IID_ISpVoice,
|
||||
getter_AddRefs(mSapiClient)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set interest for all the events we are interested in
|
||||
ULONGLONG eventMask =
|
||||
SPFEI(SPEI_START_INPUT_STREAM) |
|
||||
SPFEI(SPEI_TTS_BOOKMARK) |
|
||||
SPFEI(SPEI_WORD_BOUNDARY) |
|
||||
SPFEI(SPEI_SENTENCE_BOUNDARY) |
|
||||
SPFEI(SPEI_END_INPUT_STREAM);
|
||||
|
||||
if (FAILED(mSapiClient->SetInterest(eventMask, eventMask))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get all the voices from sapi and register in the SynthVoiceRegistry
|
||||
if (!RegisterVoices()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the callback function for receiving the events
|
||||
mSapiClient->SetNotifyCallbackFunction(
|
||||
(SPNOTIFYCALLBACK*) SapiService::SpeechEventCallback, (WPARAM) this, 0);
|
||||
|
||||
mInitialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SapiService::RegisterVoices()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsISynthVoiceRegistry> registry =
|
||||
do_GetService(NS_SYNTHVOICEREGISTRY_CONTRACTID);
|
||||
if (!registry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<IEnumSpObjectTokens> voiceTokens;
|
||||
if (FAILED(SpEnumTokens(SPCAT_VOICES, nullptr, nullptr,
|
||||
getter_AddRefs(voiceTokens)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
nsRefPtr<ISpObjectToken> voiceToken;
|
||||
if (voiceTokens->Next(1, getter_AddRefs(voiceToken), nullptr) != S_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
WCHAR* description = nullptr;
|
||||
if (FAILED(SpGetDescription(voiceToken, &description))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsRefPtr<ISpDataKey> attributes;
|
||||
if (FAILED(voiceToken->OpenKey(L"Attributes",
|
||||
getter_AddRefs(attributes)))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WCHAR* language = nullptr;
|
||||
if (FAILED(attributes->GetStringValue(L"Language", &language))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Language attribute is LCID by hex. So we need convert to locale
|
||||
// name.
|
||||
nsAutoString hexLcid;
|
||||
LCID lcid = wcstol(language, nullptr, 16);
|
||||
nsAutoString locale;
|
||||
nsWin32Locale::GetXPLocale(lcid, locale);
|
||||
|
||||
nsAutoString uri;
|
||||
uri.AssignLiteral("urn:moz-tts:sapi:");
|
||||
uri.Append(description);
|
||||
uri.AppendLiteral("?");
|
||||
uri.Append(locale);
|
||||
|
||||
rv = registry->AddVoice(this, uri, nsDependentString(description), locale,
|
||||
true);
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mVoices.Put(uri, voiceToken);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SapiService::Speak(const nsAString& aText, const nsAString& aUri,
|
||||
float aVolume, float aRate, float aPitch,
|
||||
nsISpeechTask* aTask)
|
||||
{
|
||||
NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
nsRefPtr<ISpObjectToken> voiceToken;
|
||||
if (!mVoices.Get(aUri, getter_AddRefs(voiceToken))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (FAILED(mSapiClient->SetVoice(voiceToken))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (FAILED(mSapiClient->SetVolume(static_cast<USHORT>(aVolume * 100)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (FAILED(mSapiClient->SetRate(static_cast<long>(10 * log10(aRate))))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Set the pitch using xml
|
||||
nsAutoString xml;
|
||||
xml.AssignLiteral("<pitch absmiddle=\"");
|
||||
xml.AppendFloat(aPitch * 10.0f - 10.0f);
|
||||
xml.AppendLiteral("\">");
|
||||
uint32_t textOffset = xml.Length();
|
||||
|
||||
xml.Append(aText);
|
||||
xml.AppendLiteral("</pitch>");
|
||||
|
||||
nsRefPtr<SapiCallback> callback =
|
||||
new SapiCallback(aTask, mSapiClient, textOffset, aText.Length());
|
||||
|
||||
// The last three parameters doesn't matter for an indirect service
|
||||
nsresult rv = aTask->Setup(callback, 0, 0, 0);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
ULONG streamNum;
|
||||
if (FAILED(mSapiClient->Speak(xml.get(), SPF_ASYNC, &streamNum))) {
|
||||
aTask->Setup(nullptr, 0, 0, 0);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
callback->SetStreamNum(streamNum);
|
||||
// streamNum reassigns same value when last stream is finished even if
|
||||
// callback for stream end isn't called
|
||||
// So we cannot use data hashtable and has to add it to vector at last.
|
||||
mCallbacks.AppendElement(callback);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SapiService::GetServiceType(SpeechServiceType* aServiceType)
|
||||
{
|
||||
*aServiceType = nsISpeechService::SERVICETYPE_INDIRECT_AUDIO;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SapiService*
|
||||
SapiService::GetInstance()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||
MOZ_ASSERT(false,
|
||||
"SapiService can only be started on main gecko process");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!sSingleton) {
|
||||
nsRefPtr<SapiService> service = new SapiService();
|
||||
if (service->Init()) {
|
||||
sSingleton = service;
|
||||
}
|
||||
}
|
||||
return sSingleton;
|
||||
}
|
||||
|
||||
already_AddRefed<SapiService>
|
||||
SapiService::GetInstanceForService()
|
||||
{
|
||||
nsRefPtr<SapiService> sapiService = GetInstance();
|
||||
return sapiService.forget();
|
||||
}
|
||||
|
||||
void
|
||||
SapiService::Shutdown()
|
||||
{
|
||||
if (!sSingleton) {
|
||||
return;
|
||||
}
|
||||
sSingleton = nullptr;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
57
dom/media/webspeech/synth/windows/SapiService.h
Normal file
57
dom/media/webspeech/synth/windows/SapiService.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* -*- 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_SapiService_h
|
||||
#define mozilla_dom_SapiService_h
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsISpeechService.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <sapi.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class SapiCallback;
|
||||
|
||||
class SapiService final : public nsISpeechService
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISPEECHSERVICE
|
||||
|
||||
SapiService();
|
||||
bool Init();
|
||||
|
||||
static SapiService* GetInstance();
|
||||
static already_AddRefed<SapiService> GetInstanceForService();
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
static void __stdcall SpeechEventCallback(WPARAM aWParam, LPARAM aLParam);
|
||||
|
||||
private:
|
||||
virtual ~SapiService();
|
||||
|
||||
bool RegisterVoices();
|
||||
|
||||
nsRefPtrHashtable<nsStringHashKey, ISpObjectToken> mVoices;
|
||||
nsTArray<nsRefPtr<SapiCallback>> mCallbacks;
|
||||
nsRefPtr<ISpVoice> mSapiClient;
|
||||
|
||||
bool mInitialized;
|
||||
|
||||
static StaticRefPtr<SapiService> sSingleton;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
13
dom/media/webspeech/synth/windows/moz.build
Normal file
13
dom/media/webspeech/synth/windows/moz.build
Normal file
@ -0,0 +1,13 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'SapiModule.cpp',
|
||||
'SapiService.cpp'
|
||||
]
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
@ -1311,6 +1311,12 @@ NS_StartCORSPreflight(nsIChannel* aRequestChannel,
|
||||
|
||||
rv = preHttp->SetRequestMethod(NS_LITERAL_CSTRING("OPTIONS"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Preflight requests should never be intercepted by service workers.
|
||||
nsCOMPtr<nsIHttpChannelInternal> preInternal = do_QueryInterface(preflightChannel);
|
||||
if (preInternal) {
|
||||
preInternal->ForceNoIntercept();
|
||||
}
|
||||
|
||||
// Set up listener which will start the original channel
|
||||
nsCOMPtr<nsIStreamListener> preflightListener =
|
||||
|
@ -268,6 +268,16 @@ SVGUseElement::CreateAnonymousContent()
|
||||
if (!newcontent)
|
||||
return nullptr;
|
||||
|
||||
#ifdef DEBUG
|
||||
// Our anonymous clone can get restyled by various things
|
||||
// (e.g. SMIL). Reconstructing its frame is OK, though, because
|
||||
// it's going to be our _only_ child in the frame tree, so can't get
|
||||
// mis-ordered with anything.
|
||||
newcontent->SetProperty(nsGkAtoms::restylableAnonymousNode,
|
||||
reinterpret_cast<void*>(true));
|
||||
#endif // DEBUG
|
||||
|
||||
|
||||
if (newcontent->IsSVGElement(nsGkAtoms::symbol)) {
|
||||
nsIDocument *document = GetComposedDoc();
|
||||
if (!document)
|
||||
|
@ -783,10 +783,6 @@ AudioManager::SetVolumeByCategory(uint32_t aCategory, uint32_t aIndex)
|
||||
}
|
||||
}
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_MUSIC, aIndex);
|
||||
if (NS_WARN_IF(NS_FAILED(status))) {
|
||||
return status;
|
||||
}
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_SYSTEM, aIndex);
|
||||
break;
|
||||
case VOLUME_NOTIFICATION:
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_NOTIFICATION, aIndex);
|
||||
@ -794,6 +790,10 @@ AudioManager::SetVolumeByCategory(uint32_t aCategory, uint32_t aIndex)
|
||||
return status;
|
||||
}
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_RING, aIndex);
|
||||
if (NS_WARN_IF(NS_FAILED(status))) {
|
||||
return status;
|
||||
}
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_SYSTEM, aIndex);
|
||||
break;
|
||||
case VOLUME_ALARM:
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_ALARM, aIndex);
|
||||
@ -814,12 +814,12 @@ AudioManager::GetVolumeByCategory(uint32_t aCategory) const
|
||||
{
|
||||
switch (static_cast<AudioVolumeCategories>(aCategory)) {
|
||||
case VOLUME_MEDIA:
|
||||
MOZ_ASSERT(mCurrentStreamVolumeTbl[AUDIO_STREAM_MUSIC] ==
|
||||
mCurrentStreamVolumeTbl[AUDIO_STREAM_SYSTEM]);
|
||||
return mCurrentStreamVolumeTbl[AUDIO_STREAM_MUSIC];
|
||||
case VOLUME_NOTIFICATION:
|
||||
MOZ_ASSERT(mCurrentStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION] ==
|
||||
mCurrentStreamVolumeTbl[AUDIO_STREAM_RING]);
|
||||
MOZ_ASSERT(mCurrentStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION] ==
|
||||
mCurrentStreamVolumeTbl[AUDIO_STREAM_SYSTEM]);
|
||||
return mCurrentStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION];
|
||||
case VOLUME_ALARM:
|
||||
return mCurrentStreamVolumeTbl[AUDIO_STREAM_ALARM];
|
||||
@ -838,12 +838,12 @@ AudioManager::GetMaxVolumeByCategory(uint32_t aCategory) const
|
||||
{
|
||||
switch (static_cast<AudioVolumeCategories>(aCategory)) {
|
||||
case VOLUME_MEDIA:
|
||||
MOZ_ASSERT(sMaxStreamVolumeTbl[AUDIO_STREAM_MUSIC] ==
|
||||
sMaxStreamVolumeTbl[AUDIO_STREAM_SYSTEM]);
|
||||
return sMaxStreamVolumeTbl[AUDIO_STREAM_MUSIC];
|
||||
case VOLUME_NOTIFICATION:
|
||||
MOZ_ASSERT(sMaxStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION] ==
|
||||
sMaxStreamVolumeTbl[AUDIO_STREAM_RING]);
|
||||
MOZ_ASSERT(sMaxStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION] ==
|
||||
sMaxStreamVolumeTbl[AUDIO_STREAM_SYSTEM]);
|
||||
return sMaxStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION];
|
||||
case VOLUME_ALARM:
|
||||
return sMaxStreamVolumeTbl[AUDIO_STREAM_ALARM];
|
||||
@ -871,6 +871,7 @@ AudioManager::SetAudioChannelVolume(uint32_t aChannel, uint32_t aIndex)
|
||||
case AudioChannel::Notification:
|
||||
case AudioChannel::Ringer:
|
||||
case AudioChannel::Publicnotification:
|
||||
case AudioChannel::System:
|
||||
status = SetVolumeByCategory(VOLUME_NOTIFICATION, aIndex);
|
||||
break;
|
||||
case AudioChannel::Alarm:
|
||||
@ -901,6 +902,7 @@ AudioManager::GetAudioChannelVolume(uint32_t aChannel, uint32_t* aIndex)
|
||||
case AudioChannel::Notification:
|
||||
case AudioChannel::Ringer:
|
||||
case AudioChannel::Publicnotification:
|
||||
case AudioChannel::System:
|
||||
*aIndex = GetVolumeByCategory(VOLUME_NOTIFICATION);
|
||||
break;
|
||||
case AudioChannel::Alarm:
|
||||
@ -931,6 +933,7 @@ AudioManager::GetMaxAudioChannelVolume(uint32_t aChannel, uint32_t* aMaxIndex)
|
||||
case AudioChannel::Notification:
|
||||
case AudioChannel::Ringer:
|
||||
case AudioChannel::Publicnotification:
|
||||
case AudioChannel::System:
|
||||
*aMaxIndex = GetMaxVolumeByCategory(VOLUME_NOTIFICATION);
|
||||
break;
|
||||
case AudioChannel::Alarm:
|
||||
|
@ -46,4 +46,5 @@ enum AudioChannel {
|
||||
"telephony",
|
||||
"ringer",
|
||||
"publicnotification",
|
||||
"system"
|
||||
};
|
||||
|
@ -140,6 +140,12 @@ fetchXHR('http://example.com/tests/dom/security/test/cors/file_CrossSiteXHR_serv
|
||||
finish();
|
||||
});
|
||||
|
||||
// Test that CORS preflight requests cannot be intercepted
|
||||
fetchXHR('http://example.com/tests/dom/security/test/cors/file_CrossSiteXHR_server.sjs?status=200&allowOrigin=*', null, function(xhr) {
|
||||
my_ok(xhr.status == 0, "cross origin load with incorrect headers should be a failure");
|
||||
finish();
|
||||
}, [["X-Unsafe", "unsafe"]]);
|
||||
|
||||
// Test that when the page fetches a url the controlling SW forces a redirect to
|
||||
// another location. This other location fetch should also be intercepted by
|
||||
// the SW.
|
||||
|
@ -7,6 +7,16 @@ onfetch = function(ev) {
|
||||
));
|
||||
}
|
||||
|
||||
else if (ev.request.url.includes('file_CrossSiteXHR_server.sjs')) {
|
||||
// N.B. this response would break the rules of CORS if it were allowed, but
|
||||
// this test relies upon the preflight request not being intercepted and
|
||||
// thus this response should not be used.
|
||||
if (ev.request.method == 'OPTIONS') {
|
||||
ev.respondWith(new Response('', {headers: {'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Headers': 'X-Unsafe'}}))
|
||||
}
|
||||
}
|
||||
|
||||
else if (ev.request.url.includes("synthesized-404.txt")) {
|
||||
ev.respondWith(Promise.resolve(
|
||||
new Response("synthesized response body", { status: 404 })
|
||||
|
@ -188,6 +188,15 @@ nsHTMLEditor::CreateAnonymousElement(const nsAString & aTag, nsIDOMNode * aPare
|
||||
parentContent->AddMutationObserver(observer);
|
||||
newContent->AddMutationObserver(observer);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Editor anonymous content gets passed to RecreateFramesFor... which can't
|
||||
// _really_ deal with anonymous content (because it can't get the frame tree
|
||||
// ordering right). But for us the ordering doesn't matter so this is sort of
|
||||
// ok.
|
||||
newContent->SetProperty(nsGkAtoms::restylableAnonymousNode,
|
||||
reinterpret_cast<void*>(true));
|
||||
#endif // DEBUG
|
||||
|
||||
// display the element
|
||||
ps->RecreateFramesFor(newContent);
|
||||
|
||||
|
@ -9,11 +9,56 @@
|
||||
#include <algorithm>
|
||||
#include <ostream>
|
||||
#include <math.h>
|
||||
#include <float.h> // for FLT_EPSILON
|
||||
|
||||
#include "mozilla/FloatingPoint.h" // for UnspecifiedNaN
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
/* Force small values to zero. We do this to avoid having sin(360deg)
|
||||
* evaluate to a tiny but nonzero value.
|
||||
*/
|
||||
double
|
||||
FlushToZero(double aVal)
|
||||
{
|
||||
// XXX Is double precision really necessary here
|
||||
if (-FLT_EPSILON < aVal && aVal < FLT_EPSILON) {
|
||||
return 0.0f;
|
||||
} else {
|
||||
return aVal;
|
||||
}
|
||||
}
|
||||
|
||||
/* Computes tan(aTheta). For values of aTheta such that tan(aTheta) is
|
||||
* undefined or very large, SafeTangent returns a manageably large value
|
||||
* of the correct sign.
|
||||
*/
|
||||
double
|
||||
SafeTangent(double aTheta)
|
||||
{
|
||||
// XXX Is double precision really necessary here
|
||||
const double kEpsilon = 0.0001;
|
||||
|
||||
/* tan(theta) = sin(theta)/cos(theta); problems arise when
|
||||
* cos(theta) is too close to zero. Limit cos(theta) to the
|
||||
* range [-1, -epsilon] U [epsilon, 1].
|
||||
*/
|
||||
|
||||
double sinTheta = sin(aTheta);
|
||||
double cosTheta = cos(aTheta);
|
||||
|
||||
if (cosTheta >= 0 && cosTheta < kEpsilon) {
|
||||
cosTheta = kEpsilon;
|
||||
} else if (cosTheta < 0 && cosTheta >= -kEpsilon) {
|
||||
cosTheta = -kEpsilon;
|
||||
}
|
||||
return FlushToZero(sinTheta / cosTheta);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
@ -397,5 +442,134 @@ Matrix4x4::SetRotationFromQuaternion(const Quaternion& q)
|
||||
_44 = 1.0f;
|
||||
}
|
||||
|
||||
void
|
||||
Matrix4x4::SkewXY(double aXSkew, double aYSkew)
|
||||
{
|
||||
// XXX Is double precision really necessary here
|
||||
float tanX = SafeTangent(aXSkew);
|
||||
float tanY = SafeTangent(aYSkew);
|
||||
float temp;
|
||||
|
||||
temp = _11;
|
||||
_11 += tanY * _21;
|
||||
_21 += tanX * temp;
|
||||
|
||||
temp = _12;
|
||||
_12 += tanY * _22;
|
||||
_22 += tanX * temp;
|
||||
|
||||
temp = _13;
|
||||
_13 += tanY * _23;
|
||||
_23 += tanX * temp;
|
||||
|
||||
temp = _14;
|
||||
_14 += tanY * _24;
|
||||
_24 += tanX * temp;
|
||||
}
|
||||
|
||||
void
|
||||
Matrix4x4::RotateX(double aTheta)
|
||||
{
|
||||
// XXX Is double precision really necessary here
|
||||
double cosTheta = FlushToZero(cos(aTheta));
|
||||
double sinTheta = FlushToZero(sin(aTheta));
|
||||
|
||||
float temp;
|
||||
|
||||
temp = _21;
|
||||
_21 = cosTheta * _21 + sinTheta * _31;
|
||||
_31 = -sinTheta * temp + cosTheta * _31;
|
||||
|
||||
temp = _22;
|
||||
_22 = cosTheta * _22 + sinTheta * _32;
|
||||
_32 = -sinTheta * temp + cosTheta * _32;
|
||||
|
||||
temp = _23;
|
||||
_23 = cosTheta * _23 + sinTheta * _33;
|
||||
_33 = -sinTheta * temp + cosTheta * _33;
|
||||
|
||||
temp = _24;
|
||||
_24 = cosTheta * _24 + sinTheta * _34;
|
||||
_34 = -sinTheta * temp + cosTheta * _34;
|
||||
}
|
||||
|
||||
void
|
||||
Matrix4x4::RotateY(double aTheta)
|
||||
{
|
||||
// XXX Is double precision really necessary here
|
||||
double cosTheta = FlushToZero(cos(aTheta));
|
||||
double sinTheta = FlushToZero(sin(aTheta));
|
||||
|
||||
float temp;
|
||||
|
||||
temp = _11;
|
||||
_11 = cosTheta * _11 + -sinTheta * _31;
|
||||
_31 = sinTheta * temp + cosTheta * _31;
|
||||
|
||||
temp = _12;
|
||||
_12 = cosTheta * _12 + -sinTheta * _32;
|
||||
_32 = sinTheta * temp + cosTheta * _32;
|
||||
|
||||
temp = _13;
|
||||
_13 = cosTheta * _13 + -sinTheta * _33;
|
||||
_33 = sinTheta * temp + cosTheta * _33;
|
||||
|
||||
temp = _14;
|
||||
_14 = cosTheta * _14 + -sinTheta * _34;
|
||||
_34 = sinTheta * temp + cosTheta * _34;
|
||||
}
|
||||
|
||||
void
|
||||
Matrix4x4::RotateZ(double aTheta)
|
||||
{
|
||||
// XXX Is double precision really necessary here
|
||||
double cosTheta = FlushToZero(cos(aTheta));
|
||||
double sinTheta = FlushToZero(sin(aTheta));
|
||||
|
||||
float temp;
|
||||
|
||||
temp = _11;
|
||||
_11 = cosTheta * _11 + sinTheta * _21;
|
||||
_21 = -sinTheta * temp + cosTheta * _21;
|
||||
|
||||
temp = _12;
|
||||
_12 = cosTheta * _12 + sinTheta * _22;
|
||||
_22 = -sinTheta * temp + cosTheta * _22;
|
||||
|
||||
temp = _13;
|
||||
_13 = cosTheta * _13 + sinTheta * _23;
|
||||
_23 = -sinTheta * temp + cosTheta * _23;
|
||||
|
||||
temp = _14;
|
||||
_14 = cosTheta * _14 + sinTheta * _24;
|
||||
_24 = -sinTheta * temp + cosTheta * _24;
|
||||
}
|
||||
|
||||
void
|
||||
Matrix4x4::Perspective(float aDepth)
|
||||
{
|
||||
MOZ_ASSERT(aDepth > 0.0f, "Perspective must be positive!");
|
||||
_31 += -1.0/aDepth * _41;
|
||||
_32 += -1.0/aDepth * _42;
|
||||
_33 += -1.0/aDepth * _43;
|
||||
_34 += -1.0/aDepth * _44;
|
||||
}
|
||||
|
||||
Point3D
|
||||
Matrix4x4::GetNormalVector() const
|
||||
{
|
||||
// Define a plane in transformed space as the transformations
|
||||
// of 3 points on the z=0 screen plane.
|
||||
Point3D a = *this * Point3D(0, 0, 0);
|
||||
Point3D b = *this * Point3D(0, 1, 0);
|
||||
Point3D c = *this * Point3D(1, 0, 0);
|
||||
|
||||
// Convert to two vectors on the surface of the plane.
|
||||
Point3D ab = b - a;
|
||||
Point3D ac = c - a;
|
||||
|
||||
return ac.CrossProduct(ab);
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
@ -716,6 +716,11 @@ public:
|
||||
(*this)[2] += (*this)[1] * aSkew;
|
||||
}
|
||||
|
||||
Matrix4x4 &ChangeBasis(const Point3D& aOrigin)
|
||||
{
|
||||
return ChangeBasis(aOrigin.x, aOrigin.y, aOrigin.z);
|
||||
}
|
||||
|
||||
Matrix4x4 &ChangeBasis(Float aX, Float aY, Float aZ)
|
||||
{
|
||||
// Translate to the origin before applying this matrix
|
||||
@ -950,6 +955,18 @@ public:
|
||||
|
||||
// Set all the members of the matrix to NaN
|
||||
void SetNAN();
|
||||
|
||||
void SkewXY(double aXSkew, double aYSkew);
|
||||
|
||||
void RotateX(double aTheta);
|
||||
|
||||
void RotateY(double aTheta);
|
||||
|
||||
void RotateZ(double aTheta);
|
||||
|
||||
void Perspective(float aDepth);
|
||||
|
||||
Point3D GetNormalVector() const;
|
||||
};
|
||||
|
||||
class Matrix5x4
|
||||
|
@ -337,7 +337,7 @@ public:
|
||||
return mLayer->GetVisibleRegion();
|
||||
}
|
||||
nsIntRegion region = mLayer->GetVisibleRegion();
|
||||
region.Transform(gfx::To3DMatrix(mLayer->GetTransform()));
|
||||
region.Transform(mLayer->GetTransform());
|
||||
return region;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <stdlib.h> // for getenv
|
||||
#include "DirectedGraph.h" // for DirectedGraph
|
||||
#include "Layers.h" // for Layer
|
||||
#include "gfx3DMatrix.h" // for gfx3DMatrix
|
||||
#include "gfxLineSegment.h" // for gfxLineSegment
|
||||
#include "gfxPoint.h" // for gfxPoint
|
||||
#include "gfxQuad.h" // for gfxQuad
|
||||
@ -41,11 +40,11 @@ enum LayerSortOrder {
|
||||
*
|
||||
* point = normal . (p0 - l0) / normal . l
|
||||
*/
|
||||
static gfxFloat RecoverZDepth(const gfx3DMatrix& aTransform, const gfxPoint& aPoint)
|
||||
static gfxFloat RecoverZDepth(const Matrix4x4& aTransform, const gfxPoint& aPoint)
|
||||
{
|
||||
const Point3D l(0, 0, 1);
|
||||
Point3D l0 = Point3D(aPoint.x, aPoint.y, 0);
|
||||
Point3D p0 = aTransform.Transform3D(Point3D(0, 0, 0));
|
||||
Point3D p0 = aTransform * Point3D(0, 0, 0);
|
||||
Point3D normal = aTransform.GetNormalVector();
|
||||
|
||||
gfxFloat n = normal.DotProduct(p0 - l0);
|
||||
@ -79,12 +78,12 @@ static LayerSortOrder CompareDepth(Layer* aOne, Layer* aTwo) {
|
||||
gfxRect ourRect = aOne->GetEffectiveVisibleRegion().GetBounds();
|
||||
gfxRect otherRect = aTwo->GetEffectiveVisibleRegion().GetBounds();
|
||||
|
||||
gfx3DMatrix ourTransform = To3DMatrix(aOne->GetTransform());
|
||||
gfx3DMatrix otherTransform = To3DMatrix(aTwo->GetTransform());
|
||||
Matrix4x4 ourTransform = aOne->GetTransform();
|
||||
Matrix4x4 otherTransform = aTwo->GetTransform();
|
||||
|
||||
// Transform both rectangles and project into 2d space.
|
||||
gfxQuad ourTransformedRect = ourTransform.TransformRect(ourRect);
|
||||
gfxQuad otherTransformedRect = otherTransform.TransformRect(otherRect);
|
||||
gfxQuad ourTransformedRect = ourRect.TransformToQuad(ourTransform);
|
||||
gfxQuad otherTransformedRect = otherRect.TransformToQuad(otherTransform);
|
||||
|
||||
gfxRect ourBounds = ourTransformedRect.GetBounds();
|
||||
gfxRect otherBounds = otherTransformedRect.GetBounds();
|
||||
|
@ -344,7 +344,7 @@ struct ContainerLayerProperties : public LayerPropertiesBase
|
||||
container->SetChildrenChanged(true);
|
||||
}
|
||||
|
||||
result.Transform(gfx::To3DMatrix(mLayer->GetLocalTransform()));
|
||||
result.Transform(mLayer->GetLocalTransform());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ struct EventRegions {
|
||||
mVerticalPanRegion.MoveBy(aXTrans, aYTrans);
|
||||
}
|
||||
|
||||
void Transform(const gfx3DMatrix& aTransform)
|
||||
void Transform(const gfx::Matrix4x4& aTransform)
|
||||
{
|
||||
mHitRegion.Transform(aTransform);
|
||||
mDispatchToContentHitRegion.Transform(aTransform);
|
||||
|
@ -188,7 +188,7 @@ DrawSurfaceWithTextureCoords(DrawTarget *aDest,
|
||||
|
||||
#ifdef MOZ_ENABLE_SKIA
|
||||
static SkMatrix
|
||||
Matrix3DToSkia(const gfx3DMatrix& aMatrix)
|
||||
Matrix3DToSkia(const Matrix4x4& aMatrix)
|
||||
{
|
||||
SkMatrix transform;
|
||||
transform.setAll(aMatrix._11,
|
||||
@ -207,7 +207,7 @@ Matrix3DToSkia(const gfx3DMatrix& aMatrix)
|
||||
static void
|
||||
Transform(DataSourceSurface* aDest,
|
||||
DataSourceSurface* aSource,
|
||||
const gfx3DMatrix& aTransform,
|
||||
const Matrix4x4& aTransform,
|
||||
const Point& aDestOffset)
|
||||
{
|
||||
if (aTransform.IsSingular()) {
|
||||
@ -233,8 +233,8 @@ Transform(DataSourceSurface* aDest,
|
||||
src.setInfo(srcInfo, aSource->Stride());
|
||||
src.setPixels((uint32_t*)aSource->GetData());
|
||||
|
||||
gfx3DMatrix transform = aTransform;
|
||||
transform.TranslatePost(Point3D(-aDestOffset.x, -aDestOffset.y, 0));
|
||||
Matrix4x4 transform = aTransform;
|
||||
transform.PostTranslate(Point3D(-aDestOffset.x, -aDestOffset.y, 0));
|
||||
destCanvas.setMatrix(Matrix3DToSkia(transform));
|
||||
|
||||
SkPaint paint;
|
||||
@ -246,7 +246,7 @@ Transform(DataSourceSurface* aDest,
|
||||
}
|
||||
#else
|
||||
static pixman_transform
|
||||
Matrix3DToPixman(const gfx3DMatrix& aMatrix)
|
||||
Matrix3DToPixman(const Matrix4x4& aMatrix)
|
||||
{
|
||||
pixman_f_transform transform;
|
||||
|
||||
@ -269,7 +269,7 @@ Matrix3DToPixman(const gfx3DMatrix& aMatrix)
|
||||
static void
|
||||
Transform(DataSourceSurface* aDest,
|
||||
DataSourceSurface* aSource,
|
||||
const gfx3DMatrix& aTransform,
|
||||
const Matrix4x4& aTransform,
|
||||
const Point& aDestOffset)
|
||||
{
|
||||
IntSize destSize = aDest->GetSize();
|
||||
@ -343,7 +343,7 @@ BasicCompositor::DrawQuad(const gfx::Rect& aRect,
|
||||
|
||||
Matrix newTransform;
|
||||
Rect transformBounds;
|
||||
gfx3DMatrix new3DTransform;
|
||||
Matrix4x4 new3DTransform;
|
||||
IntPoint offset = mRenderTarget->GetOrigin();
|
||||
|
||||
if (aTransform.Is2D()) {
|
||||
@ -358,8 +358,9 @@ BasicCompositor::DrawQuad(const gfx::Rect& aRect,
|
||||
dest->SetTransform(Matrix::Translation(-aRect.x, -aRect.y));
|
||||
|
||||
// Get the bounds post-transform.
|
||||
new3DTransform = To3DMatrix(aTransform);
|
||||
gfxRect bounds = new3DTransform.TransformBounds(ThebesRect(aRect));
|
||||
new3DTransform = aTransform;
|
||||
gfxRect bounds = ThebesRect(aRect);
|
||||
bounds.TransformBounds(new3DTransform);
|
||||
bounds.IntersectRect(bounds, gfxRect(offset.x, offset.y, buffer->GetSize().width, buffer->GetSize().height));
|
||||
|
||||
transformBounds = ToRect(bounds);
|
||||
@ -370,7 +371,7 @@ BasicCompositor::DrawQuad(const gfx::Rect& aRect,
|
||||
|
||||
// When we apply the 3D transformation, we do it against a temporary
|
||||
// surface, so undo the coordinate offset.
|
||||
new3DTransform = gfx3DMatrix::Translation(aRect.x, aRect.y, 0) * new3DTransform;
|
||||
new3DTransform = Matrix4x4::Translation(aRect.x, aRect.y, 0) * new3DTransform;
|
||||
}
|
||||
|
||||
newTransform.PostTranslate(-offset.x, -offset.y);
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "RenderTrace.h" // for RenderTraceLayers, etc
|
||||
#include "basic/BasicImplData.h" // for BasicImplData
|
||||
#include "basic/BasicLayers.h" // for BasicLayerManager, etc
|
||||
#include "gfx3DMatrix.h" // for gfx3DMatrix
|
||||
#include "gfxASurface.h" // for gfxASurface, etc
|
||||
#include "gfxColor.h" // for gfxRGBA
|
||||
#include "gfxContext.h" // for gfxContext, etc
|
||||
@ -613,7 +612,7 @@ BasicLayerManager::SetRoot(Layer* aLayer)
|
||||
|
||||
#ifdef MOZ_ENABLE_SKIA
|
||||
static SkMatrix
|
||||
BasicLayerManager_Matrix3DToSkia(const gfx3DMatrix& aMatrix)
|
||||
BasicLayerManager_Matrix3DToSkia(const Matrix4x4& aMatrix)
|
||||
{
|
||||
SkMatrix transform;
|
||||
transform.setAll(aMatrix._11,
|
||||
@ -632,7 +631,7 @@ BasicLayerManager_Matrix3DToSkia(const gfx3DMatrix& aMatrix)
|
||||
static void
|
||||
Transform(const gfxImageSurface* aDest,
|
||||
RefPtr<DataSourceSurface> aSrc,
|
||||
const gfx3DMatrix& aTransform,
|
||||
const Matrix4x4& aTransform,
|
||||
gfxPoint aDestOffset)
|
||||
{
|
||||
if (aTransform.IsSingular()) {
|
||||
@ -658,8 +657,8 @@ Transform(const gfxImageSurface* aDest,
|
||||
src.setInfo(srcInfo, aSrc->Stride());
|
||||
src.setPixels((uint32_t*)aSrc->GetData());
|
||||
|
||||
gfx3DMatrix transform = aTransform;
|
||||
transform.TranslatePost(Point3D(-aDestOffset.x, -aDestOffset.y, 0));
|
||||
Matrix4x4 transform = aTransform;
|
||||
transform.PostTranslate(Point3D(-aDestOffset.x, -aDestOffset.y, 0));
|
||||
destCanvas.setMatrix(BasicLayerManager_Matrix3DToSkia(transform));
|
||||
|
||||
SkPaint paint;
|
||||
@ -671,7 +670,7 @@ Transform(const gfxImageSurface* aDest,
|
||||
}
|
||||
#else
|
||||
static pixman_transform
|
||||
BasicLayerManager_Matrix3DToPixman(const gfx3DMatrix& aMatrix)
|
||||
BasicLayerManager_Matrix3DToPixman(const Matrix4x4& aMatrix)
|
||||
{
|
||||
pixman_f_transform transform;
|
||||
|
||||
@ -694,7 +693,7 @@ BasicLayerManager_Matrix3DToPixman(const gfx3DMatrix& aMatrix)
|
||||
static void
|
||||
Transform(const gfxImageSurface* aDest,
|
||||
RefPtr<DataSourceSurface> aSrc,
|
||||
const gfx3DMatrix& aTransform,
|
||||
const Matrix4x4& aTransform,
|
||||
gfxPoint aDestOffset)
|
||||
{
|
||||
IntSize destSize = aDest->GetSize();
|
||||
@ -743,7 +742,7 @@ Transform(const gfxImageSurface* aDest,
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Transform a surface using a gfx3DMatrix and blit to the destination if
|
||||
* Transform a surface using a Matrix4x4 and blit to the destination if
|
||||
* it is efficient to do so.
|
||||
*
|
||||
* @param aSource Source surface.
|
||||
@ -759,11 +758,12 @@ static already_AddRefed<gfxASurface>
|
||||
Transform3D(RefPtr<SourceSurface> aSource,
|
||||
gfxContext* aDest,
|
||||
const gfxRect& aBounds,
|
||||
const gfx3DMatrix& aTransform,
|
||||
const Matrix4x4& aTransform,
|
||||
gfxRect& aDestRect)
|
||||
{
|
||||
// Find the transformed rectangle of our layer.
|
||||
gfxRect offsetRect = aTransform.TransformBounds(aBounds);
|
||||
gfxRect offsetRect = aBounds;
|
||||
offsetRect.TransformBounds(aTransform);
|
||||
|
||||
// Intersect the transformed layer with the destination rectangle.
|
||||
// This is in device space since we have an identity transform set on aTarget.
|
||||
@ -779,7 +779,7 @@ Transform3D(RefPtr<SourceSurface> aSource,
|
||||
gfxPoint offset = aDestRect.TopLeft();
|
||||
|
||||
// Include a translation to the correct origin.
|
||||
gfx3DMatrix translation = gfx3DMatrix::Translation(aBounds.x, aBounds.y, 0);
|
||||
Matrix4x4 translation = Matrix4x4::Translation(aBounds.x, aBounds.y, 0);
|
||||
|
||||
// Transform the content and offset it such that the content begins at the origin.
|
||||
Transform(destImage, aSource->GetDataSurface(), translation * aTransform, offset);
|
||||
@ -961,8 +961,7 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget,
|
||||
temp->Paint();
|
||||
}
|
||||
#endif
|
||||
gfx3DMatrix effectiveTransform;
|
||||
effectiveTransform = gfx::To3DMatrix(aLayer->GetEffectiveTransform());
|
||||
Matrix4x4 effectiveTransform = aLayer->GetEffectiveTransform();
|
||||
nsRefPtr<gfxASurface> result =
|
||||
Transform3D(untransformedDT->Snapshot(), aTarget, bounds,
|
||||
effectiveTransform, destRect);
|
||||
|
@ -408,7 +408,7 @@ SampleValue(float aPortion, Animation& aAnimation, StyleAnimationValue& aStart,
|
||||
transformOrigin,
|
||||
perspectiveOrigin,
|
||||
data.perspective());
|
||||
gfx3DMatrix transform =
|
||||
Matrix4x4 transform =
|
||||
nsDisplayTransform::GetResultingTransformMatrix(props, origin,
|
||||
data.appUnitsPerDevPixel(),
|
||||
&data.bounds());
|
||||
@ -417,10 +417,10 @@ SampleValue(float aPortion, Animation& aAnimation, StyleAnimationValue& aStart,
|
||||
NS_round(NSAppUnitsToFloatPixels(origin.y, data.appUnitsPerDevPixel())),
|
||||
0.0f);
|
||||
|
||||
transform.Translate(scaledOrigin);
|
||||
transform.PreTranslate(scaledOrigin);
|
||||
|
||||
InfallibleTArray<TransformFunction> functions;
|
||||
functions.AppendElement(TransformMatrix(ToMatrix4x4(transform)));
|
||||
functions.AppendElement(TransformMatrix(transform));
|
||||
*aValue = functions;
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include "CanvasLayerComposite.h"
|
||||
#include "composite/CompositableHost.h" // for CompositableHost
|
||||
#include "gfx2DGlue.h" // for ToFilter, ToMatrix4x4
|
||||
#include "gfx2DGlue.h" // for ToFilter
|
||||
#include "GraphicsFilter.h" // for GraphicsFilter
|
||||
#include "gfxUtils.h" // for gfxUtils, etc
|
||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "apz/src/AsyncPanZoomController.h" // for AsyncPanZoomController
|
||||
#include "FrameMetrics.h" // for FrameMetrics
|
||||
#include "Units.h" // for LayerRect, LayerPixel, etc
|
||||
#include "gfx2DGlue.h" // for ToMatrix4x4
|
||||
#include "gfxPrefs.h" // for gfxPrefs
|
||||
#include "gfxUtils.h" // for gfxUtils, etc
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "ImageLayerComposite.h"
|
||||
#include "CompositableHost.h" // for CompositableHost
|
||||
#include "Layers.h" // for WriteSnapshotToDumpFile, etc
|
||||
#include "gfx2DGlue.h" // for ToFilter, ToMatrix4x4
|
||||
#include "gfx2DGlue.h" // for ToFilter
|
||||
#include "gfxRect.h" // for gfxRect
|
||||
#include "gfxUtils.h" // for gfxUtils, etc
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "TiledContentHost.h"
|
||||
#include "Units.h" // for ScreenIntRect
|
||||
#include "UnitTransforms.h" // for ViewAs
|
||||
#include "gfx2DGlue.h" // for ToMatrix4x4
|
||||
#include "gfxPrefs.h" // for gfxPrefs
|
||||
#ifdef XP_MACOSX
|
||||
#include "gfxPlatformMac.h"
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "CompositableHost.h" // for TiledLayerProperties, etc
|
||||
#include "FrameMetrics.h" // for FrameMetrics
|
||||
#include "Units.h" // for CSSRect, LayerPixel, etc
|
||||
#include "gfx2DGlue.h" // for ToMatrix4x4
|
||||
#include "gfxUtils.h" // for gfxUtils, etc
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "Layers.h" // for WriteSnapshotToDumpFile
|
||||
#include "LayerScope.h" // for LayerScope
|
||||
#include "gfx2DGlue.h" // for ThebesFilter
|
||||
#include "gfx3DMatrix.h" // for gfx3DMatrix
|
||||
#include "gfxCrashReporterUtils.h" // for ScopedGfxFeatureReporter
|
||||
#include "gfxMatrix.h" // for gfxMatrix
|
||||
#include "GraphicsFilter.h" // for GraphicsFilter
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include "nsRegion.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "gfx3DMatrix.h"
|
||||
#include "gfxUtils.h"
|
||||
|
||||
bool nsRegion::Contains(const nsRegion& aRgn) const
|
||||
@ -607,14 +606,14 @@ nsRegion& nsRegion::ScaleInverseRoundOut (float aXScale, float aYScale)
|
||||
}
|
||||
|
||||
static mozilla::gfx::IntRect
|
||||
TransformRect(const mozilla::gfx::IntRect& aRect, const gfx3DMatrix& aTransform)
|
||||
TransformRect(const mozilla::gfx::IntRect& aRect, const mozilla::gfx::Matrix4x4& aTransform)
|
||||
{
|
||||
if (aRect.IsEmpty()) {
|
||||
return mozilla::gfx::IntRect();
|
||||
}
|
||||
|
||||
gfxRect rect(aRect.x, aRect.y, aRect.width, aRect.height);
|
||||
rect = aTransform.TransformBounds(rect);
|
||||
rect.TransformBounds(aTransform);
|
||||
rect.RoundOut();
|
||||
|
||||
mozilla::gfx::IntRect intRect;
|
||||
@ -625,7 +624,7 @@ TransformRect(const mozilla::gfx::IntRect& aRect, const gfx3DMatrix& aTransform)
|
||||
return intRect;
|
||||
}
|
||||
|
||||
nsRegion& nsRegion::Transform (const gfx3DMatrix &aTransform)
|
||||
nsRegion& nsRegion::Transform (const mozilla::gfx::Matrix4x4 &aTransform)
|
||||
{
|
||||
int n;
|
||||
pixman_box32_t *boxes = pixman_region32_rectangles(&mImpl, &n);
|
||||
|
@ -21,7 +21,11 @@
|
||||
#include "mozilla/Move.h" // for mozilla::Move
|
||||
|
||||
class nsIntRegion;
|
||||
class gfx3DMatrix;
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
class Matrix4x4;
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
#include "pixman.h"
|
||||
|
||||
@ -299,7 +303,7 @@ public:
|
||||
ScaleToOtherAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const;
|
||||
nsRegion& ScaleRoundOut(float aXScale, float aYScale);
|
||||
nsRegion& ScaleInverseRoundOut(float aXScale, float aYScale);
|
||||
nsRegion& Transform (const gfx3DMatrix &aTransform);
|
||||
nsRegion& Transform (const mozilla::gfx::Matrix4x4 &aTransform);
|
||||
nsIntRegion ScaleToOutsidePixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
|
||||
nsIntRegion ScaleToInsidePixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
|
||||
nsIntRegion ScaleToNearestPixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
|
||||
@ -721,7 +725,7 @@ public:
|
||||
return This();
|
||||
}
|
||||
|
||||
Derived& Transform (const gfx3DMatrix &aTransform)
|
||||
Derived& Transform (const mozilla::gfx::Matrix4x4 &aTransform)
|
||||
{
|
||||
mImpl.Transform(aTransform);
|
||||
return This();
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxRect.h"
|
||||
#include "gfxMatrix.h"
|
||||
#include "gfx3DMatrix.h"
|
||||
#include "gfxContext.h"
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "mozilla/gfx/Rect.h"
|
||||
@ -310,52 +309,6 @@ inline gfxContext::GraphicsOperator ThebesOp(CompositionOp aOp)
|
||||
}
|
||||
}
|
||||
|
||||
inline Matrix4x4
|
||||
ToMatrix4x4(const gfx3DMatrix& aIn)
|
||||
{
|
||||
Matrix4x4 m;
|
||||
m._11 = aIn._11;
|
||||
m._12 = aIn._12;
|
||||
m._13 = aIn._13;
|
||||
m._14 = aIn._14;
|
||||
m._21 = aIn._21;
|
||||
m._22 = aIn._22;
|
||||
m._23 = aIn._23;
|
||||
m._24 = aIn._24;
|
||||
m._31 = aIn._31;
|
||||
m._32 = aIn._32;
|
||||
m._33 = aIn._33;
|
||||
m._34 = aIn._34;
|
||||
m._41 = aIn._41;
|
||||
m._42 = aIn._42;
|
||||
m._43 = aIn._43;
|
||||
m._44 = aIn._44;
|
||||
return m;
|
||||
}
|
||||
|
||||
inline gfx3DMatrix
|
||||
To3DMatrix(const Matrix4x4& aIn)
|
||||
{
|
||||
gfx3DMatrix m;
|
||||
m._11 = aIn._11;
|
||||
m._12 = aIn._12;
|
||||
m._13 = aIn._13;
|
||||
m._14 = aIn._14;
|
||||
m._21 = aIn._21;
|
||||
m._22 = aIn._22;
|
||||
m._23 = aIn._23;
|
||||
m._24 = aIn._24;
|
||||
m._31 = aIn._31;
|
||||
m._32 = aIn._32;
|
||||
m._33 = aIn._33;
|
||||
m._34 = aIn._34;
|
||||
m._41 = aIn._41;
|
||||
m._42 = aIn._42;
|
||||
m._43 = aIn._43;
|
||||
m._44 = aIn._44;
|
||||
return m;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -1,798 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; 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 "gfxMatrix.h"
|
||||
#include "gfx3DMatrix.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "mozilla/gfx/Tools.h"
|
||||
#include <math.h>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
/* Force small values to zero. We do this to avoid having sin(360deg)
|
||||
* evaluate to a tiny but nonzero value.
|
||||
*/
|
||||
static double FlushToZero(double aVal)
|
||||
{
|
||||
if (-FLT_EPSILON < aVal && aVal < FLT_EPSILON)
|
||||
return 0.0f;
|
||||
else
|
||||
return aVal;
|
||||
}
|
||||
|
||||
/* Computes tan(aTheta). For values of aTheta such that tan(aTheta) is
|
||||
* undefined or very large, SafeTangent returns a manageably large value
|
||||
* of the correct sign.
|
||||
*/
|
||||
static double SafeTangent(double aTheta)
|
||||
{
|
||||
const double kEpsilon = 0.0001;
|
||||
|
||||
/* tan(theta) = sin(theta)/cos(theta); problems arise when
|
||||
* cos(theta) is too close to zero. Limit cos(theta) to the
|
||||
* range [-1, -epsilon] U [epsilon, 1].
|
||||
*/
|
||||
double sinTheta = sin(aTheta);
|
||||
double cosTheta = cos(aTheta);
|
||||
|
||||
if (cosTheta >= 0 && cosTheta < kEpsilon)
|
||||
cosTheta = kEpsilon;
|
||||
else if (cosTheta < 0 && cosTheta >= -kEpsilon)
|
||||
cosTheta = -kEpsilon;
|
||||
|
||||
return FlushToZero(sinTheta / cosTheta);
|
||||
}
|
||||
|
||||
gfx3DMatrix::gfx3DMatrix(void)
|
||||
{
|
||||
_11 = _22 = _33 = _44 = 1.0f;
|
||||
_12 = _13 = _14 = 0.0f;
|
||||
_21 = _23 = _24 = 0.0f;
|
||||
_31 = _32 = _34 = 0.0f;
|
||||
_41 = _42 = _43 = 0.0f;
|
||||
}
|
||||
|
||||
gfx3DMatrix
|
||||
gfx3DMatrix::operator*(const gfx3DMatrix &aMatrix) const
|
||||
{
|
||||
if (Is2D() && aMatrix.Is2D()) {
|
||||
return Multiply2D(aMatrix);
|
||||
}
|
||||
|
||||
gfx3DMatrix matrix;
|
||||
|
||||
matrix._11 = _11 * aMatrix._11 + _12 * aMatrix._21 + _13 * aMatrix._31 + _14 * aMatrix._41;
|
||||
matrix._21 = _21 * aMatrix._11 + _22 * aMatrix._21 + _23 * aMatrix._31 + _24 * aMatrix._41;
|
||||
matrix._31 = _31 * aMatrix._11 + _32 * aMatrix._21 + _33 * aMatrix._31 + _34 * aMatrix._41;
|
||||
matrix._41 = _41 * aMatrix._11 + _42 * aMatrix._21 + _43 * aMatrix._31 + _44 * aMatrix._41;
|
||||
matrix._12 = _11 * aMatrix._12 + _12 * aMatrix._22 + _13 * aMatrix._32 + _14 * aMatrix._42;
|
||||
matrix._22 = _21 * aMatrix._12 + _22 * aMatrix._22 + _23 * aMatrix._32 + _24 * aMatrix._42;
|
||||
matrix._32 = _31 * aMatrix._12 + _32 * aMatrix._22 + _33 * aMatrix._32 + _34 * aMatrix._42;
|
||||
matrix._42 = _41 * aMatrix._12 + _42 * aMatrix._22 + _43 * aMatrix._32 + _44 * aMatrix._42;
|
||||
matrix._13 = _11 * aMatrix._13 + _12 * aMatrix._23 + _13 * aMatrix._33 + _14 * aMatrix._43;
|
||||
matrix._23 = _21 * aMatrix._13 + _22 * aMatrix._23 + _23 * aMatrix._33 + _24 * aMatrix._43;
|
||||
matrix._33 = _31 * aMatrix._13 + _32 * aMatrix._23 + _33 * aMatrix._33 + _34 * aMatrix._43;
|
||||
matrix._43 = _41 * aMatrix._13 + _42 * aMatrix._23 + _43 * aMatrix._33 + _44 * aMatrix._43;
|
||||
matrix._14 = _11 * aMatrix._14 + _12 * aMatrix._24 + _13 * aMatrix._34 + _14 * aMatrix._44;
|
||||
matrix._24 = _21 * aMatrix._14 + _22 * aMatrix._24 + _23 * aMatrix._34 + _24 * aMatrix._44;
|
||||
matrix._34 = _31 * aMatrix._14 + _32 * aMatrix._24 + _33 * aMatrix._34 + _34 * aMatrix._44;
|
||||
matrix._44 = _41 * aMatrix._14 + _42 * aMatrix._24 + _43 * aMatrix._34 + _44 * aMatrix._44;
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
gfx3DMatrix&
|
||||
gfx3DMatrix::operator*=(const gfx3DMatrix &aMatrix)
|
||||
{
|
||||
return *this = *this * aMatrix;
|
||||
}
|
||||
|
||||
gfx3DMatrix
|
||||
gfx3DMatrix::Multiply2D(const gfx3DMatrix &aMatrix) const
|
||||
{
|
||||
gfx3DMatrix matrix;
|
||||
|
||||
matrix._11 = _11 * aMatrix._11 + _12 * aMatrix._21;
|
||||
matrix._21 = _21 * aMatrix._11 + _22 * aMatrix._21;
|
||||
matrix._41 = _41 * aMatrix._11 + _42 * aMatrix._21 + aMatrix._41;
|
||||
matrix._12 = _11 * aMatrix._12 + _12 * aMatrix._22;
|
||||
matrix._22 = _21 * aMatrix._12 + _22 * aMatrix._22;
|
||||
matrix._42 = _41 * aMatrix._12 + _42 * aMatrix._22 + aMatrix._42;
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
bool
|
||||
gfx3DMatrix::operator==(const gfx3DMatrix& o) const
|
||||
{
|
||||
// XXX would be nice to memcmp here, but that breaks IEEE 754 semantics
|
||||
return _11 == o._11 && _12 == o._12 && _13 == o._13 && _14 == o._14 &&
|
||||
_21 == o._21 && _22 == o._22 && _23 == o._23 && _24 == o._24 &&
|
||||
_31 == o._31 && _32 == o._32 && _33 == o._33 && _34 == o._34 &&
|
||||
_41 == o._41 && _42 == o._42 && _43 == o._43 && _44 == o._44;
|
||||
}
|
||||
|
||||
bool
|
||||
gfx3DMatrix::operator!=(const gfx3DMatrix& o) const
|
||||
{
|
||||
return !((*this) == o);
|
||||
}
|
||||
|
||||
bool
|
||||
gfx3DMatrix::FuzzyEqual(const gfx3DMatrix& o) const
|
||||
{
|
||||
static const float error = 1e-4;
|
||||
return gfx::FuzzyEqual(_11, o._11, error) && gfx::FuzzyEqual(_12, o._12, error) &&
|
||||
gfx::FuzzyEqual(_13, o._13, error) && gfx::FuzzyEqual(_14, o._14, error) &&
|
||||
gfx::FuzzyEqual(_21, o._21, error) && gfx::FuzzyEqual(_22, o._22, error) &&
|
||||
gfx::FuzzyEqual(_23, o._23, error) && gfx::FuzzyEqual(_24, o._24, error) &&
|
||||
gfx::FuzzyEqual(_31, o._31, error) && gfx::FuzzyEqual(_32, o._32, error) &&
|
||||
gfx::FuzzyEqual(_33, o._33, error) && gfx::FuzzyEqual(_34, o._34, error) &&
|
||||
gfx::FuzzyEqual(_41, o._41, error) && gfx::FuzzyEqual(_42, o._42, error) &&
|
||||
gfx::FuzzyEqual(_43, o._43, error) && gfx::FuzzyEqual(_44, o._44, error);
|
||||
}
|
||||
|
||||
gfx3DMatrix&
|
||||
gfx3DMatrix::operator/=(const gfxFloat scalar)
|
||||
{
|
||||
_11 /= scalar;
|
||||
_12 /= scalar;
|
||||
_13 /= scalar;
|
||||
_14 /= scalar;
|
||||
_21 /= scalar;
|
||||
_22 /= scalar;
|
||||
_23 /= scalar;
|
||||
_24 /= scalar;
|
||||
_31 /= scalar;
|
||||
_32 /= scalar;
|
||||
_33 /= scalar;
|
||||
_34 /= scalar;
|
||||
_41 /= scalar;
|
||||
_42 /= scalar;
|
||||
_43 /= scalar;
|
||||
_44 /= scalar;
|
||||
return *this;
|
||||
}
|
||||
|
||||
gfx3DMatrix
|
||||
gfx3DMatrix::From2D(const gfxMatrix &aMatrix)
|
||||
{
|
||||
gfx3DMatrix matrix;
|
||||
matrix._11 = (float)aMatrix._11;
|
||||
matrix._12 = (float)aMatrix._12;
|
||||
matrix._21 = (float)aMatrix._21;
|
||||
matrix._22 = (float)aMatrix._22;
|
||||
matrix._41 = (float)aMatrix._31;
|
||||
matrix._42 = (float)aMatrix._32;
|
||||
return matrix;
|
||||
}
|
||||
|
||||
bool
|
||||
gfx3DMatrix::IsIdentity() const
|
||||
{
|
||||
return _11 == 1.0f && _12 == 0.0f && _13 == 0.0f && _14 == 0.0f &&
|
||||
_21 == 0.0f && _22 == 1.0f && _23 == 0.0f && _24 == 0.0f &&
|
||||
_31 == 0.0f && _32 == 0.0f && _33 == 1.0f && _34 == 0.0f &&
|
||||
_41 == 0.0f && _42 == 0.0f && _43 == 0.0f && _44 == 1.0f;
|
||||
}
|
||||
|
||||
void
|
||||
gfx3DMatrix::Translate(const Point3D& aPoint)
|
||||
{
|
||||
_41 += aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31;
|
||||
_42 += aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32;
|
||||
_43 += aPoint.x * _13 + aPoint.y * _23 + aPoint.z * _33;
|
||||
_44 += aPoint.x * _14 + aPoint.y * _24 + aPoint.z * _34;
|
||||
}
|
||||
|
||||
void
|
||||
gfx3DMatrix::TranslatePost(const Point3D& aPoint)
|
||||
{
|
||||
_11 += _14 * aPoint.x;
|
||||
_21 += _24 * aPoint.x;
|
||||
_31 += _34 * aPoint.x;
|
||||
_41 += _44 * aPoint.x;
|
||||
_12 += _14 * aPoint.y;
|
||||
_22 += _24 * aPoint.y;
|
||||
_32 += _34 * aPoint.y;
|
||||
_42 += _44 * aPoint.y;
|
||||
_13 += _14 * aPoint.z;
|
||||
_23 += _24 * aPoint.z;
|
||||
_33 += _34 * aPoint.z;
|
||||
_43 += _44 * aPoint.z;
|
||||
}
|
||||
|
||||
void
|
||||
gfx3DMatrix::ScalePost(float aX, float aY, float aZ)
|
||||
{
|
||||
_11 *= aX;
|
||||
_21 *= aX;
|
||||
_31 *= aX;
|
||||
_41 *= aX;
|
||||
|
||||
_12 *= aY;
|
||||
_22 *= aY;
|
||||
_32 *= aY;
|
||||
_42 *= aY;
|
||||
|
||||
_13 *= aZ;
|
||||
_23 *= aZ;
|
||||
_33 *= aZ;
|
||||
_43 *= aZ;
|
||||
}
|
||||
|
||||
void
|
||||
gfx3DMatrix::ChangeBasis(const Point3D& aOrigin)
|
||||
{
|
||||
// Translate to the origin before applying this matrix.
|
||||
Translate(-aOrigin);
|
||||
|
||||
// Translate back into position after applying this matrix.
|
||||
TranslatePost(aOrigin);
|
||||
}
|
||||
|
||||
void
|
||||
gfx3DMatrix::Scale(float aX, float aY, float aZ)
|
||||
{
|
||||
(*this)[0] *= aX;
|
||||
(*this)[1] *= aY;
|
||||
(*this)[2] *= aZ;
|
||||
}
|
||||
|
||||
void
|
||||
gfx3DMatrix::Perspective(float aDepth)
|
||||
{
|
||||
NS_ASSERTION(aDepth > 0.0f, "Perspective must be positive!");
|
||||
_31 += -1.0/aDepth * _41;
|
||||
_32 += -1.0/aDepth * _42;
|
||||
_33 += -1.0/aDepth * _43;
|
||||
_34 += -1.0/aDepth * _44;
|
||||
}
|
||||
|
||||
void gfx3DMatrix::SkewXY(double aXSkew, double aYSkew)
|
||||
{
|
||||
float tanX = SafeTangent(aXSkew);
|
||||
float tanY = SafeTangent(aYSkew);
|
||||
float temp;
|
||||
|
||||
temp = _11;
|
||||
_11 += tanY * _21;
|
||||
_21 += tanX * temp;
|
||||
|
||||
temp = _12;
|
||||
_12 += tanY * _22;
|
||||
_22 += tanX * temp;
|
||||
|
||||
temp = _13;
|
||||
_13 += tanY * _23;
|
||||
_23 += tanX * temp;
|
||||
|
||||
temp = _14;
|
||||
_14 += tanY * _24;
|
||||
_24 += tanX * temp;
|
||||
}
|
||||
|
||||
void
|
||||
gfx3DMatrix::RotateX(double aTheta)
|
||||
{
|
||||
double cosTheta = FlushToZero(cos(aTheta));
|
||||
double sinTheta = FlushToZero(sin(aTheta));
|
||||
|
||||
float temp;
|
||||
|
||||
temp = _21;
|
||||
_21 = cosTheta * _21 + sinTheta * _31;
|
||||
_31 = -sinTheta * temp + cosTheta * _31;
|
||||
|
||||
temp = _22;
|
||||
_22 = cosTheta * _22 + sinTheta * _32;
|
||||
_32 = -sinTheta * temp + cosTheta * _32;
|
||||
|
||||
temp = _23;
|
||||
_23 = cosTheta * _23 + sinTheta * _33;
|
||||
_33 = -sinTheta * temp + cosTheta * _33;
|
||||
|
||||
temp = _24;
|
||||
_24 = cosTheta * _24 + sinTheta * _34;
|
||||
_34 = -sinTheta * temp + cosTheta * _34;
|
||||
}
|
||||
|
||||
void
|
||||
gfx3DMatrix::RotateY(double aTheta)
|
||||
{
|
||||
double cosTheta = FlushToZero(cos(aTheta));
|
||||
double sinTheta = FlushToZero(sin(aTheta));
|
||||
|
||||
float temp;
|
||||
|
||||
temp = _11;
|
||||
_11 = cosTheta * _11 + -sinTheta * _31;
|
||||
_31 = sinTheta * temp + cosTheta * _31;
|
||||
|
||||
temp = _12;
|
||||
_12 = cosTheta * _12 + -sinTheta * _32;
|
||||
_32 = sinTheta * temp + cosTheta * _32;
|
||||
|
||||
temp = _13;
|
||||
_13 = cosTheta * _13 + -sinTheta * _33;
|
||||
_33 = sinTheta * temp + cosTheta * _33;
|
||||
|
||||
temp = _14;
|
||||
_14 = cosTheta * _14 + -sinTheta * _34;
|
||||
_34 = sinTheta * temp + cosTheta * _34;
|
||||
}
|
||||
|
||||
void
|
||||
gfx3DMatrix::RotateZ(double aTheta)
|
||||
{
|
||||
double cosTheta = FlushToZero(cos(aTheta));
|
||||
double sinTheta = FlushToZero(sin(aTheta));
|
||||
|
||||
float temp;
|
||||
|
||||
temp = _11;
|
||||
_11 = cosTheta * _11 + sinTheta * _21;
|
||||
_21 = -sinTheta * temp + cosTheta * _21;
|
||||
|
||||
temp = _12;
|
||||
_12 = cosTheta * _12 + sinTheta * _22;
|
||||
_22 = -sinTheta * temp + cosTheta * _22;
|
||||
|
||||
temp = _13;
|
||||
_13 = cosTheta * _13 + sinTheta * _23;
|
||||
_23 = -sinTheta * temp + cosTheta * _23;
|
||||
|
||||
temp = _14;
|
||||
_14 = cosTheta * _14 + sinTheta * _24;
|
||||
_24 = -sinTheta * temp + cosTheta * _24;
|
||||
}
|
||||
|
||||
void
|
||||
gfx3DMatrix::PreMultiply(const gfx3DMatrix& aOther)
|
||||
{
|
||||
*this = aOther * (*this);
|
||||
}
|
||||
|
||||
void
|
||||
gfx3DMatrix::PreMultiply(const gfxMatrix& aOther)
|
||||
{
|
||||
gfx3DMatrix temp;
|
||||
temp._11 = aOther._11 * _11 + aOther._12 * _21;
|
||||
temp._21 = aOther._21 * _11 + aOther._22 * _21;
|
||||
temp._31 = _31;
|
||||
temp._41 = aOther._31 * _11 + aOther._32 * _21 + _41;
|
||||
temp._12 = aOther._11 * _12 + aOther._12 * _22;
|
||||
temp._22 = aOther._21 * _12 + aOther._22 * _22;
|
||||
temp._32 = _32;
|
||||
temp._42 = aOther._31 * _12 + aOther._32 * _22 + _42;
|
||||
temp._13 = aOther._11 * _13 + aOther._12 * _23;
|
||||
temp._23 = aOther._21 * _13 + aOther._22 * _23;
|
||||
temp._33 = _33;
|
||||
temp._43 = aOther._31 * _13 + aOther._32 * _23 + _43;
|
||||
temp._14 = aOther._11 * _14 + aOther._12 * _24;
|
||||
temp._24 = aOther._21 * _14 + aOther._22 * _24;
|
||||
temp._34 = _34;
|
||||
temp._44 = aOther._31 * _14 + aOther._32 * _24 + _44;
|
||||
|
||||
*this = temp;
|
||||
}
|
||||
|
||||
gfx3DMatrix
|
||||
gfx3DMatrix::Translation(float aX, float aY, float aZ)
|
||||
{
|
||||
gfx3DMatrix matrix;
|
||||
|
||||
matrix._41 = aX;
|
||||
matrix._42 = aY;
|
||||
matrix._43 = aZ;
|
||||
return matrix;
|
||||
}
|
||||
|
||||
gfx3DMatrix
|
||||
gfx3DMatrix::Translation(const Point3D& aPoint)
|
||||
{
|
||||
gfx3DMatrix matrix;
|
||||
|
||||
matrix._41 = aPoint.x;
|
||||
matrix._42 = aPoint.y;
|
||||
matrix._43 = aPoint.z;
|
||||
return matrix;
|
||||
}
|
||||
|
||||
gfx3DMatrix
|
||||
gfx3DMatrix::ScalingMatrix(float aFactor)
|
||||
{
|
||||
gfx3DMatrix matrix;
|
||||
|
||||
matrix._11 = matrix._22 = matrix._33 = aFactor;
|
||||
return matrix;
|
||||
}
|
||||
|
||||
gfx3DMatrix
|
||||
gfx3DMatrix::ScalingMatrix(float aX, float aY, float aZ)
|
||||
{
|
||||
gfx3DMatrix matrix;
|
||||
|
||||
matrix._11 = aX;
|
||||
matrix._22 = aY;
|
||||
matrix._33 = aZ;
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
gfxFloat
|
||||
gfx3DMatrix::Determinant() const
|
||||
{
|
||||
return _14 * _23 * _32 * _41
|
||||
- _13 * _24 * _32 * _41
|
||||
- _14 * _22 * _33 * _41
|
||||
+ _12 * _24 * _33 * _41
|
||||
+ _13 * _22 * _34 * _41
|
||||
- _12 * _23 * _34 * _41
|
||||
- _14 * _23 * _31 * _42
|
||||
+ _13 * _24 * _31 * _42
|
||||
+ _14 * _21 * _33 * _42
|
||||
- _11 * _24 * _33 * _42
|
||||
- _13 * _21 * _34 * _42
|
||||
+ _11 * _23 * _34 * _42
|
||||
+ _14 * _22 * _31 * _43
|
||||
- _12 * _24 * _31 * _43
|
||||
- _14 * _21 * _32 * _43
|
||||
+ _11 * _24 * _32 * _43
|
||||
+ _12 * _21 * _34 * _43
|
||||
- _11 * _22 * _34 * _43
|
||||
- _13 * _22 * _31 * _44
|
||||
+ _12 * _23 * _31 * _44
|
||||
+ _13 * _21 * _32 * _44
|
||||
- _11 * _23 * _32 * _44
|
||||
- _12 * _21 * _33 * _44
|
||||
+ _11 * _22 * _33 * _44;
|
||||
}
|
||||
|
||||
gfxFloat
|
||||
gfx3DMatrix::Determinant3x3() const
|
||||
{
|
||||
return _11 * (_22 * _33 - _23 * _32) +
|
||||
_12 * (_23 * _31 - _33 * _21) +
|
||||
_13 * (_21 * _32 - _22 * _31);
|
||||
}
|
||||
|
||||
gfx3DMatrix
|
||||
gfx3DMatrix::Inverse3x3() const
|
||||
{
|
||||
gfxFloat det = Determinant3x3();
|
||||
if (det == 0.0) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
gfxFloat detInv = 1/det;
|
||||
gfx3DMatrix temp;
|
||||
|
||||
temp._11 = (_22 * _33 - _23 * _32) * detInv;
|
||||
temp._12 = (_13 * _32 - _12 * _33) * detInv;
|
||||
temp._13 = (_12 * _23 - _13 * _22) * detInv;
|
||||
temp._21 = (_23 * _31 - _33 * _21) * detInv;
|
||||
temp._22 = (_11 * _33 - _13 * _31) * detInv;
|
||||
temp._23 = (_13 * _21 - _11 * _23) * detInv;
|
||||
temp._31 = (_21 * _32 - _22 * _31) * detInv;
|
||||
temp._32 = (_31 * _12 - _11 * _32) * detInv;
|
||||
temp._33 = (_11 * _22 - _12 * _21) * detInv;
|
||||
return temp;
|
||||
}
|
||||
|
||||
bool
|
||||
gfx3DMatrix::IsSingular() const
|
||||
{
|
||||
return Determinant() == 0.0;
|
||||
}
|
||||
|
||||
gfx3DMatrix
|
||||
gfx3DMatrix::Inverse() const
|
||||
{
|
||||
if (_14 == 0 && _24 == 0 && _34 == 0 && _44 == 1) {
|
||||
/**
|
||||
* When the matrix contains no perspective, the inverse
|
||||
* is the same as the 3x3 inverse of the rotation components
|
||||
* multiplied by the inverse of the translation components.
|
||||
* Doing these steps separately is faster and more numerically
|
||||
* stable.
|
||||
*
|
||||
* Inverse of the translation matrix is just negating
|
||||
* the values.
|
||||
*/
|
||||
gfx3DMatrix matrix3 = Inverse3x3();
|
||||
matrix3.Translate(Point3D(-_41, -_42, -_43));
|
||||
return matrix3;
|
||||
}
|
||||
|
||||
gfxFloat det = Determinant();
|
||||
if (det == 0.0) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
gfx3DMatrix temp;
|
||||
|
||||
temp._11 = _23*_34*_42 - _24*_33*_42 +
|
||||
_24*_32*_43 - _22*_34*_43 -
|
||||
_23*_32*_44 + _22*_33*_44;
|
||||
temp._12 = _14*_33*_42 - _13*_34*_42 -
|
||||
_14*_32*_43 + _12*_34*_43 +
|
||||
_13*_32*_44 - _12*_33*_44;
|
||||
temp._13 = _13*_24*_42 - _14*_23*_42 +
|
||||
_14*_22*_43 - _12*_24*_43 -
|
||||
_13*_22*_44 + _12*_23*_44;
|
||||
temp._14 = _14*_23*_32 - _13*_24*_32 -
|
||||
_14*_22*_33 + _12*_24*_33 +
|
||||
_13*_22*_34 - _12*_23*_34;
|
||||
temp._21 = _24*_33*_41 - _23*_34*_41 -
|
||||
_24*_31*_43 + _21*_34*_43 +
|
||||
_23*_31*_44 - _21*_33*_44;
|
||||
temp._22 = _13*_34*_41 - _14*_33*_41 +
|
||||
_14*_31*_43 - _11*_34*_43 -
|
||||
_13*_31*_44 + _11*_33*_44;
|
||||
temp._23 = _14*_23*_41 - _13*_24*_41 -
|
||||
_14*_21*_43 + _11*_24*_43 +
|
||||
_13*_21*_44 - _11*_23*_44;
|
||||
temp._24 = _13*_24*_31 - _14*_23*_31 +
|
||||
_14*_21*_33 - _11*_24*_33 -
|
||||
_13*_21*_34 + _11*_23*_34;
|
||||
temp._31 = _22*_34*_41 - _24*_32*_41 +
|
||||
_24*_31*_42 - _21*_34*_42 -
|
||||
_22*_31*_44 + _21*_32*_44;
|
||||
temp._32 = _14*_32*_41 - _12*_34*_41 -
|
||||
_14*_31*_42 + _11*_34*_42 +
|
||||
_12*_31*_44 - _11*_32*_44;
|
||||
temp._33 = _12*_24*_41 - _14*_22*_41 +
|
||||
_14*_21*_42 - _11*_24*_42 -
|
||||
_12*_21*_44 + _11*_22*_44;
|
||||
temp._34 = _14*_22*_31 - _12*_24*_31 -
|
||||
_14*_21*_32 + _11*_24*_32 +
|
||||
_12*_21*_34 - _11*_22*_34;
|
||||
temp._41 = _23*_32*_41 - _22*_33*_41 -
|
||||
_23*_31*_42 + _21*_33*_42 +
|
||||
_22*_31*_43 - _21*_32*_43;
|
||||
temp._42 = _12*_33*_41 - _13*_32*_41 +
|
||||
_13*_31*_42 - _11*_33*_42 -
|
||||
_12*_31*_43 + _11*_32*_43;
|
||||
temp._43 = _13*_22*_41 - _12*_23*_41 -
|
||||
_13*_21*_42 + _11*_23*_42 +
|
||||
_12*_21*_43 - _11*_22*_43;
|
||||
temp._44 = _12*_23*_31 - _13*_22*_31 +
|
||||
_13*_21*_32 - _11*_23*_32 -
|
||||
_12*_21*_33 + _11*_22*_33;
|
||||
|
||||
temp /= det;
|
||||
return temp;
|
||||
}
|
||||
|
||||
gfxPoint
|
||||
gfx3DMatrix::Transform(const gfxPoint& point) const
|
||||
{
|
||||
// Note: we don't use Transform3D here because passing point.x/y via
|
||||
// a Point3D would lose precision and cause bugs, e.g. bug 1091709.
|
||||
gfxFloat px = point.x;
|
||||
gfxFloat py = point.y;
|
||||
|
||||
gfxFloat x = px * _11 + py * _21 + _41;
|
||||
gfxFloat y = px * _12 + py * _22 + _42;
|
||||
gfxFloat w = px * _14 + py * _24 + _44;
|
||||
|
||||
x /= w;
|
||||
y /= w;
|
||||
|
||||
return gfxPoint(x, y);
|
||||
}
|
||||
|
||||
Point3D
|
||||
gfx3DMatrix::Transform3D(const Point3D& point) const
|
||||
{
|
||||
gfxFloat x = point.x * _11 + point.y * _21 + point.z * _31 + _41;
|
||||
gfxFloat y = point.x * _12 + point.y * _22 + point.z * _32 + _42;
|
||||
gfxFloat z = point.x * _13 + point.y * _23 + point.z * _33 + _43;
|
||||
gfxFloat w = point.x * _14 + point.y * _24 + point.z * _34 + _44;
|
||||
|
||||
x /= w;
|
||||
y /= w;
|
||||
z /= w;
|
||||
|
||||
return Point3D(x, y, z);
|
||||
}
|
||||
|
||||
Point4D
|
||||
gfx3DMatrix::Transform4D(const Point4D& aPoint) const
|
||||
{
|
||||
gfxFloat x = aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31 + aPoint.w * _41;
|
||||
gfxFloat y = aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32 + aPoint.w * _42;
|
||||
gfxFloat z = aPoint.x * _13 + aPoint.y * _23 + aPoint.z * _33 + aPoint.w * _43;
|
||||
gfxFloat w = aPoint.x * _14 + aPoint.y * _24 + aPoint.z * _34 + aPoint.w * _44;
|
||||
|
||||
return Point4D(x, y, z, w);
|
||||
}
|
||||
|
||||
gfxRect
|
||||
gfx3DMatrix::TransformBounds(const gfxRect& rect) const
|
||||
{
|
||||
gfxPoint points[4];
|
||||
|
||||
points[0] = Transform(rect.TopLeft());
|
||||
points[1] = Transform(gfxPoint(rect.X() + rect.Width(), rect.Y()));
|
||||
points[2] = Transform(gfxPoint(rect.X(), rect.Y() + rect.Height()));
|
||||
points[3] = Transform(gfxPoint(rect.X() + rect.Width(),
|
||||
rect.Y() + rect.Height()));
|
||||
|
||||
gfxFloat min_x, max_x;
|
||||
gfxFloat min_y, max_y;
|
||||
|
||||
min_x = max_x = points[0].x;
|
||||
min_y = max_y = points[0].y;
|
||||
|
||||
for (int i=1; i<4; i++) {
|
||||
min_x = min(points[i].x, min_x);
|
||||
max_x = max(points[i].x, max_x);
|
||||
min_y = min(points[i].y, min_y);
|
||||
max_y = max(points[i].y, max_y);
|
||||
}
|
||||
|
||||
return gfxRect(min_x, min_y, max_x - min_x, max_y - min_y);
|
||||
}
|
||||
|
||||
gfxQuad
|
||||
gfx3DMatrix::TransformRect(const gfxRect& aRect) const
|
||||
{
|
||||
gfxPoint points[4];
|
||||
|
||||
points[0] = Transform(aRect.TopLeft());
|
||||
points[1] = Transform(gfxPoint(aRect.X() + aRect.Width(), aRect.Y()));
|
||||
points[2] = Transform(gfxPoint(aRect.X() + aRect.Width(),
|
||||
aRect.Y() + aRect.Height()));
|
||||
points[3] = Transform(gfxPoint(aRect.X(), aRect.Y() + aRect.Height()));
|
||||
|
||||
// Could this ever result in lines that intersect? I don't think so.
|
||||
return gfxQuad(points[0], points[1], points[2], points[3]);
|
||||
}
|
||||
|
||||
bool
|
||||
gfx3DMatrix::Is2D() const
|
||||
{
|
||||
if (_13 != 0.0f || _14 != 0.0f ||
|
||||
_23 != 0.0f || _24 != 0.0f ||
|
||||
_31 != 0.0f || _32 != 0.0f || _33 != 1.0f || _34 != 0.0f ||
|
||||
_43 != 0.0f || _44 != 1.0f) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
gfx3DMatrix::Is2D(gfxMatrix* aMatrix) const
|
||||
{
|
||||
if (!Is2D()) {
|
||||
return false;
|
||||
}
|
||||
if (aMatrix) {
|
||||
aMatrix->_11 = _11;
|
||||
aMatrix->_12 = _12;
|
||||
aMatrix->_21 = _21;
|
||||
aMatrix->_22 = _22;
|
||||
aMatrix->_31 = _41;
|
||||
aMatrix->_32 = _42;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
gfx3DMatrix::CanDraw2D(gfxMatrix* aMatrix) const
|
||||
{
|
||||
if (_14 != 0.0f ||
|
||||
_24 != 0.0f ||
|
||||
_44 != 1.0f) {
|
||||
return false;
|
||||
}
|
||||
if (aMatrix) {
|
||||
aMatrix->_11 = _11;
|
||||
aMatrix->_12 = _12;
|
||||
aMatrix->_21 = _21;
|
||||
aMatrix->_22 = _22;
|
||||
aMatrix->_31 = _41;
|
||||
aMatrix->_32 = _42;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
gfx3DMatrix&
|
||||
gfx3DMatrix::ProjectTo2D()
|
||||
{
|
||||
_31 = 0.0f;
|
||||
_32 = 0.0f;
|
||||
_13 = 0.0f;
|
||||
_23 = 0.0f;
|
||||
_33 = 1.0f;
|
||||
_43 = 0.0f;
|
||||
_34 = 0.0f;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Point4D gfx3DMatrix::ProjectPoint(const gfxPoint& aPoint) const
|
||||
{
|
||||
// Find a value for z that will transform to 0.
|
||||
|
||||
// The transformed value of z is computed as:
|
||||
// z' = aPoint.x * _13 + aPoint.y * _23 + z * _33 + _43;
|
||||
|
||||
// Solving for z when z' = 0 gives us:
|
||||
float z = -(aPoint.x * _13 + aPoint.y * _23 + _43) / _33;
|
||||
|
||||
// Compute the transformed point
|
||||
return Transform4D(Point4D(aPoint.x, aPoint.y, z, 1));
|
||||
}
|
||||
|
||||
Point3D gfx3DMatrix::GetNormalVector() const
|
||||
{
|
||||
// Define a plane in transformed space as the transformations
|
||||
// of 3 points on the z=0 screen plane.
|
||||
Point3D a = Transform3D(Point3D(0, 0, 0));
|
||||
Point3D b = Transform3D(Point3D(0, 1, 0));
|
||||
Point3D c = Transform3D(Point3D(1, 0, 0));
|
||||
|
||||
// Convert to two vectors on the surface of the plane.
|
||||
Point3D ab = b - a;
|
||||
Point3D ac = c - a;
|
||||
|
||||
return ac.CrossProduct(ab);
|
||||
}
|
||||
|
||||
bool gfx3DMatrix::IsBackfaceVisible() const
|
||||
{
|
||||
// Inverse()._33 < 0;
|
||||
gfxFloat det = Determinant();
|
||||
float _33 = _12*_24*_41 - _14*_22*_41 +
|
||||
_14*_21*_42 - _11*_24*_42 -
|
||||
_12*_21*_44 + _11*_22*_44;
|
||||
return (_33 * det) < 0;
|
||||
}
|
||||
|
||||
void gfx3DMatrix::NudgeToIntegers(void)
|
||||
{
|
||||
NudgeToInteger(&_11);
|
||||
NudgeToInteger(&_12);
|
||||
NudgeToInteger(&_13);
|
||||
NudgeToInteger(&_14);
|
||||
NudgeToInteger(&_21);
|
||||
NudgeToInteger(&_22);
|
||||
NudgeToInteger(&_23);
|
||||
NudgeToInteger(&_24);
|
||||
NudgeToInteger(&_31);
|
||||
NudgeToInteger(&_32);
|
||||
NudgeToInteger(&_33);
|
||||
NudgeToInteger(&_34);
|
||||
NudgeToInteger(&_41);
|
||||
NudgeToInteger(&_42);
|
||||
NudgeToInteger(&_43);
|
||||
NudgeToInteger(&_44);
|
||||
}
|
||||
|
||||
void gfx3DMatrix::NudgeToIntegersFixedEpsilon(void)
|
||||
{
|
||||
NudgeToInteger(&_11);
|
||||
NudgeToInteger(&_12);
|
||||
NudgeToInteger(&_13);
|
||||
NudgeToInteger(&_14);
|
||||
NudgeToInteger(&_21);
|
||||
NudgeToInteger(&_22);
|
||||
NudgeToInteger(&_23);
|
||||
NudgeToInteger(&_24);
|
||||
NudgeToInteger(&_31);
|
||||
NudgeToInteger(&_32);
|
||||
NudgeToInteger(&_33);
|
||||
NudgeToInteger(&_34);
|
||||
static const float error = 1e-5;
|
||||
NudgeToInteger(&_41, error);
|
||||
NudgeToInteger(&_42, error);
|
||||
NudgeToInteger(&_43, error);
|
||||
NudgeToInteger(&_44, error);
|
||||
}
|
@ -1,357 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 GFX_3DMATRIX_H
|
||||
#define GFX_3DMATRIX_H
|
||||
|
||||
#include <gfxTypes.h>
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include <gfxQuad.h>
|
||||
|
||||
class gfxMatrix;
|
||||
|
||||
/**
|
||||
* This class represents a 3D transformation. The matrix is laid
|
||||
* out as follows:
|
||||
*
|
||||
* _11 _12 _13 _14
|
||||
* _21 _22 _23 _24
|
||||
* _31 _32 _33 _34
|
||||
* _41 _42 _43 _44
|
||||
*
|
||||
* This matrix is treated as row-major. Assuming we consider our vectors row
|
||||
* vectors, this matrix type will be identical in memory to the OpenGL and D3D
|
||||
* matrices. OpenGL matrices are column-major, however OpenGL also treats
|
||||
* vectors as column vectors, the double transposition makes everything work
|
||||
* out nicely.
|
||||
*/
|
||||
class gfx3DMatrix
|
||||
{
|
||||
typedef mozilla::gfx::Point3D Point3D;
|
||||
typedef mozilla::gfx::Point4D Point4D;
|
||||
public:
|
||||
/**
|
||||
* Create matrix.
|
||||
*/
|
||||
gfx3DMatrix(void);
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const gfx3DMatrix& m) {
|
||||
if (m.IsIdentity()) {
|
||||
return stream << "[ I ]";
|
||||
}
|
||||
|
||||
if (m.Is2D()) {
|
||||
return stream << "["
|
||||
<< m._11 << " " << m._12 << "; "
|
||||
<< m._21 << " " << m._22 << "; "
|
||||
<< m._41 << " " << m._42
|
||||
<< "]";
|
||||
}
|
||||
|
||||
return stream << "["
|
||||
<< m._11 << " " << m._12 << " " << m._13 << " " << m._14 << "; "
|
||||
<< m._21 << " " << m._22 << " " << m._23 << " " << m._24 << "; "
|
||||
<< m._31 << " " << m._32 << " " << m._33 << " " << m._34 << "; "
|
||||
<< m._41 << " " << m._42 << " " << m._43 << " " << m._44
|
||||
<< "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Matrix multiplication.
|
||||
*/
|
||||
gfx3DMatrix operator*(const gfx3DMatrix &aMatrix) const;
|
||||
gfx3DMatrix& operator*=(const gfx3DMatrix &aMatrix);
|
||||
|
||||
Point4D& operator[](int aIndex)
|
||||
{
|
||||
MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
|
||||
return *reinterpret_cast<Point4D*>((&_11)+4*aIndex);
|
||||
}
|
||||
const Point4D& operator[](int aIndex) const
|
||||
{
|
||||
MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
|
||||
return *reinterpret_cast<const Point4D*>((&_11)+4*aIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this matrix and |aMatrix| are the same matrix.
|
||||
*/
|
||||
bool operator==(const gfx3DMatrix& aMatrix) const;
|
||||
bool operator!=(const gfx3DMatrix& aMatrix) const;
|
||||
|
||||
bool FuzzyEqual(const gfx3DMatrix& aMatrix) const;
|
||||
|
||||
/**
|
||||
* Divide all values in the matrix by a scalar value
|
||||
*/
|
||||
gfx3DMatrix& operator/=(gfxFloat scalar);
|
||||
|
||||
/**
|
||||
* Create a 3D matrix from a gfxMatrix 2D affine transformation.
|
||||
*
|
||||
* \param aMatrix gfxMatrix 2D affine transformation.
|
||||
*/
|
||||
static gfx3DMatrix From2D(const gfxMatrix &aMatrix);
|
||||
|
||||
/**
|
||||
* Returns true if the matrix is isomorphic to a 2D affine transformation
|
||||
* (i.e. as obtained by From2D). If it is, optionally returns the 2D
|
||||
* matrix in aMatrix.
|
||||
*/
|
||||
bool Is2D(gfxMatrix* aMatrix) const;
|
||||
bool Is2D() const;
|
||||
|
||||
/**
|
||||
* Returns true if the matrix can be reduced to a 2D affine transformation
|
||||
* (i.e. as obtained by From2D). If it is, optionally returns the 2D
|
||||
* matrix in aMatrix. This should only be used on matrices required for
|
||||
* rendering, not for intermediate calculations. It is assumed that the 2D
|
||||
* matrix will only be used for transforming objects on to the z=0 plane,
|
||||
* therefore any z-component perspective is ignored. This means that if
|
||||
* aMatrix is applied to objects with z != 0, the results may be incorrect.
|
||||
*
|
||||
* Since drawing is to a 2d plane, any 3d transform without perspective
|
||||
* can be reduced by dropping the z row and column.
|
||||
*/
|
||||
bool CanDraw2D(gfxMatrix* aMatrix = nullptr) const;
|
||||
|
||||
/**
|
||||
* Converts the matrix to one that doesn't modify the z coordinate of points,
|
||||
* but leaves the rest of the transformation unchanged.
|
||||
*/
|
||||
gfx3DMatrix& ProjectTo2D();
|
||||
|
||||
/**
|
||||
* Returns true if the matrix is the identity matrix. The most important
|
||||
* property we require is that gfx3DMatrix().IsIdentity() returns true.
|
||||
*/
|
||||
bool IsIdentity() const;
|
||||
|
||||
/**
|
||||
* Pre-multiplication transformation functions:
|
||||
*
|
||||
* These functions construct a temporary matrix containing
|
||||
* a single transformation and pre-multiply it onto the current
|
||||
* matrix.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add a translation by aPoint to the matrix.
|
||||
*
|
||||
* This creates this temporary matrix:
|
||||
* | 1 0 0 0 |
|
||||
* | 0 1 0 0 |
|
||||
* | 0 0 1 0 |
|
||||
* | aPoint.x aPoint.y aPoint.z 1 |
|
||||
*/
|
||||
void Translate(const Point3D& aPoint);
|
||||
|
||||
/**
|
||||
* Skew the matrix.
|
||||
*
|
||||
* This creates this temporary matrix:
|
||||
* | 1 tan(aYSkew) 0 0 |
|
||||
* | tan(aXSkew) 1 0 0 |
|
||||
* | 0 0 1 0 |
|
||||
* | 0 0 0 1 |
|
||||
*/
|
||||
void SkewXY(double aXSkew, double aYSkew);
|
||||
|
||||
/**
|
||||
* Scale the matrix
|
||||
*
|
||||
* This creates this temporary matrix:
|
||||
* | aX 0 0 0 |
|
||||
* | 0 aY 0 0 |
|
||||
* | 0 0 aZ 0 |
|
||||
* | 0 0 0 1 |
|
||||
*/
|
||||
void Scale(float aX, float aY, float aZ);
|
||||
|
||||
/**
|
||||
* Return the currently set scaling factors.
|
||||
*/
|
||||
float GetXScale() const { return _11; }
|
||||
float GetYScale() const { return _22; }
|
||||
float GetZScale() const { return _33; }
|
||||
|
||||
/**
|
||||
* Rotate around the X axis..
|
||||
*
|
||||
* This creates this temporary matrix:
|
||||
* | 1 0 0 0 |
|
||||
* | 0 cos(aTheta) sin(aTheta) 0 |
|
||||
* | 0 -sin(aTheta) cos(aTheta) 0 |
|
||||
* | 0 0 0 1 |
|
||||
*/
|
||||
void RotateX(double aTheta);
|
||||
|
||||
/**
|
||||
* Rotate around the Y axis..
|
||||
*
|
||||
* This creates this temporary matrix:
|
||||
* | cos(aTheta) 0 -sin(aTheta) 0 |
|
||||
* | 0 1 0 0 |
|
||||
* | sin(aTheta) 0 cos(aTheta) 0 |
|
||||
* | 0 0 0 1 |
|
||||
*/
|
||||
void RotateY(double aTheta);
|
||||
|
||||
/**
|
||||
* Rotate around the Z axis..
|
||||
*
|
||||
* This creates this temporary matrix:
|
||||
* | cos(aTheta) sin(aTheta) 0 0 |
|
||||
* | -sin(aTheta) cos(aTheta) 0 0 |
|
||||
* | 0 0 1 0 |
|
||||
* | 0 0 0 1 |
|
||||
*/
|
||||
void RotateZ(double aTheta);
|
||||
|
||||
/**
|
||||
* Apply perspective to the matrix.
|
||||
*
|
||||
* This creates this temporary matrix:
|
||||
* | 1 0 0 0 |
|
||||
* | 0 1 0 0 |
|
||||
* | 0 0 1 -1/aDepth |
|
||||
* | 0 0 0 1 |
|
||||
*/
|
||||
void Perspective(float aDepth);
|
||||
|
||||
/**
|
||||
* Pre multiply an existing matrix onto the current
|
||||
* matrix
|
||||
*/
|
||||
void PreMultiply(const gfx3DMatrix& aOther);
|
||||
void PreMultiply(const gfxMatrix& aOther);
|
||||
|
||||
/**
|
||||
* Post-multiplication transformation functions:
|
||||
*
|
||||
* These functions construct a temporary matrix containing
|
||||
* a single transformation and post-multiply it onto the current
|
||||
* matrix.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add a translation by aPoint after the matrix.
|
||||
* This is functionally equivalent to:
|
||||
* matrix * gfx3DMatrix::Translation(aPoint)
|
||||
*/
|
||||
void TranslatePost(const Point3D& aPoint);
|
||||
|
||||
void ScalePost(float aX, float aY, float aZ);
|
||||
|
||||
/**
|
||||
* Let T be the transformation matrix translating points in the coordinate
|
||||
* space with origin aOrigin to the coordinate space used by this matrix.
|
||||
* If this matrix is M, this function changes it to be (T-1)MT, the matrix
|
||||
* that's equivalent to M but in the coordinate space that treats aOrigin
|
||||
* as the origin.
|
||||
*
|
||||
* @param aOrigin The origin to translate to
|
||||
* @return The modified matrix
|
||||
*/
|
||||
void ChangeBasis(const Point3D& aOrigin);
|
||||
|
||||
/**
|
||||
* Transforms a point according to this matrix.
|
||||
*/
|
||||
gfxPoint Transform(const gfxPoint& point) const;
|
||||
|
||||
/**
|
||||
* Transforms a rectangle according to this matrix
|
||||
*/
|
||||
gfxRect TransformBounds(const gfxRect& rect) const;
|
||||
|
||||
|
||||
gfxQuad TransformRect(const gfxRect& aRect) const;
|
||||
|
||||
/**
|
||||
* Transforms a 3D vector according to this matrix.
|
||||
*/
|
||||
Point3D Transform3D(const Point3D& point) const;
|
||||
Point4D Transform4D(const Point4D& aPoint) const;
|
||||
|
||||
/**
|
||||
* Given a point (x,y) find a value for z such that (x,y,z,1) transforms
|
||||
* into (x',y',0,w') and returns the latter.
|
||||
*/
|
||||
Point4D ProjectPoint(const gfxPoint& aPoint) const;
|
||||
|
||||
/**
|
||||
* Inverts this matrix, if possible. Otherwise, the matrix is left
|
||||
* unchanged.
|
||||
*/
|
||||
gfx3DMatrix Inverse() const;
|
||||
|
||||
gfx3DMatrix& Invert()
|
||||
{
|
||||
*this = Inverse();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unit vector that is perpendicular to the plane formed
|
||||
* by transform the screen plane (z=0) by this matrix.
|
||||
*/
|
||||
Point3D GetNormalVector() const;
|
||||
|
||||
/**
|
||||
* Returns true if a plane transformed by this matrix will
|
||||
* have it's back face visible.
|
||||
*/
|
||||
bool IsBackfaceVisible() const;
|
||||
|
||||
/**
|
||||
* Check if matrix is singular (no inverse exists).
|
||||
*/
|
||||
bool IsSingular() const;
|
||||
|
||||
/**
|
||||
* Create a translation matrix.
|
||||
*
|
||||
* \param aX Translation on X-axis.
|
||||
* \param aY Translation on Y-axis.
|
||||
* \param aZ Translation on Z-axis.
|
||||
*/
|
||||
static gfx3DMatrix Translation(float aX, float aY, float aZ);
|
||||
static gfx3DMatrix Translation(const Point3D& aPoint);
|
||||
|
||||
/**
|
||||
* Create a scale matrix. Scales uniformly along all axes.
|
||||
*
|
||||
* \param aScale Scale factor
|
||||
*/
|
||||
static gfx3DMatrix ScalingMatrix(float aFactor);
|
||||
|
||||
/**
|
||||
* Create a scale matrix.
|
||||
*/
|
||||
static gfx3DMatrix ScalingMatrix(float aX, float aY, float aZ);
|
||||
|
||||
gfxFloat Determinant() const;
|
||||
|
||||
void NudgeToIntegers(void);
|
||||
void NudgeToIntegersFixedEpsilon();
|
||||
|
||||
private:
|
||||
|
||||
gfxFloat Determinant3x3() const;
|
||||
gfx3DMatrix Inverse3x3() const;
|
||||
|
||||
gfx3DMatrix Multiply2D(const gfx3DMatrix &aMatrix) const;
|
||||
|
||||
public:
|
||||
|
||||
/** Matrix elements */
|
||||
float _11, _12, _13, _14;
|
||||
float _21, _22, _23, _24;
|
||||
float _31, _32, _33, _34;
|
||||
float _41, _42, _43, _44;
|
||||
};
|
||||
|
||||
#endif /* GFX_3DMATRIX_H */
|
@ -6,6 +6,7 @@
|
||||
#include "gfxMatrix.h"
|
||||
#include "cairo.h"
|
||||
#include "mozilla/gfx/Tools.h"
|
||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
||||
|
||||
#define CAIRO_MATRIX(x) reinterpret_cast<cairo_matrix_t*>((x))
|
||||
#define CONST_CAIRO_MATRIX(x) reinterpret_cast<const cairo_matrix_t*>((x))
|
||||
@ -158,3 +159,31 @@ gfxMatrix::NudgeToIntegers(void)
|
||||
NudgeToInteger(&_32);
|
||||
return *this;
|
||||
}
|
||||
|
||||
mozilla::gfx::Matrix4x4
|
||||
gfxMatrix::operator *(const mozilla::gfx::Matrix4x4& aMatrix) const
|
||||
{
|
||||
Matrix4x4 resultMatrix;
|
||||
|
||||
resultMatrix._11 = _11 * aMatrix._11 + _12 * aMatrix._21;
|
||||
resultMatrix._12 = _11 * aMatrix._12 + _12 * aMatrix._22;
|
||||
resultMatrix._13 = _11 * aMatrix._13 + _12 * aMatrix._23;
|
||||
resultMatrix._14 = _11 * aMatrix._14 + _12 * aMatrix._24;
|
||||
|
||||
resultMatrix._21 = _21 * aMatrix._11 + _22 * aMatrix._21;
|
||||
resultMatrix._22 = _21 * aMatrix._12 + _22 * aMatrix._22;
|
||||
resultMatrix._23 = _21 * aMatrix._13 + _22 * aMatrix._23;
|
||||
resultMatrix._24 = _21 * aMatrix._14 + _22 * aMatrix._24;
|
||||
|
||||
resultMatrix._31 = aMatrix._31;
|
||||
resultMatrix._32 = aMatrix._32;
|
||||
resultMatrix._33 = aMatrix._33;
|
||||
resultMatrix._34 = aMatrix._34;
|
||||
|
||||
resultMatrix._41 = _31 * aMatrix._11 + _32 * aMatrix._21 + aMatrix._41;
|
||||
resultMatrix._42 = _31 * aMatrix._12 + _32 * aMatrix._22 + aMatrix._42;
|
||||
resultMatrix._43 = _31 * aMatrix._13 + _32 * aMatrix._23 + aMatrix._43;
|
||||
resultMatrix._44 = _31 * aMatrix._14 + _32 * aMatrix._24 + aMatrix._44;
|
||||
|
||||
return resultMatrix;
|
||||
}
|
||||
|
@ -11,6 +11,12 @@
|
||||
#include "gfxRect.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
class Matrix4x4;
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
// XX - I don't think this class should use gfxFloat at all,
|
||||
// but should use 'double' and be called gfxDoubleMatrix;
|
||||
// we can then typedef that to gfxMatrix where we typedef
|
||||
@ -79,6 +85,11 @@ public:
|
||||
return gfxMatrix(*this) *= m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies *this with aMatrix and returns the result.
|
||||
*/
|
||||
mozilla::gfx::Matrix4x4 operator * (const mozilla::gfx::Matrix4x4& aMatrix) const;
|
||||
|
||||
/* Returns true if the other matrix is fuzzy-equal to this matrix.
|
||||
* Note that this isn't a cheap comparison!
|
||||
*/
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "nsMathUtils.h"
|
||||
#include "mozilla/gfx/BaseSize.h"
|
||||
#include "mozilla/gfx/BasePoint.h"
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "nsSize.h"
|
||||
#include "nsPoint.h"
|
||||
|
||||
@ -32,6 +33,20 @@ struct gfxPoint : public mozilla::gfx::BasePoint<gfxFloat, gfxPoint> {
|
||||
bool WithinEpsilonOf(const gfxPoint& aPoint, gfxFloat aEpsilon) {
|
||||
return fabs(aPoint.x - x) < aEpsilon && fabs(aPoint.y - y) < aEpsilon;
|
||||
}
|
||||
|
||||
void Transform(const mozilla::gfx::Matrix4x4 &aMatrix)
|
||||
{
|
||||
// Transform this point with aMatrix
|
||||
double px = x;
|
||||
double py = y;
|
||||
|
||||
x = px * aMatrix._11 + py * aMatrix._21 + aMatrix._41;
|
||||
y = px * aMatrix._12 + py * aMatrix._22 + aMatrix._42;
|
||||
|
||||
double w = px * aMatrix._14 + py * aMatrix._24 + aMatrix._44;
|
||||
x /= w;
|
||||
y /= w;
|
||||
}
|
||||
};
|
||||
|
||||
inline gfxPoint
|
||||
|
@ -7,6 +7,59 @@
|
||||
|
||||
#include "nsMathUtils.h"
|
||||
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
|
||||
#include "gfxQuad.h"
|
||||
|
||||
gfxQuad
|
||||
gfxRect::TransformToQuad(const mozilla::gfx::Matrix4x4 &aMatrix) const
|
||||
{
|
||||
gfxPoint points[4];
|
||||
|
||||
points[0] = TopLeft();
|
||||
points[1] = TopRight();
|
||||
points[2] = BottomRight();
|
||||
points[3] = BottomLeft();
|
||||
|
||||
points[0].Transform(aMatrix);
|
||||
points[1].Transform(aMatrix);
|
||||
points[2].Transform(aMatrix);
|
||||
points[3].Transform(aMatrix);
|
||||
|
||||
// Could this ever result in lines that intersect? I don't think so.
|
||||
return gfxQuad(points[0], points[1], points[2], points[3]);
|
||||
}
|
||||
|
||||
void
|
||||
gfxRect::TransformBounds(const mozilla::gfx::Matrix4x4 &aMatrix)
|
||||
{
|
||||
gfxPoint quad[4];
|
||||
|
||||
quad[0] = TopLeft();
|
||||
quad[1] = TopRight();
|
||||
quad[2] = BottomLeft();
|
||||
quad[3] = BottomRight();
|
||||
|
||||
quad[0].Transform(aMatrix);
|
||||
double min_x = quad[0].x;
|
||||
double max_x = quad[0].x;
|
||||
double min_y = quad[0].y;
|
||||
double max_y = quad[0].y;
|
||||
|
||||
for (int i=1; i<4; i++) {
|
||||
quad[i].Transform(aMatrix);
|
||||
min_x = std::min(quad[i].x, min_x);
|
||||
max_x = std::max(quad[i].x, max_x);
|
||||
min_y = std::min(quad[i].y, min_y);
|
||||
max_y = std::max(quad[i].y, max_y);
|
||||
}
|
||||
|
||||
x = min_x;
|
||||
y = min_y;
|
||||
width = max_x - min_x;
|
||||
height = max_y - min_y;
|
||||
}
|
||||
|
||||
static bool
|
||||
WithinEpsilonOfInteger(gfxFloat aX, gfxFloat aEpsilon)
|
||||
{
|
||||
|
@ -14,6 +14,14 @@
|
||||
#include "mozilla/gfx/BaseRect.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
class Matrix4x4;
|
||||
} // namepsace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
struct gfxQuad;
|
||||
|
||||
struct gfxMargin : public mozilla::gfx::BaseMargin<gfxFloat, gfxMargin> {
|
||||
typedef mozilla::gfx::BaseMargin<gfxFloat, gfxMargin> Super;
|
||||
|
||||
@ -137,6 +145,16 @@ struct gfxRect :
|
||||
width /= k;
|
||||
height /= k;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform this rectangle with aMatrix, resulting in a gfxQuad.
|
||||
*/
|
||||
gfxQuad TransformToQuad(const mozilla::gfx::Matrix4x4 &aMatrix) const;
|
||||
|
||||
/*
|
||||
* Transform this rectangle with aMatrix, as an axis-aligned bounding box
|
||||
*/
|
||||
void TransformBounds(const mozilla::gfx::Matrix4x4 &aMatrix);
|
||||
};
|
||||
|
||||
#endif /* GFX_RECT_H */
|
||||
|
@ -1889,6 +1889,9 @@ gfxFontGroup::GetDefaultFont()
|
||||
needsBold);
|
||||
if (fe) {
|
||||
mDefaultFont = fe->FindOrMakeFont(&mStyle, needsBold);
|
||||
if (mDefaultFont) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ EXPORTS += [
|
||||
'ContextStateTracker.h',
|
||||
'DrawMode.h',
|
||||
'gfx2DGlue.h',
|
||||
'gfx3DMatrix.h',
|
||||
'gfxAlphaRecovery.h',
|
||||
'gfxASurface.h',
|
||||
'gfxBaseSharedMemorySurface.h',
|
||||
@ -212,7 +211,6 @@ SOURCES += [
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'CJKCompatSVS.cpp',
|
||||
'gfx3DMatrix.cpp',
|
||||
'gfxAlphaRecovery.cpp',
|
||||
'gfxBaseSharedMemorySurface.cpp',
|
||||
'gfxBlur.cpp',
|
||||
|
@ -5,9 +5,30 @@
|
||||
#ifndef mozilla_image_BMPFileHeaders_h
|
||||
#define mozilla_image_BMPFileHeaders_h
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace image {
|
||||
|
||||
// This is the real BIH size (as contained in the bihsize field of
|
||||
// BMPFILEHEADER).
|
||||
struct BIH_LENGTH {
|
||||
enum {
|
||||
OS2 = 12,
|
||||
WIN_V3 = 40,
|
||||
WIN_V5 = 124
|
||||
};
|
||||
};
|
||||
|
||||
struct BIH_INTERNAL_LENGTH {
|
||||
enum {
|
||||
OS2 = 8,
|
||||
WIN_V3 = 36,
|
||||
WIN_V5 = 120
|
||||
};
|
||||
};
|
||||
|
||||
struct BMPFILEHEADER {
|
||||
char signature[2]; // String "BM"
|
||||
uint32_t filesize;
|
||||
@ -15,32 +36,22 @@ struct BMPFILEHEADER {
|
||||
uint32_t dataoffset; // Offset to raster data
|
||||
|
||||
uint32_t bihsize;
|
||||
|
||||
// The length of the bitmap file header as defined in the BMP spec.
|
||||
static const size_t LENGTH = 14;
|
||||
|
||||
// Internally we store the bitmap file header with an additional 4 bytes which
|
||||
// is used to store the bitmap information header size.
|
||||
static const size_t INTERNAL_LENGTH = 18;
|
||||
};
|
||||
|
||||
// The length of the bitmap file header as defined in the BMP spec.
|
||||
#define BFH_LENGTH 14
|
||||
// Internally we store the bitmap file header with an additional 4 bytes which
|
||||
// is used to store the bitmap information header size.
|
||||
#define BFH_INTERNAL_LENGTH 18
|
||||
|
||||
#define OS2_INTERNAL_BIH_LENGTH 8
|
||||
#define WIN_V3_INTERNAL_BIH_LENGTH 36
|
||||
#define WIN_V5_INTERNAL_BIH_LENGTH 120
|
||||
|
||||
#define OS2_BIH_LENGTH 12 // This is the real BIH size (as contained in the
|
||||
// bihsize field of BMPFILEHEADER)
|
||||
#define WIN_V3_BIH_LENGTH 40 // This is the real BIH size (as contained in the
|
||||
// bihsize field of BMPFILEHEADER)
|
||||
#define WIN_V5_BIH_LENGTH 124 // This is the real BIH size (as contained in the
|
||||
// bihsize field of BMPFILEHEADER)
|
||||
|
||||
#define OS2_HEADER_LENGTH (BFH_INTERNAL_LENGTH + OS2_INTERNAL_BIH_LENGTH)
|
||||
#define WIN_V3_HEADER_LENGTH (BFH_INTERNAL_LENGTH + WIN_V3_INTERNAL_BIH_LENGTH)
|
||||
#define WIN_V5_HEADER_LENGTH (BFH_INTERNAL_LENGTH + WIN_V5_INTERNAL_BIH_LENGTH)
|
||||
|
||||
#ifndef LCS_sRGB
|
||||
#define LCS_sRGB 0x73524742
|
||||
#endif
|
||||
struct BMP_HEADER_LENGTH {
|
||||
enum {
|
||||
OS2 = BMPFILEHEADER::INTERNAL_LENGTH + BIH_INTERNAL_LENGTH::OS2,
|
||||
WIN_V3 = BMPFILEHEADER::INTERNAL_LENGTH + BIH_INTERNAL_LENGTH::WIN_V3,
|
||||
WIN_V5 = BMPFILEHEADER::INTERNAL_LENGTH + BIH_INTERNAL_LENGTH::WIN_V5
|
||||
};
|
||||
};
|
||||
|
||||
struct xyz {
|
||||
int32_t x, y, z;
|
||||
@ -78,6 +89,8 @@ struct BITMAPV5HEADER {
|
||||
uint32_t profile_offset; // Offset to profile data in bytes
|
||||
uint32_t profile_size; // Size of profile data in bytes
|
||||
uint32_t reserved; // =0
|
||||
|
||||
static const uint32_t COLOR_SPACE_LCS_SRGB = 0x73524742;
|
||||
};
|
||||
|
||||
struct colorTable {
|
||||
@ -96,38 +109,34 @@ struct bitFields {
|
||||
uint8_t greenRightShift;
|
||||
uint8_t blueLeftShift;
|
||||
uint8_t blueRightShift;
|
||||
|
||||
// Length of the bitfields structure in the BMP file.
|
||||
static const size_t LENGTH = 12;
|
||||
};
|
||||
|
||||
} // namespace image
|
||||
} // namespace mozilla
|
||||
struct BMPINFOHEADER {
|
||||
// BMPINFOHEADER.compression definitions.
|
||||
enum {
|
||||
RGB = 0,
|
||||
RLE8 = 1,
|
||||
RLE4 = 2,
|
||||
BITFIELDS = 3,
|
||||
|
||||
#define BITFIELD_LENGTH 12 // Length of the bitfields structure in the bmp file
|
||||
#define USE_RGB
|
||||
// ALPHABITFIELDS means no compression and specifies alpha bits. Valid only
|
||||
// for 32bpp and 16bpp.
|
||||
ALPHABITFIELDS = 4
|
||||
};
|
||||
};
|
||||
|
||||
// BMPINFOHEADER.compression defines
|
||||
#ifndef BI_RGB
|
||||
#define BI_RGB 0
|
||||
#endif
|
||||
#ifndef BI_RLE8
|
||||
#define BI_RLE8 1
|
||||
#endif
|
||||
#ifndef BI_RLE4
|
||||
#define BI_RLE4 2
|
||||
#endif
|
||||
#ifndef BI_BITFIELDS
|
||||
#define BI_BITFIELDS 3
|
||||
#endif
|
||||
// BI_ALPHABITFIELDS means no compression and specifies alpha bits
|
||||
// valid only for 32bpp and 16bpp
|
||||
#ifndef BI_ALPHABITFIELDS
|
||||
#define BI_ALPHABITFIELDS 4
|
||||
#endif
|
||||
|
||||
// RLE Escape codes
|
||||
#define RLE_ESCAPE 0
|
||||
#define RLE_ESCAPE_EOL 0
|
||||
#define RLE_ESCAPE_EOF 1
|
||||
#define RLE_ESCAPE_DELTA 2
|
||||
// RLE escape codes.
|
||||
struct RLE {
|
||||
enum {
|
||||
ESCAPE = 0,
|
||||
ESCAPE_EOL = 0,
|
||||
ESCAPE_EOF = 1,
|
||||
ESCAPE_DELTA = 2
|
||||
};
|
||||
};
|
||||
|
||||
/// enums for mState
|
||||
enum ERLEState {
|
||||
@ -141,4 +150,7 @@ enum ERLEState {
|
||||
///< be read as padding
|
||||
};
|
||||
|
||||
} // namespace image
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_image_BMPFileHeaders_h
|
||||
|
@ -203,8 +203,8 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
if (aDecoder->IsSizeDecode()) {
|
||||
mSizeDecodeQueue.AppendElement(Move(decoder));
|
||||
if (aDecoder->IsMetadataDecode()) {
|
||||
mMetadataDecodeQueue.AppendElement(Move(decoder));
|
||||
} else {
|
||||
mFullDecodeQueue.AppendElement(Move(decoder));
|
||||
}
|
||||
@ -218,9 +218,9 @@ public:
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
|
||||
do {
|
||||
// Prioritize size decodes over full decodes.
|
||||
if (!mSizeDecodeQueue.IsEmpty()) {
|
||||
return PopWorkFromQueue(mSizeDecodeQueue);
|
||||
// Prioritize metadata decodes over full decodes.
|
||||
if (!mMetadataDecodeQueue.IsEmpty()) {
|
||||
return PopWorkFromQueue(mMetadataDecodeQueue);
|
||||
}
|
||||
|
||||
if (!mFullDecodeQueue.IsEmpty()) {
|
||||
@ -253,9 +253,9 @@ private:
|
||||
|
||||
nsThreadPoolNaming mThreadNaming;
|
||||
|
||||
// mMonitor guards mQueue and mShuttingDown.
|
||||
// mMonitor guards the queues and mShuttingDown.
|
||||
Monitor mMonitor;
|
||||
nsTArray<nsRefPtr<Decoder>> mSizeDecodeQueue;
|
||||
nsTArray<nsRefPtr<Decoder>> mMetadataDecodeQueue;
|
||||
nsTArray<nsRefPtr<Decoder>> mFullDecodeQueue;
|
||||
bool mShuttingDown;
|
||||
};
|
||||
|
@ -42,7 +42,7 @@ Decoder::Decoder(RasterImage* aImage)
|
||||
, mFrameCount(0)
|
||||
, mFailCode(NS_OK)
|
||||
, mInitialized(false)
|
||||
, mSizeDecode(false)
|
||||
, mMetadataDecode(false)
|
||||
, mInFrame(false)
|
||||
, mIsAnimated(false)
|
||||
{ }
|
||||
@ -169,7 +169,7 @@ Decoder::Write(const char* aBuffer, uint32_t aCount)
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsSizeDecode() && HasSize()) {
|
||||
if (IsMetadataDecode() && HasSize()) {
|
||||
// More data came in since we found the size. We have nothing to do here.
|
||||
return;
|
||||
}
|
||||
@ -200,7 +200,7 @@ Decoder::CompleteDecode()
|
||||
// early because of low-memory conditions or losing a race with another
|
||||
// decoder, we need to send teardown notifications (and report an error to the
|
||||
// console later).
|
||||
if (!IsSizeDecode() && !mDecodeDone && !WasAborted()) {
|
||||
if (!IsMetadataDecode() && !mDecodeDone && !WasAborted()) {
|
||||
mShouldReportError = true;
|
||||
|
||||
// If we only have a data error, we're usable if we have at least one
|
||||
@ -218,7 +218,7 @@ Decoder::CompleteDecode()
|
||||
PostDecodeDone();
|
||||
} else {
|
||||
// We're not usable. Record some final progress indicating the error.
|
||||
if (!IsSizeDecode()) {
|
||||
if (!IsMetadataDecode()) {
|
||||
mProgress |= FLAG_DECODE_COMPLETE;
|
||||
}
|
||||
mProgress |= FLAG_HAS_ERROR;
|
||||
@ -269,7 +269,7 @@ Decoder::Finish()
|
||||
SetSizeOnImage();
|
||||
}
|
||||
|
||||
if (mDecodeDone && !IsSizeDecode()) {
|
||||
if (mDecodeDone && !IsMetadataDecode()) {
|
||||
MOZ_ASSERT(HasError() || mCurrentFrame, "Should have an error or a frame");
|
||||
|
||||
// If this image wasn't animated and isn't a transient image, mark its frame
|
||||
@ -424,7 +424,6 @@ Decoder::SetSizeOnImage()
|
||||
*/
|
||||
|
||||
void Decoder::InitInternal() { }
|
||||
void Decoder::WriteInternal(const char* aBuffer, uint32_t aCount) { }
|
||||
void Decoder::FinishInternal() { }
|
||||
void Decoder::FinishWithErrorInternal() { }
|
||||
|
||||
@ -478,7 +477,7 @@ Decoder::PostFrameStop(Opacity aFrameOpacity /* = Opacity::TRANSPARENT */,
|
||||
BlendMethod aBlendMethod /* = BlendMethod::OVER */)
|
||||
{
|
||||
// We should be mid-frame
|
||||
MOZ_ASSERT(!IsSizeDecode(), "Stopping frame during a size decode");
|
||||
MOZ_ASSERT(!IsMetadataDecode(), "Stopping frame during metadata decode");
|
||||
MOZ_ASSERT(mInFrame, "Stopping frame when we didn't start one");
|
||||
MOZ_ASSERT(mCurrentFrame, "Stopping frame when we don't have one");
|
||||
|
||||
@ -517,7 +516,7 @@ Decoder::PostInvalidation(const nsIntRect& aRect,
|
||||
void
|
||||
Decoder::PostDecodeDone(int32_t aLoopCount /* = 0 */)
|
||||
{
|
||||
MOZ_ASSERT(!IsSizeDecode(), "Can't be done with decoding with size decode!");
|
||||
MOZ_ASSERT(!IsMetadataDecode(), "Done with decoding in metadata decode");
|
||||
MOZ_ASSERT(!mInFrame, "Can't be done decoding if we're mid-frame!");
|
||||
MOZ_ASSERT(!mDecodeDone, "Decode already done!");
|
||||
mDecodeDone = true;
|
||||
|
@ -97,15 +97,17 @@ public:
|
||||
* State.
|
||||
*/
|
||||
|
||||
// If we're doing a "size decode", we more or less pass through the image
|
||||
// data, stopping only to scoop out the image dimensions. A size decode
|
||||
// must be enabled by SetSizeDecode() _before_calling Init().
|
||||
bool IsSizeDecode() { return mSizeDecode; }
|
||||
void SetSizeDecode(bool aSizeDecode)
|
||||
/**
|
||||
* If we're doing a metadata decode, we only decode the image's headers, which
|
||||
* is enough to determine the image's intrinsic size. A metadata decode is
|
||||
* enabled by calling SetMetadataDecode() *before* calling Init().
|
||||
*/
|
||||
void SetMetadataDecode(bool aMetadataDecode)
|
||||
{
|
||||
MOZ_ASSERT(!mInitialized, "Shouldn't be initialized yet");
|
||||
mSizeDecode = aSizeDecode;
|
||||
mMetadataDecode = aMetadataDecode;
|
||||
}
|
||||
bool IsMetadataDecode() { return mMetadataDecode; }
|
||||
|
||||
/**
|
||||
* If this decoder supports downscale-during-decode, sets the target size that
|
||||
@ -209,7 +211,8 @@ public:
|
||||
|
||||
bool GetDecodeDone() const
|
||||
{
|
||||
return mDecodeDone || (mSizeDecode && HasSize()) || HasError() || mDataDone;
|
||||
return mDecodeDone || (mMetadataDecode && HasSize()) ||
|
||||
HasError() || mDataDone;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -282,7 +285,7 @@ protected:
|
||||
* only these methods.
|
||||
*/
|
||||
virtual void InitInternal();
|
||||
virtual void WriteInternal(const char* aBuffer, uint32_t aCount);
|
||||
virtual void WriteInternal(const char* aBuffer, uint32_t aCount) = 0;
|
||||
virtual void FinishInternal();
|
||||
virtual void FinishWithErrorInternal();
|
||||
|
||||
@ -423,7 +426,7 @@ private:
|
||||
nsresult mFailCode;
|
||||
|
||||
bool mInitialized;
|
||||
bool mSizeDecode;
|
||||
bool mMetadataDecode;
|
||||
bool mInFrame;
|
||||
bool mIsAnimated;
|
||||
};
|
||||
|
177
image/DecoderFactory.cpp
Normal file
177
image/DecoderFactory.cpp
Normal file
@ -0,0 +1,177 @@
|
||||
/* -*- 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 "DecoderFactory.h"
|
||||
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nsRefPtr.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include "Decoder.h"
|
||||
#include "nsPNGDecoder.h"
|
||||
#include "nsGIFDecoder2.h"
|
||||
#include "nsJPEGDecoder.h"
|
||||
#include "nsBMPDecoder.h"
|
||||
#include "nsICODecoder.h"
|
||||
#include "nsIconDecoder.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace gfx;
|
||||
|
||||
namespace image {
|
||||
|
||||
/* static */ DecoderType
|
||||
DecoderFactory::GetDecoderType(const char* aMimeType)
|
||||
{
|
||||
// By default we don't know.
|
||||
DecoderType type = DecoderType::UNKNOWN;
|
||||
|
||||
// PNG
|
||||
if (!strcmp(aMimeType, IMAGE_PNG)) {
|
||||
type = DecoderType::PNG;
|
||||
} else if (!strcmp(aMimeType, IMAGE_X_PNG)) {
|
||||
type = DecoderType::PNG;
|
||||
|
||||
// GIF
|
||||
} else if (!strcmp(aMimeType, IMAGE_GIF)) {
|
||||
type = DecoderType::GIF;
|
||||
|
||||
// JPEG
|
||||
} else if (!strcmp(aMimeType, IMAGE_JPEG)) {
|
||||
type = DecoderType::JPEG;
|
||||
} else if (!strcmp(aMimeType, IMAGE_PJPEG)) {
|
||||
type = DecoderType::JPEG;
|
||||
} else if (!strcmp(aMimeType, IMAGE_JPG)) {
|
||||
type = DecoderType::JPEG;
|
||||
|
||||
// BMP
|
||||
} else if (!strcmp(aMimeType, IMAGE_BMP)) {
|
||||
type = DecoderType::BMP;
|
||||
} else if (!strcmp(aMimeType, IMAGE_BMP_MS)) {
|
||||
type = DecoderType::BMP;
|
||||
|
||||
// ICO
|
||||
} else if (!strcmp(aMimeType, IMAGE_ICO)) {
|
||||
type = DecoderType::ICO;
|
||||
} else if (!strcmp(aMimeType, IMAGE_ICO_MS)) {
|
||||
type = DecoderType::ICO;
|
||||
|
||||
// Icon
|
||||
} else if (!strcmp(aMimeType, IMAGE_ICON_MS)) {
|
||||
type = DecoderType::ICON;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Decoder>
|
||||
DecoderFactory::GetDecoder(DecoderType aType,
|
||||
RasterImage* aImage,
|
||||
bool aIsRedecode)
|
||||
{
|
||||
nsRefPtr<Decoder> decoder;
|
||||
|
||||
switch (aType) {
|
||||
case DecoderType::PNG:
|
||||
decoder = new nsPNGDecoder(aImage);
|
||||
break;
|
||||
case DecoderType::GIF:
|
||||
decoder = new nsGIFDecoder2(aImage);
|
||||
break;
|
||||
case DecoderType::JPEG:
|
||||
// If we have all the data we don't want to waste cpu time doing
|
||||
// a progressive decode.
|
||||
decoder = new nsJPEGDecoder(aImage,
|
||||
aIsRedecode ? Decoder::SEQUENTIAL
|
||||
: Decoder::PROGRESSIVE);
|
||||
break;
|
||||
case DecoderType::BMP:
|
||||
decoder = new nsBMPDecoder(aImage);
|
||||
break;
|
||||
case DecoderType::ICO:
|
||||
decoder = new nsICODecoder(aImage);
|
||||
break;
|
||||
case DecoderType::ICON:
|
||||
decoder = new nsIconDecoder(aImage);
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Unknown decoder type");
|
||||
}
|
||||
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Decoder>
|
||||
DecoderFactory::CreateDecoder(DecoderType aType,
|
||||
RasterImage* aImage,
|
||||
SourceBuffer* aSourceBuffer,
|
||||
const Maybe<IntSize>& aTargetSize,
|
||||
uint32_t aFlags,
|
||||
bool aIsRedecode,
|
||||
bool aImageIsTransient,
|
||||
bool aImageIsLocked)
|
||||
{
|
||||
if (aType == DecoderType::UNKNOWN) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Decoder> decoder = GetDecoder(aType, aImage, aIsRedecode);
|
||||
MOZ_ASSERT(decoder, "Should have a decoder now");
|
||||
|
||||
// Initialize the decoder.
|
||||
decoder->SetMetadataDecode(false);
|
||||
decoder->SetIterator(aSourceBuffer->Iterator());
|
||||
decoder->SetFlags(aFlags);
|
||||
decoder->SetSendPartialInvalidations(!aIsRedecode);
|
||||
decoder->SetImageIsTransient(aImageIsTransient);
|
||||
|
||||
if (aImageIsLocked) {
|
||||
decoder->SetImageIsLocked();
|
||||
}
|
||||
|
||||
// Set a target size for downscale-during-decode if applicable.
|
||||
if (aTargetSize) {
|
||||
DebugOnly<nsresult> rv = decoder->SetTargetSize(*aTargetSize);
|
||||
MOZ_ASSERT(nsresult(rv) != NS_ERROR_NOT_AVAILABLE,
|
||||
"We're downscale-during-decode but decoder doesn't support it?");
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "Bad downscale-during-decode target size?");
|
||||
}
|
||||
|
||||
decoder->Init();
|
||||
if (NS_FAILED(decoder->GetDecoderError())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Decoder>
|
||||
DecoderFactory::CreateMetadataDecoder(DecoderType aType,
|
||||
RasterImage* aImage,
|
||||
SourceBuffer* aSourceBuffer)
|
||||
{
|
||||
if (aType == DecoderType::UNKNOWN) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Decoder> decoder =
|
||||
GetDecoder(aType, aImage, /* aIsRedecode = */ false);
|
||||
MOZ_ASSERT(decoder, "Should have a decoder now");
|
||||
|
||||
// Initialize the decoder.
|
||||
decoder->SetMetadataDecode(true);
|
||||
decoder->SetIterator(aSourceBuffer->Iterator());
|
||||
|
||||
decoder->Init();
|
||||
if (NS_FAILED(decoder->GetDecoderError())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
} // namespace image
|
||||
} // namespace mozilla
|
106
image/DecoderFactory.h
Normal file
106
image/DecoderFactory.h
Normal file
@ -0,0 +1,106 @@
|
||||
/* -*- 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_image_DecoderFactory_h
|
||||
#define mozilla_image_DecoderFactory_h
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsACString;
|
||||
|
||||
namespace mozilla {
|
||||
namespace image {
|
||||
|
||||
class Decoder;
|
||||
class RasterImage;
|
||||
class SourceBuffer;
|
||||
|
||||
enum class DecoderType
|
||||
{
|
||||
PNG,
|
||||
GIF,
|
||||
JPEG,
|
||||
BMP,
|
||||
ICO,
|
||||
ICON,
|
||||
UNKNOWN
|
||||
};
|
||||
|
||||
class DecoderFactory
|
||||
{
|
||||
public:
|
||||
/// @return the type of decoder which is appropriate for @aMimeType.
|
||||
static DecoderType GetDecoderType(const char* aMimeType);
|
||||
|
||||
/**
|
||||
* Creates and initializes a decoder of type @aType. The decoder will send
|
||||
* notifications to @aImage.
|
||||
*
|
||||
* XXX(seth): @aIsRedecode, @aImageIsTransient, and @aImageIsLocked should
|
||||
* really be part of @aFlags. This requires changes to the way that decoder
|
||||
* flags work, though. See bug 1185800.
|
||||
*
|
||||
* @param aType Which type of decoder to create - JPEG, PNG, etc.
|
||||
* @param aImage The image will own the decoder and which should receive
|
||||
* notifications as decoding progresses.
|
||||
* @param aSourceBuffer The SourceBuffer which the decoder will read its data
|
||||
* from.
|
||||
* @param aTargetSize If not Nothing(), the target size which the image should
|
||||
* be scaled to during decoding. It's an error to specify
|
||||
* a target size for a decoder type which doesn't support
|
||||
* downscale-during-decode.
|
||||
* @param aFlags Flags specifying what type of output the decoder should
|
||||
* produce; see GetDecodeFlags() in RasterImage.h.
|
||||
* @param aIsRedecode Specify 'true' if this image has been decoded before.
|
||||
* @param aImageIsTransient Specify 'true' if this image is transient.
|
||||
* @param aImageIsLocked Specify 'true' if this image is locked for the
|
||||
* lifetime of this decoder, and should be unlocked
|
||||
* when the decoder finishes.
|
||||
*/
|
||||
static already_AddRefed<Decoder>
|
||||
CreateDecoder(DecoderType aType,
|
||||
RasterImage* aImage,
|
||||
SourceBuffer* aSourceBuffer,
|
||||
const Maybe<gfx::IntSize>& aTargetSize,
|
||||
uint32_t aFlags,
|
||||
bool aIsRedecode,
|
||||
bool aImageIsTransient,
|
||||
bool aImageIsLocked);
|
||||
|
||||
/**
|
||||
* Creates and initializes a metadata decoder of type @aType. This decoder
|
||||
* will only decode the image's header, extracting metadata like the size of
|
||||
* the image. No actual image data will be decoded and no surfaces will be
|
||||
* allocated. The decoder will send notifications to @aImage.
|
||||
*
|
||||
* @param aType Which type of decoder to create - JPEG, PNG, etc.
|
||||
* @param aImage The image will own the decoder and which should receive
|
||||
* notifications as decoding progresses.
|
||||
* @param aSourceBuffer The SourceBuffer which the decoder will read its data
|
||||
* from.
|
||||
*/
|
||||
static already_AddRefed<Decoder>
|
||||
CreateMetadataDecoder(DecoderType aType,
|
||||
RasterImage* aImage,
|
||||
SourceBuffer* aSourceBuffer);
|
||||
|
||||
private:
|
||||
virtual ~DecoderFactory() = 0;
|
||||
|
||||
/**
|
||||
* An internal method which allocates a new decoder of the requested @aType.
|
||||
*/
|
||||
static already_AddRefed<Decoder> GetDecoder(DecoderType aType,
|
||||
RasterImage* aImage,
|
||||
bool aIsRedecode);
|
||||
};
|
||||
|
||||
} // namespace image
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_image_DecoderFactory_h
|
@ -3,8 +3,6 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsMimeTypes.h"
|
||||
|
||||
#include "Image.h"
|
||||
#include "nsRefreshDriver.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
@ -69,52 +67,6 @@ ImageResource::~ImageResource()
|
||||
mProgressTracker->ResetImage();
|
||||
}
|
||||
|
||||
// Translates a mimetype into a concrete decoder
|
||||
Image::eDecoderType
|
||||
Image::GetDecoderType(const char* aMimeType)
|
||||
{
|
||||
// By default we don't know
|
||||
eDecoderType rv = eDecoderType_unknown;
|
||||
|
||||
// PNG
|
||||
if (!strcmp(aMimeType, IMAGE_PNG)) {
|
||||
rv = eDecoderType_png;
|
||||
|
||||
} else if (!strcmp(aMimeType, IMAGE_X_PNG)) {
|
||||
rv = eDecoderType_png;
|
||||
|
||||
// GIF
|
||||
} else if (!strcmp(aMimeType, IMAGE_GIF)) {
|
||||
rv = eDecoderType_gif;
|
||||
|
||||
// JPEG
|
||||
} else if (!strcmp(aMimeType, IMAGE_JPEG)) {
|
||||
rv = eDecoderType_jpeg;
|
||||
} else if (!strcmp(aMimeType, IMAGE_PJPEG)) {
|
||||
rv = eDecoderType_jpeg;
|
||||
} else if (!strcmp(aMimeType, IMAGE_JPG)) {
|
||||
rv = eDecoderType_jpeg;
|
||||
|
||||
// BMP
|
||||
} else if (!strcmp(aMimeType, IMAGE_BMP)) {
|
||||
rv = eDecoderType_bmp;
|
||||
} else if (!strcmp(aMimeType, IMAGE_BMP_MS)) {
|
||||
rv = eDecoderType_bmp;
|
||||
|
||||
// ICO
|
||||
} else if (!strcmp(aMimeType, IMAGE_ICO)) {
|
||||
rv = eDecoderType_ico;
|
||||
} else if (!strcmp(aMimeType, IMAGE_ICO_MS)) {
|
||||
rv = eDecoderType_ico;
|
||||
|
||||
// Icon
|
||||
} else if (!strcmp(aMimeType, IMAGE_ICON_MS)) {
|
||||
rv = eDecoderType_icon;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
ImageResource::IncrementAnimationConsumers()
|
||||
{
|
||||
|
@ -129,18 +129,6 @@ private:
|
||||
class Image : public imgIContainer
|
||||
{
|
||||
public:
|
||||
// Mimetype translation
|
||||
enum eDecoderType {
|
||||
eDecoderType_png = 0,
|
||||
eDecoderType_gif = 1,
|
||||
eDecoderType_jpeg = 2,
|
||||
eDecoderType_bmp = 3,
|
||||
eDecoderType_ico = 4,
|
||||
eDecoderType_icon = 5,
|
||||
eDecoderType_unknown = 6
|
||||
};
|
||||
static eDecoderType GetDecoderType(const char* aMimeType);
|
||||
|
||||
/**
|
||||
* Flags for Image initialization.
|
||||
*
|
||||
|
@ -21,18 +21,12 @@
|
||||
#include "ImageRegion.h"
|
||||
#include "Layers.h"
|
||||
#include "LookupResult.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "SourceBuffer.h"
|
||||
#include "SurfaceCache.h"
|
||||
#include "FrameAnimator.h"
|
||||
|
||||
#include "nsPNGDecoder.h"
|
||||
#include "nsGIFDecoder2.h"
|
||||
#include "nsJPEGDecoder.h"
|
||||
#include "nsBMPDecoder.h"
|
||||
#include "nsICODecoder.h"
|
||||
#include "nsIconDecoder.h"
|
||||
|
||||
#include "gfxContext.h"
|
||||
|
||||
#include "mozilla/gfx/2D.h"
|
||||
@ -282,8 +276,8 @@ RasterImage::Init(const char* aMimeType,
|
||||
// Use the MIME type to select a decoder type, and make sure there *is* a
|
||||
// decoder for this MIME type.
|
||||
NS_ENSURE_ARG_POINTER(aMimeType);
|
||||
mDecoderType = GetDecoderType(aMimeType);
|
||||
if (mDecoderType == eDecoderType_unknown) {
|
||||
mDecoderType = DecoderFactory::GetDecoderType(aMimeType);
|
||||
if (mDecoderType == DecoderType::UNKNOWN) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@ -294,8 +288,8 @@ RasterImage::Init(const char* aMimeType,
|
||||
}
|
||||
|
||||
if (!mSyncLoad) {
|
||||
// Create an async size decoder and verify that we succeed in doing so.
|
||||
nsresult rv = Decode(Nothing(), DECODE_FLAGS_DEFAULT);
|
||||
// Create an async metadata decoder and verify we succeed in doing so.
|
||||
nsresult rv = DecodeMetadata(DECODE_FLAGS_DEFAULT);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -488,7 +482,7 @@ RasterImage::LookupFrame(uint32_t aFrameNum,
|
||||
// yet.) Trigger decoding so it'll be available next time.
|
||||
MOZ_ASSERT(!mAnim, "Animated frames should be locked");
|
||||
|
||||
Decode(Some(requestedSize), aFlags);
|
||||
Decode(requestedSize, aFlags);
|
||||
|
||||
// If we can sync decode, we should already have the frame.
|
||||
if (aFlags & FLAG_SYNC_DECODE) {
|
||||
@ -1166,21 +1160,22 @@ RasterImage::OnImageDataComplete(nsIRequest*, nsISupports*, nsresult aStatus,
|
||||
// Let decoders know that there won't be any more data coming.
|
||||
mSourceBuffer->Complete(aStatus);
|
||||
|
||||
// Allow a synchronous size decode if mSyncLoad was set, or if we're running
|
||||
// on a single thread (in which case waiting for the async size decoder could
|
||||
// delay this image's load event quite a bit), or if this image is transient.
|
||||
bool canSyncSizeDecode = mSyncLoad || mTransient ||
|
||||
DecodePool::NumberOfCores() < 2;
|
||||
// Allow a synchronous metadata decode if mSyncLoad was set, or if we're
|
||||
// running on a single thread (in which case waiting for the async metadata
|
||||
// decoder could delay this image's load event quite a bit), or if this image
|
||||
// is transient.
|
||||
bool canSyncDecodeMetadata = mSyncLoad || mTransient ||
|
||||
DecodePool::NumberOfCores() < 2;
|
||||
|
||||
if (canSyncSizeDecode && !mHasSize) {
|
||||
if (canSyncDecodeMetadata && !mHasSize) {
|
||||
// We're loading this image synchronously, so it needs to be usable after
|
||||
// this call returns. Since we haven't gotten our size yet, we need to do a
|
||||
// synchronous size decode here.
|
||||
Decode(Nothing(), FLAG_SYNC_DECODE);
|
||||
// synchronous metadata decode here.
|
||||
DecodeMetadata(FLAG_SYNC_DECODE);
|
||||
}
|
||||
|
||||
// Determine our final status, giving precedence to Necko failure codes. We
|
||||
// check after running the size decode above in case it triggered an error.
|
||||
// check after running the metadata decode in case it triggered an error.
|
||||
nsresult finalStatus = mError ? NS_ERROR_FAILURE : NS_OK;
|
||||
if (NS_FAILED(aStatus)) {
|
||||
finalStatus = aStatus;
|
||||
@ -1195,7 +1190,8 @@ RasterImage::OnImageDataComplete(nsIRequest*, nsISupports*, nsresult aStatus,
|
||||
|
||||
if (!mHasSize && !mError) {
|
||||
// We don't have our size yet, so we'll fire the load event in SetSize().
|
||||
MOZ_ASSERT(!canSyncSizeDecode, "Firing load async but canSyncSizeDecode?");
|
||||
MOZ_ASSERT(!canSyncDecodeMetadata,
|
||||
"Firing load async after metadata sync decode?");
|
||||
NotifyProgress(FLAG_ONLOAD_BLOCKED);
|
||||
mLoadProgress = Some(loadProgress);
|
||||
return finalStatus;
|
||||
@ -1325,117 +1321,6 @@ RasterImage::CanDiscard() {
|
||||
!mAnim; // Can never discard animated images
|
||||
}
|
||||
|
||||
// Sets up a decoder for this image.
|
||||
already_AddRefed<Decoder>
|
||||
RasterImage::CreateDecoder(const Maybe<IntSize>& aSize, uint32_t aFlags)
|
||||
{
|
||||
// Make sure we actually get size before doing a full decode.
|
||||
if (aSize) {
|
||||
MOZ_ASSERT(mHasSize, "Must do a size decode before a full decode!");
|
||||
MOZ_ASSERT(mDownscaleDuringDecode || *aSize == mSize,
|
||||
"Can only decode to our intrinsic size if we're not allowed to "
|
||||
"downscale-during-decode");
|
||||
} else {
|
||||
MOZ_ASSERT(!mHasSize, "Should not do unnecessary size decodes");
|
||||
}
|
||||
|
||||
// Instantiate the appropriate decoder.
|
||||
nsRefPtr<Decoder> decoder;
|
||||
switch (mDecoderType) {
|
||||
case eDecoderType_png:
|
||||
decoder = new nsPNGDecoder(this);
|
||||
break;
|
||||
case eDecoderType_gif:
|
||||
decoder = new nsGIFDecoder2(this);
|
||||
break;
|
||||
case eDecoderType_jpeg:
|
||||
// If we have all the data we don't want to waste cpu time doing
|
||||
// a progressive decode.
|
||||
decoder = new nsJPEGDecoder(this,
|
||||
mHasBeenDecoded ? Decoder::SEQUENTIAL :
|
||||
Decoder::PROGRESSIVE);
|
||||
break;
|
||||
case eDecoderType_bmp:
|
||||
decoder = new nsBMPDecoder(this);
|
||||
break;
|
||||
case eDecoderType_ico:
|
||||
decoder = new nsICODecoder(this);
|
||||
break;
|
||||
case eDecoderType_icon:
|
||||
decoder = new nsIconDecoder(this);
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Unknown decoder type");
|
||||
}
|
||||
|
||||
MOZ_ASSERT(decoder, "Should have a decoder now");
|
||||
|
||||
// Initialize the decoder.
|
||||
decoder->SetSizeDecode(!aSize);
|
||||
decoder->SetSendPartialInvalidations(!mHasBeenDecoded);
|
||||
decoder->SetImageIsTransient(mTransient);
|
||||
decoder->SetFlags(aFlags);
|
||||
|
||||
if (!mHasBeenDecoded && aSize) {
|
||||
// Lock the image while we're decoding, so that it doesn't get evicted from
|
||||
// the SurfaceCache before we have a chance to realize that it's animated.
|
||||
// The corresponding unlock happens in FinalizeDecoder.
|
||||
LockImage();
|
||||
decoder->SetImageIsLocked();
|
||||
}
|
||||
|
||||
decoder->SetIterator(mSourceBuffer->Iterator());
|
||||
|
||||
// Set a target size for downscale-during-decode if applicable.
|
||||
if (mDownscaleDuringDecode && aSize && *aSize != mSize) {
|
||||
DebugOnly<nsresult> rv = decoder->SetTargetSize(*aSize);
|
||||
MOZ_ASSERT(nsresult(rv) != NS_ERROR_NOT_AVAILABLE,
|
||||
"We're downscale-during-decode but decoder doesn't support it?");
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "Bad downscale-during-decode target size?");
|
||||
}
|
||||
|
||||
decoder->Init();
|
||||
|
||||
if (NS_FAILED(decoder->GetDecoderError())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aSize) {
|
||||
// Add a placeholder for the first frame to the SurfaceCache so we won't
|
||||
// trigger any more decoders with the same parameters.
|
||||
InsertOutcome outcome =
|
||||
SurfaceCache::InsertPlaceholder(ImageKey(this),
|
||||
RasterSurfaceKey(*aSize,
|
||||
decoder->GetDecodeFlags(),
|
||||
/* aFrameNum = */ 0));
|
||||
if (outcome != InsertOutcome::SUCCESS) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!aSize) {
|
||||
Telemetry::GetHistogramById(
|
||||
Telemetry::IMAGE_DECODE_COUNT)->Subtract(mDecodeCount);
|
||||
mDecodeCount++;
|
||||
Telemetry::GetHistogramById(
|
||||
Telemetry::IMAGE_DECODE_COUNT)->Add(mDecodeCount);
|
||||
|
||||
if (mDecodeCount > sMaxDecodeCount) {
|
||||
// Don't subtract out 0 from the histogram, because that causes its count
|
||||
// to go negative, which is not kosher.
|
||||
if (sMaxDecodeCount > 0) {
|
||||
Telemetry::GetHistogramById(
|
||||
Telemetry::IMAGE_MAX_DECODE_COUNT)->Subtract(sMaxDecodeCount);
|
||||
}
|
||||
sMaxDecodeCount = mDecodeCount;
|
||||
Telemetry::GetHistogramById(
|
||||
Telemetry::IMAGE_MAX_DECODE_COUNT)->Add(sMaxDecodeCount);
|
||||
}
|
||||
}
|
||||
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
/* void requestDecode() */
|
||||
NS_IMETHODIMP
|
||||
@ -1486,22 +1371,52 @@ RasterImage::RequestDecodeForSize(const IntSize& aSize, uint32_t aFlags)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RasterImage::Decode(const Maybe<IntSize>& aSize, uint32_t aFlags)
|
||||
static void
|
||||
LaunchDecoder(Decoder* aDecoder,
|
||||
RasterImage* aImage,
|
||||
uint32_t aFlags,
|
||||
bool aHaveSourceData)
|
||||
{
|
||||
MOZ_ASSERT(!aSize || NS_IsMainThread());
|
||||
if (aHaveSourceData) {
|
||||
// If we have all the data, we can sync decode if requested.
|
||||
if (aFlags & imgIContainer::FLAG_SYNC_DECODE) {
|
||||
PROFILER_LABEL_PRINTF("DecodePool", "SyncDecodeIfPossible",
|
||||
js::ProfileEntry::Category::GRAPHICS,
|
||||
"%s", aImage->GetURIString().get());
|
||||
DecodePool::Singleton()->SyncDecodeIfPossible(aDecoder);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aFlags & imgIContainer::FLAG_SYNC_DECODE_IF_FAST) {
|
||||
PROFILER_LABEL_PRINTF("DecodePool", "SyncDecodeIfSmall",
|
||||
js::ProfileEntry::Category::GRAPHICS,
|
||||
"%s", aImage->GetURIString().get());
|
||||
DecodePool::Singleton()->SyncDecodeIfSmall(aDecoder);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Perform an async decode. We also take this path if we don't have all the
|
||||
// source data yet, since sync decoding is impossible in that situation.
|
||||
DecodePool::Singleton()->AsyncDecode(aDecoder);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RasterImage::Decode(const IntSize& aSize, uint32_t aFlags)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mError) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// If we don't have a size yet, we can't do any other decoding.
|
||||
if (!mHasSize && aSize) {
|
||||
if (!mHasSize) {
|
||||
mWantFullDecode = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mDownscaleDuringDecode && aSize) {
|
||||
if (mDownscaleDuringDecode) {
|
||||
// We're about to decode again, which may mean that some of the previous
|
||||
// sizes we've decoded at aren't useful anymore. We can allow them to
|
||||
// expire from the cache by unlocking them here. When the decode finishes,
|
||||
@ -1512,32 +1427,87 @@ RasterImage::Decode(const Maybe<IntSize>& aSize, uint32_t aFlags)
|
||||
SurfaceCache::UnlockSurfaces(ImageKey(this));
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mDownscaleDuringDecode || aSize == mSize,
|
||||
"Can only decode to our intrinsic size if we're not allowed to "
|
||||
"downscale-during-decode");
|
||||
|
||||
Maybe<IntSize> targetSize = mSize != aSize ? Some(aSize) : Nothing();
|
||||
|
||||
bool imageIsLocked = false;
|
||||
if (!mHasBeenDecoded) {
|
||||
// Lock the image while we're decoding, so that it doesn't get evicted from
|
||||
// the SurfaceCache before we have a chance to realize that it's animated.
|
||||
// The corresponding unlock happens in FinalizeDecoder.
|
||||
LockImage();
|
||||
imageIsLocked = true;
|
||||
}
|
||||
|
||||
// Create a decoder.
|
||||
nsRefPtr<Decoder> decoder = CreateDecoder(aSize, aFlags);
|
||||
nsRefPtr<Decoder> decoder =
|
||||
DecoderFactory::CreateDecoder(mDecoderType, this, mSourceBuffer, targetSize,
|
||||
aFlags, mHasBeenDecoded, mTransient,
|
||||
imageIsLocked);
|
||||
|
||||
// Make sure DecoderFactory was able to create a decoder successfully.
|
||||
if (!decoder) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (mHasSourceData) {
|
||||
// If we have all the data, we can sync decode if requested.
|
||||
if (aFlags & FLAG_SYNC_DECODE) {
|
||||
PROFILER_LABEL_PRINTF("DecodePool", "SyncDecodeIfPossible",
|
||||
js::ProfileEntry::Category::GRAPHICS, "%s", GetURIString().get());
|
||||
DecodePool::Singleton()->SyncDecodeIfPossible(decoder);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aFlags & FLAG_SYNC_DECODE_IF_FAST) {
|
||||
PROFILER_LABEL_PRINTF("DecodePool", "SyncDecodeIfSmall",
|
||||
js::ProfileEntry::Category::GRAPHICS, "%s", GetURIString().get());
|
||||
DecodePool::Singleton()->SyncDecodeIfSmall(decoder);
|
||||
return NS_OK;
|
||||
}
|
||||
// Add a placeholder for the first frame to the SurfaceCache so we won't
|
||||
// trigger any more decoders with the same parameters.
|
||||
InsertOutcome outcome =
|
||||
SurfaceCache::InsertPlaceholder(ImageKey(this),
|
||||
RasterSurfaceKey(aSize,
|
||||
decoder->GetDecodeFlags(),
|
||||
/* aFrameNum = */ 0));
|
||||
if (outcome != InsertOutcome::SUCCESS) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Perform an async decode. We also take this path if we don't have all the
|
||||
// source data yet, since sync decoding is impossible in that situation.
|
||||
DecodePool::Singleton()->AsyncDecode(decoder);
|
||||
// Report telemetry.
|
||||
Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)
|
||||
->Subtract(mDecodeCount);
|
||||
mDecodeCount++;
|
||||
Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)
|
||||
->Add(mDecodeCount);
|
||||
|
||||
if (mDecodeCount > sMaxDecodeCount) {
|
||||
// Don't subtract out 0 from the histogram, because that causes its count
|
||||
// to go negative, which is not kosher.
|
||||
if (sMaxDecodeCount > 0) {
|
||||
Telemetry::GetHistogramById(Telemetry::IMAGE_MAX_DECODE_COUNT)
|
||||
->Subtract(sMaxDecodeCount);
|
||||
}
|
||||
sMaxDecodeCount = mDecodeCount;
|
||||
Telemetry::GetHistogramById(Telemetry::IMAGE_MAX_DECODE_COUNT)
|
||||
->Add(sMaxDecodeCount);
|
||||
}
|
||||
|
||||
// We're ready to decode; start the decoder.
|
||||
LaunchDecoder(decoder, this, aFlags, mHasSourceData);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RasterImage::DecodeMetadata(uint32_t aFlags)
|
||||
{
|
||||
if (mError) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mHasSize, "Should not do unnecessary metadata decodes");
|
||||
|
||||
// Create a decoder.
|
||||
nsRefPtr<Decoder> decoder =
|
||||
DecoderFactory::CreateMetadataDecoder(mDecoderType, this, mSourceBuffer);
|
||||
|
||||
// Make sure DecoderFactory was able to create a decoder successfully.
|
||||
if (!decoder) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// We're ready to decode; start the decoder.
|
||||
LaunchDecoder(decoder, this, aFlags, mHasSourceData);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1556,13 +1526,13 @@ RasterImage::RecoverFromLossOfFrames(const IntSize& aSize, uint32_t aFlags)
|
||||
// Animated images require some special handling, because we normally require
|
||||
// that they never be discarded.
|
||||
if (mAnim) {
|
||||
Decode(Some(mSize), aFlags | FLAG_SYNC_DECODE);
|
||||
Decode(mSize, aFlags | FLAG_SYNC_DECODE);
|
||||
ResetAnimation();
|
||||
return;
|
||||
}
|
||||
|
||||
// For non-animated images, it's fine to recover using an async decode.
|
||||
Decode(Some(aSize), aFlags);
|
||||
Decode(aSize, aFlags);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -2048,17 +2018,17 @@ RasterImage::FinalizeDecoder(Decoder* aDecoder)
|
||||
aDecoder->TakeInvalidRect(),
|
||||
aDecoder->GetDecodeFlags());
|
||||
|
||||
bool wasSize = aDecoder->IsSizeDecode();
|
||||
bool wasMetadata = aDecoder->IsMetadataDecode();
|
||||
bool done = aDecoder->GetDecodeDone();
|
||||
|
||||
if (!wasSize && aDecoder->ChunkCount()) {
|
||||
if (!wasMetadata && aDecoder->ChunkCount()) {
|
||||
Telemetry::Accumulate(Telemetry::IMAGE_DECODE_CHUNKS,
|
||||
aDecoder->ChunkCount());
|
||||
}
|
||||
|
||||
if (done) {
|
||||
// Do some telemetry if this isn't a size decode.
|
||||
if (!wasSize) {
|
||||
// Do some telemetry if this isn't a metadata decode.
|
||||
if (!wasMetadata) {
|
||||
Telemetry::Accumulate(Telemetry::IMAGE_DECODE_TIME,
|
||||
int32_t(aDecoder->DecodeTime().ToMicroseconds()));
|
||||
|
||||
@ -2075,12 +2045,12 @@ RasterImage::FinalizeDecoder(Decoder* aDecoder)
|
||||
// Detect errors.
|
||||
if (aDecoder->HasError() && !aDecoder->WasAborted()) {
|
||||
DoError();
|
||||
} else if (wasSize && !mHasSize) {
|
||||
} else if (wasMetadata && !mHasSize) {
|
||||
DoError();
|
||||
}
|
||||
|
||||
// If we were waiting to fire the load event, go ahead and fire it now.
|
||||
if (mLoadProgress && wasSize) {
|
||||
if (mLoadProgress && wasMetadata) {
|
||||
NotifyForLoadEvent(*mLoadProgress);
|
||||
mLoadProgress = Nothing();
|
||||
NotifyProgress(FLAG_ONLOAD_UNBLOCKED);
|
||||
@ -2092,8 +2062,8 @@ RasterImage::FinalizeDecoder(Decoder* aDecoder)
|
||||
UnlockImage();
|
||||
}
|
||||
|
||||
// If we were a size decode and a full decode was requested, now's the time.
|
||||
if (done && wasSize && mWantFullDecode) {
|
||||
// If we were a metadata decode and a full decode was requested, do it.
|
||||
if (done && wasMetadata && mWantFullDecode) {
|
||||
mWantFullDecode = false;
|
||||
RequestDecode();
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "LookupResult.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "DecodePool.h"
|
||||
#include "DecoderFactory.h"
|
||||
#include "Orientation.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
@ -339,19 +340,23 @@ private:
|
||||
|
||||
/**
|
||||
* Creates and runs a decoder, either synchronously or asynchronously
|
||||
* according to @aFlags. Passes the provided target size @aSize and decode
|
||||
* flags @aFlags to CreateDecoder. If a size decode is desired, pass Nothing
|
||||
* for @aSize.
|
||||
* according to @aFlags. Decodes at the provided target size @aSize, using
|
||||
* decode flags @aFlags.
|
||||
*
|
||||
* It's an error to call Decode() before this image's intrinsic size is
|
||||
* available. A metadata decode must successfully complete first.
|
||||
*
|
||||
* If downscale-during-decode is not enabled for this image (i.e., if
|
||||
* mDownscaleDuringDecode is false), it is an error to pass an @aSize value
|
||||
* different from this image's intrinsic size.
|
||||
*/
|
||||
NS_IMETHOD Decode(const Maybe<nsIntSize>& aSize, uint32_t aFlags);
|
||||
NS_IMETHOD Decode(const gfx::IntSize& aSize, uint32_t aFlags);
|
||||
|
||||
/**
|
||||
* Creates a new decoder with a target size of @aSize and decode flags
|
||||
* specified by @aFlags. If a size decode is desired, pass Nothing() for
|
||||
* @aSize.
|
||||
* Creates and runs a metadata decoder, either synchronously or
|
||||
* asynchronously according to @aFlags.
|
||||
*/
|
||||
already_AddRefed<Decoder> CreateDecoder(const Maybe<nsIntSize>& aSize,
|
||||
uint32_t aFlags);
|
||||
NS_IMETHOD DecodeMetadata(uint32_t aFlags);
|
||||
|
||||
/**
|
||||
* In catastrophic circumstances like a GPU driver crash, we may lose our
|
||||
@ -376,7 +381,7 @@ private: // data
|
||||
uint32_t mLockCount;
|
||||
|
||||
// The type of decoder this image needs. Computed from the MIME type in Init().
|
||||
eDecoderType mDecoderType;
|
||||
DecoderType mDecoderType;
|
||||
|
||||
// How many times we've decoded this image.
|
||||
// This is currently only used for statistics
|
||||
@ -425,8 +430,8 @@ private: // data
|
||||
// of frames, or no more owning request
|
||||
bool mAnimationFinished:1;
|
||||
|
||||
// Whether, once we are done doing a size decode, we should immediately kick
|
||||
// off a full decode.
|
||||
// Whether, once we are done doing a metadata decode, we should immediately
|
||||
// kick off a full decode.
|
||||
bool mWantFullDecode:1;
|
||||
|
||||
TimeStamp mDrawStartTime;
|
||||
|
@ -32,9 +32,11 @@
|
||||
// undef the GetCurrentTime macro defined in WinBase.h from the MS Platform SDK
|
||||
#undef GetCurrentTime
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace dom;
|
||||
using namespace gfx;
|
||||
|
||||
namespace image {
|
||||
|
||||
NS_IMPL_ISUPPORTS(SVGDocumentWrapper,
|
||||
|
@ -39,7 +39,7 @@ GetBMPLog()
|
||||
nsBMPDecoder::nsBMPDecoder(RasterImage* aImage)
|
||||
: Decoder(aImage)
|
||||
, mPos(0)
|
||||
, mLOH(WIN_V3_HEADER_LENGTH)
|
||||
, mLOH(BMP_HEADER_LENGTH::WIN_V3)
|
||||
, mNumColors(0)
|
||||
, mColors(nullptr)
|
||||
, mRow(nullptr)
|
||||
@ -101,13 +101,14 @@ nsBMPDecoder::GetImageData()
|
||||
int32_t
|
||||
nsBMPDecoder::GetCompressedImageSize() const
|
||||
{
|
||||
// For everything except BI_RGB the header field must be defined
|
||||
if (mBIH.compression != BI_RGB) {
|
||||
// For everything except BMPINFOHEADER::RGB the header field must be defined
|
||||
if (mBIH.compression != BMPINFOHEADER::RGB) {
|
||||
return mBIH.image_size;
|
||||
}
|
||||
|
||||
// mBIH.image_size isn't always filled for BI_RGB so calculate it manually
|
||||
// The pixel array size is calculated based on extra 4 byte boundary padding
|
||||
// mBIH.image_size isn't always filled for BMPINFOHEADER::RGB so calculate it
|
||||
// manually. The pixel array size is calculated based on extra 4 byte
|
||||
// boundary padding.
|
||||
uint32_t rowSize = (mBIH.bpp * mBIH.width + 7) / 8; // + 7 to round up
|
||||
|
||||
// Pad to DWORD Boundary
|
||||
@ -140,7 +141,7 @@ nsBMPDecoder::FinishInternal()
|
||||
MOZ_ASSERT(GetFrameCount() <= 1, "Multiple BMP frames?");
|
||||
|
||||
// Send notifications if appropriate
|
||||
if (!IsSizeDecode() && HasSize()) {
|
||||
if (!IsMetadataDecode() && HasSize()) {
|
||||
|
||||
// Invalidate
|
||||
nsIntRect r(0, 0, mBIH.width, GetHeight());
|
||||
@ -206,39 +207,39 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
return;
|
||||
}
|
||||
|
||||
// This code assumes that mRawBuf == WIN_V3_INTERNAL_BIH_LENGTH
|
||||
// and that sizeof(mRawBuf) >= BFH_INTERNAL_LENGTH
|
||||
MOZ_ASSERT(sizeof(mRawBuf) == WIN_V3_INTERNAL_BIH_LENGTH);
|
||||
MOZ_ASSERT(sizeof(mRawBuf) >= BFH_INTERNAL_LENGTH);
|
||||
MOZ_ASSERT(OS2_INTERNAL_BIH_LENGTH < WIN_V3_INTERNAL_BIH_LENGTH);
|
||||
// This code assumes that mRawBuf == BIH_INTERNAL_LENGTH::WIN_V3
|
||||
// and that sizeof(mRawBuf) >= BMPFILEHEADER::INTERNAL_LENGTH
|
||||
MOZ_ASSERT(sizeof(mRawBuf) == BIH_INTERNAL_LENGTH::WIN_V3);
|
||||
MOZ_ASSERT(sizeof(mRawBuf) >= BMPFILEHEADER::INTERNAL_LENGTH);
|
||||
MOZ_ASSERT(BIH_INTERNAL_LENGTH::OS2 < BIH_INTERNAL_LENGTH::WIN_V3);
|
||||
|
||||
// This code also assumes it's working with a byte array
|
||||
MOZ_ASSERT(sizeof(mRawBuf[0]) == 1);
|
||||
|
||||
if (mPos < BFH_INTERNAL_LENGTH) { /* In BITMAPFILEHEADER */
|
||||
// BFH_INTERNAL_LENGTH < sizeof(mRawBuf)
|
||||
// mPos < BFH_INTERNAL_LENGTH
|
||||
// BFH_INTERNAL_LENGTH - mPos < sizeof(mRawBuf)
|
||||
// so toCopy <= BFH_INTERNAL_LENGTH
|
||||
if (mPos < BMPFILEHEADER::INTERNAL_LENGTH) { /* In BITMAPFILEHEADER */
|
||||
// BMPFILEHEADER::INTERNAL_LENGTH < sizeof(mRawBuf)
|
||||
// mPos < BMPFILEHEADER::INTERNAL_LENGTH
|
||||
// BMPFILEHEADER::INTERNAL_LENGTH - mPos < sizeof(mRawBuf)
|
||||
// so toCopy <= BMPFILEHEADER::INTERNAL_LENGTH
|
||||
// so toCopy < sizeof(mRawBuf)
|
||||
// so toCopy > 0 && toCopy <= BFH_INTERNAL_LENGTH
|
||||
uint32_t toCopy = BFH_INTERNAL_LENGTH - mPos;
|
||||
// so toCopy > 0 && toCopy <= BMPFILEHEADER::INTERNAL_LENGTH
|
||||
uint32_t toCopy = BMPFILEHEADER::INTERNAL_LENGTH - mPos;
|
||||
if (toCopy > aCount) {
|
||||
toCopy = aCount;
|
||||
}
|
||||
|
||||
// mRawBuf is a byte array of size WIN_V3_INTERNAL_BIH_LENGTH
|
||||
// mRawBuf is a byte array of size BIH_INTERNAL_LENGTH::WIN_V3
|
||||
// (verified above)
|
||||
// mPos is < BFH_INTERNAL_LENGTH
|
||||
// BFH_INTERNAL_LENGTH < WIN_V3_INTERNAL_BIH_LENGTH
|
||||
// mPos is < BMPFILEHEADER::INTERNAL_LENGTH
|
||||
// BMPFILEHEADER::INTERNAL_LENGTH < BIH_INTERNAL_LENGTH::WIN_V3
|
||||
// so mPos < sizeof(mRawBuf)
|
||||
//
|
||||
// Therefore this assert should hold
|
||||
MOZ_ASSERT(mPos < sizeof(mRawBuf));
|
||||
|
||||
// toCopy <= BFH_INTERNAL_LENGTH
|
||||
// mPos >= 0 && mPos < BFH_INTERNAL_LENGTH
|
||||
// sizeof(mRawBuf) >= BFH_INTERNAL_LENGTH (verified above)
|
||||
// toCopy <= BMPFILEHEADER::INTERNAL_LENGTH
|
||||
// mPos >= 0 && mPos < BMPFILEHEADER::INTERNAL_LENGTH
|
||||
// sizeof(mRawBuf) >= BMPFILEHEADER::INTERNAL_LENGTH (verified above)
|
||||
//
|
||||
// Therefore this assert should hold
|
||||
MOZ_ASSERT(mPos + toCopy <= sizeof(mRawBuf));
|
||||
@ -248,37 +249,37 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
aCount -= toCopy;
|
||||
aBuffer += toCopy;
|
||||
}
|
||||
if (mPos == BFH_INTERNAL_LENGTH) {
|
||||
if (mPos == BMPFILEHEADER::INTERNAL_LENGTH) {
|
||||
ProcessFileHeader();
|
||||
if (mBFH.signature[0] != 'B' || mBFH.signature[1] != 'M') {
|
||||
PostDataError();
|
||||
return;
|
||||
}
|
||||
if (mBFH.bihsize == OS2_BIH_LENGTH) {
|
||||
mLOH = OS2_HEADER_LENGTH;
|
||||
if (mBFH.bihsize == BIH_LENGTH::OS2) {
|
||||
mLOH = BMP_HEADER_LENGTH::OS2;
|
||||
}
|
||||
}
|
||||
if (mPos >= BFH_INTERNAL_LENGTH && mPos < mLOH) { /* In BITMAPINFOHEADER */
|
||||
// mLOH == WIN_V3_HEADER_LENGTH || mLOH == OS2_HEADER_LENGTH
|
||||
// OS2_HEADER_LENGTH < WIN_V3_HEADER_LENGTH
|
||||
// BFH_INTERNAL_LENGTH < OS2_HEADER_LENGTH
|
||||
// BFH_INTERNAL_LENGTH < WIN_V3_HEADER_LENGTH
|
||||
if (mPos >= BMPFILEHEADER::INTERNAL_LENGTH && mPos < mLOH) { /* In BITMAPINFOHEADER */
|
||||
// mLOH == BMP_HEADER_LENGTH::WIN_V3 || mLOH == BMP_HEADER_LENGTH::OS2
|
||||
// BMP_HEADER_LENGTH::OS2 < BMP_HEADER_LENGTH::WIN_V3
|
||||
// BMPFILEHEADER::INTERNAL_LENGTH < BMP_HEADER_LENGTH::OS2
|
||||
// BMPFILEHEADER::INTERNAL_LENGTH < BMP_HEADER_LENGTH::WIN_V3
|
||||
//
|
||||
// So toCopy is in the range
|
||||
// 1 to (WIN_V3_HEADER_LENGTH - BFH_INTERNAL_LENGTH)
|
||||
// or 1 to (OS2_HEADER_LENGTH - BFH_INTERNAL_LENGTH)
|
||||
// 1 to (BMP_HEADER_LENGTH::WIN_V3 - BMPFILEHEADER::INTERNAL_LENGTH)
|
||||
// or 1 to (BMP_HEADER_LENGTH::OS2 - BMPFILEHEADER::INTERNAL_LENGTH)
|
||||
//
|
||||
// But WIN_V3_HEADER_LENGTH =
|
||||
// BFH_INTERNAL_LENGTH + WIN_V3_INTERNAL_BIH_LENGTH
|
||||
// and OS2_HEADER_LENGTH = BFH_INTERNAL_LENGTH + OS2_INTERNAL_BIH_LENGTH
|
||||
// But BMP_HEADER_LENGTH::WIN_V3 =
|
||||
// BMPFILEHEADER::INTERNAL_LENGTH + BIH_INTERNAL_LENGTH::WIN_V3
|
||||
// and BMP_HEADER_LENGTH::OS2 = BMPFILEHEADER::INTERNAL_LENGTH + BIH_INTERNAL_LENGTH::OS2
|
||||
//
|
||||
// So toCopy is in the range
|
||||
//
|
||||
// 1 to WIN_V3_INTERNAL_BIH_LENGTH
|
||||
// or 1 to OS2_INTERNAL_BIH_LENGTH
|
||||
// and OS2_INTERNAL_BIH_LENGTH < WIN_V3_INTERNAL_BIH_LENGTH
|
||||
// 1 to BIH_INTERNAL_LENGTH::WIN_V3
|
||||
// or 1 to BIH_INTERNAL_LENGTH::OS2
|
||||
// and BIH_INTERNAL_LENGTH::OS2 < BIH_INTERNAL_LENGTH::WIN_V3
|
||||
//
|
||||
// sizeof(mRawBuf) = WIN_V3_INTERNAL_BIH_LENGTH
|
||||
// sizeof(mRawBuf) = BIH_INTERNAL_LENGTH::WIN_V3
|
||||
// so toCopy <= sizeof(mRawBuf)
|
||||
uint32_t toCopy = mLOH - mPos;
|
||||
if (toCopy > aCount) {
|
||||
@ -286,37 +287,37 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
}
|
||||
|
||||
// mPos is in the range
|
||||
// BFH_INTERNAL_LENGTH to (WIN_V3_HEADER_LENGTH - 1)
|
||||
// BMPFILEHEADER::INTERNAL_LENGTH to (BMP_HEADER_LENGTH::WIN_V3 - 1)
|
||||
//
|
||||
// offset is then in the range (see toCopy comments for more details)
|
||||
// 0 to (WIN_V3_INTERNAL_BIH_LENGTH - 1)
|
||||
// 0 to (BIH_INTERNAL_LENGTH::WIN_V3 - 1)
|
||||
//
|
||||
// sizeof(mRawBuf) is WIN_V3_INTERNAL_BIH_LENGTH so this
|
||||
// sizeof(mRawBuf) is BIH_INTERNAL_LENGTH::WIN_V3 so this
|
||||
// offset stays within bounds and this assert should hold
|
||||
const uint32_t offset = mPos - BFH_INTERNAL_LENGTH;
|
||||
const uint32_t offset = mPos - BMPFILEHEADER::INTERNAL_LENGTH;
|
||||
MOZ_ASSERT(offset < sizeof(mRawBuf));
|
||||
|
||||
// Two cases:
|
||||
// mPos = BFH_INTERNAL_LENGTH
|
||||
// mLOH = WIN_V3_HEADER_LENGTH
|
||||
// mPos = BMPFILEHEADER::INTERNAL_LENGTH
|
||||
// mLOH = BMP_HEADER_LENGTH::WIN_V3
|
||||
//
|
||||
// offset = 0
|
||||
// toCopy = WIN_V3_INTERNAL_BIH_LENGTH
|
||||
// toCopy = BIH_INTERNAL_LENGTH::WIN_V3
|
||||
//
|
||||
// This will be in the bounds of sizeof(mRawBuf)
|
||||
//
|
||||
// Second Case:
|
||||
// mPos = WIN_V3_HEADER_LENGTH - 1
|
||||
// mLOH = WIN_V3_HEADER_LENGTH
|
||||
// mPos = BMP_HEADER_LENGTH::WIN_V3 - 1
|
||||
// mLOH = BMP_HEADER_LENGTH::WIN_V3
|
||||
//
|
||||
// offset = WIN_V3_INTERNAL_BIH_LENGTH - 1
|
||||
// offset = BIH_INTERNAL_LENGTH::WIN_V3 - 1
|
||||
// toCopy = 1
|
||||
//
|
||||
// This will be in the bounds of sizeof(mRawBuf)
|
||||
//
|
||||
// As sizeof(mRawBuf) == WIN_V3_INTERNAL_BIH_LENGTH (verified above)
|
||||
// and WIN_V3_HEADER_LENGTH is the largest range of values. If mLOH
|
||||
// was equal to OS2_HEADER_LENGTH then the ranges are smaller.
|
||||
// As sizeof(mRawBuf) == BIH_INTERNAL_LENGTH::WIN_V3 (verified above)
|
||||
// and BMP_HEADER_LENGTH::WIN_V3 is the largest range of values. If mLOH
|
||||
// was equal to BMP_HEADER_LENGTH::OS2 then the ranges are smaller.
|
||||
MOZ_ASSERT(offset + toCopy <= sizeof(mRawBuf));
|
||||
|
||||
memcpy(mRawBuf + offset, aBuffer, toCopy);
|
||||
@ -368,9 +369,8 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
return;
|
||||
}
|
||||
|
||||
// We have the size. If we're doing a size decode, we got what
|
||||
// we came for.
|
||||
if (IsSizeDecode()) {
|
||||
// We have the size. If we're doing a metadata decode, we're done.
|
||||
if (IsMetadataDecode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -386,7 +386,8 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
// Always allocate 256 even though mNumColors might be smaller
|
||||
mColors = new colorTable[256];
|
||||
memset(mColors, 0, 256 * sizeof(colorTable));
|
||||
} else if (mBIH.compression != BI_BITFIELDS && mBIH.bpp == 16) {
|
||||
} else if (mBIH.compression != BMPINFOHEADER::BITFIELDS &&
|
||||
mBIH.bpp == 16) {
|
||||
// Use default 5-5-5 format
|
||||
mBitFields.red = 0x7C00;
|
||||
mBitFields.green = 0x03E0;
|
||||
@ -396,27 +397,30 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
|
||||
// Make sure we have a valid value for our supported compression modes
|
||||
// before adding the frame
|
||||
if (mBIH.compression != BI_RGB && mBIH.compression != BI_RLE8 &&
|
||||
mBIH.compression != BI_RLE4 && mBIH.compression != BI_BITFIELDS) {
|
||||
if (mBIH.compression != BMPINFOHEADER::RGB &&
|
||||
mBIH.compression != BMPINFOHEADER::RLE8 &&
|
||||
mBIH.compression != BMPINFOHEADER::RLE4 &&
|
||||
mBIH.compression != BMPINFOHEADER::BITFIELDS) {
|
||||
PostDataError();
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have RLE4 or RLE8 or BI_ALPHABITFIELDS, then ensure we
|
||||
// have valid BPP values before adding the frame
|
||||
if (mBIH.compression == BI_RLE8 && mBIH.bpp != 8) {
|
||||
// If we have RLE4 or RLE8 or BMPINFOHEADER::ALPHABITFIELDS, then ensure
|
||||
// we have valid BPP values before adding the frame.
|
||||
if (mBIH.compression == BMPINFOHEADER::RLE8 && mBIH.bpp != 8) {
|
||||
MOZ_LOG(GetBMPLog(), LogLevel::Debug,
|
||||
("BMP RLE8 compression only supports 8 bits per pixel\n"));
|
||||
PostDataError();
|
||||
return;
|
||||
}
|
||||
if (mBIH.compression == BI_RLE4 && mBIH.bpp != 4 && mBIH.bpp != 1) {
|
||||
if (mBIH.compression == BMPINFOHEADER::RLE4 &&
|
||||
mBIH.bpp != 4 && mBIH.bpp != 1) {
|
||||
MOZ_LOG(GetBMPLog(), LogLevel::Debug,
|
||||
("BMP RLE4 compression only supports 4 bits per pixel\n"));
|
||||
PostDataError();
|
||||
return;
|
||||
}
|
||||
if (mBIH.compression == BI_ALPHABITFIELDS &&
|
||||
if (mBIH.compression == BMPINFOHEADER::ALPHABITFIELDS &&
|
||||
mBIH.bpp != 16 && mBIH.bpp != 32) {
|
||||
MOZ_LOG(GetBMPLog(), LogLevel::Debug,
|
||||
("BMP ALPHABITFIELDS only supports 16 or 32 bits per pixel\n"
|
||||
@ -425,8 +429,9 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
return;
|
||||
}
|
||||
|
||||
if (mBIH.compression != BI_RLE8 && mBIH.compression != BI_RLE4 &&
|
||||
mBIH.compression != BI_ALPHABITFIELDS) {
|
||||
if (mBIH.compression != BMPINFOHEADER::RLE8 &&
|
||||
mBIH.compression != BMPINFOHEADER::RLE4 &&
|
||||
mBIH.compression != BMPINFOHEADER::ALPHABITFIELDS) {
|
||||
// mRow is not used for RLE encoded images
|
||||
mRow = (uint8_t*)malloc((mBIH.width * mBIH.bpp) / 8 + 4);
|
||||
// + 4 because the line is padded to a 4 bit boundary, but
|
||||
@ -447,7 +452,8 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
MOZ_ASSERT(mImageData, "Should have a buffer now");
|
||||
|
||||
// Prepare for transparency
|
||||
if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
|
||||
if ((mBIH.compression == BMPINFOHEADER::RLE8) ||
|
||||
(mBIH.compression == BMPINFOHEADER::RLE4)) {
|
||||
// Clear the image, as the RLE may jump over areas
|
||||
memset(mImageData, 0, mImageDataLength);
|
||||
}
|
||||
@ -455,7 +461,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
|
||||
if (mColors && mPos >= mLOH) {
|
||||
// OS/2 Bitmaps have no padding byte
|
||||
uint8_t bytesPerColor = (mBFH.bihsize == OS2_BIH_LENGTH) ? 3 : 4;
|
||||
uint8_t bytesPerColor = (mBFH.bihsize == BIH_LENGTH::OS2) ? 3 : 4;
|
||||
if (mPos < (mLOH + mNumColors * bytesPerColor)) {
|
||||
// Number of bytes already received
|
||||
uint32_t colorBytes = mPos - mLOH;
|
||||
@ -488,62 +494,62 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
at = (at + 1) % bytesPerColor;
|
||||
}
|
||||
}
|
||||
} else if (aCount && mBIH.compression == BI_BITFIELDS && mPos <
|
||||
(WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH)) {
|
||||
// If compression is used, this is a windows bitmap (compression
|
||||
// can't be used with OS/2 bitmaps),
|
||||
// hence we can use WIN_V3_HEADER_LENGTH instead of mLOH.
|
||||
// (verified below)
|
||||
} else if (aCount &&
|
||||
mBIH.compression == BMPINFOHEADER::BITFIELDS &&
|
||||
mPos < (BMP_HEADER_LENGTH::WIN_V3 + bitFields::LENGTH)) {
|
||||
// If compression is used, this is a windows bitmap (compression can't be
|
||||
// used with OS/2 bitmaps), hence we can use BMP_HEADER_LENGTH::WIN_V3
|
||||
// instead of mLOH. (verified below)
|
||||
|
||||
// If aCount != 0 then mPos should be >= mLOH due to the if statements
|
||||
// at the beginning of the function
|
||||
MOZ_ASSERT(mPos >= mLOH);
|
||||
MOZ_ASSERT(mLOH == WIN_V3_HEADER_LENGTH);
|
||||
MOZ_ASSERT(mLOH == BMP_HEADER_LENGTH::WIN_V3);
|
||||
|
||||
// mLOH == WIN_V3_HEADER_LENGTH (verified above)
|
||||
// mLOH == BMP_HEADER_LENGTH::WIN_V3 (verified above)
|
||||
// mPos >= mLOH (verified above)
|
||||
// mPos < WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH
|
||||
// mPos < BMP_HEADER_LENGTH::WIN_V3 + bitFields::LENGTH
|
||||
//
|
||||
// So toCopy is in the range
|
||||
// 0 to (BITFIELD_LENGTH - 1)
|
||||
uint32_t toCopy = (WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH) - mPos;
|
||||
// 0 to (bitFields::LENGTH - 1)
|
||||
uint32_t toCopy = (BMP_HEADER_LENGTH::WIN_V3 + bitFields::LENGTH) - mPos;
|
||||
if (toCopy > aCount) {
|
||||
toCopy = aCount;
|
||||
}
|
||||
|
||||
// mPos >= WIN_V3_HEADER_LENGTH
|
||||
// mPos < WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH
|
||||
// mPos >= BMP_HEADER_LENGTH::WIN_V3
|
||||
// mPos < BMP_HEADER_LENGTH::WIN_V3 + bitFields::LENGTH
|
||||
//
|
||||
// offset is in the range
|
||||
// 0 to (BITFIELD_LENGTH - 1)
|
||||
// 0 to (bitFields::LENGTH - 1)
|
||||
//
|
||||
// BITFIELD_LENGTH < WIN_V3_INTERNAL_BIH_LENGTH
|
||||
// and sizeof(mRawBuf) == WIN_V3_INTERNAL_BIH_LENGTH (verified at
|
||||
// bitFields::LENGTH < BIH_INTERNAL_LENGTH::WIN_V3
|
||||
// and sizeof(mRawBuf) == BIH_INTERNAL_LENGTH::WIN_V3 (verified at
|
||||
// top of function)
|
||||
//
|
||||
// Therefore this assert should hold
|
||||
const uint32_t offset = mPos - WIN_V3_HEADER_LENGTH;
|
||||
const uint32_t offset = mPos - BMP_HEADER_LENGTH::WIN_V3;
|
||||
MOZ_ASSERT(offset < sizeof(mRawBuf));
|
||||
|
||||
// Two cases:
|
||||
// mPos = WIN_V3_HEADER_LENGTH
|
||||
// mPos = BMP_HEADER_LENGTH::WIN_V3
|
||||
//
|
||||
// offset = 0
|
||||
// toCopy = BITFIELD_LENGTH
|
||||
// toCopy = bitFields::LENGTH
|
||||
//
|
||||
// This will be in the bounds of sizeof(mRawBuf)
|
||||
//
|
||||
// Second case:
|
||||
//
|
||||
// mPos = WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH - 1
|
||||
// mPos = BMP_HEADER_LENGTH::WIN_V3 + bitFields::LENGTH - 1
|
||||
//
|
||||
// offset = BITFIELD_LENGTH - 1
|
||||
// offset = bitFields::LENGTH - 1
|
||||
// toCopy = 1
|
||||
//
|
||||
// This will be in the bounds of sizeof(mRawBuf)
|
||||
//
|
||||
// As BITFIELD_LENGTH < WIN_V3_INTERNAL_BIH_LENGTH and
|
||||
// sizeof(mRawBuf) == WIN_V3_INTERNAL_BIH_LENGTH
|
||||
// As bitFields::LENGTH < BIH_INTERNAL_LENGTH::WIN_V3 and
|
||||
// sizeof(mRawBuf) == BIH_INTERNAL_LENGTH::WIN_V3
|
||||
//
|
||||
// Therefore this assert should hold
|
||||
MOZ_ASSERT(offset + toCopy <= sizeof(mRawBuf));
|
||||
@ -553,8 +559,8 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
aBuffer += toCopy;
|
||||
aCount -= toCopy;
|
||||
}
|
||||
if (mPos == WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH &&
|
||||
mBIH.compression == BI_BITFIELDS) {
|
||||
if (mPos == BMP_HEADER_LENGTH::WIN_V3 + bitFields::LENGTH &&
|
||||
mBIH.compression == BMPINFOHEADER::BITFIELDS) {
|
||||
mBitFields.red = LittleEndian::readUint32(reinterpret_cast<uint32_t*>
|
||||
(mRawBuf));
|
||||
mBitFields.green = LittleEndian::readUint32(reinterpret_cast<uint32_t*>
|
||||
@ -570,7 +576,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
if (aCount && ++mPos >= mBFH.dataoffset) {
|
||||
// Need to increment mPos, else we might get to mPos==mLOH again
|
||||
// From now on, mPos is irrelevant
|
||||
if (!mBIH.compression || mBIH.compression == BI_BITFIELDS) {
|
||||
if (!mBIH.compression || mBIH.compression == BMPINFOHEADER::BITFIELDS) {
|
||||
uint32_t rowSize = (mBIH.bpp * mBIH.width + 7) / 8; // + 7 to
|
||||
// round up
|
||||
if (rowSize % 4) {
|
||||
@ -689,10 +695,10 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
mRowBytes = 0;
|
||||
}
|
||||
} while (aCount > 0);
|
||||
} else if ((mBIH.compression == BI_RLE8) ||
|
||||
(mBIH.compression == BI_RLE4)) {
|
||||
if (((mBIH.compression == BI_RLE8) && (mBIH.bpp != 8)) ||
|
||||
((mBIH.compression == BI_RLE4) && (mBIH.bpp != 4) &&
|
||||
} else if ((mBIH.compression == BMPINFOHEADER::RLE8) ||
|
||||
(mBIH.compression == BMPINFOHEADER::RLE4)) {
|
||||
if (((mBIH.compression == BMPINFOHEADER::RLE8) && (mBIH.bpp != 8)) ||
|
||||
((mBIH.compression == BMPINFOHEADER::RLE4) && (mBIH.bpp != 4) &&
|
||||
(mBIH.bpp != 1))) {
|
||||
MOZ_LOG(GetBMPLog(), LogLevel::Debug,
|
||||
("BMP RLE8/RLE4 compression only supports 8/4 bits per"
|
||||
@ -715,7 +721,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
case eRLEStateNeedSecondEscapeByte:
|
||||
byte = *aBuffer++;
|
||||
aCount--;
|
||||
if (mStateData != RLE_ESCAPE) { // encoded mode
|
||||
if (mStateData != RLE::ESCAPE) { // encoded mode
|
||||
// Encoded mode consists of two bytes:
|
||||
// the first byte (mStateData) specifies the
|
||||
// number of consecutive pixels to be drawn
|
||||
@ -729,7 +735,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
uint32_t* d = reinterpret_cast<uint32_t*>
|
||||
(mImageData) + PIXEL_OFFSET(mCurLine, mCurPos);
|
||||
mCurPos += pixelsNeeded;
|
||||
if (mBIH.compression == BI_RLE8) {
|
||||
if (mBIH.compression == BMPINFOHEADER::RLE8) {
|
||||
do {
|
||||
SetPixel(d, byte, mColors);
|
||||
pixelsNeeded --;
|
||||
@ -744,18 +750,18 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
}
|
||||
|
||||
switch(byte) {
|
||||
case RLE_ESCAPE_EOL:
|
||||
case RLE::ESCAPE_EOL:
|
||||
// End of Line: Go to next row
|
||||
mCurLine --;
|
||||
mCurPos = 0;
|
||||
mState = eRLEStateInitial;
|
||||
break;
|
||||
|
||||
case RLE_ESCAPE_EOF: // EndOfFile
|
||||
case RLE::ESCAPE_EOF: // EndOfFile
|
||||
mCurPos = mCurLine = 0;
|
||||
break;
|
||||
|
||||
case RLE_ESCAPE_DELTA:
|
||||
case RLE::ESCAPE_DELTA:
|
||||
mState = eRLEStateNeedXDelta;
|
||||
continue;
|
||||
|
||||
@ -834,7 +840,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
(mImageData) +
|
||||
PIXEL_OFFSET(mCurLine, mCurPos);
|
||||
uint32_t* oldPos = d;
|
||||
if (mBIH.compression == BI_RLE8) {
|
||||
if (mBIH.compression == BMPINFOHEADER::RLE8) {
|
||||
while (aCount > 0 && mStateData > 0) {
|
||||
byte = *aBuffer++;
|
||||
aCount--;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user