Merge mozilla-central to fx-team

This commit is contained in:
Carsten "Tomcat" Book 2015-07-08 12:04:53 +02:00
commit 1fcc543445
192 changed files with 2348 additions and 1218 deletions

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="938375d0abafd92d78b3913db1735e49f46a6598"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="938375d0abafd92d78b3913db1735e49f46a6598"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
@ -117,7 +117,7 @@
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9afc4e0e3e883f3a22a5eb94470d50f4b1cfe5c5"/>
<project name="platform/system/extras" path="system/extras" revision="10e78a05252b3de785f88c2d0b9ea8a428009c50"/>
<project name="platform/system/media" path="system/media" revision="7ff72c2ea2496fa50b5e8a915e56e901c3ccd240"/>
<project name="platform/system/media" path="system/media" revision="188b3e51e0a2ce1e16dc8067edef7be3d2365ad9"/>
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3c5405863d2002f665ef2b901abb3853c420129b"/>
<project name="platform/system/netd" path="system/netd" revision="3ae56364946d4a5bf5a5f83f12f9a45a30398e33"/>
<project name="platform/system/security" path="system/security" revision="ee8068b9e7bfb2770635062fc9c2035be2142bd8"/>

View File

@ -19,7 +19,7 @@
<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="938375d0abafd92d78b3913db1735e49f46a6598"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="87a2d8ab9248540910e56921654367b78a587095"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="938375d0abafd92d78b3913db1735e49f46a6598"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="47f48a42502b1c694db2b162011a67a2ff888c5d"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="938375d0abafd92d78b3913db1735e49f46a6598"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="938375d0abafd92d78b3913db1735e49f46a6598"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<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="938375d0abafd92d78b3913db1735e49f46a6598"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="87a2d8ab9248540910e56921654367b78a587095"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="938375d0abafd92d78b3913db1735e49f46a6598"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "938375d0abafd92d78b3913db1735e49f46a6598",
"git_revision": "553e4e281d11500bea702918841f011bfb5405f7",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "2c98eea0fc57337386cb7c527503b0950c117167",
"revision": "0f653f6e0c527eee11b3d0e21f41509976c1daed",
"repo_path": "integration/gaia-central"
}

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="938375d0abafd92d78b3913db1735e49f46a6598"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="47f48a42502b1c694db2b162011a67a2ff888c5d"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="938375d0abafd92d78b3913db1735e49f46a6598"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="553e4e281d11500bea702918841f011bfb5405f7"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -128,6 +128,7 @@
#ifndef MOZ_FOLD_LIBS
@BINPATH@/@DLL_PREFIX@mozsqlite3@DLL_SUFFIX@
#endif
@BINPATH@/@DLL_PREFIX@lgpllibs@DLL_SUFFIX@
@RESPATH@/blocklist.xml
@RESPATH@/ua-update.json
#ifdef XP_UNIX

View File

@ -94,6 +94,34 @@ Sanitizer.prototype = {
return deferred.promise;
}
let cookiesIndex = itemsToClear.indexOf("cookies");
if (cookiesIndex != -1) {
itemsToClear.splice(cookiesIndex, 1);
let item = this.items.cookies;
item.range = this.range;
let ok = item.clear(() => {
try {
if (!itemsToClear.length) {
// we're done
deferred.resolve();
return;
}
let clearedPromise = this.sanitize(itemsToClear);
clearedPromise.then(deferred.resolve, deferred.reject);
} catch(e) {
let error = "Sanitizer threw after clearing cookies: " + e;
Cu.reportError(error);
deferred.reject(error);
}
});
// When cancelled, reject immediately
if (!ok) {
deferred.reject("Sanitizer canceled clearing cookies");
}
return deferred.promise;
}
TelemetryStopwatch.start("FX_SANITIZE_TOTAL");
// Cache the range of times to clear
@ -177,7 +205,7 @@ Sanitizer.prototype = {
},
cookies: {
clear: function ()
clear: function (aCallback)
{
TelemetryStopwatch.start("FX_SANITIZE_COOKIES");
TelemetryStopwatch.start("FX_SANITIZE_COOKIES_2");
@ -209,6 +237,16 @@ Sanitizer.prototype = {
// Clear plugin data.
TelemetryStopwatch.start("FX_SANITIZE_PLUGINS");
this.clearPluginCookies().then(
function() {
TelemetryStopwatch.finish("FX_SANITIZE_PLUGINS");
TelemetryStopwatch.finish("FX_SANITIZE_COOKIES");
aCallback();
});
return true;
},
clearPluginCookies: function() {
const phInterface = Ci.nsIPluginHost;
const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
let ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface);
@ -217,29 +255,35 @@ Sanitizer.prototype = {
// that this.range[1] is actually now, so we compute age range based
// on the lower bound. If this.range results in a negative age, do
// nothing.
let age = this.range ? (Date.now() / 1000 - this.range[0] / 1000000)
: -1;
let age = this.range ? (Date.now() / 1000 - this.range[0] / 1000000) : -1;
if (!this.range || age >= 0) {
let tags = ph.getPluginTags();
for (let i = 0; i < tags.length; i++) {
try {
ph.clearSiteData(tags[i], null, FLAG_CLEAR_ALL, age);
} catch (e) {
// If the plugin doesn't support clearing by age, clear everything.
if (e.result == Components.results.
NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED) {
try {
ph.clearSiteData(tags[i], null, FLAG_CLEAR_ALL, -1);
} catch (e) {
// Ignore errors from the plugin
}
function iterate(tag) {
let promise = new Promise(resolve => {
try {
let onClear = function(rv) {
// If the plugin doesn't support clearing by age, clear everything.
if (rv == Components.results. NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED) {
ph.clearSiteData(tag, null, FLAG_CLEAR_ALL, -1, function() {
resolve();
});
} else {
resolve();
}
};
ph.clearSiteData(tag, null, FLAG_CLEAR_ALL, age, onClear);
} catch (ex) {
resolve();
}
}
});
return promise;
}
let promises = [];
for (let tag of tags) {
promises.push(iterate(tag));
}
return Promise.all(promises);
}
TelemetryStopwatch.finish("FX_SANITIZE_PLUGINS");
TelemetryStopwatch.finish("FX_SANITIZE_COOKIES");
},
get canClear()

View File

@ -84,7 +84,7 @@ add_task(function* () {
// Clear 20 seconds ago
let now_uSec = Date.now() * 1000;
sanitizer.range = [now_uSec - 20*1000000, now_uSec];
sanitizer.sanitize();
yield sanitizer.sanitize();
ok(stored(["bar.com","qux.com"]), "Data stored for sites");
ok(!stored(["foo.com"]), "Data cleared for foo.com");
@ -92,7 +92,7 @@ add_task(function* () {
// Clear everything
sanitizer.range = null;
sanitizer.sanitize();
yield sanitizer.sanitize();
ok(!stored(null), "All data cleared");
@ -117,7 +117,7 @@ add_task(function* () {
// clearing all data regardless of age.
let now_uSec = Date.now() * 1000;
sanitizer.range = [now_uSec - 20*1000000, now_uSec];
sanitizer.sanitize();
yield sanitizer.sanitize();
ok(!stored(null), "All data cleared");

View File

@ -151,6 +151,7 @@
@BINPATH@/@DLL_PREFIX@mozsqlite3@DLL_SUFFIX@
#endif
#endif
@BINPATH@/@DLL_PREFIX@lgpllibs@DLL_SUFFIX@
@RESPATH@/browser/blocklist.xml
#ifdef XP_UNIX
#ifndef XP_MACOSX

View File

@ -629,10 +629,36 @@ EXPAND_MKSHLIB_ARGS += --symbol-order $(SYMBOL_ORDER)
endif
EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) $(EXPAND_MKSHLIB_ARGS) -- $(MKSHLIB)
# $(call CHECK_SYMBOLS,lib,PREFIX,dep_name,test)
# Checks that the given `lib` doesn't contain dependency on symbols with a
# version starting with `PREFIX`_ and matching the `test`. `dep_name` is only
# used for the error message.
# `test` is an awk expression using the information in the variable `v` which
# contains a list of version items ([major, minor, ...]).
define CHECK_SYMBOLS
@$(TOOLCHAIN_PREFIX)readelf -sW $(1) | \
awk '$$8 ~ /@$(2)_/ { \
split($$8,a,"@"); \
split(a[2],b,"_"); \
split(b[2],v,"."); \
if ($(4)) { \
if (!found) { \
print "TEST-UNEXPECTED-FAIL | check_stdcxx | We do not want these $(3) symbols to be used:" \
} \
print " ",$$8; \
found=1 \
} \
} \
END { \
if (found) { \
exit(1) \
} \
}'
endef
ifneq (,$(MOZ_LIBSTDCXX_TARGET_VERSION)$(MOZ_LIBSTDCXX_HOST_VERSION))
ifneq ($(OS_ARCH),Darwin)
CHECK_STDCXX = @$(TOOLCHAIN_PREFIX)objdump -p $(1) | grep -e 'GLIBCXX_3\.4\.\(1[1-9]\|[2-9][0-9]\)' > /dev/null && echo 'TEST-UNEXPECTED-FAIL | check_stdcxx | We do not want these libstdc++ symbols to be used:' && $(TOOLCHAIN_PREFIX)objdump -T $(1) | grep -e 'GLIBCXX_3\.4\.\(1[1-9]\|[2-9][0-9]\)' && exit 1 || true
endif
CHECK_STDCXX = $(call CHECK_SYMBOLS,$(1),GLIBCXX,libstdc++,v[1] > 3 || (v[1] == 3 && v[2] == 4 && v[3] > 10))
CHECK_GLIBC = $(call CHECK_SYMBOLS,$(1),GLIBC,libc,v[1] > 2 || (v[1] == 2 && v[2] > 7))
endif
ifeq (,$(filter $(OS_TARGET),WINNT Darwin))
@ -648,6 +674,7 @@ CHECK_MOZGLUE_ORDER = @$(TOOLCHAIN_PREFIX)readelf -d $(1) | grep NEEDED | awk '{
endif
define CHECK_BINARY
$(call CHECK_GLIBC,$(1))
$(call CHECK_STDCXX,$(1))
$(call CHECK_TEXTREL,$(1))
$(call LOCAL_CHECKS,$(1))

14
config/external/lgpllibs/moz.build vendored Normal file
View File

@ -0,0 +1,14 @@
# -*- 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/.
# The lgpllibs library stores symbols from third-party LGPL licensed libraries,
# such as libav and libsoundtouch. It fulfills the requirement of dynamically
# linking these symbols into gecko.
#
# Any library added here should also be reflected in the about:license page.
SharedLibrary('lgpllibs')
SHARED_LIBRARY_NAME = 'lgpllibs'

View File

@ -7,6 +7,7 @@
external_dirs = []
DIRS += [
'lgpllibs',
'sqlite',
]
if not CONFIG['MOZ_NATIVE_JPEG']:

View File

@ -1257,6 +1257,7 @@ X11/Xos.h
X11/Xutil.h
zmouse.h
soundtouch/SoundTouch.h
soundtouch/SoundTouchFactory.h
#if MOZ_NATIVE_PNG==1
png.h
#endif

View File

@ -106,6 +106,7 @@ static RedirEntry kRedirMap[] = {
{
"serviceworkers", "chrome://global/content/aboutServiceWorkers.xhtml",
nsIAboutModule::URI_CAN_LOAD_IN_CHILD |
nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
nsIAboutModule::ALLOW_SCRIPT
},
// about:srcdoc is unresolvable by specification. It is included here

View File

@ -3196,7 +3196,10 @@ nsDOMWindowUtils::ExitFullscreen()
{
MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsIDocument::ExitFullscreen(nullptr, /* async */ false);
nsCOMPtr<nsIDocument> doc = GetDocument();
NS_ENSURE_STATE(doc);
nsIDocument::ExitFullscreen(doc, /* async */ false);
return NS_OK;
}

View File

@ -98,6 +98,9 @@ nsImageLoadingContent::nsImageLoadingContent()
if (!nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) {
mLoadingEnabled = false;
}
bool isInconsistent;
mMostRecentRequestChange = TimeStamp::ProcessCreation(isInconsistent);
}
void
@ -1235,6 +1238,22 @@ nsImageLoadingContent::FireEvent(const nsAString& aEventType)
nsRefPtr<imgRequestProxy>&
nsImageLoadingContent::PrepareNextRequest(ImageLoadType aImageLoadType)
{
nsImageFrame* frame = do_QueryFrame(GetOurPrimaryFrame());
if (frame) {
// Detect JavaScript-based animations created by changing the |src|
// attribute on a timer.
TimeStamp now = TimeStamp::Now();
TimeDuration threshold =
TimeDuration::FromMilliseconds(
gfxPrefs::ImageInferSrcAnimationThresholdMS());
// If the length of time between request changes is less than the threshold,
// then force sync decoding to eliminate flicker from the animation.
frame->SetForceSyncDecoding(now - mMostRecentRequestChange < threshold);
mMostRecentRequestChange = now;
}
// If we don't have a usable current request, get rid of any half-baked
// request that might be sitting there and make this one current.
if (!HaveSize(mCurrentRequest))

View File

@ -17,6 +17,7 @@
#include "imgIOnloadBlocker.h"
#include "mozilla/CORSMode.h"
#include "mozilla/EventStates.h"
#include "mozilla/TimeStamp.h"
#include "nsCOMPtr.h"
#include "nsIImageLoadingContent.h"
#include "nsIRequest.h"
@ -397,6 +398,8 @@ private:
*/
mozilla::EventStates mForcedImageState;
mozilla::TimeStamp mMostRecentRequestChange;
int16_t mImageBlockingStatus;
bool mLoadingEnabled : 1;

View File

@ -501,7 +501,11 @@ nsPerformance::Navigation()
DOMHighResTimeStamp
nsPerformance::Now() const
{
return GetDOMTiming()->TimeStampToDOMHighRes(TimeStamp::Now());
double nowTimeMs = GetDOMTiming()->TimeStampToDOMHighRes(TimeStamp::Now());
// Round down to the nearest 0.005ms (5us), because if the timer is too
// accurate people can do nasty timing attacks with it.
const double maxResolutionMs = 0.005;
return floor(nowTimeMs / maxResolutionMs) * maxResolutionMs;
}
JSObject*

View File

@ -90,6 +90,10 @@ function make_json()
function parent_test(finish)
{
function f(check_func) {
// Make sure this doesn't crash.
let array = new Uint32Array(10);
content.crypto.getRandomValues(array);
let result = check_func(10);
ok(result == 20, "calling function in parent worked");
return result;

View File

@ -34,9 +34,17 @@ function runTest() {
event = ifr.contentDocument.createEvent("Events");
event.initEvent("foo", true, true);
xhr.dispatchEvent(event);
is(eventCount, 1,
"Shouldn't have handled an event because the context has changed");
SimpleTest.finish();
is(eventCount, 2,
"Should have handled the event because open()/close() keep the active document");
ifr.onload = function() {
event = ifr.contentDocument.createEvent("Events");
event.initEvent("foo", true, true);
xhr.dispatchEvent(event);
is(eventCount, 2,
"Shouldn't have handled an event because the context has changed");
SimpleTest.finish();
};
ifr.contentWindow.location = "about:blank";
}
SimpleTest.waitForExplicitFinish();

View File

@ -91,14 +91,13 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
nsGlobalWindow* win =
aIsJSImplementedWebIDL ? nullptr : xpc::WindowGlobalOrNull(realCallback);
if (win) {
// Make sure that if this is a window it's the current inner, since the
// nsIScriptContext and hence JSContext are associated with the outer
// window. Which means that if someone holds on to a function from a
// now-unloaded document we'd have the new document as the script entry
// point...
// Make sure that if this is a window it has an active document, since
// the nsIScriptContext and hence JSContext are associated with the
// outer window. Which means that if someone holds on to a function
// from a now-unloaded document we'd have the new document as the
// script entry point...
MOZ_ASSERT(win->IsInnerWindow());
nsPIDOMWindow* outer = win->GetOuterWindow();
if (!outer || win != outer->GetCurrentInnerWindow()) {
if (!win->HasActiveDocument()) {
// Just bail out from here
return;
}

View File

@ -25,6 +25,7 @@ skip-if = debug == false
[test_bug1041646.html]
[test_bug1123875.html]
[test_barewordGetsWindow.html]
[test_callback_across_document_open.html]
[test_callback_default_thisval.html]
[test_cloneAndImportNode.html]
[test_defineProperty.html]

View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Test for callback invocation for a callback that comes from a
no-longer-current window that still has an active document.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<iframe srcdoc='<script>function f() { parent.callCount++; }</script>'></iframe>
<script>
var callCount = 0;
var t = async_test("A test of callback invocation in a no-longer-current window with a still-active document");
window.addEventListener("load", t.step_func_done(function() {
var d = document.createElement("div");
d.addEventListener("xyz", frames[0].f);
frames[0].document.open();
frames[0].document.write("All gone");
frames[0].document.close();
d.dispatchEvent(new Event("xyz"));
assert_equals(callCount, 1, "Callback should have been called");
}));
</script>

View File

@ -1195,8 +1195,41 @@ DataStoreService::CheckPermission(nsIPrincipal* aPrincipal)
return false;
}
// Only support DataStore API for certified apps for now.
return status == nsIPrincipal::APP_STATUS_CERTIFIED;
// Certified apps are always allowed.
if (status == nsIPrincipal::APP_STATUS_CERTIFIED) {
return true;
}
if (status != nsIPrincipal::APP_STATUS_PRIVILEGED) {
return false;
}
// Privileged apps are allowed if they are the homescreen.
nsAdoptingString homescreen =
Preferences::GetString("dom.mozApps.homescreenURL");
if (!homescreen) {
return false;
}
uint32_t appId;
nsresult rv = aPrincipal->GetAppId(&appId);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
nsCOMPtr<nsIAppsService> appsService =
do_GetService("@mozilla.org/AppsService;1");
if (NS_WARN_IF(!appsService)) {
return false;
}
nsAutoString manifestURL;
rv = appsService->GetManifestURLByLocalId(appId, manifestURL);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
return manifestURL.Equals(homescreen);
}
NS_IMETHODIMP

View File

@ -111,7 +111,10 @@ function tests() {
// Release.
sendMouseEvent("mouseup", label);
yield undefined;
compareSnapshots_(normalFocusedButtonCanvas, currentSnapshot, true, "Releasing the mouse over the label should have unpressed (and focused) the button.");
var focusOnMouse = (navigator.platform.indexOf("Mac") != 0);
compareSnapshots_(focusOnMouse ? normalFocusedButtonCanvas : normalButtonCanvas,
currentSnapshot, true, "Releasing the mouse over the label should have unpressed" +
(focusOnMouse ? " (and focused)" : "") + " the button.");
// Press the label and remove it.
sendMouseEvent("mousemove", label);
sendMouseEvent("mousedown", label);

View File

@ -127,7 +127,10 @@ function tests() {
// Release.
sendMouseEvent("mouseup", label);
yield undefined;
compareSnapshots_(normalFocusedButtonCanvas, currentSnapshot, true, "Releasing the mouse over the label should have unpressed (and focused) the button.");
var focusOnMouse = (navigator.platform.indexOf("Mac") != 0);
compareSnapshots_(focusOnMouse ? normalFocusedButtonCanvas : normalButtonCanvas,
currentSnapshot, true, "Releasing the mouse over the label should have unpressed" +
(focusOnMouse ? " (and focused)" : "") + " the button.");
// Press the label and remove it.
sendMouseEvent("mousemove", label);
sendMouseEvent("mousedown", label);

View File

@ -169,8 +169,14 @@ HTMLLabelElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
// be selected only when focused via a key or when the navigation
// flag is used and we want to select the text on label clicks as
// well.
// If the label has been clicked by the user, we also want to
// pass FLAG_BYMOUSE so that we get correct focus ring behavior,
// but we don't want to pass FLAG_BYMOUSE if this click event was
// caused by the user pressing an accesskey.
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(content);
fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOVEFOCUS);
bool byMouse = (mouseEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD);
fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOVEFOCUS |
(byMouse ? nsIFocusManager::FLAG_BYMOUSE : 0));
}
}
// Dispatch a new click event to |content|

View File

@ -72,11 +72,29 @@ const ACTION_FUNCS = [
}
];
const DISABLE_LIST = [
// Bug 1180574
{ openWinFunc: "openNewWindow",
actionFunc: "navigate",
platform: "Linux i686" }
];
function* testGenerator() {
for (var openWinFunc of OPEN_WINDOW_FUNCS) {
for (var actionFunc of ACTION_FUNCS) {
info(`Testing ${openWinFunc.name}, ${actionFunc.name}`);
yield { openWinFunc: openWinFunc, actionFunc: actionFunc };
var skipTest = false;
for (var disabledItem of DISABLE_LIST) {
if (openWinFunc.name == disabledItem.openWinFunc &&
actionFunc.name == disabledItem.actionFunc &&
navigator.platform == disabledItem.platform) {
skipTest = true;
break;
}
}
if (!skipTest) {
info(`Testing ${openWinFunc.name}, ${actionFunc.name}`);
yield { openWinFunc: openWinFunc, actionFunc: actionFunc };
}
}
}
}

View File

@ -732,7 +732,7 @@ parent:
sync PCrashReporter(NativeThreadId tid, uint32_t processType);
sync GetRandomValues(uint32_t length)
prio(urgent) sync GetRandomValues(uint32_t length)
returns (uint8_t[] randomValues);
async GetSystemMemory(uint64_t getterId);

View File

@ -11,112 +11,82 @@
*
* BUG: https://bugzilla.mozilla.org/show_bug.cgi?id=1083410
*/
/*globals content, sendAsyncMessage, addMessageListener, Components*/
/*globals Task, ManifestObtainer, ManifestFinder, content, sendAsyncMessage, addMessageListener, Components*/
'use strict';
const {
utils: Cu,
classes: Cc,
interfaces: Ci
} = Components;
const {
ManifestProcessor
} = Cu.import('resource://gre/modules/WebManifest.jsm', {});
const {
Task: {
spawn, async
}
} = Components.utils.import('resource://gre/modules/Task.jsm', {});
Cu.import('resource://gre/modules/ManifestObtainer.jsm');
Cu.import('resource://gre/modules/ManifestFinder.jsm');
Cu.import('resource://gre/modules/Task.jsm');
addMessageListener('DOM:ManifestObtainer:Obtain', async(function* (aMsg) {
const response = {
msgId: aMsg.data.msgId,
success: true,
result: undefined
};
try {
response.result = yield fetchManifest();
} catch (err) {
response.success = false;
response.result = cloneError(err);
}
sendAsyncMessage('DOM:ManifestObtainer:Obtain', response);
}));
const finder = new ManifestFinder();
function cloneError(aError) {
const clone = {
'fileName': String(aError.fileName),
'lineNumber': String(aError.lineNumber),
'columnNumber': String(aError.columnNumber),
'stack': String(aError.stack),
'message': String(aError.message),
'name': String(aError.name)
};
return clone;
}
const MessageHandler = {
registerListeners() {
addMessageListener(
'DOM:WebManifest:hasManifestLink',
this.hasManifestLink.bind(this)
);
addMessageListener(
'DOM:ManifestObtainer:Obtain',
this.obtainManifest.bind(this)
);
},
function fetchManifest() {
return spawn(function* () {
if (!content || content.top !== content) {
let msg = 'Content window must be a top-level browsing context.';
throw new Error(msg);
/**
* Check if the content document includes a link to a web manifest.
* @param {Object} aMsg The IPC message.
*/
hasManifestLink: Task.async(function* ({data: {id}}) {
const response = this.makeMsgResponse(id);
response.result = yield finder.hasManifestLink(content);
response.success = true;
sendAsyncMessage('DOM:WebManifest:hasManifestLink', response);
}),
/**
* Obtains a web manifest from content by using the ManifestObtainer
* and messages back the result.
* @param {Object} aMsg The IPC message.
*/
obtainManifest: Task.async(function* ({data: {id}}) {
const obtainer = new ManifestObtainer();
const response = this.makeMsgResponse(id);
try {
response.result = yield obtainer.obtainManifest(content);
response.success = true;
} catch (err) {
response.result = this.serializeError(err);
}
const elem = content.document.querySelector('link[rel~="manifest"]');
if (!elem || !elem.getAttribute('href')) {
let msg = 'No manifest to fetch.';
throw new Error(msg);
}
// Throws on malformed URLs
const manifestURL = new content.URL(elem.href, elem.baseURI);
if (!canLoadManifest(elem)) {
let msg = `Content Security Policy: The page's settings blocked the `;
msg += `loading of a resource at ${elem.href}`;
throw new Error(msg);
}
const reqInit = {
mode: 'cors'
sendAsyncMessage('DOM:ManifestObtainer:Obtain', response);
}),
makeMsgResponse(aId) {
return {
id: aId,
success: false,
result: undefined
};
if (elem.crossOrigin === 'use-credentials') {
reqInit.credentials = 'include';
}
const req = new content.Request(manifestURL, reqInit);
req.setContentPolicyType(Ci.nsIContentPolicy.TYPE_WEB_MANIFEST);
const response = yield content.fetch(req);
const manifest = yield processResponse(response, content);
return manifest;
});
}
},
function canLoadManifest(aElem) {
const contentPolicy = Cc['@mozilla.org/layout/content-policy;1']
.getService(Ci.nsIContentPolicy);
const mimeType = aElem.type || 'application/manifest+json';
const elemURI = BrowserUtils.makeURI(
aElem.href, aElem.ownerDocument.characterSet
);
const shouldLoad = contentPolicy.shouldLoad(
Ci.nsIContentPolicy.TYPE_WEB_MANIFEST, elemURI,
aElem.ownerDocument.documentURIObject,
aElem, mimeType, null
);
return shouldLoad === Ci.nsIContentPolicy.ACCEPT;
}
function processResponse(aResp, aContentWindow) {
return spawn(function* () {
const badStatus = aResp.status < 200 || aResp.status >= 300;
if (aResp.type === 'error' || badStatus) {
let msg =
`Fetch error: ${aResp.status} - ${aResp.statusText} at ${aResp.url}`;
throw new Error(msg);
}
const text = yield aResp.text();
const args = {
jsonText: text,
manifestURL: aResp.url,
docURL: aContentWindow.location.href
/**
* Utility function to Serializes an JS Error, so it can be transferred over
* the message channel.
* FIX ME: https://bugzilla.mozilla.org/show_bug.cgi?id=1172586
* @param {Error} aError The error to serialize.
* @return {Object} The serialized object.
*/
serializeError(aError) {
const clone = {
'fileName': aError.fileName,
'lineNumber': aError.lineNumber,
'columnNumber': aError.columnNumber,
'stack': aError.stack,
'message': aError.message,
'name': aError.name
};
const processor = new ManifestProcessor();
const manifest = processor.process(args);
return Cu.cloneInto(manifest, content);
});
}
return clone;
},
};
MessageHandler.registerListeners();

View File

@ -0,0 +1,58 @@
/* 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 https://mozilla.org/MPL/2.0/. */
/* globals Components, Task, PromiseMessage */
'use strict';
const {
utils: Cu
} = Components;
Cu.import('resource://gre/modules/PromiseMessage.jsm');
Cu.import('resource://gre/modules/Task.jsm');
/**
* @constructor
*/
function ManifestFinder() {}
/**
* checks if a browser window's document has a conforming
* manifest link relationship.
* @param aWindowOrBrowser the XUL browser or window to check.
* @return {Promise}
*/
ManifestFinder.prototype.hasManifestLink = Task.async(
function* (aWindowOrBrowser) {
const msgKey = 'DOM:WebManifest:hasManifestLink';
if (!(aWindowOrBrowser && (aWindowOrBrowser.namespaceURI || aWindowOrBrowser.location))) {
throw new TypeError('Invalid input.');
}
if (isXULBrowser(aWindowOrBrowser)) {
const mm = aWindowOrBrowser.messageManager;
const reply = yield PromiseMessage.send(mm, msgKey);
return reply.data.result;
}
return checkForManifest(aWindowOrBrowser);
}
);
function isXULBrowser(aBrowser) {
const XUL = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
return (aBrowser.namespaceURI && aBrowser.namespaceURI === XUL);
}
function checkForManifest(aWindow) {
// Only top-level browsing contexts are valid.
if (!aWindow || aWindow.top !== aWindow) {
return false;
}
const elem = aWindow.document.querySelector('link[rel~="manifest"]');
// Only if we have an element and a non-empty href attribute.
if (!elem || !elem.getAttribute('href')) {
return false;
}
return true;
}
this.EXPORTED_SYMBOLS = [ // jshint ignore:line
'ManifestFinder'
];

View File

@ -1,92 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ManifestObtainer is an implementation of:
* http://w3c.github.io/manifest/#obtaining
*
* Exposes public method `.obtainManifest(browserWindow)`, which returns
* a promise. If successful, you get back a manifest (string).
*
* For e10s compat, this JSM relies on the following to do
* the nessesary IPC:
* dom/ipc/manifestMessages.js
*
* whose internal URL is:
* 'chrome://global/content/manifestMessages.js'
*
* Which is injected into every browser instance via browser.js.
*
* BUG: https://bugzilla.mozilla.org/show_bug.cgi?id=1083410
* exported ManifestObtainer
*/
'use strict';
const MSG_KEY = 'DOM:ManifestObtainer:Obtain';
let messageCounter = 0;
// FIXME: Ideally, we would store a reference to the
// message manager in a weakmap instead of needing a
// browserMap. However, trying to store a messageManager
// results in a TypeError because of:
// https://bugzilla.mozilla.org/show_bug.cgi?id=888600
const browsersMap = new WeakMap();
function ManifestObtainer() {}
ManifestObtainer.prototype = {
obtainManifest(aBrowserWindow) {
if (!aBrowserWindow) {
const err = new TypeError('Invalid input. Expected xul browser.');
return Promise.reject(err);
}
const mm = aBrowserWindow.messageManager;
const onMessage = function(aMsg) {
const msgId = aMsg.data.msgId;
const {
resolve, reject
} = browsersMap.get(aBrowserWindow).get(msgId);
browsersMap.get(aBrowserWindow).delete(msgId);
// If we we've processed all messages,
// stop listening.
if (!browsersMap.get(aBrowserWindow).size) {
browsersMap.delete(aBrowserWindow);
mm.removeMessageListener(MSG_KEY, onMessage);
}
if (aMsg.data.success) {
return resolve(aMsg.data.result);
}
reject(toError(aMsg.data.result));
};
// If we are not already listening for messages
// start listening.
if (!browsersMap.has(aBrowserWindow)) {
browsersMap.set(aBrowserWindow, new Map());
mm.addMessageListener(MSG_KEY, onMessage);
}
return new Promise((resolve, reject) => {
const msgId = messageCounter++;
browsersMap.get(aBrowserWindow).set(msgId, {
resolve: resolve,
reject: reject
});
mm.sendAsyncMessage(MSG_KEY, {
msgId: msgId
});
});
function toError(aErrorClone) {
let error;
switch (aErrorClone.name) {
case 'TypeError':
error = new TypeError();
break;
default:
error = new Error();
}
Object.getOwnPropertyNames(aErrorClone)
.forEach(name => error[name] = aErrorClone[name]);
return error;
}
}
};
this.ManifestObtainer = ManifestObtainer; // jshint ignore:line
this.EXPORTED_SYMBOLS = ['ManifestObtainer']; // jshint ignore:line

View File

@ -0,0 +1,170 @@
/* 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/.
*/
/*
* ManifestObtainer is an implementation of:
* http://w3c.github.io/manifest/#obtaining
*
* Exposes public method `.obtainManifest(Window)`, which returns
* a promise. If successful, you get back a manifest object.
*
* Import it with URL:
* 'chrome://global/content/manifestMessages.js'
*
* e10s IPC messaage from this components are handled by:
* dom/ipc/manifestMessages.js
*
* Which is injected into every browser instance via browser.js.
*
* exported ManifestObtainer
*/
/*globals Components, Task, PromiseMessage, XPCOMUtils, ManifestProcessor, BrowserUtils*/
'use strict';
const {
utils: Cu,
classes: Cc,
interfaces: Ci
} = Components;
Cu.import('resource://gre/modules/Task.jsm');
Cu.import('resource://gre/modules/PromiseMessage.jsm');
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/ManifestProcessor.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'BrowserUtils', // jshint ignore:line
'resource://gre/modules/BrowserUtils.jsm');
const processor = new ManifestProcessor();
/**
* Asynchronously processes the result of response after having fetched
* a manifest.
* @param {Response} aResp Response from fetch().
* @param {Window} aContentWindow The content window.
* @return {Promise<Object>} The processed manifest.
*/
const processResponse = Task.async(function* (aResp, aContentWindow) {
const badStatus = aResp.status < 200 || aResp.status >= 300;
if (aResp.type === 'error' || badStatus) {
const msg =
`Fetch error: ${aResp.status} - ${aResp.statusText} at ${aResp.url}`;
throw new Error(msg);
}
const text = yield aResp.text();
const args = {
jsonText: text,
manifestURL: aResp.url,
docURL: aContentWindow.location.href
};
const manifest = processor.process(args);
return manifest;
});
/**
* Asynchronously fetches a web manifest.
* @param {Window} a The content Window from where to extract the manifest.
* @return {Promise<Object>}
*/
const fetchManifest = Task.async(function* (aWindow) {
if (!aWindow || aWindow.top !== aWindow) {
let msg = 'Window must be a top-level browsing context.';
throw new Error(msg);
}
const elem = aWindow.document.querySelector('link[rel~="manifest"]');
if (!elem || !elem.getAttribute('href')) {
let msg = `No manifest to fetch at ${aWindow.location}`;
throw new Error(msg);
}
// Throws on malformed URLs
const manifestURL = new aWindow.URL(elem.href, elem.baseURI);
if (!canLoadManifest(elem)) {
let msg = `Content Security Policy: The page's settings blocked the `;
msg += `loading of a resource at ${elem.href}`;
throw new Error(msg);
}
const reqInit = {
mode: 'cors'
};
if (elem.crossOrigin === 'use-credentials') {
reqInit.credentials = 'include';
}
const req = new aWindow.Request(manifestURL, reqInit);
req.setContentPolicyType(Ci.nsIContentPolicy.TYPE_WEB_MANIFEST);
const response = yield aWindow.fetch(req);
const manifest = yield processResponse(response, aWindow);
return manifest;
});
/**
* Checks against security manager if we can load the web manifest.
* @param {HTMLLinkElement} aElem The HTML element to security check.
* @return {Boolean} True if it can, false if it can't.
*/
function canLoadManifest(aElem) {
const contentPolicy = Cc['@mozilla.org/layout/content-policy;1']
.getService(Ci.nsIContentPolicy);
const mimeType = aElem.type || 'application/manifest+json';
const elemURI = BrowserUtils.makeURI(
aElem.href, aElem.ownerDocument.characterSet
);
const shouldLoad = contentPolicy.shouldLoad(
Ci.nsIContentPolicy.TYPE_WEB_MANIFEST, elemURI,
aElem.ownerDocument.documentURIObject,
aElem, mimeType, null
);
return shouldLoad === Ci.nsIContentPolicy.ACCEPT;
}
/**
* ManifestObtainer
* @constructor
*/
function ManifestObtainer() {
}
/**
* Public interface for obtaining a web manifest.
* @param {XULWindow or DOMWindow} aWindow The Window from which to fetch
* the manifest.
* @return {Promise<Object>} The processed manifest.
*/
ManifestObtainer.prototype.obtainManifest = Task.async(
function* (aWindowOrBrowser) {
const msgKey = 'DOM:ManifestObtainer:Obtain';
if (!(aWindowOrBrowser && (aWindowOrBrowser.namespaceURI || aWindowOrBrowser.location))) {
throw new TypeError('Invalid input.');
}
if (isXULBrowser(aWindowOrBrowser)) {
const mm = aWindowOrBrowser.messageManager;
const {data: {success, result}} = yield PromiseMessage.send(mm, msgKey);
if (!success) {
const error = toError(result);
throw error;
}
return result;
}
const manifest = yield fetchManifest(aWindowOrBrowser);
return manifest;
}
);
function toError(aErrorClone) {
let error;
switch (aErrorClone.name) {
case 'TypeError':
error = new TypeError();
break;
default:
error = new Error();
}
Object.getOwnPropertyNames(aErrorClone)
.forEach(name => error[name] = aErrorClone[name]);
return error;
}
function isXULBrowser(aBrowser) {
const XUL = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
return (aBrowser.namespaceURI && aBrowser.namespaceURI === XUL);
}
this.ManifestObtainer = ManifestObtainer; // jshint ignore:line
this.EXPORTED_SYMBOLS = ['ManifestObtainer']; // jshint ignore:line

View File

@ -19,12 +19,10 @@
* TODO: The constructor should accept the UA's supported display modes.
* TODO: hook up developer tools to console. (1086997).
*/
/*globals Components*/
/*globals Components, ValueExtractor, ImageObjectProcessor, ConsoleAPI*/
'use strict';
const {
utils: Cu,
interfaces: Ci,
classes: Cc
utils: Cu
} = Components;
Cu.importGlobalProperties(['URL']);
const displayModes = new Set(['fullscreen', 'standalone', 'minimal-ui',
@ -34,18 +32,12 @@ const orientationTypes = new Set(['any', 'natural', 'landscape', 'portrait',
'portrait-primary', 'portrait-secondary', 'landscape-primary',
'landscape-secondary'
]);
const {
ConsoleAPI
} = Cu.import('resource://gre/modules/devtools/Console.jsm', {});
Cu.import('resource://gre/modules/devtools/Console.jsm');
// ValueExtractor is used by the various processors to get values
// from the manifest and to report errors.
const {
ValueExtractor
} = Cu.import('resource://gre/modules/ValueExtractor.js', {});
Cu.import('resource://gre/modules/ValueExtractor.jsm');
// ImageObjectProcessor is used to process things like icons and images
const {
ImageObjectProcessor
} = Cu.import('resource://gre/modules/ImageObjectProcessor.js', {});
Cu.import('resource://gre/modules/ImageObjectProcessor.jsm');
function ManifestProcessor() {}

View File

@ -25,9 +25,7 @@ ValueExtractor.prototype = {
// objectName: string used to construct the developer warning.
// property: the name of the property being extracted.
// trim: boolean, if the value should be trimmed (used by string type).
extractValue({
expectedType, object, objectName, property, trim
}) {
extractValue({expectedType, object, objectName, property, trim}) {
const value = object[property];
const isArray = Array.isArray(value);
// We need to special-case "array", as it's not a JS primitive.

View File

@ -1,19 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
/*exported EXPORTED_SYMBOLS, ManifestProcessor, ManifestObtainer*/
/*globals Components */
'use strict';
const {
utils: Cu
} = Components;
this.EXPORTED_SYMBOLS = [
'ManifestObtainer',
'ManifestProcessor'
];
// Export public interfaces
for (let symbl of EXPORTED_SYMBOLS) {
Cu.import(`resource://gre/modules/${symbl}.js`);
}

View File

@ -5,11 +5,11 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXTRA_JS_MODULES += [
'ImageObjectProcessor.js',
'ManifestObtainer.js',
'ManifestProcessor.js',
'ValueExtractor.js',
'WebManifest.jsm'
'ImageObjectProcessor.jsm',
'ManifestFinder.jsm',
'ManifestObtainer.jsm',
'ManifestProcessor.jsm',
'ValueExtractor.jsm',
]
MOCHITEST_MANIFESTS += ['test/mochitest.ini']

View File

@ -1,2 +1,3 @@
[DEFAULT]
[browser_ManifestObtainer_obtain.js]
[browser_hasManifestLink.js]
[browser_ManifestObtainer_obtain.js]

View File

@ -3,7 +3,7 @@
'use strict';
const {
ManifestObtainer
} = Cu.import('resource://gre/modules/WebManifest.jsm', {});
} = Cu.import('resource://gre/modules/ManifestObtainer.jsm', {});
requestLongerTimeout(4); // e10s tests take time.
const defaultURL =

View File

@ -0,0 +1,109 @@
//Used by JSHint:
/*global Cu, BrowserTestUtils, is, ok, add_task, gBrowser, ManifestFinder */
'use strict';
Cu.import('resource://gre/modules/ManifestFinder.jsm', this); // jshint ignore:line
const finder = new ManifestFinder();
const defaultURL =
'http://example.org/tests/dom/manifest/test/resource.sjs';
const tests = [{
expected: 'Document has a web manifest.',
get tabURL() {
let query = [
`body=<h1>${this.expected}</h1>`,
'Content-Type=text/html; charset=utf-8',
];
const URL = `${defaultURL}?${query.join('&')}`;
return URL;
},
run(result) {
is(result, true, this.expected);
},
testData: `
<link rel="manifesto" href='${defaultURL}?body={"name":"fail"}'>
<link rel="foo bar manifest bar test" href='${defaultURL}?body={"name":"value"}'>
<link rel="manifest" href='${defaultURL}?body={"name":"fail"}'>`
}, {
expected: 'Document does not have a web manifest.',
get tabURL() {
let query = [
`body=<h1>${this.expected}</h1>`,
'Content-Type=text/html; charset=utf-8',
];
const URL = `${defaultURL}?${query.join('&')}`;
return URL;
},
run(result) {
is(result, false, this.expected);
},
testData: `
<link rel="amanifista" href='${defaultURL}?body={"name":"fail"}'>
<link rel="foo bar manifesto bar test" href='${defaultURL}?body={"name":"pass-1"}'>
<link rel="manifesto" href='${defaultURL}?body={"name":"fail"}'>`
}, {
expected: 'Manifest link is has empty href.',
get tabURL() {
let query = [
`body=<h1>${this.expected}</h1>`,
'Content-Type=text/html; charset=utf-8',
];
const URL = `${defaultURL}?${query.join('&')}`;
return URL;
},
run(result) {
is(result, false, this.expected);
},
testData: `
<link rel="manifest" href="">
<link rel="manifest" href='${defaultURL}?body={"name":"fail"}'>`
}, {
expected: 'Manifest link is missing.',
get tabURL() {
let query = [
`body=<h1>${this.expected}</h1>`,
'Content-Type=text/html; charset=utf-8',
];
const URL = `${defaultURL}?${query.join('&')}`;
return URL;
},
run(result) {
is(result, false, this.expected);
},
testData: `
<link rel="manifest">
<link rel="manifest" href='${defaultURL}?body={"name":"fail"}'>`
}];
/**
* Test basic API error conditions
*/
add_task(function* () {
let expected = 'Invalid types should throw a TypeError.';
for (let invalidValue of [undefined, null, 1, {}, 'test']) {
try {
yield finder.hasManifestLink(invalidValue);
ok(false, expected);
} catch (e) {
is(e.name, 'TypeError', expected);
}
}
});
add_task(function* () {
for (let test of tests) {
let tabOptions = {
gBrowser: gBrowser,
url: test.tabURL,
};
yield BrowserTestUtils.withNewTab(
tabOptions,
browser => testHasManifest(browser, test)
);
}
function* testHasManifest(aBrowser, aTest) {
aBrowser.contentWindowAsCPOW.document.head.innerHTML = aTest.testData;
const result = yield finder.hasManifestLink(aBrowser);
aTest.run(result);
}
});

View File

@ -1,11 +1,11 @@
/**
* Common infrastructure for manifest tests.
**/
/*globals SpecialPowers, ManifestProcessor*/
'use strict';
const {
ManifestProcessor
} = SpecialPowers.Cu.import('resource://gre/modules/WebManifest.jsm');
} = SpecialPowers.Cu.import('resource://gre/modules/ManifestProcessor.jsm');
const processor = new ManifestProcessor();
const manifestURL = new URL(document.location.origin + '/manifest.json');
const docURL = document.location;

View File

@ -15,7 +15,6 @@
#include "mozilla/Snprintf.h"
#include <algorithm>
#include "mozilla/Telemetry.h"
#include "soundtouch/SoundTouch.h"
#include "Latency.h"
#include "CubebUtils.h"
#include "nsPrintfCString.h"
@ -130,6 +129,7 @@ AudioStream::AudioStream()
, mOutChannels(0)
, mWritten(0)
, mAudioClock(this)
, mTimeStretcher(nullptr)
, mLatencyRequest(HighLatency)
, mReadPoint(0)
, mDumpFile(nullptr)
@ -152,6 +152,9 @@ AudioStream::~AudioStream()
if (mDumpFile) {
fclose(mDumpFile);
}
if (mTimeStretcher) {
soundtouch::destroySoundTouchObj(mTimeStretcher);
}
}
size_t
@ -174,7 +177,7 @@ nsresult AudioStream::EnsureTimeStretcherInitializedUnlocked()
{
mMonitor.AssertCurrentThreadOwns();
if (!mTimeStretcher) {
mTimeStretcher = new soundtouch::SoundTouch();
mTimeStretcher = soundtouch::createSoundTouchObj();
mTimeStretcher->setSampleRate(mInRate);
mTimeStretcher->setChannels(mOutChannels);
mTimeStretcher->setPitch(1.0);

View File

@ -15,10 +15,7 @@
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
#include "CubebUtils.h"
namespace soundtouch {
class SoundTouch;
}
#include "soundtouch/SoundTouchFactory.h"
namespace mozilla {
@ -332,7 +329,7 @@ private:
// Number of frames written to the buffers.
int64_t mWritten;
AudioClock mAudioClock;
nsAutoPtr<soundtouch::SoundTouch> mTimeStretcher;
soundtouch::SoundTouch* mTimeStretcher;
nsRefPtr<AsyncLatencyLogger> mLatencyLog;
// copy of Latency logger's starting time for offset calculations

View File

@ -119,6 +119,14 @@ public:
return TimeUnit(INT64_MAX);
}
static TimeUnit Invalid() {
TimeUnit ret;
ret.mValue = CheckedInt64(INT64_MAX);
// Force an overflow to render the CheckedInt invalid.
ret.mValue += 1;
return ret;
}
int64_t ToMicroseconds() const {
return mValue.value();
}

View File

@ -29,6 +29,10 @@ CheckedInt64 FramesToUsecs(int64_t aFrames, uint32_t aRate) {
return (CheckedInt64(aFrames) * USECS_PER_S) / aRate;
}
media::TimeUnit FramesToTimeUnit(int64_t aFrames, uint32_t aRate) {
return (media::TimeUnit::FromMicroseconds(aFrames) * USECS_PER_S) / aRate;
}
// Converts from microseconds to number of audio frames, given the specified
// audio rate.
CheckedInt64 UsecsToFrames(int64_t aUsecs, uint32_t aRate) {

View File

@ -127,10 +127,11 @@ media::TimeIntervals GetEstimatedBufferedTimeRanges(mozilla::MediaResource* aStr
int64_t aDurationUsecs);
// Converts from number of audio frames (aFrames) to microseconds, given
// the specified audio rate (aRate). Stores result in aOutUsecs. Returns true
// if the operation succeeded, or false if there was an integer overflow
// while calulating the conversion.
// the specified audio rate (aRate).
CheckedInt64 FramesToUsecs(int64_t aFrames, uint32_t aRate);
// Converts from number of audio frames (aFrames) TimeUnit, given
// the specified audio rate (aRate).
media::TimeUnit FramesToTimeUnit(int64_t aFrames, uint32_t aRate);
// Converts from microseconds (aUsecs) to number of audio frames, given the
// specified audio rate (aRate). Stores the result in aOutFrames. Returns

View File

@ -14,3 +14,7 @@ FAIL_ON_WARNINGS = True
LOCAL_INCLUDES += [
'..',
]
USE_LIBS += [
'lgpllibs',
]

View File

@ -423,7 +423,7 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
}
// Get the duration, and report it to the decoder if we have it.
Microseconds duration;
mp4_demuxer::Microseconds duration;
{
MonitorAutoLock lock(mDemuxerMonitor);
duration = mDemuxer->Duration();
@ -561,7 +561,7 @@ MP4Reader::GetDecoderData(TrackType aTrack)
return mVideo;
}
Microseconds
mp4_demuxer::Microseconds
MP4Reader::GetNextKeyframeTime()
{
MonitorAutoLock mon(mDemuxerMonitor);
@ -596,7 +596,7 @@ MP4Reader::ShouldSkip(bool aSkipToNextKeyframe, int64_t aTimeThreshold)
// if the time threshold (the current playback position) is after the next
// keyframe in the stream. This means we'll only skip frames that we have
// no hope of ever playing.
Microseconds nextKeyframe = -1;
mp4_demuxer::Microseconds nextKeyframe = -1;
if (!sDemuxSkipToNextKeyframe ||
(nextKeyframe = GetNextKeyframeTime()) == -1) {
return aSkipToNextKeyframe;
@ -1090,7 +1090,7 @@ MP4Reader::GetBuffered()
nsresult rv = resource->GetCachedRanges(ranges);
if (NS_SUCCEEDED(rv)) {
nsTArray<Interval<Microseconds>> timeRanges;
nsTArray<Interval<mp4_demuxer::Microseconds>> timeRanges;
mDemuxer->ConvertByteRangesToTime(ranges, &timeRanges);
for (size_t i = 0; i < timeRanges.Length(); i++) {
buffered += media::TimeInterval(

View File

@ -118,7 +118,7 @@ private:
bool IsSupportedVideoMimeType(const nsACString& aMimeType);
virtual bool IsWaitingOnCDMResource() override;
Microseconds GetNextKeyframeTime();
mp4_demuxer::Microseconds GetNextKeyframeTime();
bool ShouldSkip(bool aSkipToNextKeyframe, int64_t aTimeThreshold);
size_t SizeOfQueue(TrackType aTrack);

View File

@ -27,7 +27,6 @@ class MediaDataDecoder;
class MediaDataDecoderCallback;
class FlushableMediaTaskQueue;
class CDMProxy;
typedef int64_t Microseconds;
// The PlatformDecoderModule interface is used by the MP4Reader to abstract
// access to the H264 and Audio (AAC/MP3) decoders provided by various platforms.

View File

@ -13,6 +13,7 @@
#include "ImageContainer.h"
#include "MediaInfo.h"
#include "MediaTaskQueue.h"
#include "TimeUnits.h"
namespace mozilla {
@ -51,9 +52,10 @@ public:
}
NS_IMETHOD Run() override
{
nsRefPtr<MediaData> data = mCreator->Create(mSample->mTime,
mSample->mDuration,
mSample->mOffset);
nsRefPtr<MediaData> data =
mCreator->Create(media::TimeUnit::FromMicroseconds(mSample->mTime),
media::TimeUnit::FromMicroseconds(mSample->mDuration),
mSample->mOffset);
mCallback->Output(data);
return NS_OK;
}
@ -103,7 +105,7 @@ public:
}
already_AddRefed<MediaData>
Create(Microseconds aDTS, Microseconds aDuration, int64_t aOffsetInStream)
Create(const media::TimeUnit& aDTS, const media::TimeUnit& aDuration, int64_t aOffsetInStream)
{
// Create a fake YUV buffer in a 420 format. That is, an 8bpp Y plane,
// with a U and V plane that are half the size of the Y plane, i.e 8 bit,
@ -141,11 +143,11 @@ public:
mImageContainer,
nullptr,
aOffsetInStream,
aDTS,
aDuration,
aDTS.ToMicroseconds(),
aDuration.ToMicroseconds(),
buffer,
true,
aDTS,
aDTS.ToMicroseconds(),
mPicture);
}
private:
@ -164,13 +166,14 @@ public:
{
}
MediaData* Create(Microseconds aDTS,
Microseconds aDuration,
MediaData* Create(const media::TimeUnit& aDTS,
const media::TimeUnit& aDuration,
int64_t aOffsetInStream)
{
// Convert duration to frames. We add 1 to duration to account for
// rounding errors, so we get a consistent tone.
CheckedInt64 frames = UsecsToFrames(aDuration+1, mSampleRate);
CheckedInt64 frames =
UsecsToFrames(aDuration.ToMicroseconds()+1, mSampleRate);
if (!frames.isValid() ||
!mChannelCount ||
!mSampleRate ||
@ -189,8 +192,8 @@ public:
mFrameSum++;
}
return new AudioData(aOffsetInStream,
aDTS,
aDuration,
aDTS.ToMicroseconds(),
aDuration.ToMicroseconds(),
uint32_t(frames.value()),
samples,
mChannelCount,

View File

@ -105,7 +105,8 @@ public:
return eglImage;
}
virtual nsresult PostOutput(BufferInfo::Param aInfo, MediaFormat::Param aFormat, Microseconds aDuration) override {
virtual nsresult PostOutput(BufferInfo::Param aInfo, MediaFormat::Param aFormat,
const media::TimeUnit& aDuration) override {
if (!EnsureGLContext()) {
return NS_ERROR_FAILURE;
}
@ -168,7 +169,7 @@ public:
mImageContainer,
offset,
presentationTimeUs,
aDuration,
aDuration.ToMicroseconds(),
img,
isSync,
presentationTimeUs,
@ -213,7 +214,9 @@ public:
}
}
nsresult Output(BufferInfo::Param aInfo, void* aBuffer, MediaFormat::Param aFormat, Microseconds aDuration) {
nsresult Output(BufferInfo::Param aInfo, void* aBuffer,
MediaFormat::Param aFormat,
const media::TimeUnit& aDuration) {
// The output on Android is always 16-bit signed
nsresult rv;
@ -239,7 +242,7 @@ public:
NS_ENSURE_SUCCESS(rv = aInfo->PresentationTimeUs(&presentationTimeUs), rv);
nsRefPtr<AudioData> data = new AudioData(offset, presentationTimeUs,
aDuration,
aDuration.ToMicroseconds(),
numFrames,
audio,
numChannels,
@ -485,7 +488,7 @@ void MediaCodecDataDecoder::DecoderLoop()
sample->mTime, 0);
HANDLE_DECODER_ERROR();
mDurations.push(sample->mDuration);
mDurations.push(media::TimeUnit::FromMicroseconds(sample->mDuration));
sample = nullptr;
outputDone = false;
}
@ -543,7 +546,7 @@ void MediaCodecDataDecoder::DecoderLoop()
MOZ_ASSERT(!mDurations.empty(), "Should have had a duration queued");
Microseconds duration = 0;
media::TimeUnit duration;
if (!mDurations.empty()) {
duration = mDurations.front();
mDurations.pop();

View File

@ -9,6 +9,7 @@
#include "AndroidSurfaceTexture.h"
#include "MediaCodec.h"
#include "TimeUnits.h"
#include "mozilla/Monitor.h"
#include <queue>
@ -81,12 +82,13 @@ protected:
bool mStopping;
SampleQueue mQueue;
std::queue<Microseconds> mDurations;
// Durations are stored in microseconds.
std::queue<media::TimeUnit> mDurations;
virtual nsresult InitDecoder(widget::sdk::Surface::Param aSurface);
virtual nsresult Output(widget::sdk::BufferInfo::Param aInfo, void* aBuffer, widget::sdk::MediaFormat::Param aFormat, Microseconds aDuration) { return NS_OK; }
virtual nsresult PostOutput(widget::sdk::BufferInfo::Param aInfo, widget::sdk::MediaFormat::Param aFormat, Microseconds aDuration) { return NS_OK; }
virtual nsresult Output(widget::sdk::BufferInfo::Param aInfo, void* aBuffer, widget::sdk::MediaFormat::Param aFormat, const media::TimeUnit& aDuration) { return NS_OK; }
virtual nsresult PostOutput(widget::sdk::BufferInfo::Param aInfo, widget::sdk::MediaFormat::Param aFormat, const media::TimeUnit& aDuration) { return NS_OK; }
virtual void Cleanup() {};
nsresult ResetInputBuffers();

View File

@ -261,8 +261,8 @@ AppleATDecoder::DecodeSample(MediaRawData* aSample)
size_t numFrames = outputData.Length() / channels;
int rate = mOutputFormat.mSampleRate;
CheckedInt<Microseconds> duration = FramesToUsecs(numFrames, rate);
if (!duration.isValid()) {
media::TimeUnit duration = FramesToTimeUnit(numFrames, rate);
if (!duration.IsValid()) {
NS_WARNING("Invalid count of accumulated audio samples");
return NS_ERROR_FAILURE;
}
@ -270,14 +270,14 @@ AppleATDecoder::DecodeSample(MediaRawData* aSample)
#ifdef LOG_SAMPLE_DECODE
LOG("pushed audio at time %lfs; duration %lfs\n",
(double)aSample->mTime / USECS_PER_S,
(double)duration.value() / USECS_PER_S);
duration.ToSeconds());
#endif
nsAutoArrayPtr<AudioDataValue> data(new AudioDataValue[outputData.Length()]);
PodCopy(data.get(), &outputData[0], outputData.Length());
nsRefPtr<AudioData> audio = new AudioData(aSample->mOffset,
aSample->mTime,
duration.value(),
duration.ToMicroseconds(),
numFrames,
data.forget(),
channels,

View File

@ -195,9 +195,9 @@ PlatformCallback(void* decompressionOutputRefCon,
AutoCFRelease<CFNumberRef> kfref =
(CFNumberRef)CFDictionaryGetValue(frameInfo, CFSTR("FRAME_KEYFRAME"));
Microseconds dts;
Microseconds pts;
Microseconds duration;
int64_t dts;
int64_t pts;
int64_t duration;
int64_t byte_offset;
char is_sync_point;
@ -208,11 +208,12 @@ PlatformCallback(void* decompressionOutputRefCon,
CFNumberGetValue(kfref, kCFNumberSInt8Type, &is_sync_point);
nsAutoPtr<AppleVDADecoder::AppleFrameRef> frameRef(
new AppleVDADecoder::AppleFrameRef(dts,
pts,
duration,
byte_offset,
is_sync_point == 1));
new AppleVDADecoder::AppleFrameRef(
media::TimeUnit::FromMicroseconds(dts),
media::TimeUnit::FromMicroseconds(pts),
media::TimeUnit::FromMicroseconds(duration),
byte_offset,
is_sync_point == 1));
// Forward the data back to an object method which can access
// the correct MP4Reader callback.
@ -252,9 +253,9 @@ AppleVDADecoder::OutputFrame(CVPixelBufferRef aImage,
LOG("mp4 output frame %lld dts %lld pts %lld duration %lld us%s",
aFrameRef->byte_offset,
aFrameRef->decode_timestamp,
aFrameRef->composition_timestamp,
aFrameRef->duration,
aFrameRef->decode_timestamp.ToMicroseconds(),
aFrameRef->composition_timestamp.ToMicroseconds(),
aFrameRef->duration.ToMicroseconds(),
aFrameRef->is_sync_point ? " keyframe" : ""
);
@ -277,10 +278,11 @@ AppleVDADecoder::OutputFrame(CVPixelBufferRef aImage,
data = VideoData::CreateFromImage(info,
mImageContainer,
aFrameRef->byte_offset,
aFrameRef->composition_timestamp,
aFrameRef->duration, image.forget(),
aFrameRef->composition_timestamp.ToMicroseconds(),
aFrameRef->duration.ToMicroseconds(),
image.forget(),
aFrameRef->is_sync_point,
aFrameRef->decode_timestamp,
aFrameRef->decode_timestamp.ToMicroseconds(),
visible);
if (!data) {

View File

@ -13,6 +13,7 @@
#include "MP4Decoder.h"
#include "nsIThread.h"
#include "ReorderQueue.h"
#include "TimeUnits.h"
#include "VideoDecodeAcceleration/VDADecoder.h"
@ -28,24 +29,24 @@ class AppleVDADecoder : public MediaDataDecoder {
public:
class AppleFrameRef {
public:
Microseconds decode_timestamp;
Microseconds composition_timestamp;
Microseconds duration;
media::TimeUnit decode_timestamp;
media::TimeUnit composition_timestamp;
media::TimeUnit duration;
int64_t byte_offset;
bool is_sync_point;
explicit AppleFrameRef(const MediaRawData& aSample)
: decode_timestamp(aSample.mTimecode)
, composition_timestamp(aSample.mTime)
, duration(aSample.mDuration)
: decode_timestamp(media::TimeUnit::FromMicroseconds(aSample.mTimecode))
, composition_timestamp(media::TimeUnit::FromMicroseconds(aSample.mTime))
, duration(media::TimeUnit::FromMicroseconds(aSample.mDuration))
, byte_offset(aSample.mOffset)
, is_sync_point(aSample.mKeyframe)
{
}
AppleFrameRef(Microseconds aDts,
Microseconds aPts,
Microseconds aDuration,
AppleFrameRef(const media::TimeUnit& aDts,
const media::TimeUnit& aPts,
const media::TimeUnit& aDuration,
int64_t aByte_offset,
bool aIs_sync_point)
: decode_timestamp(aDts)

View File

@ -8,6 +8,7 @@
#include "FFmpegRuntimeLinker.h"
#include "FFmpegAudioDecoder.h"
#include "TimeUnits.h"
#define MAX_CHANNELS 16
@ -97,7 +98,7 @@ FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MediaRawData* aSample)
}
int64_t samplePosition = aSample->mOffset;
Microseconds pts = aSample->mTime;
media::TimeUnit pts = media::TimeUnit::FromMicroseconds(aSample->mTime);
while (packet.size > 0) {
int decoded;
@ -117,23 +118,28 @@ FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MediaRawData* aSample)
nsAutoArrayPtr<AudioDataValue> audio(
CopyAndPackAudio(mFrame, numChannels, mFrame->nb_samples));
CheckedInt<Microseconds> duration =
FramesToUsecs(mFrame->nb_samples, samplingRate);
if (!duration.isValid()) {
media::TimeUnit duration =
FramesToTimeUnit(mFrame->nb_samples, samplingRate);
if (!duration.IsValid()) {
NS_WARNING("Invalid count of accumulated audio samples");
mCallback->Error();
return;
}
nsRefPtr<AudioData> data = new AudioData(samplePosition,
pts,
duration.value(),
pts.ToMicroseconds(),
duration.ToMicroseconds(),
mFrame->nb_samples,
audio.forget(),
numChannels,
samplingRate);
mCallback->Output(data);
pts += duration.value();
pts += duration;
if (!pts.IsValid()) {
NS_WARNING("Invalid count of accumulated audio samples");
mCallback->Error();
return;
}
}
packet.data += bytesConsumed;
packet.size -= bytesConsumed;

View File

@ -9,6 +9,7 @@
#include "VideoUtils.h"
#include "WMFUtils.h"
#include "nsTArray.h"
#include "TimeUnits.h"
#include "mozilla/Logging.h"
@ -290,17 +291,18 @@ WMFAudioMFTManager::Output(int64_t aStreamOffset,
buffer->Unlock();
CheckedInt64 timestamp = FramesToUsecs(mAudioFrameOffset + mAudioFrameSum, mAudioRate);
NS_ENSURE_TRUE(timestamp.isValid(), E_FAIL);
media::TimeUnit timestamp =
FramesToTimeUnit(mAudioFrameOffset + mAudioFrameSum, mAudioRate);
NS_ENSURE_TRUE(timestamp.IsValid(), E_FAIL);
mAudioFrameSum += numFrames;
CheckedInt64 duration = FramesToUsecs(numFrames, mAudioRate);
NS_ENSURE_TRUE(duration.isValid(), E_FAIL);
media::TimeUnit duration = FramesToTimeUnit(numFrames, mAudioRate);
NS_ENSURE_TRUE(duration.IsValid(), E_FAIL);
aOutData = new AudioData(aStreamOffset,
timestamp.value(),
duration.value(),
timestamp.ToMicroseconds(),
duration.ToMicroseconds(),
numFrames,
audioData.forget(),
mAudioChannels,
@ -308,7 +310,7 @@ WMFAudioMFTManager::Output(int64_t aStreamOffset,
#ifdef LOG_SAMPLE_DECODE
LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u",
timestamp, duration, currentLength);
timestamp.ToMicroseconds(), duration.ToMicroseconds(), currentLength);
#endif
return S_OK;

View File

@ -70,23 +70,23 @@ MFOffsetToInt32(const MFOffset& aOffset)
return int32_t(aOffset.value + (aOffset.fract / 65536.0f));
}
int64_t
media::TimeUnit
GetSampleDuration(IMFSample* aSample)
{
NS_ENSURE_TRUE(aSample, -1);
NS_ENSURE_TRUE(aSample, media::TimeUnit::Invalid());
int64_t duration = 0;
aSample->GetSampleDuration(&duration);
return HNsToUsecs(duration);
return media::TimeUnit::FromMicroseconds(HNsToUsecs(duration));
}
int64_t
media::TimeUnit
GetSampleTime(IMFSample* aSample)
{
NS_ENSURE_TRUE(aSample, -1);
NS_ENSURE_TRUE(aSample, media::TimeUnit::Invalid());
LONGLONG timestampHns = 0;
HRESULT hr = aSample->GetSampleTime(&timestampHns);
NS_ENSURE_TRUE(SUCCEEDED(hr), -1);
return HNsToUsecs(timestampHns);
NS_ENSURE_TRUE(SUCCEEDED(hr), media::TimeUnit::Invalid());
return media::TimeUnit::FromMicroseconds(HNsToUsecs(timestampHns));
}
// Gets the sub-region of the video frame that should be displayed.

View File

@ -10,6 +10,7 @@
#include "WMF.h"
#include "nsString.h"
#include "nsRect.h"
#include "TimeUnits.h"
#include "VideoUtils.h"
// Various utilities shared by WMF backend files.
@ -46,14 +47,14 @@ MFOffsetToInt32(const MFOffset& aOffset);
HRESULT
GetPictureRegion(IMFMediaType* aMediaType, nsIntRect& aOutPictureRegion);
// Returns the duration of a IMFSample in microseconds.
// Returns -1 on failure.
int64_t
// Returns the duration of a IMFSample in TimeUnit.
// Returns media::TimeUnit::Invalid() on failure.
media::TimeUnit
GetSampleDuration(IMFSample* aSample);
// Returns the presentation time of a IMFSample in microseconds.
// Returns -1 on failure.
int64_t
// Returns the presentation time of a IMFSample in TimeUnit.
// Returns media::TimeUnit::Invalid() on failure.
media::TimeUnit
GetSampleTime(IMFSample* aSample);
inline bool

View File

@ -410,8 +410,10 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
b.mPlanes[2].mOffset = 0;
b.mPlanes[2].mSkip = 0;
Microseconds pts = GetSampleTime(aSample);
Microseconds duration = GetSampleDuration(aSample);
media::TimeUnit pts = GetSampleTime(aSample);
NS_ENSURE_TRUE(pts.IsValid(), E_FAIL);
media::TimeUnit duration = GetSampleDuration(aSample);
NS_ENSURE_TRUE(duration.IsValid(), E_FAIL);
nsRefPtr<layers::PlanarYCbCrImage> image =
new IMFYCbCrImage(buffer, twoDBuffer);
@ -426,8 +428,8 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
VideoData::CreateFromImage(mVideoInfo,
mImageContainer,
aStreamOffset,
std::max(0LL, pts),
duration,
pts.ToMicroseconds(),
duration.ToMicroseconds(),
image.forget(),
false,
-1,
@ -458,13 +460,15 @@ WMFVideoMFTManager::CreateD3DVideoFrame(IMFSample* aSample,
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
NS_ENSURE_TRUE(image, E_FAIL);
Microseconds pts = GetSampleTime(aSample);
Microseconds duration = GetSampleDuration(aSample);
media::TimeUnit pts = GetSampleTime(aSample);
NS_ENSURE_TRUE(pts.IsValid(), E_FAIL);
media::TimeUnit duration = GetSampleDuration(aSample);
NS_ENSURE_TRUE(duration.IsValid(), E_FAIL);
nsRefPtr<VideoData> v = VideoData::CreateFromImage(mVideoInfo,
mImageContainer,
aStreamOffset,
pts,
duration,
pts.ToMicroseconds(),
duration.ToMicroseconds(),
image.forget(),
false,
-1,

View File

@ -204,7 +204,7 @@ PluginPRLibrary::NPP_New(NPMIMEType pluginType, NPP instance,
nsresult
PluginPRLibrary::NPP_ClearSiteData(const char* site, uint64_t flags,
uint64_t maxAge)
uint64_t maxAge, nsCOMPtr<nsIClearSiteDataCallback> callback)
{
if (!mNPP_ClearSiteData) {
return NS_ERROR_NOT_AVAILABLE;
@ -213,39 +213,44 @@ PluginPRLibrary::NPP_ClearSiteData(const char* site, uint64_t flags,
MAIN_THREAD_JNI_REF_GUARD;
NPError result = mNPP_ClearSiteData(site, flags, maxAge);
nsresult rv;
switch (result) {
case NPERR_NO_ERROR:
return NS_OK;
rv = NS_OK;
break;
case NPERR_TIME_RANGE_NOT_SUPPORTED:
return NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED;
rv = NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED;
break;
case NPERR_MALFORMED_SITE:
return NS_ERROR_INVALID_ARG;
rv = NS_ERROR_INVALID_ARG;
break;
default:
return NS_ERROR_FAILURE;
rv = NS_ERROR_FAILURE;
}
callback->Callback(rv);
return NS_OK;
}
nsresult
PluginPRLibrary::NPP_GetSitesWithData(InfallibleTArray<nsCString>& result)
PluginPRLibrary::NPP_GetSitesWithData(nsCOMPtr<nsIGetSitesWithDataCallback> callback)
{
if (!mNPP_GetSitesWithData) {
return NS_ERROR_NOT_AVAILABLE;
}
result.Clear();
MAIN_THREAD_JNI_REF_GUARD;
char** sites = mNPP_GetSitesWithData();
if (!sites) {
return NS_OK;
}
InfallibleTArray<nsCString> result;
char** iterator = sites;
while (*iterator) {
result.AppendElement(*iterator);
free(*iterator);
++iterator;
}
callback->SitesWithData(result);
free(sites);
return NS_OK;

View File

@ -105,8 +105,8 @@ public:
NPError* aError) override;
virtual nsresult NPP_ClearSiteData(const char* aSite, uint64_t aFlags,
uint64_t aMaxAge) override;
virtual nsresult NPP_GetSitesWithData(InfallibleTArray<nsCString>& aResult) override;
uint64_t aMaxAge, nsCOMPtr<nsIClearSiteDataCallback> callback) override;
virtual nsresult NPP_GetSitesWithData(nsCOMPtr<nsIGetSitesWithDataCallback> callback) override;
virtual nsresult AsyncSetWindow(NPP aInstance, NPWindow* aWindow) override;
virtual nsresult GetImageContainer(NPP aInstance, mozilla::layers::ImageContainer** aContainer) override;

View File

@ -27,7 +27,16 @@ interface nsIPluginPlayPreviewInfo : nsISupports
boolean checkWhitelist(in AUTF8String pageURI, in AUTF8String objectURI);
};
[scriptable, uuid(d7d5b2e0-105b-4c9d-8558-b6b31f28b7df)]
[scriptable, function, uuid(9c311778-7c2c-4ad8-b439-b8a2786a20dd)]
interface nsIClearSiteDataCallback : nsISupports
{
/**
* callback with the result from a call to clearSiteData
*/
void callback(in nsresult rv);
};
[scriptable, uuid(a884e736-5396-4400-bc82-9a23d871d12c)]
interface nsIPluginHost : nsISupports
{
/**
@ -77,7 +86,8 @@ interface nsIPluginHost : nsISupports
* general or for that particular site and/or flag combination.
*/
void clearSiteData(in nsIPluginTag plugin, in AUTF8String domain,
in uint64_t flags, in int64_t maxAge);
in uint64_t flags, in int64_t maxAge,
in nsIClearSiteDataCallback callback);
/*
* Determine if a plugin has stored data for a given site.

View File

@ -1969,7 +1969,7 @@ nsJSNPRuntime::OnPluginDestroy(NPP npp)
}
if (sNPObjWrappers) {
for (auto i = sNPObjWrappers->RemovingIter(); !i.Done(); i.Next()) {
for (auto i = sNPObjWrappers->Iter(); !i.Done(); i.Next()) {
auto entry = static_cast<NPObjWrapperHashEntry*>(i.Get());
if (entry->mNpp == npp) {

View File

@ -1534,10 +1534,77 @@ nsPluginHost::GetPlayPreviewInfo(const nsACString& mimeType,
return NS_ERROR_NOT_AVAILABLE;
}
#define ClearDataFromSitesClosure_CID {0x9fb21761, 0x2403, 0x41ad, {0x9e, 0xfd, 0x36, 0x7e, 0xc4, 0x4f, 0xa4, 0x5e}}
// Class to hold all the data we need need for IterateMatchesAndClear and ClearDataFromSites
class ClearDataFromSitesClosure : public nsIClearSiteDataCallback, public nsIGetSitesWithDataCallback {
public:
ClearDataFromSitesClosure(nsIPluginTag* plugin, const nsACString& domain, uint64_t flags,
int64_t maxAge, nsCOMPtr<nsIClearSiteDataCallback> callback,
nsPluginHost* host) :
domain(domain), callback(callback), tag(plugin), flags(flags), maxAge(maxAge), host(host) {}
NS_DECL_ISUPPORTS
// Callback from NPP_ClearSiteData, continue to iterate the matches and clear
NS_IMETHOD Callback(nsresult rv) override {
if (NS_FAILED(rv)) {
callback->Callback(rv);
return NS_OK;
}
if (!matches.Length()) {
callback->Callback(NS_OK);
return NS_OK;
}
const nsCString match(matches[0]);
matches.RemoveElement(match);
PluginLibrary* library = static_cast<nsPluginTag*>(tag)->mPlugin->GetLibrary();
rv = library->NPP_ClearSiteData(match.get(), flags, maxAge, this);
if (NS_FAILED(rv)) {
callback->Callback(rv);
return NS_OK;
}
return NS_OK;
}
// Callback from NPP_GetSitesWithData, kick the iteration off to clear the data
NS_IMETHOD SitesWithData(InfallibleTArray<nsCString>& sites) override
{
// Enumerate the sites and build a list of matches.
nsresult rv = host->EnumerateSiteData(domain, sites, matches, false);
Callback(rv);
return NS_OK;
}
nsCString domain;
nsCOMPtr<nsIClearSiteDataCallback> callback;
InfallibleTArray<nsCString> matches;
nsIPluginTag* tag;
uint64_t flags;
int64_t maxAge;
nsPluginHost* host;
NS_DECLARE_STATIC_IID_ACCESSOR(ClearDataFromSitesClosure_CID)
private:
virtual ~ClearDataFromSitesClosure() {}
};
NS_DEFINE_STATIC_IID_ACCESSOR(ClearDataFromSitesClosure, ClearDataFromSitesClosure_CID)
NS_IMPL_ADDREF(ClearDataFromSitesClosure)
NS_IMPL_RELEASE(ClearDataFromSitesClosure)
NS_INTERFACE_MAP_BEGIN(ClearDataFromSitesClosure)
NS_INTERFACE_MAP_ENTRY(nsIClearSiteDataCallback)
NS_INTERFACE_MAP_ENTRY(nsIGetSitesWithDataCallback)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIClearSiteDataCallback)
NS_INTERFACE_MAP_END
NS_IMETHODIMP
nsPluginHost::ClearSiteData(nsIPluginTag* plugin, const nsACString& domain,
uint64_t flags, int64_t maxAge)
uint64_t flags, int64_t maxAge, nsIClearSiteDataCallback* callbackFunc)
{
nsCOMPtr<nsIClearSiteDataCallback> callback(callbackFunc);
// maxAge must be either a nonnegative integer or -1.
NS_ENSURE_ARG(maxAge >= 0 || maxAge == -1);
@ -1569,29 +1636,71 @@ nsPluginHost::ClearSiteData(nsIPluginTag* plugin, const nsACString& domain,
// If 'domain' is the null string, clear everything.
if (domain.IsVoid()) {
return library->NPP_ClearSiteData(nullptr, flags, maxAge);
return library->NPP_ClearSiteData(nullptr, flags, maxAge, callback);
}
// Get the list of sites from the plugin.
InfallibleTArray<nsCString> sites;
rv = library->NPP_GetSitesWithData(sites);
nsCOMPtr<nsIGetSitesWithDataCallback> closure(new ClearDataFromSitesClosure(plugin, domain, flags,
maxAge, callback, this));
rv = library->NPP_GetSitesWithData(closure);
NS_ENSURE_SUCCESS(rv, rv);
// Enumerate the sites and build a list of matches.
InfallibleTArray<nsCString> matches;
rv = EnumerateSiteData(domain, sites, matches, false);
NS_ENSURE_SUCCESS(rv, rv);
// Clear the matches.
for (uint32_t i = 0; i < matches.Length(); ++i) {
const nsCString& match = matches[i];
rv = library->NPP_ClearSiteData(match.get(), flags, maxAge);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
#define GetSitesClosure_CID {0x4c9268ac, 0x2fd1, 0x4f2a, {0x9a, 0x10, 0x7a, 0x09, 0xf1, 0xb7, 0x60, 0x3a}}
// Closure to contain the data needed to handle the callback from NPP_GetSitesWithData
class GetSitesClosure : public nsIGetSitesWithDataCallback {
public:
NS_DECL_ISUPPORTS
GetSitesClosure(const nsACString& domain, nsPluginHost* host)
: domain(domain), host(host), keepWaiting(true)
{
}
NS_IMETHOD SitesWithData(InfallibleTArray<nsCString>& sites) override {
retVal = HandleGetSites(sites);
keepWaiting = false;
return NS_OK;
}
nsresult HandleGetSites(InfallibleTArray<nsCString>& sites) {
// If there's no data, we're done.
if (sites.IsEmpty()) {
result = false;
return NS_OK;
}
// If 'domain' is the null string, and there's data for at least one site,
// we're done.
if (domain.IsVoid()) {
result = true;
return NS_OK;
}
// Enumerate the sites and determine if there's a match.
InfallibleTArray<nsCString> matches;
nsresult rv = host->EnumerateSiteData(domain, sites, matches, true);
NS_ENSURE_SUCCESS(rv, rv);
result = !matches.IsEmpty();
return NS_OK;
}
nsCString domain;
nsRefPtr<nsPluginHost> host;
bool result;
bool keepWaiting;
nsresult retVal;
NS_DECLARE_STATIC_IID_ACCESSOR(GetSitesClosure_CID)
private:
virtual ~GetSitesClosure() {
}
};
NS_DEFINE_STATIC_IID_ACCESSOR(GetSitesClosure, GetSitesClosure_CID)
NS_IMPL_ISUPPORTS(GetSitesClosure, GetSitesClosure, nsIGetSitesWithDataCallback)
// This will spin the event loop while waiting on an async
// call to GetSitesWithData
NS_IMETHODIMP
nsPluginHost::SiteHasData(nsIPluginTag* plugin, const nsACString& domain,
bool* result)
@ -1619,31 +1728,16 @@ nsPluginHost::SiteHasData(nsIPluginTag* plugin, const nsACString& domain,
PluginLibrary* library = tag->mPlugin->GetLibrary();
// Get the list of sites from the plugin.
InfallibleTArray<nsCString> sites;
rv = library->NPP_GetSitesWithData(sites);
// Get the list of sites from the plugin
nsCOMPtr<GetSitesClosure> closure(new GetSitesClosure(domain, this));
rv = library->NPP_GetSitesWithData(nsCOMPtr<nsIGetSitesWithDataCallback>(do_QueryInterface(closure)));
NS_ENSURE_SUCCESS(rv, rv);
// If there's no data, we're done.
if (sites.IsEmpty()) {
*result = false;
return NS_OK;
// Spin the event loop while we wait for the async call to GetSitesWithData
while (closure->keepWaiting) {
NS_ProcessNextEvent(nullptr, true);
}
// If 'domain' is the null string, and there's data for at least one site,
// we're done.
if (domain.IsVoid()) {
*result = true;
return NS_OK;
}
// Enumerate the sites and determine if there's a match.
InfallibleTArray<nsCString> matches;
rv = EnumerateSiteData(domain, sites, matches, true);
NS_ENSURE_SUCCESS(rv, rv);
*result = !matches.IsEmpty();
return NS_OK;
*result = closure->result;
return closure->retVal;
}
nsPluginHost::SpecialType

View File

@ -243,6 +243,11 @@ public:
void CreateWidget(nsPluginInstanceOwner* aOwner);
nsresult EnumerateSiteData(const nsACString& domain,
const InfallibleTArray<nsCString>& sites,
InfallibleTArray<nsCString>& result,
bool firstMatchOnly);
private:
friend class nsPluginUnloadRunnable;
@ -366,10 +371,6 @@ private:
// Helpers for ClearSiteData and SiteHasData.
nsresult NormalizeHostname(nsCString& host);
nsresult EnumerateSiteData(const nsACString& domain,
const InfallibleTArray<nsCString>& sites,
InfallibleTArray<nsCString>& result,
bool firstMatchOnly);
nsWeakPtr mCurrentDocument; // weak reference, we use it to id document only

View File

@ -76,11 +76,9 @@ child:
returns (bool aURLRedirectNotify, bool aClearSiteData,
bool aGetSitesWithData);
intr NPP_ClearSiteData(nsCString site, uint64_t flags, uint64_t maxAge)
returns (NPError rv);
async NPP_ClearSiteData(nsCString site, uint64_t flags, uint64_t maxAge, uint64_t aCallbackId);
intr NPP_GetSitesWithData()
returns (nsCString[] sites);
async NPP_GetSitesWithData(uint64_t aCallbackId);
// Windows specific message to set up an audio session in the plugin process
async SetAudioSessionData(nsID aID,
@ -148,6 +146,12 @@ parent:
async NotifyContentModuleDestroyed();
async Profile(nsCString aProfile);
// Answers to request about site data
async ReturnClearSiteData(NPError aRv, uint64_t aCallbackId);
async ReturnSitesWithData(nsCString[] aSites, uint64_t aCallbackId);
};
} // namespace plugins

View File

@ -28,6 +28,15 @@ class ImageContainer;
}
}
class nsIClearSiteDataCallback;
#define nsIGetSitesWithDataCallback_CID {0xd0028b83, 0xfdf9, 0x4c53, {0xb7, 0xbb, 0x47, 0x46, 0x0f, 0x6b, 0x83, 0x6c}}
class nsIGetSitesWithDataCallback : public nsISupports {
public:
NS_IMETHOD SitesWithData(InfallibleTArray<nsCString>& result) = 0;
NS_DECLARE_STATIC_IID_ACCESSOR(nsIGetSitesWithDataCallback_CID)
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIGetSitesWithDataCallback, nsIGetSitesWithDataCallback_CID)
namespace mozilla {
@ -62,8 +71,8 @@ public:
NPError* error) = 0;
virtual nsresult NPP_ClearSiteData(const char* site, uint64_t flags,
uint64_t maxAge) = 0;
virtual nsresult NPP_GetSitesWithData(InfallibleTArray<nsCString>& aResult) = 0;
uint64_t maxAge, nsCOMPtr<nsIClearSiteDataCallback> callback) = 0;
virtual nsresult NPP_GetSitesWithData(nsCOMPtr<nsIGetSitesWithDataCallback> callback) = 0;
virtual nsresult AsyncSetWindow(NPP instance, NPWindow* window) = 0;
virtual nsresult GetImageContainer(NPP instance, mozilla::layers::ImageContainer** aContainer) = 0;

View File

@ -734,31 +734,34 @@ PluginModuleChild::AnswerOptionalFunctionsSupported(bool *aURLRedirectNotify,
}
bool
PluginModuleChild::AnswerNPP_ClearSiteData(const nsCString& aSite,
PluginModuleChild::RecvNPP_ClearSiteData(const nsCString& aSite,
const uint64_t& aFlags,
const uint64_t& aMaxAge,
NPError* aResult)
const uint64_t& aCallbackId)
{
*aResult =
NPError result =
mFunctions.clearsitedata(NullableStringGet(aSite), aFlags, aMaxAge);
SendReturnClearSiteData(result, aCallbackId);
return true;
}
bool
PluginModuleChild::AnswerNPP_GetSitesWithData(InfallibleTArray<nsCString>* aResult)
PluginModuleChild::RecvNPP_GetSitesWithData(const uint64_t& aCallbackId)
{
char** result = mFunctions.getsiteswithdata();
if (!result)
InfallibleTArray<nsCString> array;
if (!result) {
SendReturnSitesWithData(array, aCallbackId);
return true;
}
char** iterator = result;
while (*iterator) {
aResult->AppendElement(*iterator);
array.AppendElement(*iterator);
free(*iterator);
++iterator;
}
SendReturnSitesWithData(array, aCallbackId);
free(result);
return true;
}

View File

@ -112,13 +112,13 @@ protected:
bool *aGetSitesWithData) override;
virtual bool
AnswerNPP_ClearSiteData(const nsCString& aSite,
RecvNPP_ClearSiteData(const nsCString& aSite,
const uint64_t& aFlags,
const uint64_t& aMaxAge,
NPError* aResult) override;
const uint64_t& aCallbackId) override;
virtual bool
AnswerNPP_GetSitesWithData(InfallibleTArray<nsCString>* aResult) override;
RecvNPP_GetSitesWithData(const uint64_t& aCallbackId) override;
virtual bool
RecvSetAudioSessionData(const nsID& aId,

View File

@ -2654,35 +2654,34 @@ PluginModuleChromeParent::UpdatePluginTimeout()
}
nsresult
PluginModuleParent::NPP_ClearSiteData(const char* site, uint64_t flags,
uint64_t maxAge)
PluginModuleParent::NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge,
nsCOMPtr<nsIClearSiteDataCallback> callback)
{
if (!mClearSiteDataSupported)
return NS_ERROR_NOT_AVAILABLE;
NPError result;
if (!CallNPP_ClearSiteData(NullableString(site), flags, maxAge, &result))
return NS_ERROR_FAILURE;
static uint64_t callbackId = 0;
callbackId++;
mClearSiteDataCallbacks[callbackId] = callback;
switch (result) {
case NPERR_NO_ERROR:
return NS_OK;
case NPERR_TIME_RANGE_NOT_SUPPORTED:
return NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED;
case NPERR_MALFORMED_SITE:
return NS_ERROR_INVALID_ARG;
default:
if (!SendNPP_ClearSiteData(NullableString(site), flags, maxAge, callbackId)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
PluginModuleParent::NPP_GetSitesWithData(InfallibleTArray<nsCString>& result)
PluginModuleParent::NPP_GetSitesWithData(nsCOMPtr<nsIGetSitesWithDataCallback> callback)
{
if (!mGetSitesWithDataSupported)
return NS_ERROR_NOT_AVAILABLE;
if (!CallNPP_GetSitesWithData(&result))
static uint64_t callbackId = 0;
callbackId++;
mSitesWithDataCallbacks[callbackId] = callback;
if (!SendNPP_GetSitesWithData(callbackId))
return NS_ERROR_FAILURE;
return NS_OK;
@ -2936,6 +2935,49 @@ PluginModuleChromeParent::RecvNotifyContentModuleDestroyed()
return true;
}
bool
PluginModuleParent::RecvReturnClearSiteData(const NPError& aRv,
const uint64_t& aCallbackId)
{
if (mClearSiteDataCallbacks.find(aCallbackId) == mClearSiteDataCallbacks.end()) {
return true;
}
if (!!mClearSiteDataCallbacks[aCallbackId]) {
nsresult rv;
switch (aRv) {
case NPERR_NO_ERROR:
rv = NS_OK;
break;
case NPERR_TIME_RANGE_NOT_SUPPORTED:
rv = NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED;
break;
case NPERR_MALFORMED_SITE:
rv = NS_ERROR_INVALID_ARG;
break;
default:
rv = NS_ERROR_FAILURE;
}
mClearSiteDataCallbacks[aCallbackId]->Callback(rv);
}
mClearSiteDataCallbacks.erase(aCallbackId);
return true;
}
bool
PluginModuleParent::RecvReturnSitesWithData(nsTArray<nsCString>&& aSites,
const uint64_t& aCallbackId)
{
if (mSitesWithDataCallbacks.find(aCallbackId) == mSitesWithDataCallbacks.end()) {
return true;
}
if (!!mSitesWithDataCallbacks[aCallbackId]) {
mSitesWithDataCallbacks[aCallbackId]->SitesWithData(aSites);
}
mSitesWithDataCallbacks.erase(aCallbackId);
return true;
}
#ifdef MOZ_CRASHREPORTER_INJECTOR
// We only add the crash reporter to subprocess which have the filename

View File

@ -200,6 +200,12 @@ protected:
virtual bool RecvProfile(const nsCString& aProfile) override { return true; }
virtual bool RecvReturnClearSiteData(const NPError& aRv,
const uint64_t& aCallbackId) override;
virtual bool RecvReturnSitesWithData(nsTArray<nsCString>&& aSites,
const uint64_t& aCallbackId) override;
void SetPluginFuncs(NPPluginFuncs* aFuncs);
nsresult NPP_NewInternal(NPMIMEType pluginType, NPP instance, uint16_t mode,
@ -264,9 +270,15 @@ protected:
uint16_t mode, int16_t argc, char* argn[],
char* argv[], NPSavedData* saved,
NPError* error) override;
virtual nsresult NPP_ClearSiteData(const char* site, uint64_t flags,
uint64_t maxAge) override;
virtual nsresult NPP_GetSitesWithData(InfallibleTArray<nsCString>& result) override;
virtual nsresult NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge,
nsCOMPtr<nsIClearSiteDataCallback> callback) override;
virtual nsresult NPP_GetSitesWithData(nsCOMPtr<nsIGetSitesWithDataCallback> callback) override;
private:
std::map<uint64_t, nsCOMPtr<nsIClearSiteDataCallback>> mClearSiteDataCallbacks;
std::map<uint64_t, nsCOMPtr<nsIGetSitesWithDataCallback>> mSitesWithDataCallbacks;
public:
#if defined(XP_MACOSX)
virtual nsresult IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing) override;

View File

@ -28,9 +28,7 @@
SimpleTest.executeSoon(function() {
// Make sure clearing by timerange is supported.
p.setSitesWithDataCapabilities(true);
ok(PluginUtils.withTestPlugin(runTest), "Test plugin found");
SimpleTest.finish();
});
function stored(needles) {
@ -59,7 +57,6 @@
function runTest(pluginTag) {
this.pluginTag = pluginTag;
p.setSitesWithData(
"foo.com:0:5," +
"foo.com:0:7," +
@ -69,75 +66,99 @@
"qux.com:1:5," +
"quz.com:1:8"
);
ok(stored(["foo.com","bar.com","baz.com","qux.com","quz.com"]),
"Data stored for sites");
// Clear nothing.
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_ALL, 4);
ok(stored(["foo.com","bar.com","baz.com","qux.com","quz.com"]),
"Data stored for sites");
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 4);
// Clear nothing.
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_ALL, 4, {callback: function() { test1(); }});
}
function test1() {
ok(stored(["foo.com","bar.com","baz.com","qux.com","quz.com"]),
"Data stored for sites");
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 4, {callback: function() { test2(); }});
}
function test2() {
ok(stored(["foo.com","bar.com","baz.com","qux.com","quz.com"]),
"Data stored for sites");
// Clear cache data 5 seconds or older.
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 5);
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 5, {callback: function() { test3(); }});
}
function test3() {
ok(stored(["foo.com","bar.com","baz.com","quz.com"]),
"Data stored for sites");
ok(!stored(["qux.com"]), "Data cleared for qux.com");
// Clear cache data for foo.com, but leave non-cache data.
pluginHost.clearSiteData(pluginTag, "foo.com", FLAG_CLEAR_CACHE, 20);
pluginHost.clearSiteData(pluginTag, "foo.com", FLAG_CLEAR_CACHE, 20, {callback: function() { test4(); }});
}
function test4() {
ok(stored(["foo.com","bar.com","baz.com","quz.com"]),
"Data stored for sites");
// Clear all data 7 seconds or older.
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_ALL, 7);
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_ALL, 7, {callback: function() { test5(); }});
}
function test5() {
ok(stored(["bar.com","baz.com","quz.com"]), "Data stored for sites");
ok(!stored(["foo.com"]), "Data cleared for foo.com");
ok(!stored(["qux.com"]), "Data cleared for qux.com");
// Clear all cache data.
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 20);
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 20, {callback: function() { test6(); }});
}
function test6() {
ok(stored(["bar.com","baz.com"]), "Data stored for sites");
ok(!stored(["quz.com"]), "Data cleared for quz.com");
// Clear all data for bar.com.
pluginHost.clearSiteData(pluginTag, "bar.com", FLAG_CLEAR_ALL, 20);
pluginHost.clearSiteData(pluginTag, "bar.com", FLAG_CLEAR_ALL, 20, {callback: function(rv) { test7(rv); }});
}
function test7(rv) {
ok(stored(["baz.com"]), "Data stored for baz.com");
ok(!stored(["bar.com"]), "Data cleared for bar.com");
// Disable clearing by age.
p.setSitesWithDataCapabilities(false);
// Attempt to clear data by age.
checkThrows(function() {
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_ALL, 20);
}, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
checkThrows(function() {
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 20);
}, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
checkThrows(function() {
pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_ALL, 20);
}, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
checkThrows(function() {
pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_CACHE, 20);
}, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_ALL, 20, {callback: function(rv) {
is(rv, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
test8(rv);
}});
}
function test8(rv) {
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 20, {callback: function(rv) {
is(rv, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
test9(rv);
}});
}
function test9(rv) {
pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_ALL, 20, {callback: function(rv) {
is(rv, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
test10(rv);
}});
}
function test10(rv) {
pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_CACHE, 20, {callback: function(rv) {
is(rv, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
test11();
}});
}
function test11() {
// Clear cache for baz.com and globally for all ages.
pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_CACHE, -1);
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, -1);
pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_CACHE, -1, {callback: function(rv) { test12()}});
}
function test12() {
pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, -1, {callback: function(rv) { test13()}});
}
function test13() {
// Check that all of the above were no-ops.
ok(stored(["baz.com"]), "Data stored for baz.com");
// Clear everything for baz.com.
pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_ALL, -1);
pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test14()}});
}
function test14() {
ok(!stored(["baz.com"]), "Data cleared for baz.com");
ok(!stored(null), "All data cleared");
@ -150,26 +171,33 @@
"[192.168.1.1]:0:0," +
"localhost:0:0"
);
ok(stored(["foo.com","nonexistent.foo.com","bar.com","192.168.1.1","localhost"]),
"Data stored for sites");
"Data stored for sites");
// Clear data for "foo.com" and its subdomains.
pluginHost.clearSiteData(pluginTag, "foo.com", FLAG_CLEAR_ALL, -1);
pluginHost.clearSiteData(pluginTag, "foo.com", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test15()}});
}
function test15() {
ok(stored(["bar.com","192.168.1.1","localhost"]), "Data stored for sites");
ok(!stored(["foo.com"]), "Data cleared for foo.com");
ok(!stored(["bar.foo.com"]), "Data cleared for subdomains of foo.com");
// Clear data for "bar.com" using a subdomain.
pluginHost.clearSiteData(pluginTag, "foo.bar.com", FLAG_CLEAR_ALL, -1);
pluginHost.clearSiteData(pluginTag, "foo.bar.com", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test16()}});
}
function test16() {
ok(!stored(["bar.com"]), "Data cleared for bar.com");
// Clear data for "192.168.1.1".
pluginHost.clearSiteData(pluginTag, "192.168.1.1", FLAG_CLEAR_ALL, -1);
pluginHost.clearSiteData(pluginTag, "192.168.1.1", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test17()}});
}
function test17() {
ok(!stored(["192.168.1.1"]), "Data cleared for 192.168.1.1");
// Clear data for "localhost".
pluginHost.clearSiteData(pluginTag, "localhost", FLAG_CLEAR_ALL, -1);
pluginHost.clearSiteData(pluginTag, "localhost", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test18()}});
}
function test18() {
ok(!stored(null), "All data cleared");
// Set data to test international domains.
@ -178,18 +206,21 @@
"b\u00FCcher.uk:0:0," +
"xn--bcher-kva.NZ:0:0"
);
// Check that both the ACE and UTF-8 representations register.
// Check that both the ACE and UTF-8 representations register.
ok(stored(["b\u00FCcher.es","xn--bcher-kva.es","b\u00FCcher.uk","xn--bcher-kva.uk"]),
"Data stored for sites");
"Data stored for sites");
// Clear data for the UTF-8 version.
pluginHost.clearSiteData(pluginTag, "b\u00FCcher.es", FLAG_CLEAR_ALL, -1);
pluginHost.clearSiteData(pluginTag, "b\u00FCcher.es", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test19()}});
}
function test19() {
ok(!stored(["b\u00FCcher.es"]), "Data cleared for UTF-8 representation");
ok(!stored(["xn--bcher-kva.es"]), "Data cleared for ACE representation");
// Clear data for the ACE version.
pluginHost.clearSiteData(pluginTag, "xn--bcher-kva.uk", FLAG_CLEAR_ALL, -1);
pluginHost.clearSiteData(pluginTag, "xn--bcher-kva.uk", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test20()}});
}
function test20() {
ok(!stored(["b\u00FCcher.uk"]), "Data cleared for UTF-8 representation");
ok(!stored(["xn--bcher-kva.uk"]), "Data cleared for ACE representation");
@ -197,11 +228,14 @@
// UTF-8. We do happen to normalize the result anyway, so while that's not
// strictly required, we test it here.
ok(stored(["b\u00FCcher.nz","xn--bcher-kva.nz"]),
"Data stored for sites");
pluginHost.clearSiteData(pluginTag, "b\u00FCcher.nz", FLAG_CLEAR_ALL, -1);
"Data stored for sites");
pluginHost.clearSiteData(pluginTag, "b\u00FCcher.nz", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test21()}});
}
function test21() {
ok(!stored(["b\u00FCcher.nz"]), "Data cleared for UTF-8 representation");
ok(!stored(["xn--bcher-kva.nz"]), "Data cleared for ACE representation");
ok(!stored(null), "All data cleared");
SimpleTest.finish();
}
</script>
</body>

View File

@ -5,21 +5,15 @@
* In particular, the tests check that default-src and manifest-src directives are
* are respected by the ManifestObtainer.
*/
/*globals Components*/
/*globals SpecialPowers, requestLongerTimeout, ok, Cu, is, add_task, gBrowser, BrowserTestUtils, ManifestObtainer*/
'use strict';
requestLongerTimeout(10); // e10s tests take time.
const {
ManifestObtainer
} = Components.utils.import('resource://gre/modules/WebManifest.jsm', {});
Cu.import('resource://gre/modules/ManifestObtainer.jsm', this); // jshint ignore:line
const path = '/tests/dom/security/test/csp/';
const testFile = `file=${path}file_web_manifest.html`;
const remoteFile = `file=${path}file_web_manifest_remote.html`;
const httpsManifest = `file=${path}file_web_manifest_https.html`;
const mixedContent = `file=${path}file_web_manifest_mixed_content.html`;
const server = 'file_testserver.sjs';
const defaultURL = `http://example.org${path}${server}`;
const remoteURL = `http://mochi.test:8888`;
const secureURL = `https://example.com${path}${server}`;
const tests = [
// CSP block everything, so trying to load a manifest
// will result in a policy violation.
@ -248,7 +242,7 @@ function NetworkObserver(test) {
let success = false;
this.finished = new Promise((resolver) => {
finishedTest = resolver;
})
});
this.observe = function observer(subject, topic) {
SpecialPowers.removeObserver(this, 'csp-on-violate-policy');
test.run(topic);

View File

@ -3,10 +3,12 @@
* Check that mixed content blocker works prevents fetches of
* mixed content manifests.
*/
/*globals Cu, add_task, ok, gBrowser, BrowserTestUtils, ManifestObtainer*/
'use strict';
const {
ManifestObtainer
} = Components.utils.import('resource://gre/modules/WebManifest.jsm', {});
} = Cu.import('resource://gre/modules/ManifestObtainer.jsm', this); // jshint ignore:line
const obtainer = new ManifestObtainer();
const path = '/tests/dom/security/test/csp/';
const mixedContent = `file=${path}file_web_manifest_mixed_content.html`;
const server = 'file_testserver.sjs';
@ -31,7 +33,7 @@ const tests = [
];
//jscs:disable
add_task(function*() {
add_task(function* () {
//jscs:enable
for (let test of tests) {
let tabOptions = {
@ -45,11 +47,11 @@ add_task(function*() {
}
function* testObtainingManifest(aBrowser, aTest) {
const obtainer = new ManifestObtainer();
let manifest;
try {
yield obtainer.obtainManifest(aBrowser);
} catch (e) {
aTest.run(e)
return aTest.run(e);
}
}
});

View File

@ -147,10 +147,13 @@ function expectFocusShift(callback, expectedWindow, expectedElement, focusChange
// for this test which fires a mouse event on a label, the document will
// be focused first and then the label code will focus the related
// control. This doesn't result in different focus events, but a command
// update will occur for the document and then a secon command update will
// occur when the control is focused.
if (testid == "mouse on html label with content inside")
// update will occur for the document and then a second command update will
// occur when the control is focused. However, this will only happen on
// platforms or controls where mouse clicks cause trigger focus.
if (testid == "mouse on html label with content inside" &&
mouseWillTriggerFocus(expectedElement)) {
expectedEvents += " commandupdate: cu";
}
if (expectedElement &&
(!gNewExpectedWindow || gNewExpectedWindow.document.documentElement != expectedElement)) {
@ -278,25 +281,36 @@ function getTopWindow(win)
getInterface(Components.interfaces.nsIDOMWindow);
}
function mouseWillTriggerFocus(element)
{
if (!element) {
return false;
}
if (navigator.platform.indexOf("Mac") != 0) {
return true;
}
if (element.namespaceURI == "http://www.w3.org/1999/xhtml") {
// links are special. They can be focused but show no focus ring
if (element.localName == "a" || element.localName == "div" ||
element.localName == "select" ||
element.localName == "input" && (element.type == "text" ||
element.type == "password")) {
return true;
}
} else if (element.localName == "listbox") {
return true;
}
return false;
}
function mouseOnElement(element, expectedElement, focusChanged, testid)
{
var expectedWindow = (element.ownerDocument.defaultView == gChildWindow) ? gChildWindow : window;
// on Mac, form elements are not focused when clicking, except for lists and textboxes.
var noFocusOnMouse = (navigator.platform.indexOf("Mac") == 0);
if (noFocusOnMouse) {
if (element.namespaceURI == "http://www.w3.org/1999/xhtml") {
// links are special. They can be focused but show no focus ring
if (element.localName == "a" || element.localName == "div" ||
element.localName == "select" ||
element.localName == "input" && (element.type == "text" ||
element.type == "password")) {
noFocusOnMouse = false;
}
}
else if (element.localName == "listbox") {
noFocusOnMouse = false;
}
}
var noFocusOnMouse = !mouseWillTriggerFocus(element)
if (noFocusOnMouse) {
// no focus so the last focus method will be 0
@ -552,11 +566,9 @@ function startTest()
}
// clicking on the labels
gLastFocusMethod = fm.FLAG_BYMOVEFOCUS;
expectFocusShift(function () synthesizeMouse(getById("ad"), 2, 2, { }, gChildWindow),
null, getById("t29"), true, "mouse on html label with content inside");
expectFocusShift(function () synthesizeMouse(getById("ag"), 2, 2, { }, gChildWindow),
null, getById("n6"), true, "mouse on html label with for attribute");
gLastFocusMethod = fm.FLAG_BYMOVEFOCUS | fm.FLAG_BYMOUSE;
mouseOnElement(getById("ad"), getById("t29"), true, "mouse on html label with content inside");
mouseOnElement(getById("ag"), getById("n6"), true, "mouse on html label with for attribute");
gLastFocusMethod = 0;
expectFocusShift(function () synthesizeMouse(getById("aj"), 2, 2, { }),
null, getById("o9"), true, "mouse on xul label with content inside");

View File

@ -272,6 +272,11 @@ LayerManagerComposite::EndTransaction(const TimeStamp& aTimeStamp,
return;
}
// Set composition timestamp here because we need it in
// ComputeEffectiveTransforms (so the correct video frame size is picked) and
// also to compute invalid regions properly.
mCompositor->SetCompositionTime(aTimeStamp);
if (mRoot && mClonedLayerTreeProperties) {
MOZ_ASSERT(!mTarget);
nsIntRegion invalid =
@ -290,9 +295,6 @@ LayerManagerComposite::EndTransaction(const TimeStamp& aTimeStamp,
if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
MOZ_ASSERT(!aTimeStamp.IsNull());
// Set composition timestamp here because we need it in
// ComputeEffectiveTransforms (so the correct video frame size is picked)
mCompositor->SetCompositionTime(aTimeStamp);
// The results of our drawing always go directly into a pixel buffer,
// so we don't need to pass any global transform here.
mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());

View File

@ -439,7 +439,11 @@ CreateBoxShadow(DrawTarget& aDT, SourceSurface* aBlurMask, const gfxRGBA& aShado
return nullptr;
}
MOZ_ASSERT(boxShadowDT->GetType() == aDT.GetType());
if (boxShadowDT->GetType() != aDT.GetType()) {
printf_stderr("Box shadow type: %d, dest draw target type: %d\n",
(int) boxShadowDT->GetType(), (int) aDT.GetType());
MOZ_ASSERT(false, "Box shadows are incorrect type\n");
}
ColorPattern shadowColor(ToDeviceColor(aShadowColor));
boxShadowDT->MaskSurface(shadowColor, aBlurMask, Point(0, 0));

View File

@ -266,6 +266,7 @@ private:
DECL_GFX_PREF(Live, "image.high_quality_downscaling.enabled", ImageHQDownscalingEnabled, bool, false);
DECL_GFX_PREF(Live, "image.high_quality_downscaling.min_factor", ImageHQDownscalingMinFactor, uint32_t, 1000);
DECL_GFX_PREF(Live, "image.high_quality_upscaling.max_size", ImageHQUpscalingMaxSize, uint32_t, 20971520);
DECL_GFX_PREF(Live, "image.infer-src-animation.threshold-ms", ImageInferSrcAnimationThresholdMS, uint32_t, 2000);
DECL_GFX_PREF(Once, "image.mem.decode_bytes_at_a_time", ImageMemDecodeBytesAtATime, uint32_t, 200000);
DECL_GFX_PREF(Live, "image.mem.discardable", ImageMemDiscardable, bool, false);
DECL_GFX_PREF(Once, "image.mem.surfacecache.discard_factor", ImageMemSurfaceCacheDiscardFactor, uint32_t, 1);

View File

@ -123,7 +123,7 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext* cx, bool match_only)
#ifdef JS_CODEGEN_ARM64
// ARM64 communicates stack address via sp, but uses a pseudo-sp for addressing.
MOZ_ASSERT(!masm.GetStackPointer64().Is(sp));
masm.moveStackPtrTo(masm.getStackPointer());
masm.Mov(masm.GetStackPointer64(), sp);
#endif
// Push non-volatile registers which might be modified by jitcode.

View File

@ -1095,8 +1095,12 @@ IonBuilder::initParameters()
// interpreter and didn't accumulate type information, try to use that OSR
// frame to determine possible initial types for 'this' and parameters.
if (thisTypes->empty() && baselineFrame_)
thisTypes->addType(baselineFrame_->thisType, alloc_->lifoAlloc());
if (thisTypes->empty() && baselineFrame_) {
TypeSet::Type type = baselineFrame_->thisType;
if (type.isSingletonUnchecked())
checkNurseryObject(type.singleton());
thisTypes->addType(type, alloc_->lifoAlloc());
}
MParameter* param = MParameter::New(alloc(), MParameter::THIS_SLOT, thisTypes);
current->add(param);
@ -1107,7 +1111,10 @@ IonBuilder::initParameters()
if (types->empty() && baselineFrame_ &&
!script_->baselineScript()->modifiesArguments())
{
types->addType(baselineFrame_->argTypes[i], alloc_->lifoAlloc());
TypeSet::Type type = baselineFrame_->argTypes[i];
if (type.isSingletonUnchecked())
checkNurseryObject(type.singleton());
types->addType(type, alloc_->lifoAlloc());
}
param = MParameter::New(alloc(), i, types);
@ -6995,6 +7002,9 @@ IonBuilder::newPendingLoopHeader(MBasicBlock* predecessor, jsbytecode* pc, bool
else
existingType = baselineFrame_->varTypes[var];
if (existingType.isSingletonUnchecked())
checkNurseryObject(existingType.singleton());
// Extract typeset from value.
LifoAlloc* lifoAlloc = alloc().lifoAlloc();
TemporaryTypeSet* typeSet =

View File

@ -23,6 +23,10 @@
# include <unistd.h>
#endif
#ifdef XP_WIN
# include "jswin.h"
#endif
#include "jsapi.h"
#include "jsatom.h"
#include "jscntxt.h"
@ -740,7 +744,28 @@ random_generateSeed()
seed.u64 = 0;
#if defined(XP_WIN)
/*
* Temporary diagnostic for bug 1167248: Test whether the injected hooks
* react differently to LoadLibraryW / LoadLibraryExW.
*/
HMODULE oldWay = LoadLibraryW(L"ADVAPI32.DLL");
HMODULE newWay = LoadLibraryExW(L"ADVAPI32.DLL",
nullptr,
LOAD_LIBRARY_SEARCH_SYSTEM32);
/* Fallback for older versions of Windows */
if (!newWay && GetLastError() == ERROR_INVALID_PARAMETER)
newWay = LoadLibraryExW(L"ADVAPI32.DLL", nullptr, 0);
if (oldWay && !newWay)
MOZ_CRASH();
errno_t error = rand_s(&seed.u32[0]);
if (oldWay)
FreeLibrary(oldWay);
if (newWay)
FreeLibrary(newWay);
MOZ_ASSERT(error == 0, "rand_s() error?!");
error = rand_s(&seed.u32[1]);

View File

@ -808,7 +808,7 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp* fop,
// At this point there may be JSObjects using them that have
// been removed from the other maps.
if (!nsXPConnect::XPConnect()->IsShuttingDown()) {
for (auto i = self->mNativeScriptableSharedMap->RemovingIter(); !i.Done(); i.Next()) {
for (auto i = self->mNativeScriptableSharedMap->Iter(); !i.Done(); i.Next()) {
auto entry = static_cast<XPCNativeScriptableSharedMap::Entry*>(i.Get());
XPCNativeScriptableShared* shared = entry->key;
if (shared->IsMarked()) {
@ -821,14 +821,14 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp* fop,
}
if (!isCompartmentGC) {
for (auto i = self->mClassInfo2NativeSetMap->RemovingIter(); !i.Done(); i.Next()) {
for (auto i = self->mClassInfo2NativeSetMap->Iter(); !i.Done(); i.Next()) {
auto entry = static_cast<ClassInfo2NativeSetMap::Entry*>(i.Get());
if (!entry->value->IsMarked())
i.Remove();
}
}
for (auto i = self->mNativeSetMap->RemovingIter(); !i.Done(); i.Next()) {
for (auto i = self->mNativeSetMap->Iter(); !i.Done(); i.Next()) {
auto entry = static_cast<NativeSetMap::Entry*>(i.Get());
XPCNativeSet* set = entry->key_value;
if (set->IsMarked()) {
@ -839,7 +839,7 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp* fop,
}
}
for (auto i = self->mIID2NativeInterfaceMap->RemovingIter(); !i.Done(); i.Next()) {
for (auto i = self->mIID2NativeInterfaceMap->Iter(); !i.Done(); i.Next()) {
auto entry = static_cast<IID2NativeInterfaceMap::Entry*>(i.Get());
XPCNativeInterface* iface = entry->value;
if (iface->IsMarked()) {
@ -904,7 +904,7 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp* fop,
// referencing the protos in the dying list are themselves dead.
// So, we can safely delete all the protos in the list.
for (auto i = self->mDyingWrappedNativeProtoMap->RemovingIter(); !i.Done(); i.Next()) {
for (auto i = self->mDyingWrappedNativeProtoMap->Iter(); !i.Done(); i.Next()) {
auto entry = static_cast<XPCWrappedNativeProtoMap::Entry*>(i.Get());
delete static_cast<const XPCWrappedNativeProto*>(entry->key);
i.Remove();
@ -3658,7 +3658,7 @@ XPCJSRuntime::DebugDump(int16_t depth)
// iterate sets...
if (depth && mNativeSetMap->Count()) {
XPC_LOG_INDENT();
for (auto i = mNativeSetMap->RemovingIter(); !i.Done(); i.Next()) {
for (auto i = mNativeSetMap->Iter(); !i.Done(); i.Next()) {
auto entry = static_cast<NativeSetMap::Entry*>(i.Get());
entry->key_value->DebugDump(depth);
}

View File

@ -150,8 +150,6 @@ public:
inline uint32_t Count() { return mTable->EntryCount(); }
PLDHashTable::Iterator Iter() const { return PLDHashTable::Iterator(mTable); }
PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
~Native2WrappedNativeMap();
@ -263,7 +261,7 @@ public:
inline uint32_t Count() { return mTable->EntryCount(); }
PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
PLDHashTable::Iterator Iter() { return PLDHashTable::Iterator(mTable); }
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
@ -319,7 +317,7 @@ public:
inline uint32_t Count() { return mTable->EntryCount(); }
PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
PLDHashTable::Iterator Iter() { return PLDHashTable::Iterator(mTable); }
// ClassInfo2NativeSetMap holds pointers to *some* XPCNativeSets.
// So we don't want to count those XPCNativeSets, because they are better
@ -377,7 +375,7 @@ public:
inline uint32_t Count() { return mTable->EntryCount(); }
PLDHashTable::Iterator Iter() const { return PLDHashTable::Iterator(mTable); }
PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
PLDHashTable::Iterator Iter() { return PLDHashTable::Iterator(mTable); }
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
@ -448,7 +446,7 @@ public:
inline uint32_t Count() { return mTable->EntryCount(); }
PLDHashTable::Iterator Iter() const { return PLDHashTable::Iterator(mTable); }
PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
PLDHashTable::Iterator Iter() { return PLDHashTable::Iterator(mTable); }
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
@ -545,7 +543,7 @@ public:
inline uint32_t Count() { return mTable->EntryCount(); }
PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
PLDHashTable::Iterator Iter() { return PLDHashTable::Iterator(mTable); }
~XPCNativeScriptableSharedMap();
private:
@ -586,7 +584,7 @@ public:
inline uint32_t Count() { return mTable->EntryCount(); }
PLDHashTable::Iterator Iter() const { return PLDHashTable::Iterator(mTable); }
PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
PLDHashTable::Iterator Iter() { return PLDHashTable::Iterator(mTable); }
~XPCWrappedNativeProtoMap();
private:

View File

@ -651,12 +651,12 @@ XPCWrappedNativeScope::SystemIsBeingShutDown()
// Walk the protos first. Wrapper shutdown can leave dangling
// proto pointers in the proto map.
for (auto i = cur->mWrappedNativeProtoMap->RemovingIter(); !i.Done(); i.Next()) {
for (auto i = cur->mWrappedNativeProtoMap->Iter(); !i.Done(); i.Next()) {
auto entry = static_cast<ClassInfo2WrappedNativeProtoMap::Entry*>(i.Get());
entry->value->SystemIsBeingShutDown();
i.Remove();
}
for (auto i = cur->mWrappedNativeMap->RemovingIter(); !i.Done(); i.Next()) {
for (auto i = cur->mWrappedNativeMap->Iter(); !i.Done(); i.Next()) {
auto entry = static_cast<Native2WrappedNativeMap::Entry*>(i.Get());
XPCWrappedNative* wrapper = entry->value;
if (wrapper->IsValid()) {

View File

@ -7343,6 +7343,7 @@ UnionBorderBoxes(nsIFrame* aFrame, bool aApplyTransform,
nsIAtom* fType = aFrame->GetType();
if (nsFrame::ShouldApplyOverflowClipping(aFrame, disp) ||
fType == nsGkAtoms::scrollFrame ||
fType == nsGkAtoms::listControlFrame ||
fType == nsGkAtoms::svgOuterSVGFrame) {
return u;
}

View File

@ -582,8 +582,10 @@ public:
static bool ShouldApplyOverflowClipping(const nsIFrame* aFrame,
const nsStyleDisplay* aDisp)
{
// clip overflow:-moz-hidden-unscrollable ...
if (MOZ_UNLIKELY(aDisp->mOverflowX == NS_STYLE_OVERFLOW_CLIP)) {
// clip overflow:-moz-hidden-unscrollable, except for nsListControlFrame,
// which is an nsHTMLScrollFrame.
if (MOZ_UNLIKELY(aDisp->mOverflowX == NS_STYLE_OVERFLOW_CLIP &&
aFrame->GetType() != nsGkAtoms::listControlFrame)) {
return true;
}

View File

@ -139,7 +139,8 @@ nsImageFrame::nsImageFrame(nsStyleContext* aContext) :
mIntrinsicRatio(0, 0),
mDisplayingIcon(false),
mFirstFrameComplete(false),
mReflowCallbackPosted(false)
mReflowCallbackPosted(false),
mForceSyncDecoding(false)
{
// We assume our size is not constrained and we haven't gotten an
// initial reflow yet, so don't touch those flags.
@ -1621,11 +1622,16 @@ nsImageFrame::PaintImage(nsRenderingContext& aRenderingContext, nsPoint aPt,
StylePosition(),
&anchorPoint);
uint32_t flags = aFlags;
if (mForceSyncDecoding) {
flags |= imgIContainer::FLAG_SYNC_DECODE;
}
DrawResult result =
nsLayoutUtils::DrawSingleImage(*aRenderingContext.ThebesContext(),
PresContext(), aImage,
nsLayoutUtils::GetGraphicsFilterForFrame(this), dest, aDirtyRect,
nullptr, aFlags, &anchorPoint);
nullptr, flags, &anchorPoint);
nsImageMap* map = GetImageMap();
if (map) {

View File

@ -233,6 +233,9 @@ protected:
*/
void NotifyNewCurrentRequest(imgIRequest *aRequest, nsresult aStatus);
/// Always sync decode our image when painting if @aForce is true.
void SetForceSyncDecoding(bool aForce) { mForceSyncDecoding = aForce; }
private:
// random helpers
inline void SpecToURI(const nsAString& aSpec, nsIIOService *aIOService,
@ -308,6 +311,7 @@ private:
bool mDisplayingIcon;
bool mFirstFrameComplete;
bool mReflowCallbackPosted;
bool mForceSyncDecoding;
static nsIIOService* sIOService;

View File

@ -367,8 +367,8 @@ Declaration::GetValue(nsCSSProperty aProperty, nsAString& aValue,
case eCSSProperty_border_right:
case eCSSProperty_border_bottom:
case eCSSProperty_border_left:
case eCSSProperty_border_start:
case eCSSProperty_border_end:
case eCSSProperty_border_inline_start:
case eCSSProperty_border_inline_end:
case eCSSProperty_border_block_start:
case eCSSProperty_border_block_end:
case eCSSProperty__moz_column_rule:

View File

@ -6964,15 +6964,15 @@ static const nsCSSProperty kBorderLeftIDs[] = {
eCSSProperty_border_left_style,
eCSSProperty_border_left_color
};
static const nsCSSProperty kBorderStartIDs[] = {
eCSSProperty_border_start_width,
eCSSProperty_border_start_style,
eCSSProperty_border_start_color
static const nsCSSProperty kBorderInlineStartIDs[] = {
eCSSProperty_border_inline_start_width,
eCSSProperty_border_inline_start_style,
eCSSProperty_border_inline_start_color
};
static const nsCSSProperty kBorderEndIDs[] = {
eCSSProperty_border_end_width,
eCSSProperty_border_end_style,
eCSSProperty_border_end_color
static const nsCSSProperty kBorderInlineEndIDs[] = {
eCSSProperty_border_inline_end_width,
eCSSProperty_border_inline_end_style,
eCSSProperty_border_inline_end_color
};
static const nsCSSProperty kBorderBlockStartIDs[] = {
eCSSProperty_border_block_start_width,
@ -10066,10 +10066,10 @@ CSSParserImpl::ParsePropertyByFunction(nsCSSProperty aPropID)
return ParseBorderSide(kBorderBlockStartIDs, false);
case eCSSProperty_border_bottom:
return ParseBorderSide(kBorderBottomIDs, false);
case eCSSProperty_border_end:
return ParseBorderSide(kBorderEndIDs, false);
case eCSSProperty_border_start:
return ParseBorderSide(kBorderStartIDs, false);
case eCSSProperty_border_inline_end:
return ParseBorderSide(kBorderInlineEndIDs, false);
case eCSSProperty_border_inline_start:
return ParseBorderSide(kBorderInlineStartIDs, false);
case eCSSProperty_border_left:
return ParseBorderSide(kBorderLeftIDs, false);
case eCSSProperty_border_right:

View File

@ -127,51 +127,51 @@ CSS_PROP_ALIAS(-moz-font-language-override,
font_language_override,
MozFontLanguageOverride,
"layout.css.prefixes.font-features")
CSS_PROP_ALIAS(padding-inline-end,
padding_end,
PaddingInlineEnd,
"layout.css.vertical-text.enabled")
CSS_PROP_ALIAS(padding-inline-start,
padding_start,
PaddingInlineStart,
"layout.css.vertical-text.enabled")
CSS_PROP_ALIAS(margin-inline-end,
margin_end,
MarginInlineEnd,
"layout.css.vertical-text.enabled")
CSS_PROP_ALIAS(margin-inline-start,
margin_start,
MarginInlineStart,
"layout.css.vertical-text.enabled")
CSS_PROP_ALIAS(border-inline-end,
border_end,
BorderInlineEnd,
"layout.css.vertical-text.enabled")
CSS_PROP_ALIAS(border-inline-end-color,
border_end_color,
BorderInlineEndColor,
"layout.css.vertical-text.enabled")
CSS_PROP_ALIAS(border-inline-end-style,
border_end_style,
BorderInlineEndStyle,
"layout.css.vertical-text.enabled")
CSS_PROP_ALIAS(border-inline-end-width,
border_end_width,
BorderInlineEndWidth,
"layout.css.vertical-text.enabled")
CSS_PROP_ALIAS(border-inline-start,
border_start,
BorderInlineStart,
"layout.css.vertical-text.enabled")
CSS_PROP_ALIAS(border-inline-start-color,
border_start_color,
BorderInlineStartColor,
"layout.css.vertical-text.enabled")
CSS_PROP_ALIAS(border-inline-start-style,
border_start_style,
BorderInlineStartStyle,
"layout.css.vertical-text.enabled")
CSS_PROP_ALIAS(border-inline-start-width,
border_start_width,
BorderInlineStartWidth,
"layout.css.vertical-text.enabled")
CSS_PROP_ALIAS(-moz-padding-end,
padding_inline_end,
MozPaddingEnd,
"")
CSS_PROP_ALIAS(-moz-padding-start,
padding_inline_start,
MozPaddingStart,
"")
CSS_PROP_ALIAS(-moz-margin-end,
margin_inline_end,
MozMarginEnd,
"")
CSS_PROP_ALIAS(-moz-margin-start,
margin_inline_start,
MozMarginStart,
"")
CSS_PROP_ALIAS(-moz-border-end,
border_inline_end,
MozBorderEnd,
"")
CSS_PROP_ALIAS(-moz-border-end-color,
border_inline_end_color,
MozBorderEndColor,
"")
CSS_PROP_ALIAS(-moz-border-end-style,
border_inline_end_style,
MozBorderEndStyle,
"")
CSS_PROP_ALIAS(-moz-border-end-width,
border_inline_end_width,
MozBorderEndWidth,
"")
CSS_PROP_ALIAS(-moz-border-start,
border_inline_start,
MozBorderStart,
"")
CSS_PROP_ALIAS(-moz-border-start-color,
border_inline_start_color,
MozBorderStartColor,
"")
CSS_PROP_ALIAS(-moz-border-start-style,
border_inline_start_style,
MozBorderStartStyle,
"")
CSS_PROP_ALIAS(-moz-border-start-width,
border_inline_start_width,
MozBorderStartWidth,
"")

Some files were not shown because too many files have changed in this diff Show More