зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
d0f1701bc8
|
@ -4752,7 +4752,7 @@ var CombinedStopReload = {
|
|||
var TabsProgressListener = {
|
||||
onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||
// Collect telemetry data about tab load times.
|
||||
if (aWebProgress.isTopLevel) {
|
||||
if (aWebProgress.isTopLevel && (!aRequest.originalURI || aRequest.originalURI.spec.scheme != "about")) {
|
||||
if (aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
|
||||
if (aStateFlags & Ci.nsIWebProgressListener.STATE_START) {
|
||||
TelemetryStopwatch.start("FX_PAGE_LOAD_MS", aBrowser);
|
||||
|
|
|
@ -5,10 +5,10 @@ support-files =
|
|||
[browser_displayURI.js]
|
||||
skip-if = (os == "linux" && (debug || asan))
|
||||
[browser_popupNotification.js]
|
||||
skip-if = (os == "linux" && (debug || asan)) || e10s # e10s - Bug ?????? - popup notification test probably confused re content process notifications etc
|
||||
skip-if = (os == "linux" && (debug || asan))
|
||||
[browser_popupNotification_2.js]
|
||||
skip-if = (os == "linux" && (debug || asan)) || e10s # e10s - Bug ?????? - popup notification test probably confused re content process notifications etc
|
||||
skip-if = (os == "linux" && (debug || asan))
|
||||
[browser_popupNotification_3.js]
|
||||
skip-if = (os == "linux" && (debug || asan)) || e10s # e10s - Bug ?????? - popup notification test probably confused re content process notifications etc
|
||||
skip-if = (os == "linux" && (debug || asan))
|
||||
[browser_popupNotification_4.js]
|
||||
skip-if = (os == "linux" && (debug || asan)) || e10s # e10s - Bug ?????? - popup notification test probably confused re content process notifications etc
|
||||
skip-if = (os == "linux" && (debug || asan))
|
||||
|
|
|
@ -535,7 +535,7 @@ this.BrowserUITelemetry = {
|
|||
let paletteItems =
|
||||
CustomizableUI.getUnusedWidgets(aWindow.gNavToolbox.palette);
|
||||
let defaultRemoved = [];
|
||||
for (item of paletteItems) {
|
||||
for (let item of paletteItems) {
|
||||
if (DEFAULT_ITEMS.indexOf(item.id) != -1) {
|
||||
defaultRemoved.push(item.id);
|
||||
}
|
||||
|
|
|
@ -26,13 +26,10 @@ if CONFIG['MOZ_VORBIS']:
|
|||
if CONFIG['MOZ_TREMOR']:
|
||||
external_dirs += ['media/libtremor']
|
||||
|
||||
if CONFIG['MOZ_WEBM']:
|
||||
external_dirs += ['media/libnestegg']
|
||||
|
||||
if CONFIG['MOZ_WEBM_ENCODER']:
|
||||
external_dirs += ['media/libmkv']
|
||||
|
||||
if CONFIG['MOZ_VPX'] and not CONFIG['MOZ_NATIVE_LIBVPX']:
|
||||
if not CONFIG['MOZ_NATIVE_LIBVPX']:
|
||||
external_dirs += ['media/libvpx']
|
||||
|
||||
if not CONFIG['MOZ_NATIVE_PNG']:
|
||||
|
@ -50,6 +47,7 @@ if CONFIG['MOZ_WEBSPEECH_POCKETSPHINX']:
|
|||
external_dirs += [
|
||||
'media/kiss_fft',
|
||||
'media/libcubeb',
|
||||
'media/libnestegg',
|
||||
'media/libogg',
|
||||
'media/libopus',
|
||||
'media/libtheora',
|
||||
|
|
115
configure.in
115
configure.in
|
@ -92,8 +92,8 @@ _PTHREAD_LDFLAGS=""
|
|||
|
||||
dnl Do not allow objdir == srcdir builds.
|
||||
dnl ==============================================================
|
||||
_topsrcdir=`cd \`dirname $0\`; pwd -W 2>/dev/null || pwd`
|
||||
_objdir=`pwd`
|
||||
_topsrcdir=`cd \`dirname $0\`; pwd -W 2>/dev/null || pwd -P`
|
||||
_objdir=`pwd -P`
|
||||
|
||||
dnl TODO Don't exempt L10N builds once bug 842760 is resolved.
|
||||
if test "$_topsrcdir" = "$_objdir" -a "${with_l10n_base+set}" != set; then
|
||||
|
@ -134,7 +134,7 @@ EOF
|
|||
exit 1
|
||||
break
|
||||
fi
|
||||
MOZ_BUILD_ROOT=`pwd -W 2>/dev/null || pwd`
|
||||
MOZ_BUILD_ROOT=`pwd -W 2>/dev/null || pwd -P`
|
||||
DIST="$MOZ_BUILD_ROOT/dist"
|
||||
|
||||
MOZ_PYTHON
|
||||
|
@ -157,7 +157,7 @@ if test -n "$L10NBASEDIR"; then
|
|||
if test "$L10NBASEDIR" = "yes" -o "$L10NBASEDIR" = "no"; then
|
||||
AC_MSG_ERROR([--with-l10n-base must specify a path])
|
||||
elif test -d "$L10NBASEDIR"; then
|
||||
L10NBASEDIR=`cd "$L10NBASEDIR" && pwd`
|
||||
L10NBASEDIR=`cd "$L10NBASEDIR" && pwd -P`
|
||||
else
|
||||
AC_MSG_ERROR([Invalid value --with-l10n-base, $L10NBASEDIR doesn't exist])
|
||||
fi
|
||||
|
@ -3692,10 +3692,8 @@ fi
|
|||
MOZ_RAW=
|
||||
MOZ_VORBIS=
|
||||
MOZ_TREMOR=
|
||||
MOZ_WAVE=1
|
||||
MOZ_SAMPLE_TYPE_FLOAT32=
|
||||
MOZ_SAMPLE_TYPE_S16=
|
||||
MOZ_WEBM=1
|
||||
MOZ_GSTREAMER=
|
||||
MOZ_DIRECTSHOW=
|
||||
MOZ_WMF=
|
||||
|
@ -3715,7 +3713,6 @@ MOZ_SCTP=
|
|||
MOZ_ANDROID_OMX=
|
||||
MOZ_MEDIA_NAVIGATOR=
|
||||
MOZ_OMX_PLUGIN=
|
||||
MOZ_VPX=
|
||||
MOZ_VPX_ERROR_CONCEALMENT=
|
||||
MOZ_WEBSPEECH=1
|
||||
MOZ_WEBSPEECH_MODELS=
|
||||
|
@ -4998,7 +4995,6 @@ if test -n "$MOZ_WEBRTC"; then
|
|||
dnl opt/production builds (via MOZ_CRASH())
|
||||
AC_DEFINE(MOZ_WEBRTC_ASSERT_ALWAYS)
|
||||
MOZ_RAW=1
|
||||
MOZ_VPX=1
|
||||
MOZ_VPX_ERROR_CONCEALMENT=1
|
||||
|
||||
dnl enable once Signaling lands
|
||||
|
@ -5143,19 +5139,6 @@ if test "${ac_cv_c_attribute_aligned}" != "0"; then
|
|||
[${ac_cv_c_attribute_aligned}],[Maximum supported data alignment])
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Disable VP8 decoder support
|
||||
dnl ========================================================
|
||||
MOZ_ARG_DISABLE_BOOL(webm,
|
||||
[ --disable-webm Disable support for WebM media (VP8 video and Vorbis audio)],
|
||||
MOZ_WEBM=,
|
||||
MOZ_WEBM=1)
|
||||
|
||||
if test -n "$MOZ_WEBM"; then
|
||||
AC_DEFINE(MOZ_WEBM)
|
||||
MOZ_VPX=1
|
||||
fi;
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Apple platform decoder support
|
||||
dnl ========================================================
|
||||
|
@ -5361,54 +5344,49 @@ MOZ_ARG_WITH_BOOL(system-libvpx,
|
|||
MOZ_LIBVPX_CFLAGS=
|
||||
MOZ_LIBVPX_LIBS=
|
||||
|
||||
if test -n "$MOZ_VPX"; then
|
||||
AC_DEFINE(MOZ_VPX)
|
||||
if test -n "$MOZ_VPX_ERROR_CONCEALMENT" ; then
|
||||
AC_DEFINE(MOZ_VPX_ERROR_CONCEALMENT)
|
||||
fi
|
||||
|
||||
_SAVE_CFLAGS=$CFLAGS
|
||||
_SAVE_LIBS=$LIBS
|
||||
if test -n "$MOZ_NATIVE_LIBVPX"; then
|
||||
dnl ============================
|
||||
dnl === libvpx Version check ===
|
||||
dnl ============================
|
||||
dnl Check to see if we have a system libvpx package.
|
||||
PKG_CHECK_MODULES(MOZ_LIBVPX, vpx >= 1.3.0)
|
||||
|
||||
CFLAGS="$CFLAGS $MOZ_LIBVPX_CFLAGS"
|
||||
LIBS="$LIBS $MOZ_LIBVPX_LIBS"
|
||||
|
||||
MOZ_CHECK_HEADER([vpx/vpx_decoder.h], [],
|
||||
[AC_MSG_ERROR([Couldn't find vpx/vpx_decoder.h which is required for build with system libvpx. Use --without-system-libvpx to build with in-tree libvpx.])])
|
||||
|
||||
AC_CHECK_LIB(vpx, vpx_codec_dec_init_ver, [],
|
||||
[AC_MSG_ERROR([--with-system-libvpx requested but symbol vpx_codec_dec_init_ver not found])])
|
||||
|
||||
MOZ_CHECK_HEADER([vpx_mem/vpx_mem.h],
|
||||
[AC_CHECK_FUNC(vpx_mem_set_functions)])
|
||||
if test "$ac_cv_header_vpx_mem_vpx_mem_h" = no -o \
|
||||
"$ac_cv_func_vpx_mem_set_functions" = no; then
|
||||
AC_DEFINE(MOZ_VPX_NO_MEM_REPORTING)
|
||||
fi
|
||||
fi
|
||||
CFLAGS=$_SAVE_CFLAGS
|
||||
LIBS=$_SAVE_LIBS
|
||||
if test -n "$MOZ_VPX_ERROR_CONCEALMENT" ; then
|
||||
AC_DEFINE(MOZ_VPX_ERROR_CONCEALMENT)
|
||||
fi
|
||||
|
||||
_SAVE_CFLAGS=$CFLAGS
|
||||
_SAVE_LIBS=$LIBS
|
||||
if test -n "$MOZ_NATIVE_LIBVPX"; then
|
||||
dnl ============================
|
||||
dnl === libvpx Version check ===
|
||||
dnl ============================
|
||||
dnl Check to see if we have a system libvpx package.
|
||||
PKG_CHECK_MODULES(MOZ_LIBVPX, vpx >= 1.3.0)
|
||||
|
||||
CFLAGS="$CFLAGS $MOZ_LIBVPX_CFLAGS"
|
||||
LIBS="$LIBS $MOZ_LIBVPX_LIBS"
|
||||
|
||||
MOZ_CHECK_HEADER([vpx/vpx_decoder.h], [],
|
||||
[AC_MSG_ERROR([Couldn't find vpx/vpx_decoder.h which is required for build with system libvpx. Use --without-system-libvpx to build with in-tree libvpx.])])
|
||||
|
||||
AC_CHECK_LIB(vpx, vpx_codec_dec_init_ver, [],
|
||||
[AC_MSG_ERROR([--with-system-libvpx requested but symbol vpx_codec_dec_init_ver not found])])
|
||||
|
||||
MOZ_CHECK_HEADER([vpx_mem/vpx_mem.h],
|
||||
[AC_CHECK_FUNC(vpx_mem_set_functions)])
|
||||
if test "$ac_cv_header_vpx_mem_vpx_mem_h" = no -o \
|
||||
"$ac_cv_func_vpx_mem_set_functions" = no; then
|
||||
AC_DEFINE(MOZ_VPX_NO_MEM_REPORTING)
|
||||
fi
|
||||
fi
|
||||
CFLAGS=$_SAVE_CFLAGS
|
||||
LIBS=$_SAVE_LIBS
|
||||
|
||||
AC_SUBST(MOZ_NATIVE_LIBVPX)
|
||||
AC_SUBST_LIST(MOZ_LIBVPX_CFLAGS)
|
||||
AC_SUBST_LIST(MOZ_LIBVPX_LIBS)
|
||||
|
||||
if test "$MOZ_WEBM"; then
|
||||
if test "$MOZ_SAMPLE_TYPE_FLOAT32"; then
|
||||
MOZ_VORBIS=1
|
||||
else
|
||||
MOZ_TREMOR=1
|
||||
fi
|
||||
if test "$MOZ_SAMPLE_TYPE_FLOAT32"; then
|
||||
MOZ_VORBIS=1
|
||||
else
|
||||
MOZ_TREMOR=1
|
||||
fi
|
||||
|
||||
if test -n "$MOZ_VPX" -a -z "$MOZ_NATIVE_LIBVPX"; then
|
||||
if test -z "$MOZ_NATIVE_LIBVPX"; then
|
||||
|
||||
dnl Detect if we can use an assembler to compile optimized assembly for libvpx.
|
||||
dnl We currently require yasm on all x86 platforms and require yasm 1.1.0 on Win32.
|
||||
|
@ -5510,18 +5488,6 @@ if test -n "$MOZ_VPX" -a -z "$MOZ_NATIVE_LIBVPX"; then
|
|||
AC_DEFINE(MOZ_VPX_NO_MEM_REPORTING)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Disable Wave decoder support
|
||||
dnl ========================================================
|
||||
MOZ_ARG_DISABLE_BOOL(wave,
|
||||
[ --disable-wave Disable Wave decoder support],
|
||||
MOZ_WAVE=,
|
||||
MOZ_WAVE=1)
|
||||
|
||||
if test -n "$MOZ_WAVE"; then
|
||||
AC_DEFINE(MOZ_WAVE)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Handle dependent MEDIA defines
|
||||
dnl ========================================================
|
||||
|
@ -8926,10 +8892,8 @@ AC_SUBST(NS_ENABLE_TSF)
|
|||
AC_SUBST(WIN32_CONSOLE_EXE_LDFLAGS)
|
||||
AC_SUBST(WIN32_GUI_EXE_LDFLAGS)
|
||||
|
||||
AC_SUBST(MOZ_WAVE)
|
||||
AC_SUBST(MOZ_VORBIS)
|
||||
AC_SUBST(MOZ_TREMOR)
|
||||
AC_SUBST(MOZ_WEBM)
|
||||
AC_SUBST(MOZ_WMF)
|
||||
AC_SUBST(MOZ_FFMPEG)
|
||||
AC_SUBST(MOZ_FMP4)
|
||||
|
@ -8939,7 +8903,6 @@ AC_SUBST(MOZ_ANDROID_OMX)
|
|||
AC_SUBST(MOZ_APPLEMEDIA)
|
||||
AC_SUBST(MOZ_OMX_PLUGIN)
|
||||
AC_SUBST(MOZ_VPX_ERROR_CONCEALMENT)
|
||||
AC_SUBST(MOZ_VPX)
|
||||
AC_SUBST(VPX_AS)
|
||||
AC_SUBST_LIST(VPX_ASFLAGS)
|
||||
AC_SUBST(VPX_AS_CONVERSION)
|
||||
|
|
|
@ -12,7 +12,7 @@ const { ActorPool, OriginalLocation, GeneratedLocation } = require("devtools/ser
|
|||
const { ObjectActor, createValueGrip, longStringGrip } = require("devtools/server/actors/object");
|
||||
const { DebuggerServer } = require("devtools/server/main");
|
||||
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
const { assert, dbg_assert, dumpn, update, fetch } = DevToolsUtils;
|
||||
const { assert, dumpn, update, fetch } = DevToolsUtils;
|
||||
const { dirname, joinURI } = require("devtools/shared/path");
|
||||
const promise = require("promise");
|
||||
const PromiseDebugging = require("PromiseDebugging");
|
||||
|
@ -354,8 +354,6 @@ EventLoop.prototype = {
|
|||
}
|
||||
}
|
||||
|
||||
dbg_assert(this._thread.state === "running", "Should be in the running state");
|
||||
|
||||
if (this._hooks.postNest) {
|
||||
this._hooks.postNest(nestData);
|
||||
}
|
||||
|
|
|
@ -183,8 +183,12 @@ exports.executeSoon = function executeSoon(aFn) {
|
|||
if (isWorker) {
|
||||
setImmediate(aFn);
|
||||
} else {
|
||||
let stack = components.stack;
|
||||
let executor = () => {
|
||||
Cu.callFunctionWithAsyncStack(aFn, stack, "DevToolsUtils.executeSoon");
|
||||
};
|
||||
Services.tm.mainThread.dispatch({
|
||||
run: exports.makeInfallible(aFn)
|
||||
run: exports.makeInfallible(executor)
|
||||
}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
}
|
||||
};
|
||||
|
@ -457,24 +461,6 @@ exports.defineLazyGetter = function defineLazyGetter(aObject, aName, aLambda) {
|
|||
});
|
||||
};
|
||||
|
||||
// DEPRECATED: use DevToolsUtils.assert(condition, message) instead!
|
||||
let haveLoggedDeprecationMessage = false;
|
||||
exports.dbg_assert = function dbg_assert(cond, e) {
|
||||
if (!haveLoggedDeprecationMessage) {
|
||||
haveLoggedDeprecationMessage = true;
|
||||
const deprecationMessage = "DevToolsUtils.dbg_assert is deprecated! Use DevToolsUtils.assert instead!\n"
|
||||
+ Error().stack;
|
||||
dump(deprecationMessage);
|
||||
if (typeof console === "object" && console && console.warn) {
|
||||
console.warn(deprecationMessage);
|
||||
}
|
||||
}
|
||||
|
||||
if (!cond) {
|
||||
return e;
|
||||
}
|
||||
};
|
||||
|
||||
exports.defineLazyGetter(this, "AppConstants", () => {
|
||||
if (isWorker) {
|
||||
return {};
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Client request stacks should span the entire process from before making the
|
||||
* request to handling the reply from the server. The server frames are not
|
||||
* included, nor can they be in most cases, since the server can be a remote
|
||||
* device.
|
||||
*/
|
||||
|
||||
var { executeSoon } = require("devtools/shared/DevToolsUtils");
|
||||
var promise = require("promise");
|
||||
var Services = require("Services");
|
||||
|
||||
var asyncStackEnabled =
|
||||
Services.prefs.getBoolPref("javascript.options.asyncstack");
|
||||
|
||||
do_register_cleanup(() => {
|
||||
Services.prefs.setBoolPref("javascript.options.asyncstack",
|
||||
asyncStackEnabled);
|
||||
});
|
||||
|
||||
add_task(function*() {
|
||||
Services.prefs.setBoolPref("javascript.options.asyncstack", true);
|
||||
|
||||
yield waitForTick();
|
||||
|
||||
let stack = Components.stack;
|
||||
while (stack) {
|
||||
do_print(stack.name);
|
||||
if (stack.name == "waitForTick") {
|
||||
// Reached back to outer function before executeSoon
|
||||
ok(true, "Complete stack");
|
||||
return;
|
||||
}
|
||||
stack = stack.asyncCaller || stack.caller;
|
||||
}
|
||||
ok(false, "Incomplete stack");
|
||||
});
|
||||
|
||||
function waitForTick() {
|
||||
let deferred = promise.defer();
|
||||
executeSoon(deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
|
@ -24,3 +24,4 @@ support-files =
|
|||
[test_require_lazy.js]
|
||||
[test_require.js]
|
||||
[test_stack.js]
|
||||
[test_executeSoon.js]
|
||||
|
|
|
@ -110,6 +110,8 @@ void
|
|||
DocumentTimeline::WillRefresh(mozilla::TimeStamp aTime)
|
||||
{
|
||||
MOZ_ASSERT(mIsObservingRefreshDriver);
|
||||
MOZ_ASSERT(GetRefreshDriver(),
|
||||
"Should be able to reach refresh driver from within WillRefresh");
|
||||
|
||||
bool needsTicks = false;
|
||||
nsTArray<Animation*> animationsToRemove(mAnimations.Count());
|
||||
|
@ -143,10 +145,13 @@ DocumentTimeline::WillRefresh(mozilla::TimeStamp aTime)
|
|||
}
|
||||
|
||||
if (!needsTicks) {
|
||||
// If another refresh driver observer destroys the nsPresContext,
|
||||
// nsRefreshDriver will detect it and we won't be called.
|
||||
// We already assert that GetRefreshDriver() is non-null at the beginning
|
||||
// of this function but we check it again here to be sure that ticking
|
||||
// animations does not have any side effects that cause us to lose the
|
||||
// connection with the refresh driver, such as triggering the destruction
|
||||
// of mDocument's PresShell.
|
||||
MOZ_ASSERT(GetRefreshDriver(),
|
||||
"Refresh driver should still be valid inside WillRefresh");
|
||||
"Refresh driver should still be valid at end of WillRefresh");
|
||||
GetRefreshDriver()->RemoveRefreshObserver(this, Flush_Style);
|
||||
mIsObservingRefreshDriver = false;
|
||||
}
|
||||
|
|
|
@ -96,7 +96,6 @@ KeyframeEffectReadOnly::KeyframeEffectReadOnly(
|
|||
, mPseudoType(aPseudoType)
|
||||
{
|
||||
MOZ_ASSERT(aTarget, "null animation target is not yet supported");
|
||||
ResetIsRunningOnCompositor();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
|
@ -466,19 +465,6 @@ KeyframeEffectReadOnly::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
KeyframeEffectReadOnly::IsPropertyRunningOnCompositor(
|
||||
nsCSSProperty aProperty) const
|
||||
{
|
||||
const auto& info = LayerAnimationInfo::sRecords;
|
||||
for (size_t i = 0; i < ArrayLength(mIsPropertyRunningOnCompositor); i++) {
|
||||
if (info[i].mProperty == aProperty) {
|
||||
return mIsPropertyRunningOnCompositor[i];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
KeyframeEffectReadOnly::IsRunningOnCompositor() const
|
||||
{
|
||||
|
@ -486,8 +472,8 @@ KeyframeEffectReadOnly::IsRunningOnCompositor() const
|
|||
// one property running on compositor.
|
||||
// Animation.IsRunningOnCompotitor will return more fine grained
|
||||
// information in bug 1196114.
|
||||
for (bool isPropertyRunningOnCompositor : mIsPropertyRunningOnCompositor) {
|
||||
if (isPropertyRunningOnCompositor) {
|
||||
for (const AnimationProperty& property : mProperties) {
|
||||
if (property.mIsRunningOnCompositor) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -498,19 +484,13 @@ void
|
|||
KeyframeEffectReadOnly::SetIsRunningOnCompositor(nsCSSProperty aProperty,
|
||||
bool aIsRunning)
|
||||
{
|
||||
static_assert(
|
||||
MOZ_ARRAY_LENGTH(LayerAnimationInfo::sRecords) ==
|
||||
MOZ_ARRAY_LENGTH(mIsPropertyRunningOnCompositor),
|
||||
"The length of mIsPropertyRunningOnCompositor should equal to"
|
||||
"the length of LayserAnimationInfo::sRecords");
|
||||
MOZ_ASSERT(nsCSSProps::PropHasFlags(aProperty,
|
||||
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
|
||||
"Property being animated on compositor is a recognized "
|
||||
"compositor-animatable property");
|
||||
const auto& info = LayerAnimationInfo::sRecords;
|
||||
for (size_t i = 0; i < ArrayLength(mIsPropertyRunningOnCompositor); i++) {
|
||||
if (info[i].mProperty == aProperty) {
|
||||
mIsPropertyRunningOnCompositor[i] = aIsRunning;
|
||||
for (AnimationProperty& property : mProperties) {
|
||||
if (property.mProperty == aProperty) {
|
||||
property.mIsRunningOnCompositor = aIsRunning;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -523,8 +503,8 @@ KeyframeEffectReadOnly::~KeyframeEffectReadOnly()
|
|||
void
|
||||
KeyframeEffectReadOnly::ResetIsRunningOnCompositor()
|
||||
{
|
||||
for (bool& isPropertyRunningOnCompositor : mIsPropertyRunningOnCompositor) {
|
||||
isPropertyRunningOnCompositor = false;
|
||||
for (AnimationProperty& property : mProperties) {
|
||||
property.mIsRunningOnCompositor = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -556,9 +536,7 @@ KeyframeEffectReadOnly::UpdateTargetRegistration()
|
|||
// Any effects not in the effect set will not be included in the set of
|
||||
// candidate effects for running on the compositor and hence they won't
|
||||
// have their compositor status updated so we should do that now.
|
||||
for (bool& isRunningOnCompositor : mIsPropertyRunningOnCompositor) {
|
||||
isRunningOnCompositor = false;
|
||||
}
|
||||
ResetIsRunningOnCompositor();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1822,7 +1800,7 @@ KeyframeEffectReadOnly::CanThrottle() const
|
|||
}
|
||||
|
||||
// First we need to check layer generation and transform overflow
|
||||
// prior to the IsPropertyRunningOnCompositor check because we should
|
||||
// prior to the property.mIsRunningOnCompositor check because we should
|
||||
// occasionally unthrottle these animations even if the animations are
|
||||
// already running on compositor.
|
||||
for (const LayerAnimationInfo::Record& record :
|
||||
|
@ -1854,7 +1832,7 @@ KeyframeEffectReadOnly::CanThrottle() const
|
|||
}
|
||||
|
||||
for (const AnimationProperty& property : mProperties) {
|
||||
if (!IsPropertyRunningOnCompositor(property.mProperty)) {
|
||||
if (!property.mIsRunningOnCompositor) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ struct AnimationPropertySegment
|
|||
|
||||
struct AnimationProperty
|
||||
{
|
||||
nsCSSProperty mProperty;
|
||||
nsCSSProperty mProperty = eCSSProperty_UNKNOWN;
|
||||
|
||||
// Does this property win in the CSS Cascade?
|
||||
//
|
||||
|
@ -136,16 +136,26 @@ struct AnimationProperty
|
|||
// For other properties, we make it always be true.
|
||||
// **NOTE 2**: This member is not included when comparing AnimationProperty
|
||||
// objects for equality.
|
||||
bool mWinsInCascade;
|
||||
bool mWinsInCascade = true;
|
||||
|
||||
// If true, the propery is currently being animated on the compositor.
|
||||
//
|
||||
// Note that when the owning Animation requests a non-throttled restyle, in
|
||||
// between calling RequestRestyle on its AnimationCollection and when the
|
||||
// restyle is performed, this member may temporarily become false even if
|
||||
// the animation remains on the layer after the restyle.
|
||||
bool mIsRunningOnCompositor = false;
|
||||
|
||||
InfallibleTArray<AnimationPropertySegment> mSegments;
|
||||
|
||||
// NOTE: This operator does *not* compare the mWinsInCascade member.
|
||||
// NOTE: This operator does *not* compare the mWinsInCascade member *or* the
|
||||
// mIsRunningOnCompositor member.
|
||||
// This is because AnimationProperty objects are compared when recreating
|
||||
// CSS animations to determine if mutation observer change records need to
|
||||
// be created or not. However, at the point when these objects are compared
|
||||
// the mWinsInCascade will not have been set on the new objects so we ignore
|
||||
// this member to avoid generating spurious change records.
|
||||
// neither the mWinsInCascade nor the mIsRunningOnCompositor will have been
|
||||
// set on the new objects so we ignore these members to avoid generating
|
||||
// spurious change records.
|
||||
bool operator==(const AnimationProperty& aOther) const {
|
||||
return mProperty == aOther.mProperty &&
|
||||
mSegments == aOther.mSegments;
|
||||
|
@ -279,8 +289,6 @@ public:
|
|||
// Any updated properties are added to |aSetProperties|.
|
||||
void ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
|
||||
nsCSSPropertySet& aSetProperties);
|
||||
// Returns true if |aProperty| is currently being animated on compositor.
|
||||
bool IsPropertyRunningOnCompositor(nsCSSProperty aProperty) const;
|
||||
// Returns true if at least one property is being animated on compositor.
|
||||
bool IsRunningOnCompositor() const;
|
||||
void SetIsRunningOnCompositor(nsCSSProperty aProperty, bool aIsRunning);
|
||||
|
@ -341,17 +349,6 @@ protected:
|
|||
|
||||
InfallibleTArray<AnimationProperty> mProperties;
|
||||
|
||||
// Parallel array corresponding to CommonAnimationManager::sLayerAnimationInfo
|
||||
// such that mIsPropertyRunningOnCompositor[x] is true only if this effect has
|
||||
// an animation of CommonAnimationManager::sLayerAnimationInfo[x].mProperty
|
||||
// that is currently running on the compositor.
|
||||
//
|
||||
// Note that when the owning Animation requests a non-throttled restyle, in
|
||||
// between calling RequestRestyle on its AnimationCollection and when the
|
||||
// restyle is performed, this member may temporarily become false even if
|
||||
// the animation remains on the layer after the restyle.
|
||||
bool mIsPropertyRunningOnCompositor[LayerAnimationInfo::kRecords];
|
||||
|
||||
private:
|
||||
nsIFrame* GetAnimationFrame() const;
|
||||
|
||||
|
|
|
@ -207,6 +207,9 @@ promise_test(function(t) {
|
|||
resolve();
|
||||
}));
|
||||
observer.observe(div, { animations: true, subtree: false });
|
||||
t.add_cleanup(function() {
|
||||
observer.disconnect();
|
||||
});
|
||||
div.style.animationDuration = "200s";
|
||||
}));
|
||||
}));
|
||||
|
|
|
@ -2117,7 +2117,15 @@ nsDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup)
|
|||
// Note that, since mTiming does not change during a reset, the
|
||||
// navigationStart time remains unchanged and therefore any future new
|
||||
// timeline will have the same global clock time as the old one.
|
||||
mDocumentTimeline = nullptr;
|
||||
if (mDocumentTimeline) {
|
||||
nsRefreshDriver* rd = mPresShell && mPresShell->GetPresContext() ?
|
||||
mPresShell->GetPresContext()->RefreshDriver() :
|
||||
nullptr;
|
||||
if (rd) {
|
||||
mDocumentTimeline->NotifyRefreshDriverDestroying(rd);
|
||||
}
|
||||
mDocumentTimeline = nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPropertyBag2> bag = do_QueryInterface(aChannel);
|
||||
if (bag) {
|
||||
|
|
|
@ -64,6 +64,7 @@ skip-if = debug == false
|
|||
[test_worker_UnwrapArg.html]
|
||||
[test_unforgeablesonexpando.html]
|
||||
[test_crossOriginWindowSymbolAccess.html]
|
||||
[test_primitive_this.html]
|
||||
[test_callback_exceptions.html]
|
||||
[test_bug1123516_maplikesetlike.html]
|
||||
skip-if = debug == false
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=603201
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 603201</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 603201 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
function runTest()
|
||||
{
|
||||
var nodes = document.body.childNodes;
|
||||
|
||||
Object.setPrototypeOf(Number.prototype, nodes);
|
||||
|
||||
Object.defineProperty(nodes, "getter", {get: function() {
|
||||
"use strict";
|
||||
is(this, 1);
|
||||
return "getter";
|
||||
}});
|
||||
Object.defineProperty(Object.getPrototypeOf(nodes), "getter2", {get: function() {
|
||||
"use strict";
|
||||
is(this, 1);
|
||||
return "getter2";
|
||||
}});
|
||||
|
||||
var number = 1;
|
||||
is(number.getter, "getter");
|
||||
is(number.getter2, "getter2");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="runTest();">
|
||||
<pre>Test</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -25,11 +25,8 @@ NS_IMPL_NS_NEW_HTML_ELEMENT(Audio)
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
extern bool IsAudioAPIEnabled();
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLAudioElement)
|
||||
|
||||
|
||||
HTMLAudioElement::HTMLAudioElement(already_AddRefed<NodeInfo>& aNodeInfo)
|
||||
: HTMLMediaElement(aNodeInfo)
|
||||
{
|
||||
|
@ -79,13 +76,9 @@ HTMLAudioElement::Audio(const GlobalObject& aGlobal,
|
|||
nsresult HTMLAudioElement::SetAcceptHeader(nsIHttpChannel* aChannel)
|
||||
{
|
||||
nsAutoCString value(
|
||||
#ifdef MOZ_WEBM
|
||||
"audio/webm,"
|
||||
#endif
|
||||
"audio/ogg,"
|
||||
#ifdef MOZ_WAVE
|
||||
"audio/wav,"
|
||||
#endif
|
||||
"audio/*;q=0.9,"
|
||||
"application/ogg;q=0.7,"
|
||||
"video/*;q=0.6,*/*;q=0.5");
|
||||
|
|
|
@ -936,6 +936,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLInputElement,
|
|||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFiles)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFilesAndDirectoriesPromise)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLInputElement,
|
||||
|
@ -944,6 +945,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLInputElement,
|
|||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFiles)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFileList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFilesAndDirectoriesPromise)
|
||||
if (tmp->IsSingleLineTextControl(false)) {
|
||||
tmp->mInputData.mState->Unlink();
|
||||
}
|
||||
|
|
|
@ -113,9 +113,7 @@ HTMLVideoElement::GetAttributeMappingFunction() const
|
|||
nsresult HTMLVideoElement::SetAcceptHeader(nsIHttpChannel* aChannel)
|
||||
{
|
||||
nsAutoCString value(
|
||||
#ifdef MOZ_WEBM
|
||||
"video/webm,"
|
||||
#endif
|
||||
"video/ogg,"
|
||||
"video/*;q=0.9,"
|
||||
"application/ogg;q=0.7,"
|
||||
|
|
|
@ -458,8 +458,31 @@ static void LogChannelRelevantInfo(nsIURI* aURI,
|
|||
LOG("Result principal origin: %s\n", resultPrincipalOrigin.get());
|
||||
}
|
||||
|
||||
// This is similar to nsIScriptSecurityManager.getChannelResultPrincipal
|
||||
// but taking signedPkg into account. The reason we can't rely on channel
|
||||
// loadContext/loadInfo is it's dangerous to mutate them on parent process.
|
||||
static already_AddRefed<nsIPrincipal>
|
||||
GetChannelPrincipalWithSingedPkg(nsIChannel* aChannel, const nsACString& aSignedPkg)
|
||||
{
|
||||
NeckoOriginAttributes neckoAttrs;
|
||||
NS_GetOriginAttributes(aChannel, neckoAttrs);
|
||||
|
||||
PrincipalOriginAttributes attrs;
|
||||
attrs.InheritFromNecko(neckoAttrs);
|
||||
attrs.mSignedPkg = NS_ConvertUTF8toUTF16(aSignedPkg);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal =
|
||||
BasePrincipal::CreateCodebasePrincipal(uri, attrs);
|
||||
|
||||
return principal.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::ShouldSwitchProcess(nsIChannel* aChannel)
|
||||
TabParent::ShouldSwitchProcess(nsIChannel* aChannel, const nsACString& aSignedPkg)
|
||||
{
|
||||
// If we lack of any information which is required to decide the need of
|
||||
// process switch, consider that we should switch process.
|
||||
|
@ -473,19 +496,18 @@ TabParent::ShouldSwitchProcess(nsIChannel* aChannel)
|
|||
NS_ENSURE_TRUE(loadingPrincipal, true);
|
||||
|
||||
// Prepare the channel result principal.
|
||||
nsCOMPtr<nsIPrincipal> resultPrincipal;
|
||||
nsContentUtils::GetSecurityManager()->
|
||||
GetChannelResultPrincipal(aChannel, getter_AddRefs(resultPrincipal));
|
||||
nsCOMPtr<nsIPrincipal> channelPrincipal =
|
||||
GetChannelPrincipalWithSingedPkg(aChannel, aSignedPkg);
|
||||
|
||||
// Log the debug info which is used to decide the need of proces switch.
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
aChannel->GetURI(getter_AddRefs(uri));
|
||||
LogChannelRelevantInfo(uri, loadingPrincipal, resultPrincipal,
|
||||
LogChannelRelevantInfo(uri, loadingPrincipal, channelPrincipal,
|
||||
loadInfo->InternalContentPolicyType());
|
||||
|
||||
// Check if the signed package is loaded from the same origin.
|
||||
bool sameOrigin = false;
|
||||
loadingPrincipal->Equals(resultPrincipal, &sameOrigin);
|
||||
loadingPrincipal->Equals(channelPrincipal, &sameOrigin);
|
||||
if (sameOrigin) {
|
||||
LOG("Loading singed package from the same origin. Don't switch process.\n");
|
||||
return false;
|
||||
|
@ -516,7 +538,7 @@ void
|
|||
TabParent::OnStartSignedPackageRequest(nsIChannel* aChannel,
|
||||
const nsACString& aPackageId)
|
||||
{
|
||||
if (!ShouldSwitchProcess(aChannel)) {
|
||||
if (!ShouldSwitchProcess(aChannel, aPackageId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2347,7 +2369,7 @@ TabParent::RecvStartPluginIME(const WidgetKeyboardEvent& aKeyboardEvent,
|
|||
return true;
|
||||
}
|
||||
widget->StartPluginIME(aKeyboardEvent,
|
||||
(int32_t&)aPanelX,
|
||||
(int32_t&)aPanelX,
|
||||
(int32_t&)aPanelY,
|
||||
*aCommitted);
|
||||
return true;
|
||||
|
|
|
@ -495,7 +495,7 @@ protected:
|
|||
|
||||
// Decide whether we have to use a new process to reload the URI associated
|
||||
// with the given channel.
|
||||
bool ShouldSwitchProcess(nsIChannel* aChannel);
|
||||
bool ShouldSwitchProcess(nsIChannel* aChannel, const nsACString& aSignedPkg);
|
||||
|
||||
ContentCacheInParent mContentCache;
|
||||
|
||||
|
|
|
@ -12,15 +12,14 @@
|
|||
|
||||
#include "OggDecoder.h"
|
||||
#include "OggReader.h"
|
||||
#ifdef MOZ_WAVE
|
||||
|
||||
#include "WaveDecoder.h"
|
||||
#include "WaveReader.h"
|
||||
#endif
|
||||
#ifdef MOZ_WEBM
|
||||
|
||||
#include "WebMDecoder.h"
|
||||
#include "WebMReader.h"
|
||||
#include "WebMDemuxer.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_RAW
|
||||
#include "RawDecoder.h"
|
||||
#include "RawReader.h"
|
||||
|
@ -128,7 +127,6 @@ IsOggType(const nsACString& aType)
|
|||
return CodecListContains(gOggTypes, aType);
|
||||
}
|
||||
|
||||
#ifdef MOZ_WAVE
|
||||
// See http://www.rfc-editor.org/rfc/rfc2361.txt for the definitions
|
||||
// of WAVE media types and codec types. However, the audio/vnd.wave
|
||||
// MIME type described there is not used.
|
||||
|
@ -154,33 +152,24 @@ IsWaveType(const nsACString& aType)
|
|||
|
||||
return CodecListContains(gWaveTypes, aType);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WEBM
|
||||
static bool
|
||||
IsWebMSupportedType(const nsACString& aType,
|
||||
const nsAString& aCodecs = EmptyString())
|
||||
{
|
||||
return WebMDecoder::CanHandleMediaType(aType, aCodecs);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* static */ bool
|
||||
DecoderTraits::IsWebMTypeAndEnabled(const nsACString& aType)
|
||||
{
|
||||
#ifdef MOZ_WEBM
|
||||
return IsWebMSupportedType(aType);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
DecoderTraits::IsWebMAudioType(const nsACString& aType)
|
||||
{
|
||||
#ifdef MOZ_WEBM
|
||||
return aType.EqualsASCII("audio/webm");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef MOZ_GSTREAMER
|
||||
|
@ -367,7 +356,6 @@ IsAACSupportedType(const nsACString& aType,
|
|||
/* static */
|
||||
bool DecoderTraits::ShouldHandleMediaType(const char* aMIMEType)
|
||||
{
|
||||
#ifdef MOZ_WAVE
|
||||
if (IsWaveType(nsDependentCString(aMIMEType))) {
|
||||
// We should not return true for Wave types, since there are some
|
||||
// Wave codecs actually in use in the wild that we don't support, and
|
||||
|
@ -376,7 +364,6 @@ bool DecoderTraits::ShouldHandleMediaType(const char* aMIMEType)
|
|||
// means.
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return CanHandleMediaType(aMIMEType, false, EmptyString()) != CANPLAY_NO;
|
||||
}
|
||||
|
||||
|
@ -394,11 +381,9 @@ DecoderTraits::CanHandleCodecsType(const char* aMIMEType,
|
|||
if (IsOggType(nsDependentCString(aMIMEType))) {
|
||||
codecList = MediaDecoder::IsOpusEnabled() ? gOggCodecsWithOpus : gOggCodecs;
|
||||
}
|
||||
#ifdef MOZ_WAVE
|
||||
if (IsWaveType(nsDependentCString(aMIMEType))) {
|
||||
codecList = gWaveCodecs;
|
||||
}
|
||||
#endif
|
||||
#if !defined(MOZ_OMX_WEBM_DECODER)
|
||||
if (IsWebMTypeAndEnabled(nsDependentCString(aMIMEType))) {
|
||||
if (IsWebMSupportedType(nsDependentCString(aMIMEType), aRequestedCodecs)) {
|
||||
|
@ -496,11 +481,9 @@ DecoderTraits::CanHandleMediaType(const char* aMIMEType,
|
|||
if (IsOggType(nsDependentCString(aMIMEType))) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
#ifdef MOZ_WAVE
|
||||
if (IsWaveType(nsDependentCString(aMIMEType))) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
#endif
|
||||
if (IsMP4TypeAndEnabled(nsDependentCString(aMIMEType))) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
|
@ -583,12 +566,10 @@ InstantiateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
|
|||
decoder = new OggDecoder(aOwner);
|
||||
return decoder.forget();
|
||||
}
|
||||
#ifdef MOZ_WAVE
|
||||
if (IsWaveType(aType)) {
|
||||
decoder = new WaveDecoder(aOwner);
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_OMX_DECODER
|
||||
if (IsOmxSupportedType(aType)) {
|
||||
// we are discouraging Web and App developers from using those formats in
|
||||
|
@ -623,12 +604,12 @@ InstantiateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
|
|||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_WEBM
|
||||
|
||||
if (IsWebMSupportedType(aType)) {
|
||||
decoder = new WebMDecoder(aOwner);
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_DIRECTSHOW
|
||||
// Note: DirectShow should come before WMF, so that we prefer DirectShow's
|
||||
// MP3 support over WMF's.
|
||||
|
@ -682,11 +663,9 @@ MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, Abstrac
|
|||
if (IsOggType(aType)) {
|
||||
decoderReader = new OggReader(aDecoder);
|
||||
} else
|
||||
#ifdef MOZ_WAVE
|
||||
if (IsWaveType(aType)) {
|
||||
decoderReader = new WaveReader(aDecoder);
|
||||
} else
|
||||
#endif
|
||||
#ifdef MOZ_OMX_DECODER
|
||||
if (IsOmxSupportedType(aType)) {
|
||||
decoderReader = new MediaOmxReader(aDecoder);
|
||||
|
@ -698,13 +677,13 @@ MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, Abstrac
|
|||
decoderReader = new AndroidMediaReader(aDecoder, aType);
|
||||
} else
|
||||
#endif
|
||||
#ifdef MOZ_WEBM
|
||||
|
||||
if (IsWebMSupportedType(aType)) {
|
||||
decoderReader = Preferences::GetBool("media.format-reader.webm", true) ?
|
||||
static_cast<MediaDecoderReader*>(new MediaFormatReader(aDecoder, new WebMDemuxer(aDecoder->GetResource()))) :
|
||||
new WebMReader(aDecoder);
|
||||
} else
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_DIRECTSHOW
|
||||
if (IsDirectShowSupportedType(aType)) {
|
||||
decoderReader = new DirectShowReader(aDecoder);
|
||||
|
@ -735,9 +714,7 @@ bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType)
|
|||
(IsOmxSupportedType(aType) &&
|
||||
!IsB2GSupportOnlyType(aType)) ||
|
||||
#endif
|
||||
#ifdef MOZ_WEBM
|
||||
IsWebMSupportedType(aType) ||
|
||||
#endif
|
||||
#ifdef MOZ_GSTREAMER
|
||||
IsGStreamerSupportedType(aType) ||
|
||||
#endif
|
||||
|
|
|
@ -1641,21 +1641,17 @@ MediaDecoder::IsOggEnabled()
|
|||
return Preferences::GetBool("media.ogg.enabled");
|
||||
}
|
||||
|
||||
#ifdef MOZ_WAVE
|
||||
bool
|
||||
MediaDecoder::IsWaveEnabled()
|
||||
{
|
||||
return Preferences::GetBool("media.wave.enabled");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WEBM
|
||||
bool
|
||||
MediaDecoder::IsWebMEnabled()
|
||||
{
|
||||
return Preferences::GetBool("media.webm.enabled");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NECKO_PROTOCOL_rtsp
|
||||
bool
|
||||
|
|
|
@ -662,14 +662,9 @@ private:
|
|||
|
||||
static bool IsOggEnabled();
|
||||
static bool IsOpusEnabled();
|
||||
|
||||
#ifdef MOZ_WAVE
|
||||
static bool IsWaveEnabled();
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WEBM
|
||||
static bool IsWebMEnabled();
|
||||
#endif
|
||||
|
||||
#ifdef NECKO_PROTOCOL_rtsp
|
||||
static bool IsRtspEnabled();
|
||||
#endif
|
||||
|
|
|
@ -224,6 +224,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
|||
mIsVideoPrerolling(false),
|
||||
mAudioCaptured(false, "MediaDecoderStateMachine::mAudioCaptured"),
|
||||
mAudioCompleted(false, "MediaDecoderStateMachine::mAudioCompleted"),
|
||||
mVideoCompleted(false, "MediaDecoderStateMachine::mVideoCompleted"),
|
||||
mNotifyMetadataBeforeFirstFrame(false),
|
||||
mDispatchedEventToDecode(false),
|
||||
mQuickBuffering(false),
|
||||
|
@ -355,6 +356,7 @@ MediaDecoderStateMachine::InitializationTask(MediaDecoder* aDecoder)
|
|||
mWatchManager.Watch(mBuffered, &MediaDecoderStateMachine::BufferedRangeUpdated);
|
||||
mWatchManager.Watch(mState, &MediaDecoderStateMachine::UpdateNextFrameStatus);
|
||||
mWatchManager.Watch(mAudioCompleted, &MediaDecoderStateMachine::UpdateNextFrameStatus);
|
||||
mWatchManager.Watch(mVideoCompleted, &MediaDecoderStateMachine::UpdateNextFrameStatus);
|
||||
mWatchManager.Watch(mVolume, &MediaDecoderStateMachine::VolumeChanged);
|
||||
mWatchManager.Watch(mLogicalPlaybackRate, &MediaDecoderStateMachine::LogicalPlaybackRateChanged);
|
||||
mWatchManager.Watch(mPreservesPitch, &MediaDecoderStateMachine::PreservesPitchChanged);
|
||||
|
@ -2352,10 +2354,8 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
|||
// Play the remaining media. We want to run AdvanceFrame() at least
|
||||
// once to ensure the current playback position is advanced to the
|
||||
// end of the media, and so that we update the readyState.
|
||||
if (VideoQueue().GetSize() > 1 ||
|
||||
(HasAudio() && !mAudioCompleted) ||
|
||||
(mAudioCaptured && !mStreamSink->IsFinished()))
|
||||
{
|
||||
if ((HasVideo() && !mVideoCompleted) ||
|
||||
(HasAudio() && !mAudioCompleted)) {
|
||||
// Start playback if necessary to play the remaining media.
|
||||
MaybeStartPlayback();
|
||||
UpdatePlaybackPositionPeriodically();
|
||||
|
@ -2425,6 +2425,7 @@ MediaDecoderStateMachine::Reset()
|
|||
mDecodedVideoEndTime = -1;
|
||||
mDecodedAudioEndTime = -1;
|
||||
mAudioCompleted = false;
|
||||
mVideoCompleted = false;
|
||||
AudioQueue().Reset();
|
||||
VideoQueue().Reset();
|
||||
mFirstVideoFrameAfterSeek = nullptr;
|
||||
|
@ -2836,9 +2837,11 @@ void
|
|||
MediaDecoderStateMachine::OnMediaSinkVideoComplete()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(mInfo.HasVideo());
|
||||
VERBOSE_LOG("[%s]", __func__);
|
||||
|
||||
mMediaSinkVideoPromise.Complete();
|
||||
mVideoCompleted = true;
|
||||
ScheduleStateMachine();
|
||||
}
|
||||
|
||||
|
@ -2846,9 +2849,11 @@ void
|
|||
MediaDecoderStateMachine::OnMediaSinkVideoError()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(mInfo.HasVideo());
|
||||
VERBOSE_LOG("[%s]", __func__);
|
||||
|
||||
mMediaSinkVideoPromise.Complete();
|
||||
mVideoCompleted = true;
|
||||
if (HasAudio()) {
|
||||
return;
|
||||
}
|
||||
|
@ -2858,11 +2863,11 @@ MediaDecoderStateMachine::OnMediaSinkVideoError()
|
|||
void MediaDecoderStateMachine::OnMediaSinkAudioComplete()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(mInfo.HasAudio());
|
||||
VERBOSE_LOG("[%s]", __func__);
|
||||
|
||||
mMediaSinkAudioPromise.Complete();
|
||||
// Set true only when we have audio.
|
||||
mAudioCompleted = mInfo.HasAudio();
|
||||
mAudioCompleted = true;
|
||||
// To notify PlaybackEnded as soon as possible.
|
||||
ScheduleStateMachine();
|
||||
}
|
||||
|
@ -2870,11 +2875,11 @@ void MediaDecoderStateMachine::OnMediaSinkAudioComplete()
|
|||
void MediaDecoderStateMachine::OnMediaSinkAudioError()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(mInfo.HasAudio());
|
||||
VERBOSE_LOG("[%s]", __func__);
|
||||
|
||||
mMediaSinkAudioPromise.Complete();
|
||||
// Set true only when we have audio.
|
||||
mAudioCompleted = mInfo.HasAudio();
|
||||
mAudioCompleted = true;
|
||||
|
||||
// Make the best effort to continue playback when there is video.
|
||||
if (HasVideo()) {
|
||||
|
|
|
@ -1101,6 +1101,9 @@ private:
|
|||
// been written to the MediaStream.
|
||||
Watchable<bool> mAudioCompleted;
|
||||
|
||||
// True if all video frames are already rendered.
|
||||
Watchable<bool> mVideoCompleted;
|
||||
|
||||
// Set if MDSM receives dormant request during reading metadata.
|
||||
Maybe<bool> mPendingDormant;
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ public:
|
|||
: mMutex("DecodedStreamGraphListener::mMutex")
|
||||
, mStream(aStream)
|
||||
, mLastOutputTime(aStream->StreamTimeToMicroseconds(aStream->GetCurrentTime()))
|
||||
, mStreamFinishedOnMainThread(false)
|
||||
{
|
||||
mFinishPromise = Move(aPromise);
|
||||
}
|
||||
|
@ -52,8 +51,6 @@ public:
|
|||
void DoNotifyFinished()
|
||||
{
|
||||
mFinishPromise.ResolveIfExists(true, __func__);
|
||||
MutexAutoLock lock(mMutex);
|
||||
mStreamFinishedOnMainThread = true;
|
||||
}
|
||||
|
||||
int64_t GetLastOutputTime()
|
||||
|
@ -70,18 +67,11 @@ public:
|
|||
mStream = nullptr;
|
||||
}
|
||||
|
||||
bool IsFinishedOnMainThread()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
return mStreamFinishedOnMainThread;
|
||||
}
|
||||
|
||||
private:
|
||||
Mutex mMutex;
|
||||
// Members below are protected by mMutex.
|
||||
RefPtr<MediaStream> mStream;
|
||||
int64_t mLastOutputTime; // microseconds
|
||||
bool mStreamFinishedOnMainThread;
|
||||
// Main thread only.
|
||||
MozPromiseHolder<GenericPromise> mFinishPromise;
|
||||
};
|
||||
|
@ -119,7 +109,6 @@ public:
|
|||
DecodedStreamData(SourceMediaStream* aStream,
|
||||
MozPromiseHolder<GenericPromise>&& aPromise);
|
||||
~DecodedStreamData();
|
||||
bool IsFinished() const;
|
||||
int64_t GetPosition() const;
|
||||
void SetPlaying(bool aPlaying);
|
||||
|
||||
|
@ -180,12 +169,6 @@ DecodedStreamData::~DecodedStreamData()
|
|||
mStream->Destroy();
|
||||
}
|
||||
|
||||
bool
|
||||
DecodedStreamData::IsFinished() const
|
||||
{
|
||||
return mListener->IsFinishedOnMainThread();
|
||||
}
|
||||
|
||||
int64_t
|
||||
DecodedStreamData::GetPosition() const
|
||||
{
|
||||
|
@ -346,13 +329,14 @@ DecodedStream::OnEnded(TrackType aType)
|
|||
AssertOwnerThread();
|
||||
MOZ_ASSERT(mStartTime.isSome());
|
||||
|
||||
if (aType == TrackInfo::kAudioTrack) {
|
||||
if (aType == TrackInfo::kAudioTrack && mInfo.HasAudio()) {
|
||||
// TODO: we should return a promise which is resolved when the audio track
|
||||
// is finished. For now this promise is resolved when the whole stream is
|
||||
// finished.
|
||||
return mFinishPromise;
|
||||
} else if (aType == TrackInfo::kVideoTrack && mInfo.HasVideo()) {
|
||||
return mFinishPromise;
|
||||
}
|
||||
// TODO: handle video track.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -883,13 +867,6 @@ DecodedStream::GetPosition(TimeStamp* aTimeStamp) const
|
|||
return mStartTime.ref() + (mData ? mData->GetPosition() : 0);
|
||||
}
|
||||
|
||||
bool
|
||||
DecodedStream::IsFinished() const
|
||||
{
|
||||
AssertOwnerThread();
|
||||
return mData && mData->IsFinished();
|
||||
}
|
||||
|
||||
void
|
||||
DecodedStream::ConnectListener()
|
||||
{
|
||||
|
|
|
@ -123,7 +123,6 @@ public:
|
|||
void AddOutput(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
|
||||
void RemoveOutput(MediaStream* aStream);
|
||||
void SetSameOrigin(bool aSameOrigin);
|
||||
bool IsFinished() const;
|
||||
bool HasConsumers() const;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -166,8 +166,29 @@ VideoSink::Start(int64_t aStartTime, const MediaInfo& aInfo)
|
|||
|
||||
if (mHasVideo) {
|
||||
mEndPromise = mEndPromiseHolder.Ensure(__func__);
|
||||
|
||||
// If the underlying MediaSink has an end promise for the video track (which
|
||||
// happens when mAudioSink refers to a DecodedStream), we must wait for it
|
||||
// to complete before resolving our own end promise. Otherwise, MDSM might
|
||||
// stop playback before DecodedStream plays to the end and cause
|
||||
// test_streams_element_capture.html to time out.
|
||||
RefPtr<GenericPromise> p = mAudioSink->OnEnded(TrackInfo::kVideoTrack);
|
||||
if (p) {
|
||||
RefPtr<VideoSink> self = this;
|
||||
mVideoSinkEndRequest.Begin(p->Then(mOwnerThread, __func__,
|
||||
[self] () {
|
||||
self->mVideoSinkEndRequest.Complete();
|
||||
self->TryUpdateRenderedVideoFrames();
|
||||
}, [self] () {
|
||||
self->mVideoSinkEndRequest.Complete();
|
||||
self->TryUpdateRenderedVideoFrames();
|
||||
}));
|
||||
}
|
||||
|
||||
ConnectListener();
|
||||
TryUpdateRenderedVideoFrames();
|
||||
// Run the render loop at least once so we can resolve the end promise
|
||||
// when video duration is 0.
|
||||
UpdateRenderedVideoFrames();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,7 +204,8 @@ VideoSink::Stop()
|
|||
mUpdateScheduler.Reset();
|
||||
if (mHasVideo) {
|
||||
DisconnectListener();
|
||||
mEndPromiseHolder.Resolve(true, __func__);
|
||||
mVideoSinkEndRequest.DisconnectIfExists();
|
||||
mEndPromiseHolder.ResolveIfExists(true, __func__);
|
||||
mEndPromise = nullptr;
|
||||
}
|
||||
mVideoFrameEndTime = -1;
|
||||
|
@ -216,7 +238,7 @@ VideoSink::Shutdown()
|
|||
}
|
||||
|
||||
void
|
||||
VideoSink::OnVideoQueueEvent(RefPtr<MediaData>&& aSample)
|
||||
VideoSink::OnVideoQueuePushed(RefPtr<MediaData>&& aSample)
|
||||
{
|
||||
AssertOwnerThread();
|
||||
// Listen to push event, VideoSink should try rendering ASAP if first frame
|
||||
|
@ -230,6 +252,18 @@ VideoSink::OnVideoQueueEvent(RefPtr<MediaData>&& aSample)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
VideoSink::OnVideoQueueFinished()
|
||||
{
|
||||
AssertOwnerThread();
|
||||
// Run render loop if the end promise is not resolved yet.
|
||||
if (!mUpdateScheduler.IsScheduled() &&
|
||||
mAudioSink->IsPlaying() &&
|
||||
!mEndPromiseHolder.IsEmpty()) {
|
||||
UpdateRenderedVideoFrames();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VideoSink::Redraw()
|
||||
{
|
||||
|
@ -260,7 +294,9 @@ VideoSink::ConnectListener()
|
|||
{
|
||||
AssertOwnerThread();
|
||||
mPushListener = VideoQueue().PushEvent().Connect(
|
||||
mOwnerThread, this, &VideoSink::OnVideoQueueEvent);
|
||||
mOwnerThread, this, &VideoSink::OnVideoQueuePushed);
|
||||
mFinishListener = VideoQueue().FinishEvent().Connect(
|
||||
mOwnerThread, this, &VideoSink::OnVideoQueueFinished);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -268,6 +304,7 @@ VideoSink::DisconnectListener()
|
|||
{
|
||||
AssertOwnerThread();
|
||||
mPushListener.Disconnect();
|
||||
mFinishListener.Disconnect();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -371,6 +408,13 @@ VideoSink::UpdateRenderedVideoFrames()
|
|||
}
|
||||
}
|
||||
|
||||
// All frames are rendered, Let's resolve the promise.
|
||||
if (VideoQueue().IsFinished() &&
|
||||
VideoQueue().GetSize() <= 1 &&
|
||||
!mVideoSinkEndRequest.Exists()) {
|
||||
mEndPromiseHolder.ResolveIfExists(true, __func__);
|
||||
}
|
||||
|
||||
RenderVideoFrames(mVideoQueueSendToCompositorSize, clockTime, nowTime);
|
||||
|
||||
// No next fame to render. There is no need to schedule next render
|
||||
|
|
|
@ -72,7 +72,8 @@ private:
|
|||
virtual ~VideoSink();
|
||||
|
||||
// VideoQueue listener related.
|
||||
void OnVideoQueueEvent(RefPtr<MediaData>&& aSample);
|
||||
void OnVideoQueuePushed(RefPtr<MediaData>&& aSample);
|
||||
void OnVideoQueueFinished();
|
||||
void ConnectListener();
|
||||
void DisconnectListener();
|
||||
|
||||
|
@ -129,6 +130,7 @@ private:
|
|||
|
||||
// Event listeners for VideoQueue
|
||||
MediaEventListener mPushListener;
|
||||
MediaEventListener mFinishListener;
|
||||
|
||||
// True if this sink is going to handle video track.
|
||||
bool mHasVideo;
|
||||
|
|
|
@ -12,10 +12,7 @@
|
|||
#include "mozilla/StateMirroring.h"
|
||||
#include "SourceBufferResource.h"
|
||||
#include "SourceBuffer.h"
|
||||
|
||||
#ifdef MOZ_WEBM
|
||||
#include "WebMDemuxer.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_FMP4
|
||||
#include "MP4Demuxer.h"
|
||||
|
@ -798,12 +795,10 @@ TrackBuffersManager::CreateDemuxerforMIMEType()
|
|||
{
|
||||
ShutdownDemuxers();
|
||||
|
||||
#ifdef MOZ_WEBM
|
||||
if (mType.LowerCaseEqualsLiteral("video/webm") || mType.LowerCaseEqualsLiteral("audio/webm")) {
|
||||
mInputDemuxer = new WebMDemuxer(mCurrentInputBuffer, true /* IsMediaSource*/ );
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_FMP4
|
||||
if (mType.LowerCaseEqualsLiteral("video/mp4") || mType.LowerCaseEqualsLiteral("audio/mp4")) {
|
||||
|
|
|
@ -30,7 +30,9 @@ DIRS += [
|
|||
'ogg',
|
||||
'platforms',
|
||||
'systemservices',
|
||||
'wave',
|
||||
'webaudio',
|
||||
'webm',
|
||||
'webrtc',
|
||||
'webspeech',
|
||||
'webvtt',
|
||||
|
@ -40,12 +42,6 @@ DIRS += [
|
|||
if CONFIG['MOZ_RAW']:
|
||||
DIRS += ['raw']
|
||||
|
||||
if CONFIG['MOZ_WAVE']:
|
||||
DIRS += ['wave']
|
||||
|
||||
if CONFIG['MOZ_WEBM']:
|
||||
DIRS += ['webm']
|
||||
|
||||
if CONFIG['MOZ_GSTREAMER']:
|
||||
DIRS += ['gstreamer']
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ OmxDataDecoder::OmxDataDecoder(const TrackInfo& aTrackInfo,
|
|||
, mOmxState(OMX_STATETYPE::OMX_StateInvalid, "OmxDataDecoder::mOmxState")
|
||||
, mTrackInfo(aTrackInfo.Clone())
|
||||
, mFlushing(false)
|
||||
, mShutdown(false)
|
||||
, mShuttingDown(false)
|
||||
, mCheckingInputExhausted(false)
|
||||
, mPortSettingsChanged(-1, "OmxDataDecoder::mPortSettingsChanged")
|
||||
, mAudioCompactor(mAudioQueue)
|
||||
|
@ -86,7 +86,6 @@ OmxDataDecoder::~OmxDataDecoder()
|
|||
{
|
||||
LOG("(%p)", this);
|
||||
mWatchManager.Shutdown();
|
||||
mOmxTaskQueue->AwaitShutdownAndIdle();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -207,12 +206,25 @@ OmxDataDecoder::Shutdown()
|
|||
{
|
||||
LOG("(%p)", this);
|
||||
|
||||
mShutdown = true;
|
||||
mShuttingDown = true;
|
||||
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NS_NewRunnableMethod(this, &OmxDataDecoder::DoAsyncShutdown);
|
||||
mOmxTaskQueue->Dispatch(r.forget());
|
||||
|
||||
{
|
||||
// DoAsyncShutdown() will be running for a while, it could be still running
|
||||
// when reader releasing the decoder and then it causes problem. To avoid it,
|
||||
// Shutdown() must block until DoAsyncShutdown() is completed.
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
while (mShuttingDown) {
|
||||
lock.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
mOmxTaskQueue->BeginShutdown();
|
||||
mOmxTaskQueue->AwaitShutdownAndIdle();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -273,9 +285,17 @@ OmxDataDecoder::DoAsyncShutdown()
|
|||
[self] () {
|
||||
LOG("DoAsyncShutdown: OMX_StateLoaded, it is safe to shutdown omx");
|
||||
self->mOmxLayer->Shutdown();
|
||||
|
||||
MonitorAutoLock lock(self->mMonitor);
|
||||
self->mShuttingDown = false;
|
||||
self->mMonitor.Notify();
|
||||
},
|
||||
[self] () {
|
||||
self->mOmxLayer->Shutdown();
|
||||
|
||||
MonitorAutoLock lock(self->mMonitor);
|
||||
self->mShuttingDown = false;
|
||||
self->mMonitor.Notify();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -400,12 +420,8 @@ OmxDataDecoder::FillAndEmptyBuffers()
|
|||
MOZ_ASSERT(mOmxTaskQueue->IsCurrentThreadIn());
|
||||
MOZ_ASSERT(mOmxState == OMX_StateExecuting);
|
||||
|
||||
// During the port setting changed, it is forbided to do any buffer operations.
|
||||
if (mPortSettingsChanged != -1 || mShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFlushing) {
|
||||
// During the port setting changed, it is forbidden to do any buffer operation.
|
||||
if (mPortSettingsChanged != -1 || mShuttingDown || mFlushing) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -842,7 +858,6 @@ OmxDataDecoder::DoFlush()
|
|||
|
||||
// 1. Call OMX command OMX_CommandFlush in Omx TaskQueue.
|
||||
// 2. Remove all elements in mMediaRawDatas when flush is completed.
|
||||
RefPtr<OmxDataDecoder> self = this;
|
||||
mOmxLayer->SendCommand(OMX_CommandFlush, OMX_ALL, nullptr)
|
||||
->Then(mOmxTaskQueue, __func__, this,
|
||||
&OmxDataDecoder::FlushComplete,
|
||||
|
|
|
@ -163,7 +163,7 @@ protected:
|
|||
Atomic<bool> mFlushing;
|
||||
|
||||
// It is accessed in Omx/reader TaskQeueu.
|
||||
Atomic<bool> mShutdown;
|
||||
Atomic<bool> mShuttingDown;
|
||||
|
||||
// It is accessed in Omx TaskQeueu.
|
||||
bool mCheckingInputExhausted;
|
||||
|
|
|
@ -22,9 +22,10 @@ extern mozilla::LogModule* GetPDMLog();
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
extern void GetPortIndex(nsTArray<uint32_t>& aPortIndex);
|
||||
|
||||
OmxPromiseLayer::OmxPromiseLayer(TaskQueue* aTaskQueue, OmxDataDecoder* aDataDecoder)
|
||||
: mTaskQueue(aTaskQueue)
|
||||
, mFlushPortIndex(0)
|
||||
{
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION < 21
|
||||
mPlatformLayer = new GonkOmxPlatformLayer(aDataDecoder, this, aTaskQueue);
|
||||
|
@ -196,27 +197,48 @@ OmxPromiseLayer::EmptyFillBufferDone(OMX_DIRTYPE aType, BufferData::BufferID aID
|
|||
RefPtr<OmxPromiseLayer::OmxCommandPromise>
|
||||
OmxPromiseLayer::SendCommand(OMX_COMMANDTYPE aCmd, OMX_U32 aParam1, OMX_PTR aCmdData)
|
||||
{
|
||||
// No need to issue flush because of buffers are in client already.
|
||||
//
|
||||
// Some components fail to respond flush event when all of buffers are in
|
||||
// client.
|
||||
if (aCmd == OMX_CommandFlush) {
|
||||
bool needFlush = false;
|
||||
if ((aParam1 & OMX_DirInput && mInbufferHolders.Length()) ||
|
||||
(aParam1 & OMX_DirOutput && mOutbufferHolders.Length())) {
|
||||
needFlush = true;
|
||||
}
|
||||
if (!needFlush) {
|
||||
LOG("SendCommand: buffers are in client already, no need to flush");
|
||||
mRawDatas.Clear();
|
||||
return OmxCommandPromise::CreateAndResolve(OMX_CommandFlush, __func__);
|
||||
}
|
||||
}
|
||||
// It doesn't support another flush commands before previous one is completed.
|
||||
MOZ_RELEASE_ASSERT(!mFlushCommands.Length());
|
||||
|
||||
OMX_ERRORTYPE err = mPlatformLayer->SendCommand(aCmd, aParam1, aCmdData);
|
||||
if (err != OMX_ErrorNone) {
|
||||
OmxCommandFailureHolder failure(OMX_ErrorNotReady, aCmd);
|
||||
return OmxCommandPromise::CreateAndReject(failure, __func__);
|
||||
// Some coomponents don't send event with OMX_ALL, they send flush complete
|
||||
// event with input port and another event for output port.
|
||||
// In prupose of better compatibility, we inteprete the OMX_ALL to OMX_DirInput
|
||||
// and OMX_DirOutput flush separately.
|
||||
OMX_DIRTYPE types[] = {OMX_DIRTYPE::OMX_DirInput, OMX_DIRTYPE::OMX_DirOutput};
|
||||
for(const auto type : types) {
|
||||
if ((aParam1 == type) || (aParam1 == OMX_ALL)) {
|
||||
mFlushCommands.AppendElement(FlushCommand({type, aCmdData}));
|
||||
}
|
||||
|
||||
if (type == OMX_DirInput) {
|
||||
// Clear all buffered raw data.
|
||||
mRawDatas.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Don't overlay more than one fush command, some components can't overlay flush commands.
|
||||
// So here we send another flush after receiving the previous flush completed event.
|
||||
if (mFlushCommands.Length()) {
|
||||
OMX_ERRORTYPE err =
|
||||
mPlatformLayer->SendCommand(OMX_CommandFlush,
|
||||
mFlushCommands.ElementAt(0).type,
|
||||
mFlushCommands.ElementAt(0).cmd);
|
||||
if (err != OMX_ErrorNone) {
|
||||
OmxCommandFailureHolder failure(OMX_ErrorNotReady, OMX_CommandFlush);
|
||||
return OmxCommandPromise::CreateAndReject(failure, __func__);
|
||||
}
|
||||
} else {
|
||||
LOG("SendCommand: OMX_CommandFlush parameter error");
|
||||
OmxCommandFailureHolder failure(OMX_ErrorNotReady, OMX_CommandFlush);
|
||||
return OmxCommandPromise::CreateAndReject(failure, __func__);
|
||||
}
|
||||
} else {
|
||||
OMX_ERRORTYPE err = mPlatformLayer->SendCommand(aCmd, aParam1, aCmdData);
|
||||
if (err != OMX_ErrorNone) {
|
||||
OmxCommandFailureHolder failure(OMX_ErrorNotReady, aCmd);
|
||||
return OmxCommandPromise::CreateAndReject(failure, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<OmxCommandPromise> p;
|
||||
|
@ -224,9 +246,6 @@ OmxPromiseLayer::SendCommand(OMX_COMMANDTYPE aCmd, OMX_U32 aParam1, OMX_PTR aCmd
|
|||
p = mCommandStatePromise.Ensure(__func__);
|
||||
} else if (aCmd == OMX_CommandFlush) {
|
||||
p = mFlushPromise.Ensure(__func__);
|
||||
mFlushPortIndex = aParam1;
|
||||
// Clear all buffered raw data.
|
||||
mRawDatas.Clear();
|
||||
} else if (aCmd == OMX_CommandPortEnable) {
|
||||
p = mPortEnablePromise.Ensure(__func__);
|
||||
} else if (aCmd == OMX_CommandPortDisable) {
|
||||
|
@ -248,8 +267,24 @@ OmxPromiseLayer::Event(OMX_EVENTTYPE aEvent, OMX_U32 aData1, OMX_U32 aData2)
|
|||
{
|
||||
if (cmd == OMX_CommandStateSet) {
|
||||
mCommandStatePromise.Resolve(OMX_CommandStateSet, __func__);
|
||||
} else if (cmd == OMX_CommandFlush && mFlushPortIndex == aData2) {
|
||||
mFlushPromise.Resolve(OMX_CommandFlush, __func__);
|
||||
} else if (cmd == OMX_CommandFlush) {
|
||||
MOZ_RELEASE_ASSERT(mFlushCommands.ElementAt(0).type == aData2);
|
||||
LOG("Event: OMX_CommandFlush completed port type %d", aData2);
|
||||
mFlushCommands.RemoveElementAt(0);
|
||||
|
||||
// Sending next flush command.
|
||||
if (mFlushCommands.Length()) {
|
||||
OMX_ERRORTYPE err =
|
||||
mPlatformLayer->SendCommand(OMX_CommandFlush,
|
||||
mFlushCommands.ElementAt(0).type,
|
||||
mFlushCommands.ElementAt(0).cmd);
|
||||
if (err != OMX_ErrorNone) {
|
||||
OmxCommandFailureHolder failure(OMX_ErrorNotReady, OMX_CommandFlush);
|
||||
mFlushPromise.Reject(failure, __func__);
|
||||
}
|
||||
} else {
|
||||
mFlushPromise.Resolve(OMX_CommandFlush, __func__);
|
||||
}
|
||||
} else if (cmd == OMX_CommandPortDisable) {
|
||||
mPortDisablePromise.Resolve(OMX_CommandPortDisable, __func__);
|
||||
} else if (cmd == OMX_CommandPortEnable) {
|
||||
|
@ -262,7 +297,7 @@ OmxPromiseLayer::Event(OMX_EVENTTYPE aEvent, OMX_U32 aData1, OMX_U32 aData2)
|
|||
if (cmd == OMX_CommandStateSet) {
|
||||
OmxCommandFailureHolder failure(OMX_ErrorUndefined, OMX_CommandStateSet);
|
||||
mCommandStatePromise.Reject(failure, __func__);
|
||||
} else if (cmd == OMX_CommandFlush && mFlushPortIndex == aData2) {
|
||||
} else if (cmd == OMX_CommandFlush) {
|
||||
OmxCommandFailureHolder failure(OMX_ErrorUndefined, OMX_CommandFlush);
|
||||
mFlushPromise.Reject(failure, __func__);
|
||||
} else if (cmd == OMX_CommandPortDisable) {
|
||||
|
|
|
@ -183,6 +183,11 @@ public:
|
|||
bool Event(OMX_EVENTTYPE aEvent, OMX_U32 aData1, OMX_U32 aData2);
|
||||
|
||||
protected:
|
||||
struct FlushCommand {
|
||||
OMX_DIRTYPE type;
|
||||
OMX_PTR cmd;
|
||||
};
|
||||
|
||||
BUFFERLIST* GetBufferHolders(OMX_DIRTYPE aType);
|
||||
|
||||
already_AddRefed<MediaRawData> FindAndRemoveRawData(OMX_TICKS aTimecode);
|
||||
|
@ -197,7 +202,7 @@ protected:
|
|||
|
||||
MozPromiseHolder<OmxCommandPromise> mFlushPromise;
|
||||
|
||||
OMX_U32 mFlushPortIndex;
|
||||
nsTArray<FlushCommand> mFlushCommands;
|
||||
|
||||
nsAutoPtr<OmxPlatformLayer> mPlatformLayer;
|
||||
|
||||
|
|
|
@ -50,11 +50,12 @@ DecoderFuzzingWrapper::Input(MediaRawData* aData)
|
|||
nsresult
|
||||
DecoderFuzzingWrapper::Flush()
|
||||
{
|
||||
DFW_LOGV("");
|
||||
DFW_LOGV("Calling mDecoder[%p]->Flush()", mDecoder.get());
|
||||
MOZ_ASSERT(mDecoder);
|
||||
// Flush may output some frames (though unlikely).
|
||||
// Flush may block a bit, it's ok if we output some frames in the meantime.
|
||||
nsresult result = mDecoder->Flush();
|
||||
DFW_LOGV("mDecoder[%p]->Flush() -> result=%u", mDecoder.get(), uint32_t(result));
|
||||
// Clear any delayed output we may have.
|
||||
mCallbackWrapper->ClearDelayedOutput();
|
||||
return result;
|
||||
|
@ -254,13 +255,28 @@ void
|
|||
DecoderCallbackFuzzingWrapper::ScheduleOutputDelayedFrame()
|
||||
{
|
||||
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
|
||||
if (mDelayedOutputRequest.Exists()) {
|
||||
// A delayed output is already scheduled, no need for more than one timer.
|
||||
return;
|
||||
}
|
||||
RefPtr<DecoderCallbackFuzzingWrapper> self = this;
|
||||
mDelayedOutputTimer->WaitUntil(
|
||||
mPreviousOutput + mFrameOutputMinimumInterval,
|
||||
__func__)
|
||||
->Then(mTaskQueue, __func__,
|
||||
[self] () -> void { self->OutputDelayedFrame(); },
|
||||
[self] () -> void { self->OutputDelayedFrame(); });
|
||||
mDelayedOutputRequest.Begin(
|
||||
mDelayedOutputTimer->WaitUntil(
|
||||
mPreviousOutput + mFrameOutputMinimumInterval,
|
||||
__func__)
|
||||
->Then(mTaskQueue, __func__,
|
||||
[self] () -> void {
|
||||
if (self->mDelayedOutputRequest.Exists()) {
|
||||
self->mDelayedOutputRequest.Complete();
|
||||
self->OutputDelayedFrame();
|
||||
}
|
||||
},
|
||||
[self] () -> void {
|
||||
if (self->mDelayedOutputRequest.Exists()) {
|
||||
self->mDelayedOutputRequest.Complete();
|
||||
self->ClearDelayedOutput();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -300,11 +316,16 @@ void
|
|||
DecoderCallbackFuzzingWrapper::ClearDelayedOutput()
|
||||
{
|
||||
if (!mTaskQueue->IsCurrentThreadIn()) {
|
||||
DFW_LOGV("(dispatching self)");
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::ClearDelayedOutput);
|
||||
mTaskQueue->Dispatch(task.forget());
|
||||
return;
|
||||
}
|
||||
DFW_LOGV("");
|
||||
// In case a timer hasn't lapsed yet, before destroying the timer and its
|
||||
// attached waitUntil() promise, the 'Then' request must be disconnected.
|
||||
mDelayedOutputRequest.DisconnectIfExists();
|
||||
mDelayedOutputTimer = nullptr;
|
||||
mDelayedOutput.clear();
|
||||
}
|
||||
|
@ -312,10 +333,16 @@ DecoderCallbackFuzzingWrapper::ClearDelayedOutput()
|
|||
void
|
||||
DecoderCallbackFuzzingWrapper::Shutdown()
|
||||
{
|
||||
DFW_LOGV("Shutting down mTaskQueue");
|
||||
CFW_LOGV("Clear delayed output (if any) before shutting down mTaskQueue");
|
||||
ClearDelayedOutput();
|
||||
// Await idle here, so that 'ClearDelayedOutput' runs to completion before
|
||||
// the task queue is shutdown (and tasks can't be queued anymore).
|
||||
mTaskQueue->AwaitIdle();
|
||||
|
||||
CFW_LOGV("Shutting down mTaskQueue");
|
||||
mTaskQueue->BeginShutdown();
|
||||
mTaskQueue->AwaitIdle();
|
||||
DFW_LOGV("mTaskQueue shut down");
|
||||
CFW_LOGV("mTaskQueue shut down");
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -81,6 +81,7 @@ private:
|
|||
typedef Pair<RefPtr<MediaData>, bool> MediaDataAndInputExhausted;
|
||||
std::deque<MediaDataAndInputExhausted> mDelayedOutput;
|
||||
RefPtr<MediaTimer> mDelayedOutputTimer;
|
||||
MozPromiseRequestHolder<MediaTimerPromise> mDelayedOutputRequest;
|
||||
// If draining, a 'DrainComplete' will be sent after all delayed frames have
|
||||
// been output.
|
||||
bool mDraining;
|
||||
|
|
|
@ -851,14 +851,6 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
|||
# The tests below contain backend-specific tests. Write backend independent
|
||||
# tests rather than adding to this list.
|
||||
[test_can_play_type_webm.html]
|
||||
skip-if = !webm
|
||||
[test_can_play_type_no_webm.html]
|
||||
skip-if = webm
|
||||
[test_can_play_type_wave.html]
|
||||
skip-if = !wave
|
||||
[test_can_play_type_no_wave.html]
|
||||
skip-if = wave
|
||||
[test_fragment_noplay.html]
|
||||
skip-if = !wave
|
||||
[test_fragment_play.html]
|
||||
skip-if = !wave
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=469247
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 469247: WAVE backend disabled</title>
|
||||
<script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=469247">Mozill
|
||||
a Bug 469247</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
|
||||
<video id="v"></video>
|
||||
|
||||
<pre id="test">
|
||||
<script src="can_play_type_wave.js"></script>
|
||||
|
||||
check_wave(document.getElementById('v'), false);
|
||||
|
||||
mediaTestCleanup();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,32 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=566245
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 566245: WebM backend disabled</title>
|
||||
<script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=566245">Mozill
|
||||
a Bug 566245</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
|
||||
<video id="v"></video>
|
||||
|
||||
<pre id="test">
|
||||
<script src="can_play_type_webm.js"></script>
|
||||
|
||||
check_webm(document.getElementById('v'), false);
|
||||
|
||||
mediaTestCleanup();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -90,11 +90,11 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' &
|
|||
[test_peerConnection_basicScreenshare.html]
|
||||
# no screenshare on b2g/android
|
||||
# frequent timeouts/crashes on e10s (bug 1048455)
|
||||
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' || e10s # Bug 1141029 Mulet parity with B2G Desktop for TC
|
||||
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' # Bug 1141029 Mulet parity with B2G Desktop for TC
|
||||
[test_peerConnection_basicWindowshare.html]
|
||||
# no screenshare on b2g/android
|
||||
# frequent timeouts/crashes on e10s (bug 1048455)
|
||||
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' || e10s # Bug 1141029 Mulet parity with B2G Desktop for TC
|
||||
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' # Bug 1141029 Mulet parity with B2G Desktop for TC
|
||||
[test_peerConnection_basicH264Video.html]
|
||||
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || os == 'android' # bug 1043403 # Bug 1141029 Mulet parity with B2G Desktop for TC
|
||||
[test_peerConnection_bug822674.html]
|
||||
|
@ -161,16 +161,16 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' &
|
|||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g (Bug 1059867), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_twoAudioVideoStreams.html]
|
||||
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s) || android_version == '18'
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18'
|
||||
[test_peerConnection_twoAudioVideoStreamsCombined.html]
|
||||
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s) || android_version == '18'
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18'
|
||||
[test_peerConnection_twoVideoStreams.html]
|
||||
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s) || android_version == '18'
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18'
|
||||
[test_peerConnection_twoVideoTracksInOneStream.html]
|
||||
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug)
|
||||
[test_peerConnection_addSecondAudioStream.html]
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
[test_peerConnection_answererAddSecondAudioStream.html]
|
||||
|
@ -181,26 +181,26 @@ skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator
|
|||
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_addSecondVideoStream.html]
|
||||
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || android_version == '18'
|
||||
skip-if = toolkit == 'gonk' || android_version == '18'
|
||||
[test_peerConnection_removeVideoTrack.html]
|
||||
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
|
||||
skip-if = toolkit == 'gonk' || (android_version == '18' && debug)
|
||||
[test_peerConnection_removeThenAddVideoTrack.html]
|
||||
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
|
||||
skip-if = toolkit == 'gonk' || (android_version == '18' && debug)
|
||||
[test_peerConnection_replaceVideoThenRenegotiate.html]
|
||||
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
|
||||
skip-if = toolkit == 'gonk' || (android_version == '18' && debug)
|
||||
[test_peerConnection_addSecondAudioStreamNoBundle.html]
|
||||
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_removeThenAddAudioTrackNoBundle.html]
|
||||
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_addSecondVideoStreamNoBundle.html]
|
||||
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || android_version == '18'
|
||||
skip-if = toolkit == 'gonk' || android_version == '18'
|
||||
[test_peerConnection_removeThenAddVideoTrackNoBundle.html]
|
||||
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || android_version == '18'
|
||||
skip-if = toolkit == 'gonk' || android_version == '18'
|
||||
[test_peerConnection_addDataChannel.html]
|
||||
skip-if = toolkit == 'gonk' # B2G emulator seems to be so slow that DTLS cannot establish properly
|
||||
[test_peerConnection_addDataChannelNoBundle.html]
|
||||
|
|
|
@ -2650,7 +2650,12 @@ Notification::CreateAndShow(nsIGlobalObject* aGlobal,
|
|||
MOZ_ASSERT(aGlobal);
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init(aGlobal);
|
||||
if (NS_WARN_IF(!jsapi.Init(aGlobal)))
|
||||
{
|
||||
aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
RefPtr<Notification> notification = CreateInternal(aGlobal, EmptyString(),
|
||||
|
|
|
@ -1162,6 +1162,11 @@ public:
|
|||
int32_t limit = 0,
|
||||
int32_t allocLimit = 0);
|
||||
|
||||
/**
|
||||
* Make sure that the given buffer size doesn't exceed the allocation limit.
|
||||
*/
|
||||
static bool CheckBufferSize(int32_t bufSize);
|
||||
|
||||
/** Make sure the given dimension satisfies the CheckSurfaceSize and is
|
||||
* within 8k limit. The 8k value is chosen a bit randomly.
|
||||
*/
|
||||
|
|
|
@ -333,6 +333,10 @@ GetCairoSurfaceForSourceSurface(SourceSurface *aSurface,
|
|||
bool aExistingOnly = false,
|
||||
const IntRect& aSubImage = IntRect())
|
||||
{
|
||||
if (!aSurface) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IntRect subimage = IntRect(IntPoint(), aSurface->GetSize());
|
||||
if (!aSubImage.IsEmpty()) {
|
||||
MOZ_ASSERT(!aExistingOnly);
|
||||
|
@ -792,7 +796,7 @@ DrawTargetCairo::DrawSurface(SourceSurface *aSurface,
|
|||
return;
|
||||
}
|
||||
|
||||
if (!IsValid()) {
|
||||
if (!IsValid() || !aSurface) {
|
||||
gfxCriticalNote << "DrawSurface with bad surface " << cairo_surface_status(mSurface);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -264,6 +264,12 @@ Factory::AllowedSurfaceSize(const IntSize &aSize)
|
|||
return CheckSurfaceSize(aSize);
|
||||
}
|
||||
|
||||
bool
|
||||
Factory::CheckBufferSize(int32_t bufSize)
|
||||
{
|
||||
return !sConfig || bufSize < sConfig->mMaxAllocSize;
|
||||
}
|
||||
|
||||
bool
|
||||
Factory::CheckSurfaceSize(const IntSize &sz,
|
||||
int32_t extentLimit,
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "mozilla/layers/AsyncDragMetrics.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
#include "ImageTypes.h"
|
||||
#include "FrameMetrics.h"
|
||||
#include "FilterSupport.h"
|
||||
#include "mozilla/layers/GeckoContentController.h"
|
||||
|
@ -714,6 +715,7 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
|
|||
WriteParam(aMsg, aParam.mMaskLayerIndex);
|
||||
WriteParam(aMsg, aParam.mIsLayersIdRoot);
|
||||
WriteParam(aMsg, aParam.mUsesContainerScrolling);
|
||||
WriteParam(aMsg, aParam.mIsScrollInfoLayer);
|
||||
WriteParam(aMsg, aParam.GetContentDescription());
|
||||
}
|
||||
|
||||
|
@ -760,6 +762,7 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
|
|||
ReadParam(aMsg, aIter, &aResult->mMaskLayerIndex) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mIsLayersIdRoot) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mUsesContainerScrolling) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mIsScrollInfoLayer) &&
|
||||
ReadContentDescription(aMsg, aIter, aResult));
|
||||
}
|
||||
};
|
||||
|
@ -797,7 +800,7 @@ template<>
|
|||
struct ParamTraits<mozilla::layers::TextureInfo>
|
||||
{
|
||||
typedef mozilla::layers::TextureInfo paramType;
|
||||
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mCompositableType);
|
||||
|
@ -827,6 +830,14 @@ struct ParamTraits<mozilla::gfx::SurfaceFormat>
|
|||
mozilla::gfx::SurfaceFormat::UNKNOWN>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::StereoMode>
|
||||
: public ContiguousEnumSerializer<
|
||||
mozilla::StereoMode,
|
||||
mozilla::StereoMode::MONO,
|
||||
mozilla::StereoMode::TOP_BOTTOM>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::layers::ScrollableLayerGuid>
|
||||
{
|
||||
|
@ -847,6 +858,7 @@ struct ParamTraits<mozilla::layers::ScrollableLayerGuid>
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::layers::ZoomConstraints>
|
||||
{
|
||||
|
|
|
@ -30,10 +30,10 @@ public:
|
|||
|
||||
virtual void Deallocate(ISurfaceAllocator*) override;
|
||||
|
||||
MemoryTextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
MemoryTextureData(const BufferDescriptor& aDesc,
|
||||
gfx::BackendType aMoz2DBackend,
|
||||
uint8_t* aBuffer, size_t aBufferSize)
|
||||
: BufferTextureData(aSize, aFormat, aMoz2DBackend)
|
||||
: BufferTextureData(aDesc, aMoz2DBackend)
|
||||
, mBuffer(aBuffer)
|
||||
, mBufferSize(aBufferSize)
|
||||
{
|
||||
|
@ -67,9 +67,9 @@ public:
|
|||
|
||||
virtual void Deallocate(ISurfaceAllocator* aAllocator) override;
|
||||
|
||||
ShmemTextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
ShmemTextureData(const BufferDescriptor& aDesc,
|
||||
gfx::BackendType aMoz2DBackend, mozilla::ipc::Shmem aShmem)
|
||||
: BufferTextureData(aSize, aFormat, aMoz2DBackend)
|
||||
: BufferTextureData(aDesc, aMoz2DBackend)
|
||||
, mShmem(aShmem)
|
||||
{
|
||||
MOZ_ASSERT(mShmem.Size<uint8_t>());
|
||||
|
@ -97,43 +97,46 @@ BufferTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
|||
}
|
||||
|
||||
BufferTextureData*
|
||||
BufferTextureData::CreateWithBufferSize(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
size_t aSize,
|
||||
TextureFlags aTextureFlags)
|
||||
BufferTextureData::CreateInternal(ISurfaceAllocator* aAllocator,
|
||||
const BufferDescriptor& aDesc,
|
||||
gfx::BackendType aMoz2DBackend,
|
||||
int32_t aBufferSize,
|
||||
TextureFlags aTextureFlags)
|
||||
{
|
||||
if (aSize == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BufferTextureData* data;
|
||||
if (!aAllocator || aAllocator->IsSameProcess()) {
|
||||
uint8_t* buffer = new (fallible) uint8_t[aSize];
|
||||
uint8_t* buffer = new (fallible) uint8_t[aBufferSize];
|
||||
if (!buffer) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
data = new MemoryTextureData(gfx::IntSize(), aFormat, gfx::BackendType::NONE, buffer, aSize);
|
||||
return new MemoryTextureData(aDesc, aMoz2DBackend, buffer, aBufferSize);
|
||||
} else {
|
||||
ipc::Shmem shm;
|
||||
if (!aAllocator->AllocUnsafeShmem(aSize, OptimalShmemType(), &shm)) {
|
||||
if (!aAllocator->AllocUnsafeShmem(aBufferSize, OptimalShmemType(), &shm)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
data = new ShmemTextureData(gfx::IntSize(), aFormat, gfx::BackendType::NONE, shm);
|
||||
return new ShmemTextureData(aDesc, aMoz2DBackend, shm);
|
||||
}
|
||||
}
|
||||
|
||||
BufferTextureData*
|
||||
BufferTextureData::CreateForYCbCrWithBufferSize(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
int32_t aBufferSize,
|
||||
TextureFlags aTextureFlags)
|
||||
{
|
||||
if (aBufferSize == 0 || !gfx::Factory::CheckBufferSize(aBufferSize)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Initialize the metadata with something, even if it will have to be rewritten
|
||||
// afterwards since we don't know the dimensions of the texture at this point.
|
||||
if (aFormat == gfx::SurfaceFormat::YUV) {
|
||||
YCbCrImageDataSerializer serializer(data->GetBuffer(), data->GetBufferSize());
|
||||
serializer.InitializeBufferInfo(gfx::IntSize(0,0), gfx::IntSize(0,0), StereoMode::MONO);
|
||||
} else {
|
||||
ImageDataSerializer serializer(data->GetBuffer(), data->GetBufferSize());
|
||||
serializer.InitializeBufferInfo(gfx::IntSize(0, 0), aFormat);
|
||||
}
|
||||
BufferDescriptor desc = YCbCrDescriptor(gfx::IntSize(), gfx::IntSize(),
|
||||
0, 0, 0, StereoMode::MONO);
|
||||
|
||||
return data;
|
||||
return CreateInternal(aAllocator, desc, gfx::BackendType::NONE, aBufferSize,
|
||||
aTextureFlags);
|
||||
}
|
||||
|
||||
BufferTextureData*
|
||||
|
@ -143,24 +146,41 @@ BufferTextureData::CreateForYCbCr(ISurfaceAllocator* aAllocator,
|
|||
StereoMode aStereoMode,
|
||||
TextureFlags aTextureFlags)
|
||||
{
|
||||
size_t bufSize = YCbCrImageDataSerializer::ComputeMinBufferSize(aYSize, aCbCrSize);
|
||||
BufferTextureData* texture = CreateWithBufferSize(aAllocator, gfx::SurfaceFormat::YUV,
|
||||
bufSize, aTextureFlags);
|
||||
if (!texture) {
|
||||
uint32_t bufSize = ImageDataSerializer::ComputeYCbCrBufferSize(aYSize, aCbCrSize);
|
||||
if (bufSize == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
YCbCrImageDataSerializer serializer(texture->GetBuffer(), texture->GetBufferSize());
|
||||
serializer.InitializeBufferInfo(aYSize, aCbCrSize, aStereoMode);
|
||||
texture->mSize = aYSize;
|
||||
uint32_t yOffset;
|
||||
uint32_t cbOffset;
|
||||
uint32_t crOffset;
|
||||
ImageDataSerializer::ComputeYCbCrOffsets(aYSize.width, aYSize.height,
|
||||
aCbCrSize.width, aCbCrSize.height,
|
||||
yOffset, cbOffset, crOffset);
|
||||
|
||||
return texture;
|
||||
YCbCrDescriptor descriptor = YCbCrDescriptor(aYSize, aCbCrSize, yOffset, cbOffset,
|
||||
crOffset, aStereoMode);
|
||||
|
||||
return CreateInternal(aAllocator, descriptor, gfx::BackendType::NONE, bufSize,
|
||||
aTextureFlags);
|
||||
}
|
||||
|
||||
gfx::IntSize
|
||||
BufferTextureData::GetSize() const
|
||||
{
|
||||
return ImageDataSerializer::SizeFromBufferDescriptor(mDescriptor);
|
||||
}
|
||||
|
||||
gfx::SurfaceFormat
|
||||
BufferTextureData::GetFormat() const
|
||||
{
|
||||
return ImageDataSerializer::FormatFromBufferDescriptor(mDescriptor);
|
||||
}
|
||||
|
||||
bool
|
||||
BufferTextureData::SupportsMoz2D() const
|
||||
{
|
||||
switch (mFormat) {
|
||||
switch (GetFormat()) {
|
||||
case gfx::SurfaceFormat::YUV:
|
||||
case gfx::SurfaceFormat::NV12:
|
||||
case gfx::SurfaceFormat::UNKNOWN:
|
||||
|
@ -179,12 +199,17 @@ BufferTextureData::BorrowDrawTarget()
|
|||
return dt.forget();
|
||||
}
|
||||
|
||||
ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
|
||||
if (!serializer.IsValid()) {
|
||||
if (mDescriptor.type() != BufferDescriptor::TRGBDescriptor) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mDrawTarget = serializer.GetAsDrawTarget(mMoz2DBackend);
|
||||
const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor();
|
||||
|
||||
uint32_t stride = ImageDataSerializer::GetRGBStride(rgb);
|
||||
mDrawTarget = gfx::Factory::CreateDrawTargetForData(mMoz2DBackend,
|
||||
GetBuffer(), rgb.size(),
|
||||
stride, rgb.format());
|
||||
|
||||
if (mDrawTarget) {
|
||||
RefPtr<gfx::DrawTarget> dt = mDrawTarget;
|
||||
return dt.forget();
|
||||
|
@ -192,7 +217,12 @@ BufferTextureData::BorrowDrawTarget()
|
|||
|
||||
// TODO - should we warn? should we really fallback to cairo? perhaps
|
||||
// at least update mMoz2DBackend...
|
||||
mDrawTarget = serializer.GetAsDrawTarget(gfx::BackendType::CAIRO);
|
||||
if (mMoz2DBackend != gfx::BackendType::CAIRO) {
|
||||
mDrawTarget = gfx::Factory::CreateDrawTargetForData(gfx::BackendType::CAIRO,
|
||||
GetBuffer(), rgb.size(),
|
||||
stride, rgb.format());
|
||||
}
|
||||
|
||||
if (!mDrawTarget) {
|
||||
gfxCriticalNote << "BorrowDrawTarget failure, original backend " << (int)mMoz2DBackend;
|
||||
}
|
||||
|
@ -204,19 +234,16 @@ BufferTextureData::BorrowDrawTarget()
|
|||
bool
|
||||
BufferTextureData::BorrowMappedData(MappedTextureData& aData)
|
||||
{
|
||||
if (mFormat == gfx::SurfaceFormat::YUV) {
|
||||
if (GetFormat() == gfx::SurfaceFormat::YUV) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ImageDataDeserializer view(GetBuffer(), GetBufferSize());
|
||||
if (!view.IsValid()) {
|
||||
return false;
|
||||
}
|
||||
gfx::IntSize size = GetSize();
|
||||
|
||||
aData.data = view.GetData();
|
||||
aData.size = view.GetSize();
|
||||
aData.stride = view.GetStride();
|
||||
aData.format = mFormat;
|
||||
aData.data = GetBuffer();
|
||||
aData.size = size;
|
||||
aData.format = GetFormat();
|
||||
aData.stride = ImageDataSerializer::ComputeRGBStride(aData.format, size.width);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -224,31 +251,32 @@ BufferTextureData::BorrowMappedData(MappedTextureData& aData)
|
|||
bool
|
||||
BufferTextureData::BorrowMappedYCbCrData(MappedYCbCrTextureData& aMap)
|
||||
{
|
||||
if (mFormat != gfx::SurfaceFormat::YUV) {
|
||||
if (mDescriptor.type() != BufferDescriptor::TYCbCrDescriptor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
YCbCrImageDataDeserializer view(GetBuffer(), GetBufferSize());
|
||||
if (!view.IsValid()) {
|
||||
return false;
|
||||
}
|
||||
const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
|
||||
|
||||
aMap.stereoMode = view.GetStereoMode();
|
||||
aMap.metadata = GetBuffer();
|
||||
uint8_t* data = GetBuffer();
|
||||
auto ySize = desc.ySize();
|
||||
auto cbCrSize = desc.cbCrSize();
|
||||
|
||||
aMap.y.data = view.GetYData();
|
||||
aMap.y.size = view.GetYSize();
|
||||
aMap.y.stride = view.GetYStride();
|
||||
aMap.stereoMode = desc.stereoMode();
|
||||
aMap.metadata = nullptr;
|
||||
|
||||
aMap.y.data = data + desc.yOffset();
|
||||
aMap.y.size = ySize;
|
||||
aMap.y.stride = ySize.width;
|
||||
aMap.y.skip = 0;
|
||||
|
||||
aMap.cb.data = view.GetCbData();
|
||||
aMap.cb.size = view.GetCbCrSize();
|
||||
aMap.cb.stride = view.GetCbCrStride();
|
||||
aMap.cb.data = data + desc.cbOffset();
|
||||
aMap.cb.size = cbCrSize;
|
||||
aMap.cb.stride = cbCrSize.width;
|
||||
aMap.cb.skip = 0;
|
||||
|
||||
aMap.cr.data = view.GetCrData();
|
||||
aMap.cr.size = view.GetCbCrSize();
|
||||
aMap.cr.stride = view.GetCbCrStride();
|
||||
aMap.cr.data = data + desc.crOffset();
|
||||
aMap.cr.size = cbCrSize;
|
||||
aMap.cr.stride = cbCrSize.width;
|
||||
aMap.cr.skip = 0;
|
||||
|
||||
return true;
|
||||
|
@ -257,9 +285,15 @@ BufferTextureData::BorrowMappedYCbCrData(MappedYCbCrTextureData& aMap)
|
|||
bool
|
||||
BufferTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
|
||||
{
|
||||
ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
|
||||
if (mDescriptor.type() != BufferDescriptor::TRGBDescriptor) {
|
||||
return false;
|
||||
}
|
||||
const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor();
|
||||
|
||||
RefPtr<gfx::DataSourceSurface> surface = serializer.GetAsSurface();
|
||||
uint32_t stride = ImageDataSerializer::GetRGBStride(rgb);
|
||||
RefPtr<gfx::DataSourceSurface> surface =
|
||||
gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(), stride,
|
||||
rgb.size(), rgb.format());
|
||||
|
||||
if (!surface) {
|
||||
gfxCriticalError() << "Failed to get serializer as surface!";
|
||||
|
@ -304,6 +338,14 @@ BufferTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
BufferTextureData::SetDesciptor(const BufferDescriptor& aDescriptor)
|
||||
{
|
||||
MOZ_ASSERT(mDescriptor.type() == BufferDescriptor::TYCbCrDescriptor);
|
||||
MOZ_ASSERT(mDescriptor.get_YCbCrDescriptor().ySize() == gfx::IntSize());
|
||||
mDescriptor = aDescriptor;
|
||||
}
|
||||
|
||||
bool
|
||||
MemoryTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
|
@ -312,14 +354,13 @@ MemoryTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
|||
return false;
|
||||
}
|
||||
|
||||
aOutDescriptor = SurfaceDescriptorMemory(reinterpret_cast<uintptr_t>(mBuffer),
|
||||
GetFormat());
|
||||
uintptr_t ptr = reinterpret_cast<uintptr_t>(mBuffer);
|
||||
aOutDescriptor = SurfaceDescriptorBuffer(mDescriptor, MemoryOrShmem(ptr));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool InitBuffer(uint8_t* buf, size_t bufSize,
|
||||
gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
TextureAllocationFlags aAllocFlags)
|
||||
static bool InitBuffer(uint8_t* buf, size_t bufSize, TextureAllocationFlags aAllocFlags)
|
||||
{
|
||||
if (!buf) {
|
||||
gfxDebug() << "BufferTextureData: Failed to allocate " << bufSize << " bytes";
|
||||
|
@ -333,8 +374,6 @@ static bool InitBuffer(uint8_t* buf, size_t bufSize,
|
|||
memset(buf, 0xFF, bufSize);
|
||||
}
|
||||
|
||||
ImageDataSerializer serializer(buf, bufSize);
|
||||
serializer.InitializeBufferInfo(aSize, aFormat);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -344,24 +383,29 @@ MemoryTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
|||
TextureAllocationFlags aAllocFlags,
|
||||
ISurfaceAllocator*)
|
||||
{
|
||||
// Should have used CreateForYCbCr.
|
||||
MOZ_ASSERT(aFormat != gfx::SurfaceFormat::YUV);
|
||||
|
||||
if (aSize.width <= 0 || aSize.height <= 0) {
|
||||
gfxDebug() << "Asking for buffer of invalid size " << aSize.width << "x" << aSize.height;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t bufSize = ImageDataSerializer::ComputeMinBufferSize(aSize, aFormat);
|
||||
uint32_t bufSize = ImageDataSerializer::ComputeRGBBufferSize(aSize, aFormat);
|
||||
if (!bufSize) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint8_t* buf = new (fallible) uint8_t[bufSize];
|
||||
|
||||
if (InitBuffer(buf, bufSize, aSize, aFormat, aAllocFlags)) {
|
||||
GfxMemoryImageReporter::DidAlloc(buf);
|
||||
return new MemoryTextureData(aSize, aFormat, aMoz2DBackend, buf, bufSize);
|
||||
if (!InitBuffer(buf, bufSize, aAllocFlags)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
GfxMemoryImageReporter::DidAlloc(buf);
|
||||
|
||||
BufferDescriptor descriptor = RGBDescriptor(aSize, aFormat);
|
||||
|
||||
return new MemoryTextureData(descriptor, aMoz2DBackend, buf, bufSize);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -378,7 +422,7 @@ MemoryTextureData::CreateSimilar(ISurfaceAllocator* aAllocator,
|
|||
TextureFlags aFlags,
|
||||
TextureAllocationFlags aAllocFlags) const
|
||||
{
|
||||
return MemoryTextureData::Create(mSize, mFormat, mMoz2DBackend,
|
||||
return MemoryTextureData::Create(GetSize(), GetFormat(), mMoz2DBackend,
|
||||
aFlags, aAllocFlags, aAllocator);
|
||||
}
|
||||
|
||||
|
@ -390,7 +434,7 @@ ShmemTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
|||
return false;
|
||||
}
|
||||
|
||||
aOutDescriptor = SurfaceDescriptorShmem(mShmem, GetFormat());
|
||||
aOutDescriptor = SurfaceDescriptorBuffer(mDescriptor, MemoryOrShmem(mShmem));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -402,6 +446,9 @@ ShmemTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
|||
ISurfaceAllocator* aAllocator)
|
||||
{
|
||||
MOZ_ASSERT(aAllocator);
|
||||
// Should have used CreateForYCbCr.
|
||||
MOZ_ASSERT(aFormat != gfx::SurfaceFormat::YUV);
|
||||
|
||||
if (!aAllocator) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -411,7 +458,7 @@ ShmemTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t bufSize = ImageDataSerializer::ComputeMinBufferSize(aSize, aFormat);
|
||||
uint32_t bufSize = ImageDataSerializer::ComputeRGBBufferSize(aSize, aFormat);
|
||||
if (!bufSize) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -422,11 +469,14 @@ ShmemTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
|||
}
|
||||
|
||||
uint8_t* buf = shm.get<uint8_t>();
|
||||
|
||||
if (InitBuffer(buf, bufSize, aSize, aFormat, aAllocFlags)) {
|
||||
return new ShmemTextureData(aSize, aFormat, aMoz2DBackend, shm);
|
||||
if (!InitBuffer(buf, bufSize, aAllocFlags)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BufferDescriptor descriptor = RGBDescriptor(aSize, aFormat);
|
||||
|
||||
return new ShmemTextureData(descriptor, aMoz2DBackend, shm);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -435,7 +485,7 @@ ShmemTextureData::CreateSimilar(ISurfaceAllocator* aAllocator,
|
|||
TextureFlags aFlags,
|
||||
TextureAllocationFlags aAllocFlags) const
|
||||
{
|
||||
return ShmemTextureData::Create(mSize, mFormat, mMoz2DBackend,
|
||||
return ShmemTextureData::Create(GetSize(), GetFormat(), mMoz2DBackend,
|
||||
aFlags, aAllocFlags, aAllocator);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
#ifndef MOZILLA_LAYERS_BUFFERETEXTURE
|
||||
#define MOZILLA_LAYERS_BUFFERETEXTURE
|
||||
|
||||
#include "mozilla/layers/ImageDataSerializer.h"
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "mozilla/gfx/Types.h"
|
||||
|
@ -25,24 +23,27 @@ public:
|
|||
TextureAllocationFlags aAllocFlags,
|
||||
ISurfaceAllocator* aAllocator);
|
||||
|
||||
static BufferTextureData* CreateWithBufferSize(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
size_t aSize,
|
||||
TextureFlags aTextureFlags);
|
||||
|
||||
static BufferTextureData* CreateForYCbCr(ISurfaceAllocator* aAllocator,
|
||||
gfx::IntSize aYSize,
|
||||
gfx::IntSize aCbCrSize,
|
||||
StereoMode aStereoMode,
|
||||
TextureFlags aTextureFlags);
|
||||
|
||||
// It is generally better to use CreateForYCbCr instead.
|
||||
// This creates a half-initialized texture since we don't know the sizes and
|
||||
// offsets in the buffer.
|
||||
static BufferTextureData* CreateForYCbCrWithBufferSize(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
int32_t aSize,
|
||||
TextureFlags aTextureFlags);
|
||||
|
||||
virtual bool Lock(OpenMode aMode, FenceHandle*) override { return true; }
|
||||
|
||||
virtual void Unlock() override {}
|
||||
|
||||
virtual gfx::IntSize GetSize() const override { return mSize; }
|
||||
virtual gfx::IntSize GetSize() const override;
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
|
||||
virtual gfx::SurfaceFormat GetFormat() const override;
|
||||
|
||||
virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override;
|
||||
|
||||
|
@ -59,19 +60,26 @@ public:
|
|||
// use TextureClient's default implementation
|
||||
virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) override;
|
||||
|
||||
// Don't use this.
|
||||
void SetDesciptor(const BufferDescriptor& aDesc);
|
||||
|
||||
protected:
|
||||
static BufferTextureData* CreateInternal(ISurfaceAllocator* aAllocator,
|
||||
const BufferDescriptor& aDesc,
|
||||
gfx::BackendType aMoz2DBackend,
|
||||
int32_t aBufferSize,
|
||||
TextureFlags aTextureFlags);
|
||||
|
||||
virtual uint8_t* GetBuffer() = 0;
|
||||
virtual size_t GetBufferSize() = 0;
|
||||
|
||||
BufferTextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, gfx::BackendType aMoz2DBackend)
|
||||
: mSize(aSize)
|
||||
, mFormat(aFormat)
|
||||
BufferTextureData(const BufferDescriptor& aDescriptor, gfx::BackendType aMoz2DBackend)
|
||||
: mDescriptor(aDescriptor)
|
||||
, mMoz2DBackend(aMoz2DBackend)
|
||||
{}
|
||||
|
||||
RefPtr<gfx::DrawTarget> mDrawTarget;
|
||||
gfx::IntSize mSize;
|
||||
gfx::SurfaceFormat mFormat;
|
||||
BufferDescriptor mDescriptor;
|
||||
gfx::BackendType mMoz2DBackend;
|
||||
};
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ public:
|
|||
, mAllowVerticalScrollWithWheel(false)
|
||||
, mIsLayersIdRoot(false)
|
||||
, mUsesContainerScrolling(false)
|
||||
, mIsScrollInfoLayer(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -104,7 +105,8 @@ public:
|
|||
mClipRect == aOther.mClipRect &&
|
||||
mMaskLayerIndex == aOther.mMaskLayerIndex &&
|
||||
mIsLayersIdRoot == aOther.mIsLayersIdRoot &&
|
||||
mUsesContainerScrolling == aOther.mUsesContainerScrolling;
|
||||
mUsesContainerScrolling == aOther.mUsesContainerScrolling &&
|
||||
mIsScrollInfoLayer == aOther.mIsScrollInfoLayer;
|
||||
}
|
||||
bool operator!=(const FrameMetrics& aOther) const
|
||||
{
|
||||
|
@ -545,6 +547,13 @@ public:
|
|||
return mUsesContainerScrolling;
|
||||
}
|
||||
|
||||
void SetIsScrollInfoLayer(bool aIsScrollInfoLayer) {
|
||||
mIsScrollInfoLayer = aIsScrollInfoLayer;
|
||||
}
|
||||
bool IsScrollInfoLayer() const {
|
||||
return mIsScrollInfoLayer;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// The pres-shell resolution that has been induced on the document containing
|
||||
|
@ -732,6 +741,9 @@ private:
|
|||
// when containerful scrolling is eliminated.
|
||||
bool mUsesContainerScrolling;
|
||||
|
||||
// Whether or not this frame has a "scroll info layer" to capture events.
|
||||
bool mIsScrollInfoLayer;
|
||||
|
||||
// WARNING!!!!
|
||||
//
|
||||
// When adding new fields to FrameMetrics, the following places should be
|
||||
|
|
|
@ -4,70 +4,27 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ImageDataSerializer.h"
|
||||
#include <string.h> // for memcpy
|
||||
#include "gfx2DGlue.h" // for SurfaceFormatToImageFormat
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory
|
||||
#include "mozilla/gfx/Logging.h" // for gfxDebug
|
||||
#include "mozilla/gfx/Tools.h" // for GetAlignedStride, etc
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "mozilla/mozalloc.h" // for operator delete, etc
|
||||
#include "yuv_convert.h" // for ConvertYCbCrToRGB32, etc
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
namespace ImageDataSerializer {
|
||||
|
||||
using namespace gfx;
|
||||
|
||||
// The Data is layed out as follows:
|
||||
//
|
||||
// +-------------------+ -++ --+ <-- ImageDataSerializerBase::mData pointer
|
||||
// | SurfaceBufferInfo | | |
|
||||
// +-------------------+ --+ | offset
|
||||
// | ... | |
|
||||
// +-------------------+ ------+
|
||||
// | |
|
||||
// | data |
|
||||
// | |
|
||||
// +-------------------+
|
||||
#define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
|
||||
|
||||
// Structure written at the beginning of the data blob containing the image
|
||||
// (as shown in the figure above). It contains the necessary informations to
|
||||
// read the image in the blob.
|
||||
namespace {
|
||||
struct SurfaceBufferInfo
|
||||
{
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
SurfaceFormat format;
|
||||
|
||||
static int32_t GetOffset()
|
||||
{
|
||||
return GetAlignedStride<16>(sizeof(SurfaceBufferInfo));
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
static SurfaceBufferInfo*
|
||||
GetBufferInfo(uint8_t* aData, size_t aDataSize)
|
||||
{
|
||||
return aDataSize >= sizeof(SurfaceBufferInfo)
|
||||
? reinterpret_cast<SurfaceBufferInfo*>(aData)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ImageDataSerializer::InitializeBufferInfo(IntSize aSize,
|
||||
SurfaceFormat aFormat)
|
||||
{
|
||||
SurfaceBufferInfo* info = GetBufferInfo(mData, mDataSize);
|
||||
MOZ_ASSERT(info); // OK to assert here, this method is client-side-only
|
||||
info->width = aSize.width;
|
||||
info->height = aSize.height;
|
||||
info->format = aFormat;
|
||||
Validate();
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
ComputeStride(SurfaceFormat aFormat, int32_t aWidth)
|
||||
int32_t
|
||||
ComputeRGBStride(SurfaceFormat aFormat, int32_t aWidth)
|
||||
{
|
||||
CheckedInt<int32_t> size = BytesPerPixel(aFormat);
|
||||
size *= aWidth;
|
||||
|
@ -79,9 +36,14 @@ ComputeStride(SurfaceFormat aFormat, int32_t aWidth)
|
|||
return GetAlignedStride<4>(size.value());
|
||||
}
|
||||
|
||||
int32_t
|
||||
GetRGBStride(const RGBDescriptor& aDescriptor)
|
||||
{
|
||||
return ComputeRGBStride(aDescriptor.format(), aDescriptor.size().width);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ImageDataSerializerBase::ComputeMinBufferSize(IntSize aSize,
|
||||
SurfaceFormat aFormat)
|
||||
ComputeRGBBufferSize(IntSize aSize, SurfaceFormat aFormat)
|
||||
{
|
||||
MOZ_ASSERT(aSize.height >= 0 && aSize.width >= 0);
|
||||
|
||||
|
@ -91,9 +53,8 @@ ImageDataSerializerBase::ComputeMinBufferSize(IntSize aSize,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int32_t bufsize = GetAlignedStride<16>(ComputeStride(aFormat, aSize.width)
|
||||
* aSize.height)
|
||||
+ SurfaceBufferInfo::GetOffset();
|
||||
int32_t bufsize = GetAlignedStride<16>(ComputeRGBStride(aFormat, aSize.width)
|
||||
* aSize.height);
|
||||
|
||||
if (bufsize < 0) {
|
||||
// This should not be possible thanks to Factory::AllowedSurfaceSize
|
||||
|
@ -103,75 +64,121 @@ ImageDataSerializerBase::ComputeMinBufferSize(IntSize aSize,
|
|||
return bufsize;
|
||||
}
|
||||
|
||||
void
|
||||
ImageDataSerializerBase::Validate()
|
||||
{
|
||||
mIsValid = false;
|
||||
if (!mData) {
|
||||
return;
|
||||
}
|
||||
SurfaceBufferInfo* info = GetBufferInfo(mData, mDataSize);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
size_t requiredSize =
|
||||
ComputeMinBufferSize(IntSize(info->width, info->height), info->format);
|
||||
|
||||
mIsValid = !!requiredSize && requiredSize <= mDataSize;
|
||||
|
||||
// Minimum required shmem size in bytes
|
||||
uint32_t
|
||||
ComputeYCbCrBufferSize(const gfx::IntSize& aYSize, int32_t aYStride,
|
||||
const gfx::IntSize& aCbCrSize, int32_t aCbCrStride)
|
||||
{
|
||||
MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0);
|
||||
|
||||
if (aYSize.height < 0 || aYSize.width < 0 || aCbCrSize.height < 0 || aCbCrSize.width < 0 ||
|
||||
aYSize.width > aYStride || aCbCrSize.width > aCbCrStride ||
|
||||
aCbCrStride > aYStride || aCbCrSize.height > aYSize.height ||
|
||||
!gfx::Factory::AllowedSurfaceSize(IntSize(aYStride, aYSize.height))) {
|
||||
return 0;
|
||||
}
|
||||
// Overflow checks are performed in AllowedSurfaceSize
|
||||
return MOZ_ALIGN_WORD(aYSize.height * aYStride)
|
||||
+ 2 * MOZ_ALIGN_WORD(aCbCrSize.height * aCbCrStride);
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
ImageDataSerializerBase::GetData()
|
||||
// Minimum required shmem size in bytes
|
||||
uint32_t
|
||||
ComputeYCbCrBufferSize(const gfx::IntSize& aYSize, const gfx::IntSize& aCbCrSize)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
return mData + SurfaceBufferInfo::GetOffset();
|
||||
return ComputeYCbCrBufferSize(aYSize, aYSize.width, aCbCrSize, aCbCrSize.width);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ImageDataSerializerBase::GetStride() const
|
||||
ComputeYCbCrBufferSize(uint32_t aBufferSize)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
SurfaceBufferInfo* info = GetBufferInfo(mData, mDataSize);
|
||||
return ComputeStride(GetFormat(), info->width);
|
||||
return MOZ_ALIGN_WORD(aBufferSize);
|
||||
}
|
||||
|
||||
IntSize
|
||||
ImageDataSerializerBase::GetSize() const
|
||||
void ComputeYCbCrOffsets(int32_t yStride, int32_t yHeight,
|
||||
int32_t cbCrStride, int32_t cbCrHeight,
|
||||
uint32_t& outYOffset, uint32_t& outCbOffset, uint32_t& outCrOffset)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
SurfaceBufferInfo* info = GetBufferInfo(mData, mDataSize);
|
||||
return IntSize(info->width, info->height);
|
||||
outYOffset = 0;
|
||||
outCbOffset = outYOffset + MOZ_ALIGN_WORD(yStride * yHeight);
|
||||
outCrOffset = outCbOffset + MOZ_ALIGN_WORD(cbCrStride * cbCrHeight);
|
||||
}
|
||||
|
||||
SurfaceFormat
|
||||
ImageDataSerializerBase::GetFormat() const
|
||||
gfx::SurfaceFormat FormatFromBufferDescriptor(const BufferDescriptor& aDescriptor)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
return GetBufferInfo(mData, mDataSize)->format;
|
||||
}
|
||||
|
||||
already_AddRefed<DrawTarget>
|
||||
ImageDataSerializerBase::GetAsDrawTarget(gfx::BackendType aBackend)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
RefPtr<DrawTarget> dt = gfx::Factory::CreateDrawTargetForData(aBackend,
|
||||
GetData(), GetSize(),
|
||||
GetStride(), GetFormat());
|
||||
if (!dt) {
|
||||
gfxCriticalNote << "Failed GetAsDrawTarget " << IsValid() << ", " << hexa(size_t(mData)) << " + " << SurfaceBufferInfo::GetOffset() << ", " << GetSize() << ", " << GetStride() << ", " << (int)GetFormat();
|
||||
switch (aDescriptor.type()) {
|
||||
case BufferDescriptor::TRGBDescriptor:
|
||||
return aDescriptor.get_RGBDescriptor().format();
|
||||
case BufferDescriptor::TYCbCrDescriptor:
|
||||
return gfx::SurfaceFormat::YUV;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
return dt.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::DataSourceSurface>
|
||||
ImageDataSerializerBase::GetAsSurface()
|
||||
gfx::IntSize SizeFromBufferDescriptor(const BufferDescriptor& aDescriptor)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
return Factory::CreateWrappingDataSourceSurface(GetData(),
|
||||
GetStride(),
|
||||
GetSize(),
|
||||
GetFormat());
|
||||
switch (aDescriptor.type()) {
|
||||
case BufferDescriptor::TRGBDescriptor:
|
||||
return aDescriptor.get_RGBDescriptor().size();
|
||||
case BufferDescriptor::TYCbCrDescriptor:
|
||||
return aDescriptor.get_YCbCrDescriptor().ySize();
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* GetYChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
|
||||
{
|
||||
return aBuffer + aDescriptor.yOffset();
|
||||
}
|
||||
|
||||
uint8_t* GetCbChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
|
||||
{
|
||||
return aBuffer + aDescriptor.cbOffset();
|
||||
}
|
||||
|
||||
uint8_t* GetCrChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
|
||||
{
|
||||
return aBuffer + aDescriptor.crOffset();
|
||||
}
|
||||
|
||||
already_AddRefed<DataSourceSurface>
|
||||
DataSourceSurfaceFromYCbCrDescriptor(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
|
||||
{
|
||||
gfx::IntSize ySize = aDescriptor.ySize();
|
||||
gfx::IntSize cbCrSize = aDescriptor.cbCrSize();
|
||||
int32_t yStride = ySize.width;
|
||||
int32_t cbCrStride = cbCrSize.width;
|
||||
|
||||
RefPtr<DataSourceSurface> result =
|
||||
Factory::CreateDataSourceSurface(ySize, gfx::SurfaceFormat::B8G8R8X8);
|
||||
if (NS_WARN_IF(!result)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DataSourceSurface::MappedSurface map;
|
||||
if (NS_WARN_IF(!result->Map(DataSourceSurface::MapType::WRITE, &map))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gfx::YUVType type = TypeFromSize(ySize.width, ySize.height,
|
||||
cbCrSize.width, cbCrSize.height);
|
||||
gfx::ConvertYCbCrToRGB32(GetYChannel(aBuffer, aDescriptor),
|
||||
GetCbChannel(aBuffer, aDescriptor),
|
||||
GetCrChannel(aBuffer, aDescriptor),
|
||||
map.mData,
|
||||
0, 0, //pic x and y
|
||||
ySize.width, ySize.height,
|
||||
yStride, cbCrStride,
|
||||
map.mStride, type);
|
||||
result->Unmap();
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
|
||||
} // namespace ImageDataSerializer
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -24,72 +24,49 @@ class DrawTarget;
|
|||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ImageDataSerializerBase
|
||||
{
|
||||
public:
|
||||
bool IsValid() const { return mIsValid; }
|
||||
namespace ImageDataSerializer {
|
||||
|
||||
uint8_t* GetData();
|
||||
uint32_t GetStride() const;
|
||||
gfx::IntSize GetSize() const;
|
||||
gfx::SurfaceFormat GetFormat() const;
|
||||
already_AddRefed<gfx::DataSourceSurface> GetAsSurface();
|
||||
already_AddRefed<gfx::DrawTarget> GetAsDrawTarget(gfx::BackendType aBackend);
|
||||
// RGB
|
||||
|
||||
static uint32_t ComputeMinBufferSize(gfx::IntSize aSize,
|
||||
gfx::SurfaceFormat aFormat);
|
||||
int32_t ComputeRGBStride(gfx::SurfaceFormat aFormat, int32_t aWidth);
|
||||
|
||||
size_t GetBufferSize() const { return mDataSize; }
|
||||
int32_t GetRGBStride(const RGBDescriptor& aDescriptor);
|
||||
|
||||
protected:
|
||||
uint32_t ComputeRGBBufferSize(gfx::IntSize aSize, gfx::SurfaceFormat aFormat);
|
||||
|
||||
ImageDataSerializerBase(uint8_t* aData, size_t aDataSize)
|
||||
: mData(aData)
|
||||
, mDataSize(aDataSize)
|
||||
, mIsValid(false)
|
||||
{}
|
||||
|
||||
void Validate();
|
||||
// YCbCr
|
||||
|
||||
uint8_t* mData;
|
||||
size_t mDataSize;
|
||||
bool mIsValid;
|
||||
};
|
||||
///This function is meant as a helper to know how much shared memory we need
|
||||
///to allocate in a shmem in order to place a shared YCbCr image blob of
|
||||
///given dimensions.
|
||||
uint32_t ComputeYCbCrBufferSize(const gfx::IntSize& aYSize,
|
||||
int32_t aYStride,
|
||||
const gfx::IntSize& aCbCrSize,
|
||||
int32_t aCbCrStride);
|
||||
uint32_t ComputeYCbCrBufferSize(const gfx::IntSize& aYSize,
|
||||
const gfx::IntSize& aCbCrSize);
|
||||
|
||||
/**
|
||||
* A facility to serialize an image into a buffer of memory.
|
||||
* This is intended for use with the IPC code, in order to copy image data
|
||||
* into shared memory.
|
||||
* Note that there is a separate serializer class for YCbCr images
|
||||
* (see YCbCrImageDataSerializer.h).
|
||||
*/
|
||||
class MOZ_STACK_CLASS ImageDataSerializer : public ImageDataSerializerBase
|
||||
{
|
||||
public:
|
||||
ImageDataSerializer(uint8_t* aData, size_t aDataSize)
|
||||
: ImageDataSerializerBase(aData, aDataSize)
|
||||
{
|
||||
// a serializer needs to be usable before correct buffer info has been written to it
|
||||
mIsValid = !!mData;
|
||||
}
|
||||
void InitializeBufferInfo(gfx::IntSize aSize,
|
||||
gfx::SurfaceFormat aFormat);
|
||||
};
|
||||
uint32_t ComputeYCbCrBufferSize(uint32_t aBufferSize);
|
||||
|
||||
/**
|
||||
* A facility to deserialize image data that has been serialized by an
|
||||
* ImageDataSerializer.
|
||||
*/
|
||||
class MOZ_STACK_CLASS ImageDataDeserializer : public ImageDataSerializerBase
|
||||
{
|
||||
public:
|
||||
ImageDataDeserializer(uint8_t* aData, size_t aDataSize)
|
||||
: ImageDataSerializerBase(aData, aDataSize)
|
||||
{
|
||||
Validate();
|
||||
}
|
||||
void ComputeYCbCrOffsets(int32_t yStride, int32_t yHeight,
|
||||
int32_t cbCrStride, int32_t cbCrHeight,
|
||||
uint32_t& outYOffset, uint32_t& outCbOffset, uint32_t& outCrOffset);
|
||||
|
||||
};
|
||||
gfx::SurfaceFormat FormatFromBufferDescriptor(const BufferDescriptor& aDescriptor);
|
||||
|
||||
gfx::IntSize SizeFromBufferDescriptor(const BufferDescriptor& aDescriptor);
|
||||
|
||||
uint8_t* GetYChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor);
|
||||
|
||||
uint8_t* GetCbChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor);
|
||||
|
||||
uint8_t* GetCrChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor);
|
||||
|
||||
already_AddRefed<gfx::DataSourceSurface>
|
||||
DataSourceSurfaceFromYCbCrDescriptor(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor);
|
||||
|
||||
} // ImageDataSerializer
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -1,317 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include <string.h> // for memcpy
|
||||
#include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory
|
||||
#include "mozilla/gfx/BaseSize.h" // for BaseSize
|
||||
#include "mozilla/gfx/Logging.h" // for gfxDebug
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "nsDebug.h" // for NS_WARN_IF
|
||||
#include "yuv_convert.h" // for ConvertYCbCrToRGB32, etc
|
||||
#include "nsDebug.h"
|
||||
|
||||
#define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace gfx;
|
||||
|
||||
namespace layers {
|
||||
|
||||
// The Data is layed out as follows:
|
||||
//
|
||||
// +-----------------+ -++ --+ --+ <-- Beginning of the buffer
|
||||
// | YCbCrBufferInfo | | | |
|
||||
// +-----------------+ --+ | |
|
||||
// | data | | | YCbCrBufferInfo->[mY/mCb/mCr]Offset
|
||||
// +-----------------+ ------+ |
|
||||
// | data | |
|
||||
// +-----------------+ ----------+
|
||||
// | data |
|
||||
// +-----------------+
|
||||
//
|
||||
// There can be padding between the blocks above to keep word alignment.
|
||||
|
||||
// Structure written at the beginning og the data blob containing the image
|
||||
// (as shown in the figure above). It contains the necessary informations to
|
||||
// read the image in the blob.
|
||||
struct YCbCrBufferInfo
|
||||
{
|
||||
uint32_t mYOffset;
|
||||
uint32_t mCbOffset;
|
||||
uint32_t mCrOffset;
|
||||
uint32_t mYStride;
|
||||
uint32_t mYWidth;
|
||||
uint32_t mYHeight;
|
||||
uint32_t mCbCrStride;
|
||||
uint32_t mCbCrWidth;
|
||||
uint32_t mCbCrHeight;
|
||||
StereoMode mStereoMode;
|
||||
};
|
||||
|
||||
static YCbCrBufferInfo* GetYCbCrBufferInfo(uint8_t* aData, size_t aDataSize)
|
||||
{
|
||||
return aDataSize >= sizeof(YCbCrBufferInfo)
|
||||
? reinterpret_cast<YCbCrBufferInfo*>(aData)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
void YCbCrImageDataDeserializerBase::Validate()
|
||||
{
|
||||
mIsValid = false;
|
||||
if (!mData) {
|
||||
return;
|
||||
}
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
size_t requiredSize = ComputeMinBufferSize(
|
||||
IntSize(info->mYWidth, info->mYHeight),
|
||||
info->mYStride,
|
||||
IntSize(info->mCbCrWidth, info->mCbCrHeight),
|
||||
info->mCbCrStride);
|
||||
mIsValid = requiredSize <= mDataSize;
|
||||
|
||||
}
|
||||
|
||||
uint8_t* YCbCrImageDataDeserializerBase::GetYData()
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
|
||||
return reinterpret_cast<uint8_t*>(info) + info->mYOffset;
|
||||
}
|
||||
|
||||
uint8_t* YCbCrImageDataDeserializerBase::GetCbData()
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
|
||||
return reinterpret_cast<uint8_t*>(info) + info->mCbOffset;
|
||||
}
|
||||
|
||||
uint8_t* YCbCrImageDataDeserializerBase::GetCrData()
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
|
||||
return reinterpret_cast<uint8_t*>(info) + info->mCrOffset;
|
||||
}
|
||||
|
||||
uint8_t* YCbCrImageDataDeserializerBase::GetData()
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
|
||||
return (reinterpret_cast<uint8_t*>(info)) + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
|
||||
}
|
||||
|
||||
uint32_t YCbCrImageDataDeserializerBase::GetYStride()
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
|
||||
return info->mYStride;
|
||||
}
|
||||
|
||||
uint32_t YCbCrImageDataDeserializerBase::GetCbCrStride()
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
|
||||
return info->mCbCrStride;
|
||||
}
|
||||
|
||||
gfx::IntSize YCbCrImageDataDeserializerBase::GetYSize()
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
|
||||
return gfx::IntSize(info->mYWidth, info->mYHeight);
|
||||
}
|
||||
|
||||
gfx::IntSize YCbCrImageDataDeserializerBase::GetCbCrSize()
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
|
||||
return gfx::IntSize(info->mCbCrWidth, info->mCbCrHeight);
|
||||
}
|
||||
|
||||
StereoMode YCbCrImageDataDeserializerBase::GetStereoMode()
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
|
||||
return info->mStereoMode;
|
||||
}
|
||||
|
||||
// Offset in bytes
|
||||
static size_t ComputeOffset(uint32_t aHeight, uint32_t aStride)
|
||||
{
|
||||
return MOZ_ALIGN_WORD(aHeight * aStride);
|
||||
}
|
||||
|
||||
// Minimum required shmem size in bytes
|
||||
size_t
|
||||
YCbCrImageDataDeserializerBase::ComputeMinBufferSize(const gfx::IntSize& aYSize,
|
||||
uint32_t aYStride,
|
||||
const gfx::IntSize& aCbCrSize,
|
||||
uint32_t aCbCrStride)
|
||||
{
|
||||
MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0);
|
||||
if (aYSize.height < 0 || aYSize.width < 0 || aCbCrSize.height < 0 || aCbCrSize.width < 0) {
|
||||
gfxDebug() << "Non-positive YCbCr buffer size request " << aYSize.height << "x" << aYSize.width << ", " << aCbCrSize.height << "x" << aCbCrSize.width;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (aYSize != IntSize() &&
|
||||
(!gfx::Factory::AllowedSurfaceSize(aYSize) ||
|
||||
aCbCrSize.width > aYSize.width ||
|
||||
aCbCrSize.height > aYSize.height)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ComputeOffset(aYSize.height, aYStride)
|
||||
+ 2 * ComputeOffset(aCbCrSize.height, aCbCrStride)
|
||||
+ MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
|
||||
}
|
||||
|
||||
// Minimum required shmem size in bytes
|
||||
size_t
|
||||
YCbCrImageDataDeserializerBase::ComputeMinBufferSize(const gfx::IntSize& aYSize,
|
||||
const gfx::IntSize& aCbCrSize)
|
||||
{
|
||||
return ComputeMinBufferSize(aYSize, aYSize.width, aCbCrSize, aCbCrSize.width);
|
||||
}
|
||||
|
||||
// Offset in bytes
|
||||
static size_t ComputeOffset(uint32_t aSize)
|
||||
{
|
||||
return MOZ_ALIGN_WORD(aSize);
|
||||
}
|
||||
|
||||
// Minimum required shmem size in bytes
|
||||
size_t
|
||||
YCbCrImageDataDeserializerBase::ComputeMinBufferSize(uint32_t aSize)
|
||||
{
|
||||
return ComputeOffset(aSize) + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
|
||||
}
|
||||
|
||||
void
|
||||
YCbCrImageDataSerializer::InitializeBufferInfo(uint32_t aYOffset,
|
||||
uint32_t aCbOffset,
|
||||
uint32_t aCrOffset,
|
||||
uint32_t aYStride,
|
||||
uint32_t aCbCrStride,
|
||||
const gfx::IntSize& aYSize,
|
||||
const gfx::IntSize& aCbCrSize,
|
||||
StereoMode aStereoMode)
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
|
||||
MOZ_ASSERT(info); // OK to assert here, this method is client-side-only
|
||||
uint32_t info_size = MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
|
||||
info->mYOffset = info_size + aYOffset;
|
||||
info->mCbOffset = info_size + aCbOffset;
|
||||
info->mCrOffset = info_size + aCrOffset;
|
||||
info->mYStride = aYStride;
|
||||
info->mYWidth = aYSize.width;
|
||||
info->mYHeight = aYSize.height;
|
||||
info->mCbCrStride = aCbCrStride;
|
||||
info->mCbCrWidth = aCbCrSize.width;
|
||||
info->mCbCrHeight = aCbCrSize.height;
|
||||
info->mStereoMode = aStereoMode;
|
||||
Validate();
|
||||
}
|
||||
|
||||
void
|
||||
YCbCrImageDataSerializer::InitializeBufferInfo(uint32_t aYStride,
|
||||
uint32_t aCbCrStride,
|
||||
const gfx::IntSize& aYSize,
|
||||
const gfx::IntSize& aCbCrSize,
|
||||
StereoMode aStereoMode)
|
||||
{
|
||||
uint32_t yOffset = 0;
|
||||
uint32_t cbOffset = yOffset + MOZ_ALIGN_WORD(aYStride * aYSize.height);
|
||||
uint32_t crOffset = cbOffset + MOZ_ALIGN_WORD(aCbCrStride * aCbCrSize.height);
|
||||
return InitializeBufferInfo(yOffset, cbOffset, crOffset,
|
||||
aYStride, aCbCrStride, aYSize, aCbCrSize, aStereoMode);
|
||||
}
|
||||
|
||||
void
|
||||
YCbCrImageDataSerializer::InitializeBufferInfo(const gfx::IntSize& aYSize,
|
||||
const gfx::IntSize& aCbCrSize,
|
||||
StereoMode aStereoMode)
|
||||
{
|
||||
return InitializeBufferInfo(aYSize.width, aCbCrSize.width, aYSize, aCbCrSize, aStereoMode);
|
||||
}
|
||||
|
||||
static void CopyLineWithSkip(const uint8_t* src, uint8_t* dst, uint32_t len, uint32_t skip) {
|
||||
for (uint32_t i = 0; i < len; ++i) {
|
||||
*dst = *src;
|
||||
src += 1 + skip;
|
||||
++dst;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
YCbCrImageDataSerializer::CopyData(const uint8_t* aYData,
|
||||
const uint8_t* aCbData, const uint8_t* aCrData,
|
||||
gfx::IntSize aYSize, uint32_t aYStride,
|
||||
gfx::IntSize aCbCrSize, uint32_t aCbCrStride,
|
||||
uint32_t aYSkip, uint32_t aCbCrSkip)
|
||||
{
|
||||
if (!IsValid() || GetYSize() != aYSize || GetCbCrSize() != aCbCrSize) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < aYSize.height; ++i) {
|
||||
if (aYSkip == 0) {
|
||||
// fast path
|
||||
memcpy(GetYData() + i * GetYStride(),
|
||||
aYData + i * aYStride,
|
||||
aYSize.width);
|
||||
} else {
|
||||
// slower path
|
||||
CopyLineWithSkip(aYData + i * aYStride,
|
||||
GetYData() + i * GetYStride(),
|
||||
aYSize.width, aYSkip);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < aCbCrSize.height; ++i) {
|
||||
if (aCbCrSkip == 0) {
|
||||
// fast path
|
||||
memcpy(GetCbData() + i * GetCbCrStride(),
|
||||
aCbData + i * aCbCrStride,
|
||||
aCbCrSize.width);
|
||||
memcpy(GetCrData() + i * GetCbCrStride(),
|
||||
aCrData + i * aCbCrStride,
|
||||
aCbCrSize.width);
|
||||
} else {
|
||||
// slower path
|
||||
CopyLineWithSkip(aCbData + i * aCbCrStride,
|
||||
GetCbData() + i * GetCbCrStride(),
|
||||
aCbCrSize.width, aCbCrSkip);
|
||||
CopyLineWithSkip(aCrData + i * aCbCrStride,
|
||||
GetCrData() + i * GetCbCrStride(),
|
||||
aCbCrSize.width, aCbCrSkip);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<DataSourceSurface>
|
||||
YCbCrImageDataDeserializer::ToDataSourceSurface()
|
||||
{
|
||||
RefPtr<DataSourceSurface> result =
|
||||
Factory::CreateDataSourceSurface(GetYSize(), gfx::SurfaceFormat::B8G8R8X8);
|
||||
if (NS_WARN_IF(!result)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DataSourceSurface::MappedSurface map;
|
||||
if (NS_WARN_IF(!result->Map(DataSourceSurface::MapType::WRITE, &map))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gfx::YUVType type = TypeFromSize(GetYSize().width, GetYSize().height,
|
||||
GetCbCrSize().width, GetCbCrSize().height);
|
||||
gfx::ConvertYCbCrToRGB32(GetYData(), GetCbData(), GetCrData(),
|
||||
map.mData,
|
||||
0, 0, //pic x and y
|
||||
GetYSize().width, GetYSize().height,
|
||||
GetYStride(), GetCbCrStride(),
|
||||
map.mStride, type);
|
||||
result->Unmap();
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
|
@ -1,186 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MOZILLA_LAYERS_BLOBYCBCRSURFACE_H
|
||||
#define MOZILLA_LAYERS_BLOBYCBCRSURFACE_H
|
||||
|
||||
#include <stddef.h> // for size_t
|
||||
#include <stdint.h> // for uint8_t, uint32_t
|
||||
#include "ImageTypes.h" // for StereoMode
|
||||
#include "mozilla/Attributes.h" // for MOZ_STACK_CLASS
|
||||
#include "mozilla/RefPtr.h" // for already_AddRefed
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
class DataSourceSurface;
|
||||
} // namespace gfx
|
||||
|
||||
namespace layers {
|
||||
|
||||
class Image;
|
||||
|
||||
/**
|
||||
* Convenience class to share code between YCbCrImageDataSerializer
|
||||
* and YCbCrImageDataDeserializer.
|
||||
* Do not use it.
|
||||
*/
|
||||
class YCbCrImageDataDeserializerBase
|
||||
{
|
||||
public:
|
||||
bool IsValid() const { return mIsValid; }
|
||||
|
||||
/**
|
||||
* Returns the Y channel data pointer.
|
||||
*/
|
||||
uint8_t* GetYData();
|
||||
/**
|
||||
* Returns the Cb channel data pointer.
|
||||
*/
|
||||
uint8_t* GetCbData();
|
||||
/**
|
||||
* Returns the Cr channel data pointer.
|
||||
*/
|
||||
uint8_t* GetCrData();
|
||||
|
||||
/**
|
||||
* Returns the Y channel stride.
|
||||
*/
|
||||
uint32_t GetYStride();
|
||||
/**
|
||||
* Returns the stride of the Cb and Cr channels.
|
||||
*/
|
||||
uint32_t GetCbCrStride();
|
||||
|
||||
/**
|
||||
* Returns the dimensions of the Y Channel.
|
||||
*/
|
||||
gfx::IntSize GetYSize();
|
||||
|
||||
/**
|
||||
* Returns the dimensions of the Cb and Cr Channel.
|
||||
*/
|
||||
gfx::IntSize GetCbCrSize();
|
||||
|
||||
/**
|
||||
* Stereo mode for the image.
|
||||
*/
|
||||
StereoMode GetStereoMode();
|
||||
|
||||
/**
|
||||
* Return a pointer to the begining of the data buffer.
|
||||
*/
|
||||
uint8_t* GetData();
|
||||
|
||||
/**
|
||||
* This function is meant as a helper to know how much shared memory we need
|
||||
* to allocate in a shmem in order to place a shared YCbCr image blob of
|
||||
* given dimensions.
|
||||
*/
|
||||
static size_t ComputeMinBufferSize(const gfx::IntSize& aYSize,
|
||||
uint32_t aYStride,
|
||||
const gfx::IntSize& aCbCrSize,
|
||||
uint32_t aCbCrStride);
|
||||
static size_t ComputeMinBufferSize(const gfx::IntSize& aYSize,
|
||||
const gfx::IntSize& aCbCrSize);
|
||||
static size_t ComputeMinBufferSize(uint32_t aSize);
|
||||
|
||||
protected:
|
||||
YCbCrImageDataDeserializerBase(uint8_t* aData, size_t aDataSize)
|
||||
: mData (aData)
|
||||
, mDataSize(aDataSize)
|
||||
, mIsValid(false)
|
||||
{}
|
||||
|
||||
void Validate();
|
||||
|
||||
uint8_t* mData;
|
||||
size_t mDataSize;
|
||||
bool mIsValid;
|
||||
};
|
||||
|
||||
/**
|
||||
* A view on a YCbCr image stored with its metadata in a blob of memory.
|
||||
* It is only meant as a convenience to access the image data, and does not own
|
||||
* the data. The instance can live on the stack and used as follows:
|
||||
*
|
||||
* const YCbCrImage& yuv = sharedImage.get_YCbCrImage();
|
||||
* YCbCrImageDataDeserializer deserializer(yuv.data().get<uint8_t>());
|
||||
* if (!deserializer.IsValid()) {
|
||||
* // handle error
|
||||
* }
|
||||
* size = deserializer.GetYSize(); // work with the data, etc...
|
||||
*/
|
||||
class MOZ_STACK_CLASS YCbCrImageDataSerializer : public YCbCrImageDataDeserializerBase
|
||||
{
|
||||
public:
|
||||
YCbCrImageDataSerializer(uint8_t* aData, size_t aDataSize)
|
||||
: YCbCrImageDataDeserializerBase(aData, aDataSize)
|
||||
{
|
||||
// a serializer needs to be usable before correct buffer info has been written to it
|
||||
mIsValid = !!mData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the image informations in the buffer for given dimensions.
|
||||
* The provided pointer should point to the beginning of the (chunk of)
|
||||
* buffer on which we want to store the image.
|
||||
*/
|
||||
void InitializeBufferInfo(uint32_t aYOffset,
|
||||
uint32_t aCbOffset,
|
||||
uint32_t aCrOffset,
|
||||
uint32_t aYStride,
|
||||
uint32_t aCbCrStride,
|
||||
const gfx::IntSize& aYSize,
|
||||
const gfx::IntSize& aCbCrSize,
|
||||
StereoMode aStereoMode);
|
||||
void InitializeBufferInfo(uint32_t aYStride,
|
||||
uint32_t aCbCrStride,
|
||||
const gfx::IntSize& aYSize,
|
||||
const gfx::IntSize& aCbCrSize,
|
||||
StereoMode aStereoMode);
|
||||
void InitializeBufferInfo(const gfx::IntSize& aYSize,
|
||||
const gfx::IntSize& aCbCrSize,
|
||||
StereoMode aStereoMode);
|
||||
bool CopyData(const uint8_t* aYData,
|
||||
const uint8_t* aCbData, const uint8_t* aCrData,
|
||||
gfx::IntSize aYSize, uint32_t aYStride,
|
||||
gfx::IntSize aCbCrSize, uint32_t aCbCrStride,
|
||||
uint32_t aYSkip, uint32_t aCbCrSkip);
|
||||
};
|
||||
|
||||
/**
|
||||
* A view on a YCbCr image stored with its metadata in a blob of memory.
|
||||
* It is only meant as a convenience to access the image data, and does not own
|
||||
* the data. The instance can live on the stack and used as follows:
|
||||
*
|
||||
* const YCbCrImage& yuv = sharedImage.get_YCbCrImage();
|
||||
* YCbCrImageDataDeserializer deserializer(yuv.data().get<uint8_t>());
|
||||
* if (!deserializer.IsValid()) {
|
||||
* // handle error
|
||||
* }
|
||||
* size = deserializer.GetYSize(); // work with the data, etc...
|
||||
*/
|
||||
class MOZ_STACK_CLASS YCbCrImageDataDeserializer : public YCbCrImageDataDeserializerBase
|
||||
{
|
||||
public:
|
||||
YCbCrImageDataDeserializer(uint8_t* aData, size_t aDataSize)
|
||||
: YCbCrImageDataDeserializerBase(aData, aDataSize)
|
||||
{
|
||||
Validate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the YCbCr data into RGB and return a DataSourceSurface.
|
||||
* This is a costly operation, so use it only when YCbCr compositing is
|
||||
* not supported.
|
||||
*/
|
||||
already_AddRefed<gfx::DataSourceSurface> ToDataSourceSurface();
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -28,7 +28,6 @@
|
|||
#include "nsPoint.h" // for nsIntPoint
|
||||
#include "nsThreadUtils.h" // for NS_IsMainThread
|
||||
#include "OverscrollHandoffState.h" // for OverscrollHandoffState
|
||||
#include "TaskThrottler.h" // for TaskThrottler
|
||||
#include "TreeTraversal.h" // for generic tree traveral algorithms
|
||||
#include "LayersLogging.h" // for Stringify
|
||||
#include "Units.h" // for ParentlayerPixel
|
||||
|
@ -86,11 +85,10 @@ struct APZCTreeManager::TreeBuildingState {
|
|||
/*static*/ const ScreenMargin
|
||||
APZCTreeManager::CalculatePendingDisplayPort(
|
||||
const FrameMetrics& aFrameMetrics,
|
||||
const ParentLayerPoint& aVelocity,
|
||||
double aEstimatedPaintDuration)
|
||||
const ParentLayerPoint& aVelocity)
|
||||
{
|
||||
return AsyncPanZoomController::CalculatePendingDisplayPort(
|
||||
aFrameMetrics, aVelocity, aEstimatedPaintDuration);
|
||||
aFrameMetrics, aVelocity);
|
||||
}
|
||||
|
||||
APZCTreeManager::APZCTreeManager()
|
||||
|
@ -111,11 +109,10 @@ APZCTreeManager::~APZCTreeManager()
|
|||
|
||||
AsyncPanZoomController*
|
||||
APZCTreeManager::NewAPZCInstance(uint64_t aLayersId,
|
||||
GeckoContentController* aController,
|
||||
TaskThrottler* aPaintThrottler)
|
||||
GeckoContentController* aController)
|
||||
{
|
||||
return new AsyncPanZoomController(aLayersId, this, mInputQueue,
|
||||
aController, aPaintThrottler, AsyncPanZoomController::USE_GESTURE_DETECTOR);
|
||||
aController, AsyncPanZoomController::USE_GESTURE_DETECTOR);
|
||||
}
|
||||
|
||||
TimeStamp
|
||||
|
@ -201,32 +198,6 @@ APZCTreeManager::UpdateHitTestingTree(CompositorParent* aCompositor,
|
|||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
APZCTreeManager::InitializeForLayersId(uint64_t aLayersId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
auto throttlerInsertResult = mPaintThrottlerMap.insert(
|
||||
std::make_pair(aLayersId, RefPtr<TaskThrottler>()));
|
||||
if (throttlerInsertResult.second) {
|
||||
throttlerInsertResult.first->second = new TaskThrottler(
|
||||
GetFrameTime(), TimeDuration::FromMilliseconds(500));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
APZCTreeManager::AdoptLayersId(uint64_t aLayersId, APZCTreeManager* aOldManager)
|
||||
{
|
||||
MOZ_ASSERT(aOldManager);
|
||||
if (aOldManager == this) {
|
||||
return;
|
||||
}
|
||||
auto iter = aOldManager->mPaintThrottlerMap.find(aLayersId);
|
||||
if (iter != aOldManager->mPaintThrottlerMap.end()) {
|
||||
mPaintThrottlerMap[aLayersId] = iter->second;
|
||||
aOldManager->mPaintThrottlerMap.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the clip region to be used for a layer with an APZC. This function
|
||||
// is only called for layers which actually have scrollable metrics and an APZC.
|
||||
static ParentLayerIntRegion
|
||||
|
@ -462,12 +433,7 @@ APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer,
|
|||
// a destroyed APZC and so we need to throw that out and make a new one.
|
||||
bool newApzc = (apzc == nullptr || apzc->IsDestroyed());
|
||||
if (newApzc) {
|
||||
// Look up the paint throttler for this layers id, or create it if
|
||||
// this is the first APZC for this layers id.
|
||||
RefPtr<TaskThrottler> throttler = mPaintThrottlerMap[aLayersId];
|
||||
MOZ_ASSERT(throttler);
|
||||
|
||||
apzc = NewAPZCInstance(aLayersId, state->mController, throttler);
|
||||
apzc = NewAPZCInstance(aLayersId, state->mController);
|
||||
apzc->SetCompositorParent(aState.mCompositor);
|
||||
if (state->mCrossProcessParent != nullptr) {
|
||||
apzc->ShareFrameMetricsAcrossProcesses();
|
||||
|
@ -657,23 +623,10 @@ WillHandleInput(const PanGestureOrScrollWheelInput& aPanInput)
|
|||
void
|
||||
APZCTreeManager::FlushApzRepaints(uint64_t aLayersId)
|
||||
{
|
||||
// Previously, paints were throttled and therefore this method was used to
|
||||
// ensure any pending paints were flushed. Now, paints are flushed
|
||||
// immediately, so it is safe to simply send a notification now.
|
||||
APZCTM_LOG("Flushing repaints for layers id %" PRIu64, aLayersId);
|
||||
{ // scope lock
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
mTreeLock.AssertCurrentThreadOwns();
|
||||
|
||||
ForEachNode(mRootNode.get(),
|
||||
[aLayersId](HitTestingTreeNode* aNode)
|
||||
{
|
||||
if (aNode->IsPrimaryHolder()) {
|
||||
AsyncPanZoomController* apzc = aNode->GetApzc();
|
||||
MOZ_ASSERT(apzc);
|
||||
if (apzc->GetGuid().mLayersId == aLayersId) {
|
||||
apzc->FlushRepaintIfPending();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(aLayersId);
|
||||
MOZ_ASSERT(state && state->mController);
|
||||
NS_DispatchToMainThread(NS_NewRunnableMethod(
|
||||
|
|
|
@ -52,7 +52,6 @@ class LayerMetricsWrapper;
|
|||
class InputQueue;
|
||||
class GeckoContentController;
|
||||
class HitTestingTreeNode;
|
||||
class TaskThrottler;
|
||||
|
||||
/**
|
||||
* ****************** NOTE ON LOCK ORDERING IN APZ **************************
|
||||
|
@ -137,17 +136,6 @@ public:
|
|||
uint64_t aOriginatingLayersId,
|
||||
uint32_t aPaintSequenceNumber);
|
||||
|
||||
/**
|
||||
* Do any per-layers-id setup needed. This will be called on the main thread,
|
||||
* and may be called multiple times for the same layers id.
|
||||
*/
|
||||
void InitializeForLayersId(uint64_t aLayersId);
|
||||
|
||||
/**
|
||||
* Move any per-layers-id state from the old APZCTreeManager to this one.
|
||||
*/
|
||||
void AdoptLayersId(uint64_t aLayersId, APZCTreeManager* aOldManager);
|
||||
|
||||
/**
|
||||
* Walk the tree of APZCs and flushes the repaint requests for all the APZCS
|
||||
* corresponding to the given layers id. Finally, sends a flush complete
|
||||
|
@ -286,8 +274,7 @@ public:
|
|||
*/
|
||||
static const ScreenMargin CalculatePendingDisplayPort(
|
||||
const FrameMetrics& aFrameMetrics,
|
||||
const ParentLayerPoint& aVelocity,
|
||||
double aEstimatedPaintDuration);
|
||||
const ParentLayerPoint& aVelocity);
|
||||
|
||||
/**
|
||||
* Set the dpi value used by all AsyncPanZoomControllers.
|
||||
|
@ -420,8 +407,7 @@ protected:
|
|||
|
||||
// Protected hooks for gtests subclass
|
||||
virtual AsyncPanZoomController* NewAPZCInstance(uint64_t aLayersId,
|
||||
GeckoContentController* aController,
|
||||
TaskThrottler* aPaintThrottler);
|
||||
GeckoContentController* aController);
|
||||
public:
|
||||
// Public hooks for gtests subclass
|
||||
virtual TimeStamp GetFrameTime();
|
||||
|
@ -536,10 +522,6 @@ private:
|
|||
/* Holds the zoom constraints for scrollable layers, as determined by the
|
||||
* the main-thread gecko code. */
|
||||
std::map<ScrollableLayerGuid, ZoomConstraints> mZoomConstraints;
|
||||
/* Stores a paint throttler for each layers id. There is one for each layers
|
||||
* id to ensure that one child process painting slowly doesn't hold up
|
||||
* another. */
|
||||
std::map<uint64_t, RefPtr<TaskThrottler>> mPaintThrottlerMap;
|
||||
/* This tracks the APZC that should receive all inputs for the current input event block.
|
||||
* This allows touch points to move outside the thing they started on, but still have the
|
||||
* touch events delivered to the same initial APZC. This will only ever be touched on the
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include "InputBlockState.h" // for InputBlockState, TouchBlockState
|
||||
#include "InputQueue.h" // for InputQueue
|
||||
#include "OverscrollHandoffState.h" // for OverscrollHandoffState
|
||||
#include "TaskThrottler.h" // for TaskThrottler
|
||||
#include "Units.h" // for CSSRect, CSSPoint, etc
|
||||
#include "UnitTransforms.h" // for TransformTo
|
||||
#include "base/message_loop.h" // for MessageLoop
|
||||
|
@ -239,9 +238,6 @@ using mozilla::gfx::PointTyped;
|
|||
* rather than using the "stationary" multipliers.\n
|
||||
* Units: CSS pixels per millisecond
|
||||
*
|
||||
* \li\b apz.num_paint_duration_samples
|
||||
* Number of samples to store of how long it took to paint after the previous
|
||||
*
|
||||
* \li\b apz.overscroll.enabled
|
||||
* Pref that enables overscrolling. If this is disabled, excess scroll that
|
||||
* cannot be handed off is discarded.
|
||||
|
@ -303,12 +299,6 @@ using mozilla::gfx::PointTyped;
|
|||
* within this distance on scrollable frames.\n
|
||||
* Units: (real-world, i.e. screen) inches
|
||||
*
|
||||
* \li\b apz.use_paint_duration
|
||||
* Whether or not to use the estimated paint duration as a factor when projecting
|
||||
* the displayport in the direction of scrolling. If this value is set to false,
|
||||
* a constant 50ms paint time is used; the projection can be scaled as desired
|
||||
* using the \b apz.velocity_bias pref below.
|
||||
*
|
||||
* \li\b apz.velocity_bias
|
||||
* How much to adjust the displayport in the direction of scrolling. This value
|
||||
* is multiplied by the velocity and added to the displayport offset.
|
||||
|
@ -356,6 +346,12 @@ StaticAutoPtr<ComputedTimingFunction> gZoomAnimationFunction;
|
|||
*/
|
||||
StaticAutoPtr<ComputedTimingFunction> gVelocityCurveFunction;
|
||||
|
||||
/**
|
||||
* The estimated duration of a paint for the purposes of calculating a new
|
||||
* displayport, in milliseconds.
|
||||
*/
|
||||
static const double kDefaultEstimatedPaintDurationMs = 50;
|
||||
|
||||
/**
|
||||
* Returns true if this is a high memory system and we can use
|
||||
* extra memory for a larger displayport to reduce checkerboarding.
|
||||
|
@ -851,10 +847,8 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
|
|||
APZCTreeManager* aTreeManager,
|
||||
const RefPtr<InputQueue>& aInputQueue,
|
||||
GeckoContentController* aGeckoContentController,
|
||||
TaskThrottler* aPaintThrottler,
|
||||
GestureBehavior aGestures)
|
||||
: mLayersId(aLayersId),
|
||||
mPaintThrottler(aPaintThrottler),
|
||||
mGeckoContentController(aGeckoContentController),
|
||||
mRefPtrMonitor("RefPtrMonitor"),
|
||||
// mTreeManager must be initialized before GetFrameTime() is called
|
||||
|
@ -2695,9 +2689,14 @@ RedistributeDisplayPortExcess(CSSSize& aDisplayPortSize,
|
|||
/* static */
|
||||
const ScreenMargin AsyncPanZoomController::CalculatePendingDisplayPort(
|
||||
const FrameMetrics& aFrameMetrics,
|
||||
const ParentLayerPoint& aVelocity,
|
||||
double aEstimatedPaintDuration)
|
||||
const ParentLayerPoint& aVelocity)
|
||||
{
|
||||
if (aFrameMetrics.IsScrollInfoLayer()) {
|
||||
// Don't compute margins. Since we can't asynchronously scroll this frame,
|
||||
// we don't want to paint anything more than the composition bounds.
|
||||
return ScreenMargin();
|
||||
}
|
||||
|
||||
CSSSize compositionSize = aFrameMetrics.CalculateBoundedCompositedSizeInCssPixels();
|
||||
CSSPoint velocity = aVelocity / aFrameMetrics.GetZoom();
|
||||
CSSPoint scrollOffset = aFrameMetrics.GetScrollOffset();
|
||||
|
@ -2712,8 +2711,7 @@ const ScreenMargin AsyncPanZoomController::CalculatePendingDisplayPort(
|
|||
|
||||
// Offset the displayport, depending on how fast we're moving and the
|
||||
// estimated time it takes to paint, to try to minimise checkerboarding.
|
||||
float estimatedPaintDurationMillis = (float)(aEstimatedPaintDuration * 1000.0);
|
||||
float paintFactor = (gfxPrefs::APZUsePaintDuration() ? estimatedPaintDurationMillis : 50.0f);
|
||||
float paintFactor = kDefaultEstimatedPaintDurationMs;
|
||||
CSSRect displayPort = CSSRect(scrollOffset + (velocity * paintFactor * gfxPrefs::APZVelocityBias()),
|
||||
displayPortSize);
|
||||
|
||||
|
@ -2746,11 +2744,7 @@ void AsyncPanZoomController::ScheduleComposite() {
|
|||
|
||||
void AsyncPanZoomController::ScheduleCompositeAndMaybeRepaint() {
|
||||
ScheduleComposite();
|
||||
|
||||
TimeDuration timePaintDelta = mPaintThrottler->TimeSinceLastRequest(GetFrameTime());
|
||||
if (timePaintDelta.ToMilliseconds() > gfxPrefs::APZPanRepaintInterval()) {
|
||||
RequestContentRepaint();
|
||||
}
|
||||
RequestContentRepaint();
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::FlushRepaintForOverscrollHandoff() {
|
||||
|
@ -2763,25 +2757,10 @@ void AsyncPanZoomController::FlushRepaintForNewInputBlock() {
|
|||
APZC_LOG("%p flushing repaint for new input block\n", this);
|
||||
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
// We need to send a new repaint request unthrottled, but that
|
||||
// will obsolete any pending repaint request in the paint throttler.
|
||||
// Therefore we should clear out the pending task and restore the
|
||||
// state of mLastPaintRequestMetrics to what it was before the
|
||||
// pending task was queued.
|
||||
mPaintThrottler->CancelPendingTask();
|
||||
mLastPaintRequestMetrics = mLastDispatchedPaintMetrics;
|
||||
|
||||
RequestContentRepaint(mFrameMetrics, false /* not throttled */);
|
||||
RequestContentRepaint(mFrameMetrics);
|
||||
UpdateSharedCompositorFrameMetrics();
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::FlushRepaintIfPending() {
|
||||
// Just tell the paint throttler to send the pending repaint request if
|
||||
// there is one.
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
mPaintThrottler->TaskComplete(GetFrameTime());
|
||||
}
|
||||
|
||||
bool AsyncPanZoomController::SnapBackIfOverscrolled() {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
// It's possible that we're already in the middle of an overscroll
|
||||
|
@ -2824,11 +2803,8 @@ void AsyncPanZoomController::RequestContentRepaint() {
|
|||
RequestContentRepaint(mFrameMetrics);
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::RequestContentRepaint(FrameMetrics& aFrameMetrics, bool aThrottled) {
|
||||
aFrameMetrics.SetDisplayPortMargins(
|
||||
CalculatePendingDisplayPort(aFrameMetrics,
|
||||
GetVelocityVector(),
|
||||
mPaintThrottler->AverageDuration().ToSeconds()));
|
||||
void AsyncPanZoomController::RequestContentRepaint(FrameMetrics& aFrameMetrics) {
|
||||
aFrameMetrics.SetDisplayPortMargins(CalculatePendingDisplayPort(aFrameMetrics, GetVelocityVector()));
|
||||
aFrameMetrics.SetUseDisplayPortMargins();
|
||||
|
||||
// If we're trying to paint what we already think is painted, discard this
|
||||
|
@ -2852,19 +2828,8 @@ void AsyncPanZoomController::RequestContentRepaint(FrameMetrics& aFrameMetrics,
|
|||
return;
|
||||
}
|
||||
|
||||
if (aThrottled) {
|
||||
mPaintThrottler->PostTask(
|
||||
FROM_HERE,
|
||||
UniquePtr<CancelableTask>(NewRunnableMethod(this,
|
||||
&AsyncPanZoomController::DispatchRepaintRequest,
|
||||
aFrameMetrics)),
|
||||
GetFrameTime());
|
||||
} else {
|
||||
DispatchRepaintRequest(aFrameMetrics);
|
||||
}
|
||||
|
||||
DispatchRepaintRequest(aFrameMetrics);
|
||||
aFrameMetrics.SetPresShellId(mLastContentPaintMetrics.GetPresShellId());
|
||||
mLastPaintRequestMetrics = aFrameMetrics;
|
||||
}
|
||||
|
||||
/*static*/ CSSRect
|
||||
|
@ -2881,18 +2846,21 @@ GetDisplayPortRect(const FrameMetrics& aFrameMetrics)
|
|||
void
|
||||
AsyncPanZoomController::DispatchRepaintRequest(const FrameMetrics& aFrameMetrics) {
|
||||
RefPtr<GeckoContentController> controller = GetGeckoContentController();
|
||||
if (controller) {
|
||||
APZC_LOG_FM(aFrameMetrics, "%p requesting content repaint", this);
|
||||
LogRendertraceRect(GetGuid(), "requested displayport", "yellow", GetDisplayPortRect(aFrameMetrics));
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
controller->RequestContentRepaint(aFrameMetrics);
|
||||
} else {
|
||||
NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<FrameMetrics>(
|
||||
controller, &GeckoContentController::RequestContentRepaint, aFrameMetrics));
|
||||
}
|
||||
mLastDispatchedPaintMetrics = aFrameMetrics;
|
||||
if (!controller) {
|
||||
return;
|
||||
}
|
||||
|
||||
APZC_LOG_FM(aFrameMetrics, "%p requesting content repaint", this);
|
||||
LogRendertraceRect(GetGuid(), "requested displayport", "yellow", GetDisplayPortRect(aFrameMetrics));
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
controller->RequestContentRepaint(aFrameMetrics);
|
||||
} else {
|
||||
NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<FrameMetrics>(
|
||||
controller, &GeckoContentController::RequestContentRepaint, aFrameMetrics));
|
||||
}
|
||||
mExpectedGeckoMetrics = aFrameMetrics;
|
||||
mLastPaintRequestMetrics = aFrameMetrics;
|
||||
}
|
||||
|
||||
bool AsyncPanZoomController::UpdateAnimation(const TimeStamp& aSampleTime,
|
||||
|
@ -2913,16 +2881,11 @@ bool AsyncPanZoomController::UpdateAnimation(const TimeStamp& aSampleTime,
|
|||
if (mAnimation) {
|
||||
bool continueAnimation = mAnimation->Sample(mFrameMetrics, sampleTimeDelta);
|
||||
*aOutDeferredTasks = mAnimation->TakeDeferredTasks();
|
||||
if (continueAnimation) {
|
||||
if (mPaintThrottler->TimeSinceLastRequest(aSampleTime) >
|
||||
mAnimation->mRepaintInterval) {
|
||||
RequestContentRepaint();
|
||||
}
|
||||
} else {
|
||||
if (!continueAnimation) {
|
||||
mAnimation = nullptr;
|
||||
SetState(NOTHING);
|
||||
RequestContentRepaint();
|
||||
}
|
||||
RequestContentRepaint();
|
||||
UpdateSharedCompositorFrameMetrics();
|
||||
return true;
|
||||
}
|
||||
|
@ -3071,7 +3034,7 @@ Matrix4x4 AsyncPanZoomController::GetTransformToLastDispatchedPaint() const {
|
|||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
||||
LayerPoint scrollChange =
|
||||
(mLastContentPaintMetrics.GetScrollOffset() - mLastDispatchedPaintMetrics.GetScrollOffset())
|
||||
(mLastContentPaintMetrics.GetScrollOffset() - mExpectedGeckoMetrics.GetScrollOffset())
|
||||
* mLastContentPaintMetrics.GetDevPixelsPerCSSPixel()
|
||||
* mLastContentPaintMetrics.GetCumulativeResolution();
|
||||
|
||||
|
@ -3081,7 +3044,7 @@ Matrix4x4 AsyncPanZoomController::GetTransformToLastDispatchedPaint() const {
|
|||
LayoutDeviceToParentLayerScale2D lastContentZoom =
|
||||
mLastContentPaintMetrics.GetZoom() / mLastContentPaintMetrics.GetDevPixelsPerCSSPixel();
|
||||
LayoutDeviceToParentLayerScale2D lastDispatchedZoom =
|
||||
mLastDispatchedPaintMetrics.GetZoom() / mLastDispatchedPaintMetrics.GetDevPixelsPerCSSPixel();
|
||||
mExpectedGeckoMetrics.GetZoom() / mExpectedGeckoMetrics.GetDevPixelsPerCSSPixel();
|
||||
gfxSize zoomChange = lastContentZoom / lastDispatchedZoom;
|
||||
|
||||
return Matrix4x4::Translation(scrollChange.x, scrollChange.y, 0).
|
||||
|
@ -3159,7 +3122,6 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
|
|||
aLayerMetrics.GetCriticalDisplayPort() + aLayerMetrics.GetScrollOffset());
|
||||
}
|
||||
|
||||
mPaintThrottler->TaskComplete(GetFrameTime());
|
||||
bool needContentRepaint = false;
|
||||
bool viewportUpdated = false;
|
||||
if (FuzzyEqualsAdditive(aLayerMetrics.GetCompositionBounds().width, mFrameMetrics.GetCompositionBounds().width) &&
|
||||
|
@ -3190,16 +3152,13 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
|
|||
if (aIsFirstPaint || isDefault) {
|
||||
// Initialize our internal state to something sane when the content
|
||||
// that was just painted is something we knew nothing about previously
|
||||
mPaintThrottler->ClearHistory();
|
||||
mPaintThrottler->SetMaxDurations(gfxPrefs::APZNumPaintDurationSamples());
|
||||
|
||||
CancelAnimation();
|
||||
|
||||
mFrameMetrics = aLayerMetrics;
|
||||
if (scrollOffsetUpdated) {
|
||||
AcknowledgeScrollUpdate();
|
||||
}
|
||||
mLastDispatchedPaintMetrics = aLayerMetrics;
|
||||
mExpectedGeckoMetrics = aLayerMetrics;
|
||||
ShareCompositorFrameMetrics();
|
||||
|
||||
if (mFrameMetrics.GetDisplayPortMargins() != ScreenMargin()) {
|
||||
|
@ -3252,6 +3211,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
|
|||
mFrameMetrics.SetMaskLayerIndex(aLayerMetrics.GetMaskLayerIndex());
|
||||
mFrameMetrics.SetIsLayersIdRoot(aLayerMetrics.IsLayersIdRoot());
|
||||
mFrameMetrics.SetUsesContainerScrolling(aLayerMetrics.UsesContainerScrolling());
|
||||
mFrameMetrics.SetIsScrollInfoLayer(aLayerMetrics.IsScrollInfoLayer());
|
||||
|
||||
if (scrollOffsetUpdated) {
|
||||
APZC_LOG("%p updating scroll offset from %s to %s\n", this,
|
||||
|
@ -3261,13 +3221,13 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
|
|||
// Send an acknowledgement with the new scroll generation so that any
|
||||
// repaint requests later in this function go through.
|
||||
// Because of the scroll generation update, any inflight paint requests are
|
||||
// going to be ignored by layout, and so mLastDispatchedPaintMetrics
|
||||
// going to be ignored by layout, and so mExpectedGeckoMetrics
|
||||
// becomes incorrect for the purposes of calculating the LD transform. To
|
||||
// correct this we need to update mLastDispatchedPaintMetrics to be the
|
||||
// correct this we need to update mExpectedGeckoMetrics to be the
|
||||
// last thing we know was painted by Gecko.
|
||||
mFrameMetrics.CopyScrollInfoFrom(aLayerMetrics);
|
||||
AcknowledgeScrollUpdate();
|
||||
mLastDispatchedPaintMetrics = aLayerMetrics;
|
||||
mExpectedGeckoMetrics = aLayerMetrics;
|
||||
|
||||
// Cancel the animation (which might also trigger a repaint request)
|
||||
// after we update the scroll offset above. Otherwise we can be left
|
||||
|
@ -3299,7 +3259,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
|
|||
// above.
|
||||
mFrameMetrics.CopySmoothScrollInfoFrom(aLayerMetrics);
|
||||
AcknowledgeScrollUpdate();
|
||||
mLastDispatchedPaintMetrics = aLayerMetrics;
|
||||
mExpectedGeckoMetrics = aLayerMetrics;
|
||||
|
||||
if (mState == SMOOTH_SCROLL && mAnimation) {
|
||||
APZC_LOG("%p updating destination on existing animation\n", this);
|
||||
|
@ -3438,9 +3398,7 @@ void AsyncPanZoomController::ZoomToRect(CSSRect aRect) {
|
|||
|
||||
endZoomToMetrics.SetScrollOffset(aRect.TopLeft());
|
||||
endZoomToMetrics.SetDisplayPortMargins(
|
||||
CalculatePendingDisplayPort(endZoomToMetrics,
|
||||
ParentLayerPoint(0,0),
|
||||
0));
|
||||
CalculatePendingDisplayPort(endZoomToMetrics, ParentLayerPoint(0,0)));
|
||||
endZoomToMetrics.SetUseDisplayPortMargins();
|
||||
|
||||
StartAnimation(new ZoomAnimation(
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "APZUtils.h"
|
||||
#include "Layers.h" // for Layer::ScrollDirection
|
||||
#include "LayersTypes.h"
|
||||
#include "TaskThrottler.h"
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "nsRegion.h"
|
||||
|
||||
|
@ -104,7 +103,6 @@ public:
|
|||
APZCTreeManager* aTreeManager,
|
||||
const RefPtr<InputQueue>& aInputQueue,
|
||||
GeckoContentController* aController,
|
||||
TaskThrottler* aPaintThrottler,
|
||||
GestureBehavior aGestures = DEFAULT_GESTURES);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
@ -186,11 +184,6 @@ public:
|
|||
*/
|
||||
void NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint);
|
||||
|
||||
/**
|
||||
* Flush any pending repaint request.
|
||||
*/
|
||||
void FlushRepaintIfPending();
|
||||
|
||||
/**
|
||||
* The platform implementation must set the compositor parent so that we can
|
||||
* request composites.
|
||||
|
@ -269,8 +262,7 @@ public:
|
|||
*/
|
||||
static const ScreenMargin CalculatePendingDisplayPort(
|
||||
const FrameMetrics& aFrameMetrics,
|
||||
const ParentLayerPoint& aVelocity,
|
||||
double aEstimatedPaintDuration);
|
||||
const ParentLayerPoint& aVelocity);
|
||||
|
||||
nsEventStatus HandleDragEvent(const MouseInput& aEvent,
|
||||
const AsyncDragMetrics& aDragMetrics);
|
||||
|
@ -597,7 +589,7 @@ protected:
|
|||
* the paint throttler. In particular, the GeckoContentController::RequestContentRepaint
|
||||
* function will be invoked before this function returns.
|
||||
*/
|
||||
void RequestContentRepaint(FrameMetrics& aFrameMetrics, bool aThrottled = true);
|
||||
void RequestContentRepaint(FrameMetrics& aFrameMetrics);
|
||||
|
||||
/**
|
||||
* Actually send the next pending paint request to gecko.
|
||||
|
@ -651,7 +643,6 @@ protected:
|
|||
|
||||
uint64_t mLayersId;
|
||||
RefPtr<CompositorParent> mCompositorParent;
|
||||
RefPtr<TaskThrottler> mPaintThrottler;
|
||||
|
||||
/* Access to the following two fields is protected by the mRefPtrMonitor,
|
||||
since they are accessed on the UI thread but can be cleared on the
|
||||
|
@ -699,15 +690,12 @@ private:
|
|||
// the Gecko state, it should be used as a basis for untransformation when
|
||||
// sending messages back to Gecko.
|
||||
FrameMetrics mLastContentPaintMetrics;
|
||||
// The last metrics that we requested a paint for. These are used to make sure
|
||||
// that we're not requesting a paint of the same thing that's already drawn.
|
||||
// If we don't do this check, we don't get a ShadowLayersUpdated back.
|
||||
// The last metrics used for a content repaint request.
|
||||
FrameMetrics mLastPaintRequestMetrics;
|
||||
// The last metrics that we actually sent to Gecko. This allows us to transform
|
||||
// inputs into a coordinate space that Gecko knows about. This assumes the pipe
|
||||
// through which input events and repaint requests are sent to Gecko operates
|
||||
// in a FIFO manner.
|
||||
FrameMetrics mLastDispatchedPaintMetrics;
|
||||
// The metrics that we expect content to have. This is updated when we
|
||||
// request a content repaint, and when we receive a shadow layers update.
|
||||
// This allows us to transform events into Gecko's coordinate space.
|
||||
FrameMetrics mExpectedGeckoMetrics;
|
||||
|
||||
AxisX mX;
|
||||
AxisY mY;
|
||||
|
|
|
@ -1,173 +0,0 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- */
|
||||
/* vim: set sw=2 sts=2 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "TaskThrottler.h"
|
||||
|
||||
#include "mozilla/layers/APZThreadUtils.h"
|
||||
|
||||
#define TASK_LOG(...)
|
||||
// #define TASK_LOG(...) printf_stderr("TASK: " __VA_ARGS__)
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
TaskThrottler::TaskThrottler(const TimeStamp& aTimeStamp, const TimeDuration& aMaxWait)
|
||||
: mMonitor("TaskThrottler")
|
||||
, mOutstanding(false)
|
||||
, mQueuedTask(nullptr)
|
||||
, mStartTime(aTimeStamp)
|
||||
, mMaxWait(aMaxWait)
|
||||
, mMean(1)
|
||||
, mTimeoutTask(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
TaskThrottler::~TaskThrottler()
|
||||
{
|
||||
// The timeout task holds a strong reference to the TaskThrottler, so if the
|
||||
// TaskThrottler is being destroyed, there's no need to cancel the task.
|
||||
}
|
||||
|
||||
void
|
||||
TaskThrottler::PostTask(const tracked_objects::Location& aLocation,
|
||||
UniquePtr<CancelableTask> aTask, const TimeStamp& aTimeStamp)
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
|
||||
TASK_LOG("%p got a task posted; mOutstanding=%d\n", this, mOutstanding);
|
||||
aTask->SetBirthPlace(aLocation);
|
||||
|
||||
if (mOutstanding) {
|
||||
CancelPendingTask(lock);
|
||||
if (TimeSinceLastRequest(aTimeStamp, lock) < mMaxWait) {
|
||||
mQueuedTask = Move(aTask);
|
||||
TASK_LOG("%p queued task %p\n", this, mQueuedTask.get());
|
||||
// Make sure the queued task is sent after mMaxWait time elapses,
|
||||
// even if we don't get a TaskComplete() until then.
|
||||
TimeDuration timeout = mMaxWait - TimeSinceLastRequest(aTimeStamp, lock);
|
||||
mTimeoutTask = NewRunnableMethod(this, &TaskThrottler::OnTimeout);
|
||||
APZThreadUtils::RunDelayedTaskOnCurrentThread(mTimeoutTask, timeout);
|
||||
return;
|
||||
}
|
||||
// we've been waiting for more than the max-wait limit, so just fall through
|
||||
// and send the new task already.
|
||||
}
|
||||
|
||||
mStartTime = aTimeStamp;
|
||||
aTask->Run();
|
||||
mOutstanding = true;
|
||||
}
|
||||
|
||||
void
|
||||
TaskThrottler::OnTimeout()
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
if (mQueuedTask) {
|
||||
RunQueuedTask(TimeStamp::Now(), lock);
|
||||
}
|
||||
// The message loop will delete the posted timeout task. Make sure we don't
|
||||
// keep a dangling pointer to it.
|
||||
mTimeoutTask = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
TaskThrottler::TaskComplete(const TimeStamp& aTimeStamp)
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
|
||||
if (!mOutstanding) {
|
||||
return;
|
||||
}
|
||||
|
||||
mMean.insert(aTimeStamp - mStartTime);
|
||||
|
||||
if (mQueuedTask) {
|
||||
RunQueuedTask(aTimeStamp, lock);
|
||||
CancelTimeoutTask(lock);
|
||||
} else {
|
||||
mOutstanding = false;
|
||||
}
|
||||
}
|
||||
|
||||
TimeDuration
|
||||
TaskThrottler::AverageDuration()
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
|
||||
return mMean.empty() ? TimeDuration() : mMean.mean();
|
||||
}
|
||||
|
||||
void
|
||||
TaskThrottler::RunQueuedTask(const TimeStamp& aTimeStamp,
|
||||
const MonitorAutoLock& aProofOfLock)
|
||||
{
|
||||
TASK_LOG("%p running task %p\n", this, mQueuedTask.get());
|
||||
mStartTime = aTimeStamp;
|
||||
mQueuedTask->Run();
|
||||
mQueuedTask = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
TaskThrottler::CancelPendingTask()
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
CancelPendingTask(lock);
|
||||
}
|
||||
|
||||
void
|
||||
TaskThrottler::CancelPendingTask(const MonitorAutoLock& aProofOfLock)
|
||||
{
|
||||
if (mQueuedTask) {
|
||||
TASK_LOG("%p cancelling task %p\n", this, mQueuedTask.get());
|
||||
mQueuedTask->Cancel();
|
||||
mQueuedTask = nullptr;
|
||||
CancelTimeoutTask(aProofOfLock);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TaskThrottler::CancelTimeoutTask(const MonitorAutoLock& aProofOfLock)
|
||||
{
|
||||
if (mTimeoutTask) {
|
||||
mTimeoutTask->Cancel();
|
||||
mTimeoutTask = nullptr; // the MessageLoop will destroy it
|
||||
}
|
||||
}
|
||||
|
||||
TimeDuration
|
||||
TaskThrottler::TimeSinceLastRequest(const TimeStamp& aTimeStamp)
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
return TimeSinceLastRequest(aTimeStamp, lock);
|
||||
}
|
||||
|
||||
TimeDuration
|
||||
TaskThrottler::TimeSinceLastRequest(const TimeStamp& aTimeStamp,
|
||||
const MonitorAutoLock& aProofOfLock)
|
||||
{
|
||||
return aTimeStamp - mStartTime;
|
||||
}
|
||||
|
||||
void
|
||||
TaskThrottler::ClearHistory()
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
|
||||
mMean.clear();
|
||||
}
|
||||
|
||||
void
|
||||
TaskThrottler::SetMaxDurations(uint32_t aMaxDurations)
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
|
||||
if (aMaxDurations != mMean.maxValues()) {
|
||||
mMean = RollingMean<TimeDuration, TimeDuration>(aMaxDurations);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
|
@ -1,119 +0,0 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- */
|
||||
/* vim: set sw=4 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_TaskThrottler_h
|
||||
#define mozilla_dom_TaskThrottler_h
|
||||
|
||||
#include <stdint.h> // for uint32_t
|
||||
#include "base/task.h" // for CancelableTask
|
||||
#include "mozilla/Monitor.h" // for Monitor
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "mozilla/RollingMean.h" // for RollingMean
|
||||
#include "mozilla/TimeStamp.h" // for TimeDuration, TimeStamp
|
||||
#include "mozilla/UniquePtr.h" // for UniquePtr
|
||||
#include "nsCOMPtr.h" // for nsCOMPtr
|
||||
#include "nsISupportsImpl.h" // for NS_INLINE_DECL_THREADSAFE_REFCOUNTING
|
||||
#include "nsTArray.h" // for nsTArray
|
||||
|
||||
namespace tracked_objects {
|
||||
class Location;
|
||||
} // namespace tracked_objects
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
/** The TaskThrottler prevents update event overruns. It is used in cases where
|
||||
* you're sending an async message and waiting for a reply. You need to call
|
||||
* PostTask to queue a task and TaskComplete when you get a response.
|
||||
*
|
||||
* The call to TaskComplete will run the most recent task posted since the last
|
||||
* request was sent, if any. This means that at any time there can be at most 1
|
||||
* outstanding request being processed and at most 1 queued behind it.
|
||||
*
|
||||
* However, to guard against task runs that error out and fail to call TaskComplete,
|
||||
* the TaskThrottler also has a max-wait timeout. If the caller requests a new
|
||||
* task be posted, and it has been greater than the max-wait timeout since the
|
||||
* last one was sent, then we send the new one regardless of whether or not the
|
||||
* last one was marked as completed.
|
||||
*
|
||||
* This is used in the context of repainting a scrollable region. While another
|
||||
* process is painting you might get several updates from the UI thread but when
|
||||
* the paint is complete you want to send the most recent.
|
||||
*/
|
||||
|
||||
class TaskThrottler {
|
||||
public:
|
||||
TaskThrottler(const TimeStamp& aTimeStamp, const TimeDuration& aMaxWait);
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TaskThrottler)
|
||||
|
||||
/** Post a task to be run as soon as there are no outstanding tasks, or
|
||||
* post it immediately if it has been more than the max-wait time since
|
||||
* the last task was posted.
|
||||
*
|
||||
* @param aLocation Use the macro FROM_HERE
|
||||
* @param aTask Ownership of this object is transferred to TaskThrottler
|
||||
* which will delete it when it is either run or becomes
|
||||
* obsolete or the TaskThrottler is destructed.
|
||||
*/
|
||||
void PostTask(const tracked_objects::Location& aLocation,
|
||||
UniquePtr<CancelableTask> aTask, const TimeStamp& aTimeStamp);
|
||||
/**
|
||||
* Mark the task as complete and process the next queued task.
|
||||
*/
|
||||
void TaskComplete(const TimeStamp& aTimeStamp);
|
||||
|
||||
/**
|
||||
* Calculate the average time between processing the posted task and getting
|
||||
* the TaskComplete() call back.
|
||||
*/
|
||||
TimeDuration AverageDuration();
|
||||
|
||||
/**
|
||||
* Cancel the queued task if there is one.
|
||||
*/
|
||||
void CancelPendingTask();
|
||||
|
||||
/**
|
||||
* Return the time elapsed since the last request was processed
|
||||
*/
|
||||
TimeDuration TimeSinceLastRequest(const TimeStamp& aTimeStamp);
|
||||
|
||||
/**
|
||||
* Clear average history.
|
||||
*/
|
||||
void ClearHistory();
|
||||
|
||||
/**
|
||||
* @param aMaxDurations The maximum number of durations to measure.
|
||||
*/
|
||||
|
||||
void SetMaxDurations(uint32_t aMaxDurations);
|
||||
|
||||
private:
|
||||
mutable Monitor mMonitor;
|
||||
bool mOutstanding;
|
||||
UniquePtr<CancelableTask> mQueuedTask;
|
||||
TimeStamp mStartTime;
|
||||
TimeDuration mMaxWait;
|
||||
RollingMean<TimeDuration, TimeDuration> mMean;
|
||||
CancelableTask* mTimeoutTask; // not owned because it's posted to a MessageLoop
|
||||
// which deletes it
|
||||
|
||||
~TaskThrottler();
|
||||
void RunQueuedTask(const TimeStamp& aTimeStamp,
|
||||
const MonitorAutoLock& aProofOfLock);
|
||||
void CancelPendingTask(const MonitorAutoLock& aProofOfLock);
|
||||
TimeDuration TimeSinceLastRequest(const TimeStamp& aTimeStamp,
|
||||
const MonitorAutoLock& aProofOfLock);
|
||||
void OnTimeout();
|
||||
void CancelTimeoutTask(const MonitorAutoLock& aProofOfLock);
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_TaskThrottler_h
|
|
@ -154,8 +154,7 @@ public:
|
|||
|
||||
protected:
|
||||
AsyncPanZoomController* NewAPZCInstance(uint64_t aLayersId,
|
||||
GeckoContentController* aController,
|
||||
TaskThrottler* aPaintThrottler) override;
|
||||
GeckoContentController* aController) override;
|
||||
|
||||
TimeStamp GetFrameTime() override {
|
||||
return mcc->Time();
|
||||
|
@ -169,10 +168,9 @@ class TestAsyncPanZoomController : public AsyncPanZoomController {
|
|||
public:
|
||||
TestAsyncPanZoomController(uint64_t aLayersId, MockContentControllerDelayed* aMcc,
|
||||
TestAPZCTreeManager* aTreeManager,
|
||||
TaskThrottler* aPaintThrottler,
|
||||
GestureBehavior aBehavior = DEFAULT_GESTURES)
|
||||
: AsyncPanZoomController(aLayersId, aTreeManager, aTreeManager->GetInputQueue(),
|
||||
aMcc, aPaintThrottler, aBehavior)
|
||||
aMcc, aBehavior)
|
||||
, mWaitForMainThread(false)
|
||||
, mcc(aMcc)
|
||||
{}
|
||||
|
@ -261,11 +259,10 @@ private:
|
|||
|
||||
AsyncPanZoomController*
|
||||
TestAPZCTreeManager::NewAPZCInstance(uint64_t aLayersId,
|
||||
GeckoContentController* aController,
|
||||
TaskThrottler* aPaintThrottler)
|
||||
GeckoContentController* aController)
|
||||
{
|
||||
MockContentControllerDelayed* mcc = static_cast<MockContentControllerDelayed*>(aController);
|
||||
return new TestAsyncPanZoomController(aLayersId, mcc, this, aPaintThrottler,
|
||||
return new TestAsyncPanZoomController(aLayersId, mcc, this,
|
||||
AsyncPanZoomController::USE_GESTURE_DETECTOR);
|
||||
}
|
||||
|
||||
|
@ -297,9 +294,8 @@ protected:
|
|||
APZThreadUtils::SetControllerThread(MessageLoop::current());
|
||||
|
||||
mcc = new NiceMock<MockContentControllerDelayed>();
|
||||
mPaintThrottler = new TaskThrottler(mcc->Time(), TimeDuration::FromMilliseconds(500));
|
||||
tm = new TestAPZCTreeManager(mcc);
|
||||
apzc = new TestAsyncPanZoomController(0, mcc, tm, mPaintThrottler, mGestureBehavior);
|
||||
apzc = new TestAsyncPanZoomController(0, mcc, tm, mGestureBehavior);
|
||||
apzc->SetFrameMetrics(TestFrameMetrics());
|
||||
}
|
||||
|
||||
|
@ -382,7 +378,6 @@ protected:
|
|||
|
||||
AsyncPanZoomController::GestureBehavior mGestureBehavior;
|
||||
RefPtr<MockContentControllerDelayed> mcc;
|
||||
RefPtr<TaskThrottler> mPaintThrottler;
|
||||
RefPtr<TestAPZCTreeManager> tm;
|
||||
RefPtr<TestAsyncPanZoomController> apzc;
|
||||
};
|
||||
|
@ -819,7 +814,8 @@ protected:
|
|||
MakeApzcZoomable();
|
||||
|
||||
if (aShouldTriggerPinch) {
|
||||
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
|
||||
// One repaint request for each gesture.
|
||||
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(2);
|
||||
} else {
|
||||
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0);
|
||||
}
|
||||
|
@ -1141,7 +1137,7 @@ TEST_F(APZCBasicTester, ComplexTransform) {
|
|||
// sides.
|
||||
|
||||
RefPtr<TestAsyncPanZoomController> childApzc =
|
||||
new TestAsyncPanZoomController(0, mcc, tm, mPaintThrottler);
|
||||
new TestAsyncPanZoomController(0, mcc, tm);
|
||||
|
||||
const char* layerTreeSyntax = "c(c)";
|
||||
// LayerID 0 1
|
||||
|
@ -1248,7 +1244,8 @@ protected:
|
|||
void DoPanTest(bool aShouldTriggerScroll, bool aShouldBeConsumed, uint32_t aBehavior)
|
||||
{
|
||||
if (aShouldTriggerScroll) {
|
||||
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
|
||||
// One repaint request for each pan.
|
||||
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(2);
|
||||
} else {
|
||||
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0);
|
||||
}
|
||||
|
@ -1357,8 +1354,6 @@ TEST_F(APZCPanningTester, PanWithPreventDefault) {
|
|||
}
|
||||
|
||||
TEST_F(APZCBasicTester, Fling) {
|
||||
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
|
||||
|
||||
int touchStart = 50;
|
||||
int touchEnd = 10;
|
||||
ParentLayerPoint pointOut;
|
||||
|
@ -2422,10 +2417,8 @@ TEST_F(APZHitTestingTester, HitTesting2) {
|
|||
// because we have already issued a paint request with it.
|
||||
EXPECT_EQ(ScreenPoint(25, 25), transformToGecko * ParentLayerPoint(12.5, 75));
|
||||
|
||||
// This second pan will move the APZC by another 50 pixels but since the paint
|
||||
// request dispatched above has not "completed", we will not dispatch another
|
||||
// one yet. Now we have an async transform on top of the pending paint request
|
||||
// transform.
|
||||
// This second pan will move the APZC by another 50 pixels.
|
||||
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
|
||||
ApzcPanNoFling(apzcroot, mcc, 100, 50);
|
||||
|
||||
// Hit where layers[3] used to be. It should now hit the root.
|
||||
|
@ -2433,18 +2426,16 @@ TEST_F(APZHitTestingTester, HitTesting2) {
|
|||
EXPECT_EQ(apzcroot, hit.get());
|
||||
// transformToApzc doesn't unapply the root's own async transform
|
||||
EXPECT_EQ(ParentLayerPoint(75, 75), transformToApzc * ScreenPoint(75, 75));
|
||||
// transformToGecko unapplies the full async transform of -100 pixels, and then
|
||||
// reapplies the "D" transform of -50 leading to an overall adjustment of +50
|
||||
EXPECT_EQ(ScreenPoint(75, 125), transformToGecko * ParentLayerPoint(75, 75));
|
||||
// transformToGecko unapplies the full async transform of -100 pixels
|
||||
EXPECT_EQ(ScreenPoint(75, 75), transformToGecko * ParentLayerPoint(75, 75));
|
||||
|
||||
// Hit where layers[1] used to be. It should now hit the root.
|
||||
hit = GetTargetAPZC(ScreenPoint(25, 25));
|
||||
EXPECT_EQ(apzcroot, hit.get());
|
||||
// transformToApzc doesn't unapply the root's own async transform
|
||||
EXPECT_EQ(ParentLayerPoint(25, 25), transformToApzc * ScreenPoint(25, 25));
|
||||
// transformToGecko unapplies the full async transform of -100 pixels, and then
|
||||
// reapplies the "D" transform of -50 leading to an overall adjustment of +50
|
||||
EXPECT_EQ(ScreenPoint(25, 75), transformToGecko * ParentLayerPoint(25, 25));
|
||||
// transformToGecko unapplies the full async transform of -100 pixels
|
||||
EXPECT_EQ(ScreenPoint(25, 25), transformToGecko * ParentLayerPoint(25, 25));
|
||||
}
|
||||
|
||||
TEST_F(APZCTreeManagerTester, ScrollablePaintedLayers) {
|
||||
|
@ -3497,89 +3488,3 @@ public:
|
|||
private:
|
||||
TaskRunMetrics& mMetrics;
|
||||
};
|
||||
|
||||
class APZTaskThrottlerTester : public ::testing::Test {
|
||||
public:
|
||||
APZTaskThrottlerTester()
|
||||
{
|
||||
now = TimeStamp::Now();
|
||||
throttler = new TaskThrottler(now, TimeDuration::FromMilliseconds(100));
|
||||
}
|
||||
|
||||
protected:
|
||||
TimeStamp Advance(int aMillis = 5)
|
||||
{
|
||||
now = now + TimeDuration::FromMilliseconds(aMillis);
|
||||
return now;
|
||||
}
|
||||
|
||||
UniquePtr<CancelableTask> NewTask()
|
||||
{
|
||||
return MakeUnique<MockTask>(metrics);
|
||||
}
|
||||
|
||||
TimeStamp now;
|
||||
RefPtr<TaskThrottler> throttler;
|
||||
TaskRunMetrics metrics;
|
||||
};
|
||||
|
||||
TEST_F(APZTaskThrottlerTester, BasicTest) {
|
||||
// Check that posting the first task runs right away
|
||||
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 1
|
||||
EXPECT_EQ(1, metrics.GetAndClearRunCount());
|
||||
|
||||
// Check that posting the second task doesn't run until the first one is done
|
||||
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 2
|
||||
EXPECT_EQ(0, metrics.GetAndClearRunCount());
|
||||
throttler->TaskComplete(Advance()); // for task 1
|
||||
EXPECT_EQ(1, metrics.GetAndClearRunCount());
|
||||
EXPECT_EQ(0, metrics.GetAndClearCancelCount());
|
||||
|
||||
// Check that tasks are coalesced: dispatch 5 tasks
|
||||
// while there is still one outstanding, and ensure
|
||||
// that only one of the 5 runs
|
||||
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 3
|
||||
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 4
|
||||
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 5
|
||||
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 6
|
||||
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 7
|
||||
EXPECT_EQ(0, metrics.GetAndClearRunCount());
|
||||
EXPECT_EQ(4, metrics.GetAndClearCancelCount());
|
||||
|
||||
throttler->TaskComplete(Advance()); // for task 2
|
||||
EXPECT_EQ(1, metrics.GetAndClearRunCount());
|
||||
throttler->TaskComplete(Advance()); // for task 7 (tasks 3..6 were cancelled)
|
||||
EXPECT_EQ(0, metrics.GetAndClearRunCount());
|
||||
EXPECT_EQ(0, metrics.GetAndClearCancelCount());
|
||||
}
|
||||
|
||||
TEST_F(APZTaskThrottlerTester, TimeoutTest) {
|
||||
// Check that posting the first task runs right away
|
||||
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 1
|
||||
EXPECT_EQ(1, metrics.GetAndClearRunCount());
|
||||
|
||||
// Because we let 100ms pass, the second task should
|
||||
// run immediately even though the first one isn't
|
||||
// done yet
|
||||
throttler->PostTask(FROM_HERE, NewTask(), Advance(100)); // task 2; task 1 is assumed lost
|
||||
EXPECT_EQ(1, metrics.GetAndClearRunCount());
|
||||
throttler->TaskComplete(Advance()); // for task 1, but TaskThrottler thinks it's for task 2
|
||||
throttler->TaskComplete(Advance()); // for task 2, TaskThrottler ignores it
|
||||
EXPECT_EQ(0, metrics.GetAndClearRunCount());
|
||||
EXPECT_EQ(0, metrics.GetAndClearCancelCount());
|
||||
|
||||
// This time queue up a few tasks before the timeout expires
|
||||
// and ensure cancellation still works as expected
|
||||
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 3
|
||||
EXPECT_EQ(1, metrics.GetAndClearRunCount());
|
||||
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 4
|
||||
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 5
|
||||
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 6
|
||||
EXPECT_EQ(0, metrics.GetAndClearRunCount());
|
||||
throttler->PostTask(FROM_HERE, NewTask(), Advance(100)); // task 7; task 3 is assumed lost
|
||||
EXPECT_EQ(1, metrics.GetAndClearRunCount());
|
||||
EXPECT_EQ(3, metrics.GetAndClearCancelCount()); // tasks 4..6 should have been cancelled
|
||||
throttler->TaskComplete(Advance()); // for task 7
|
||||
EXPECT_EQ(0, metrics.GetAndClearRunCount());
|
||||
EXPECT_EQ(0, metrics.GetAndClearCancelCount());
|
||||
}
|
||||
|
|
|
@ -41,26 +41,26 @@ static void
|
|||
AdjustDisplayPortForScrollDelta(mozilla::layers::FrameMetrics& aFrameMetrics,
|
||||
const CSSPoint& aActualScrollOffset)
|
||||
{
|
||||
// Correct the display-port by the difference between the requested scroll
|
||||
// offset and the resulting scroll offset after setting the requested value.
|
||||
ScreenPoint shift =
|
||||
(aFrameMetrics.GetScrollOffset() - aActualScrollOffset) *
|
||||
aFrameMetrics.DisplayportPixelsPerCSSPixel();
|
||||
ScreenMargin margins = aFrameMetrics.GetDisplayPortMargins();
|
||||
margins.left -= shift.x;
|
||||
margins.right += shift.x;
|
||||
margins.top -= shift.y;
|
||||
margins.bottom += shift.y;
|
||||
aFrameMetrics.SetDisplayPortMargins(margins);
|
||||
// Correct the display-port by the difference between the requested scroll
|
||||
// offset and the resulting scroll offset after setting the requested value.
|
||||
ScreenPoint shift =
|
||||
(aFrameMetrics.GetScrollOffset() - aActualScrollOffset) *
|
||||
aFrameMetrics.DisplayportPixelsPerCSSPixel();
|
||||
ScreenMargin margins = aFrameMetrics.GetDisplayPortMargins();
|
||||
margins.left -= shift.x;
|
||||
margins.right += shift.x;
|
||||
margins.top -= shift.y;
|
||||
margins.bottom += shift.y;
|
||||
aFrameMetrics.SetDisplayPortMargins(margins);
|
||||
}
|
||||
|
||||
static void
|
||||
RecenterDisplayPort(mozilla::layers::FrameMetrics& aFrameMetrics)
|
||||
{
|
||||
ScreenMargin margins = aFrameMetrics.GetDisplayPortMargins();
|
||||
margins.right = margins.left = margins.LeftRight() / 2;
|
||||
margins.top = margins.bottom = margins.TopBottom() / 2;
|
||||
aFrameMetrics.SetDisplayPortMargins(margins);
|
||||
ScreenMargin margins = aFrameMetrics.GetDisplayPortMargins();
|
||||
margins.right = margins.left = margins.LeftRight() / 2;
|
||||
margins.top = margins.bottom = margins.TopBottom() / 2;
|
||||
aFrameMetrics.SetDisplayPortMargins(margins);
|
||||
}
|
||||
|
||||
static CSSPoint
|
||||
|
@ -128,9 +128,20 @@ ScrollFrame(nsIContent* aContent,
|
|||
CSSPoint actualScrollOffset = ScrollFrameTo(sf, apzScrollOffset, scrollUpdated);
|
||||
|
||||
if (scrollUpdated) {
|
||||
// Correct the display port due to the difference between mScrollOffset and the
|
||||
// actual scroll offset.
|
||||
AdjustDisplayPortForScrollDelta(aMetrics, actualScrollOffset);
|
||||
if (aMetrics.IsScrollInfoLayer()) {
|
||||
// In cases where the APZ scroll offset is different from the content scroll
|
||||
// offset, we want to interpret the margins as relative to the APZ scroll
|
||||
// offset except when the frame is not scrollable by APZ. Therefore, if the
|
||||
// layer is a scroll info layer, we leave the margins as-is and they will
|
||||
// be interpreted as relative to the content scroll offset.
|
||||
if (nsIFrame* frame = aContent->GetPrimaryFrame()) {
|
||||
frame->SchedulePaint();
|
||||
}
|
||||
} else {
|
||||
// Correct the display port due to the difference between mScrollOffset and the
|
||||
// actual scroll offset.
|
||||
AdjustDisplayPortForScrollDelta(aMetrics, actualScrollOffset);
|
||||
}
|
||||
} else {
|
||||
// For whatever reason we couldn't update the scroll offset on the scroll frame,
|
||||
// which means the data APZ used for its displayport calculation is stale. Fall
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "BasicLayersImpl.h" // for FillRectWithMask
|
||||
#include "TextureHostBasic.h"
|
||||
#include "mozilla/layers/Effects.h"
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
#include "mozilla/layers/ImageDataSerializer.h"
|
||||
#include "mozilla/layers/TextureClientRecycleAllocator.h"
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "ImageContainer.h" // for PlanarYCbCrData, etc
|
||||
|
@ -838,10 +837,10 @@ TextureClient::CreateForYCbCr(ISurfaceAllocator* aAllocator,
|
|||
|
||||
// static
|
||||
already_AddRefed<TextureClient>
|
||||
TextureClient::CreateWithBufferSize(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
size_t aSize,
|
||||
TextureFlags aTextureFlags)
|
||||
TextureClient::CreateForYCbCrWithBufferSize(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
size_t aSize,
|
||||
TextureFlags aTextureFlags)
|
||||
{
|
||||
// also test the validity of aAllocator
|
||||
MOZ_ASSERT(aAllocator && aAllocator->IPCOpen());
|
||||
|
@ -849,8 +848,9 @@ TextureClient::CreateWithBufferSize(ISurfaceAllocator* aAllocator,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
TextureData* data = BufferTextureData::CreateWithBufferSize(aAllocator, aFormat, aSize,
|
||||
aTextureFlags);
|
||||
TextureData* data =
|
||||
BufferTextureData::CreateForYCbCrWithBufferSize(aAllocator, aFormat, aSize,
|
||||
aTextureFlags);
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -297,10 +297,10 @@ public:
|
|||
// pointers) with a certain buffer size. It's unfortunate that we need this.
|
||||
// providing format and sizes could let us do more optimization.
|
||||
static already_AddRefed<TextureClient>
|
||||
CreateWithBufferSize(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
size_t aSize,
|
||||
TextureFlags aTextureFlags);
|
||||
CreateForYCbCrWithBufferSize(ISurfaceAllocator* aAllocator,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
size_t aSize,
|
||||
TextureFlags aTextureFlags);
|
||||
|
||||
// Creates and allocates a TextureClient of the same type.
|
||||
already_AddRefed<TextureClient>
|
||||
|
|
|
@ -13,10 +13,9 @@
|
|||
#include "mozilla/layers/CompositableTransactionParent.h" // for CompositableParentManager
|
||||
#include "mozilla/layers/Compositor.h" // for Compositor
|
||||
#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator
|
||||
#include "mozilla/layers/ImageDataSerializer.h"
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
|
||||
#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include "mozilla/layers/ImageDataSerializer.h"
|
||||
#include "nsAString.h"
|
||||
#include "mozilla/RefPtr.h" // for nsRefPtr
|
||||
#include "nsPrintfCString.h" // for nsPrintfCString
|
||||
|
@ -95,7 +94,8 @@ TextureHost::CreateIPDLActor(CompositableParentManager* aManager,
|
|||
LayersBackend aLayersBackend,
|
||||
TextureFlags aFlags)
|
||||
{
|
||||
if (aSharedData.type() == SurfaceDescriptor::TSurfaceDescriptorMemory &&
|
||||
if (aSharedData.type() == SurfaceDescriptor::TSurfaceDescriptorBuffer &&
|
||||
aSharedData.get_SurfaceDescriptorBuffer().data().type() == MemoryOrShmem::Tuintptr_t &&
|
||||
!aManager->IsSameProcess())
|
||||
{
|
||||
NS_ERROR("A client process is trying to peek at our address space using a MemoryTexture!");
|
||||
|
@ -202,8 +202,7 @@ TextureHost::Create(const SurfaceDescriptor& aDesc,
|
|||
TextureFlags aFlags)
|
||||
{
|
||||
switch (aDesc.type()) {
|
||||
case SurfaceDescriptor::TSurfaceDescriptorShmem:
|
||||
case SurfaceDescriptor::TSurfaceDescriptorMemory:
|
||||
case SurfaceDescriptor::TSurfaceDescriptorBuffer:
|
||||
case SurfaceDescriptor::TSurfaceDescriptorDIB:
|
||||
case SurfaceDescriptor::TSurfaceDescriptorFileMapping:
|
||||
return CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags);
|
||||
|
@ -252,19 +251,26 @@ CreateBackendIndependentTextureHost(const SurfaceDescriptor& aDesc,
|
|||
{
|
||||
RefPtr<TextureHost> result;
|
||||
switch (aDesc.type()) {
|
||||
case SurfaceDescriptor::TSurfaceDescriptorShmem: {
|
||||
const SurfaceDescriptorShmem& descriptor = aDesc.get_SurfaceDescriptorShmem();
|
||||
result = new ShmemTextureHost(descriptor.data(),
|
||||
descriptor.format(),
|
||||
aDeallocator,
|
||||
aFlags);
|
||||
break;
|
||||
}
|
||||
case SurfaceDescriptor::TSurfaceDescriptorMemory: {
|
||||
const SurfaceDescriptorMemory& descriptor = aDesc.get_SurfaceDescriptorMemory();
|
||||
result = new MemoryTextureHost(reinterpret_cast<uint8_t*>(descriptor.data()),
|
||||
descriptor.format(),
|
||||
aFlags);
|
||||
case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
|
||||
const SurfaceDescriptorBuffer& bufferDesc = aDesc.get_SurfaceDescriptorBuffer();
|
||||
const MemoryOrShmem& data = bufferDesc.data();
|
||||
switch (data.type()) {
|
||||
case MemoryOrShmem::TShmem: {
|
||||
result = new ShmemTextureHost(data.get_Shmem(),
|
||||
bufferDesc.desc(),
|
||||
aDeallocator,
|
||||
aFlags);
|
||||
break;
|
||||
}
|
||||
case MemoryOrShmem::Tuintptr_t: {
|
||||
result = new MemoryTextureHost(reinterpret_cast<uint8_t*>(data.get_uintptr_t()),
|
||||
bufferDesc.desc(),
|
||||
aFlags);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef XP_WIN
|
||||
|
@ -368,15 +374,30 @@ TextureSource::~TextureSource()
|
|||
MOZ_COUNT_DTOR(TextureSource);
|
||||
}
|
||||
|
||||
BufferTextureHost::BufferTextureHost(gfx::SurfaceFormat aFormat,
|
||||
BufferTextureHost::BufferTextureHost(const BufferDescriptor& aDesc,
|
||||
TextureFlags aFlags)
|
||||
: TextureHost(aFlags)
|
||||
, mCompositor(nullptr)
|
||||
, mFormat(aFormat)
|
||||
, mUpdateSerial(1)
|
||||
, mLocked(false)
|
||||
, mNeedsFullUpdate(false)
|
||||
{
|
||||
mDescriptor = aDesc;
|
||||
switch (mDescriptor.type()) {
|
||||
case BufferDescriptor::TYCbCrDescriptor: {
|
||||
const YCbCrDescriptor& ycbcr = mDescriptor.get_YCbCrDescriptor();
|
||||
mSize = ycbcr.ySize();
|
||||
mFormat = gfx::SurfaceFormat::YUV;
|
||||
break;
|
||||
}
|
||||
case BufferDescriptor::TRGBDescriptor: {
|
||||
const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor();
|
||||
mSize = rgb.size();
|
||||
mFormat = rgb.format();
|
||||
break;
|
||||
}
|
||||
default: MOZ_CRASH();
|
||||
}
|
||||
if (aFlags & TextureFlags::COMPONENT_ALPHA) {
|
||||
// One texture of a component alpha texture pair will start out all white.
|
||||
// This hack allows us to easily make sure that white will be uploaded.
|
||||
|
@ -385,22 +406,6 @@ BufferTextureHost::BufferTextureHost(gfx::SurfaceFormat aFormat,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
BufferTextureHost::InitSize()
|
||||
{
|
||||
if (mFormat == gfx::SurfaceFormat::YUV) {
|
||||
YCbCrImageDataDeserializer yuvDeserializer(GetBuffer(), GetBufferSize());
|
||||
if (yuvDeserializer.IsValid()) {
|
||||
mSize = yuvDeserializer.GetYSize();
|
||||
}
|
||||
} else if (mFormat != gfx::SurfaceFormat::UNKNOWN) {
|
||||
ImageDataDeserializer deserializer(GetBuffer(), GetBufferSize());
|
||||
if (deserializer.IsValid()) {
|
||||
mSize = deserializer.GetSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BufferTextureHost::~BufferTextureHost()
|
||||
{}
|
||||
|
||||
|
@ -512,7 +517,8 @@ BufferTextureHost::MaybeUpload(nsIntRegion *aRegion)
|
|||
bool
|
||||
BufferTextureHost::Upload(nsIntRegion *aRegion)
|
||||
{
|
||||
if (!GetBuffer()) {
|
||||
uint8_t* buf = GetBuffer();
|
||||
if (!buf) {
|
||||
// We don't have a buffer; a possible cause is that the IPDL actor
|
||||
// is already dead. This inevitably happens as IPDL actors can die
|
||||
// at any time, so we want to silently return in this case.
|
||||
|
@ -527,11 +533,11 @@ BufferTextureHost::Upload(nsIntRegion *aRegion)
|
|||
NS_WARNING("BufferTextureHost: unsupported format!");
|
||||
return false;
|
||||
} else if (mFormat == gfx::SurfaceFormat::YUV) {
|
||||
YCbCrImageDataDeserializer yuvDeserializer(GetBuffer(), GetBufferSize());
|
||||
MOZ_ASSERT(yuvDeserializer.IsValid());
|
||||
const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
|
||||
|
||||
if (!mCompositor->SupportsEffect(EffectTypes::YCBCR)) {
|
||||
RefPtr<gfx::DataSourceSurface> surf = yuvDeserializer.ToDataSourceSurface();
|
||||
RefPtr<gfx::DataSourceSurface> surf =
|
||||
ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor(buf, mDescriptor.get_YCbCrDescriptor());
|
||||
if (NS_WARN_IF(!surf)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -565,21 +571,20 @@ BufferTextureHost::Upload(nsIntRegion *aRegion)
|
|||
srcV = mFirstSource->GetNextSibling()->GetNextSibling()->AsDataTextureSource();
|
||||
}
|
||||
|
||||
|
||||
RefPtr<gfx::DataSourceSurface> tempY =
|
||||
gfx::Factory::CreateWrappingDataSourceSurface(yuvDeserializer.GetYData(),
|
||||
yuvDeserializer.GetYStride(),
|
||||
yuvDeserializer.GetYSize(),
|
||||
gfx::Factory::CreateWrappingDataSourceSurface(ImageDataSerializer::GetYChannel(buf, desc),
|
||||
desc.ySize().width,
|
||||
desc.ySize(),
|
||||
gfx::SurfaceFormat::A8);
|
||||
RefPtr<gfx::DataSourceSurface> tempCb =
|
||||
gfx::Factory::CreateWrappingDataSourceSurface(yuvDeserializer.GetCbData(),
|
||||
yuvDeserializer.GetCbCrStride(),
|
||||
yuvDeserializer.GetCbCrSize(),
|
||||
gfx::Factory::CreateWrappingDataSourceSurface(ImageDataSerializer::GetCbChannel(buf, desc),
|
||||
desc.cbCrSize().width,
|
||||
desc.cbCrSize(),
|
||||
gfx::SurfaceFormat::A8);
|
||||
RefPtr<gfx::DataSourceSurface> tempCr =
|
||||
gfx::Factory::CreateWrappingDataSourceSurface(yuvDeserializer.GetCrData(),
|
||||
yuvDeserializer.GetCbCrStride(),
|
||||
yuvDeserializer.GetCbCrSize(),
|
||||
gfx::Factory::CreateWrappingDataSourceSurface(ImageDataSerializer::GetCrChannel(buf, desc),
|
||||
desc.cbCrSize().width,
|
||||
desc.cbCrSize(),
|
||||
gfx::SurfaceFormat::A8);
|
||||
// We don't support partial updates for Y U V textures
|
||||
NS_ASSERTION(!aRegion, "Unsupported partial updates for YCbCr textures");
|
||||
|
@ -602,13 +607,10 @@ BufferTextureHost::Upload(nsIntRegion *aRegion)
|
|||
regionToUpdate = nullptr;
|
||||
}
|
||||
}
|
||||
ImageDataDeserializer deserializer(GetBuffer(), GetBufferSize());
|
||||
if (!deserializer.IsValid()) {
|
||||
NS_ERROR("Failed to deserialize image!");
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<gfx::DataSourceSurface> surf = deserializer.GetAsSurface();
|
||||
RefPtr<gfx::DataSourceSurface> surf =
|
||||
gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(),
|
||||
ImageDataSerializer::ComputeRGBStride(mFormat, mSize.width), mSize, mFormat);
|
||||
if (!surf) {
|
||||
return false;
|
||||
}
|
||||
|
@ -630,35 +632,29 @@ BufferTextureHost::GetAsSurface()
|
|||
NS_WARNING("BufferTextureHost: unsupported format!");
|
||||
return nullptr;
|
||||
} else if (mFormat == gfx::SurfaceFormat::YUV) {
|
||||
YCbCrImageDataDeserializer yuvDeserializer(GetBuffer(), GetBufferSize());
|
||||
if (!yuvDeserializer.IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
result = yuvDeserializer.ToDataSourceSurface();
|
||||
result = ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor(
|
||||
GetBuffer(), mDescriptor.get_YCbCrDescriptor());
|
||||
if (NS_WARN_IF(!result)) {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
ImageDataDeserializer deserializer(GetBuffer(), GetBufferSize());
|
||||
if (!deserializer.IsValid()) {
|
||||
NS_ERROR("Failed to deserialize image!");
|
||||
return nullptr;
|
||||
}
|
||||
result = deserializer.GetAsSurface();
|
||||
RefPtr<gfx::DataSourceSurface> surf =
|
||||
gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(),
|
||||
ImageDataSerializer::GetRGBStride(mDescriptor.get_RGBDescriptor()),
|
||||
mSize, mFormat);
|
||||
}
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
ShmemTextureHost::ShmemTextureHost(const ipc::Shmem& aShmem,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
const BufferDescriptor& aDesc,
|
||||
ISurfaceAllocator* aDeallocator,
|
||||
TextureFlags aFlags)
|
||||
: BufferTextureHost(aFormat, aFlags)
|
||||
: BufferTextureHost(aDesc, aFlags)
|
||||
, mShmem(MakeUnique<ipc::Shmem>(aShmem))
|
||||
, mDeallocator(aDeallocator)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ShmemTextureHost);
|
||||
InitSize();
|
||||
}
|
||||
|
||||
ShmemTextureHost::~ShmemTextureHost()
|
||||
|
@ -705,13 +701,12 @@ size_t ShmemTextureHost::GetBufferSize()
|
|||
}
|
||||
|
||||
MemoryTextureHost::MemoryTextureHost(uint8_t* aBuffer,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
const BufferDescriptor& aDesc,
|
||||
TextureFlags aFlags)
|
||||
: BufferTextureHost(aFormat, aFlags)
|
||||
: BufferTextureHost(aDesc, aFlags)
|
||||
, mBuffer(aBuffer)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MemoryTextureHost);
|
||||
InitSize();
|
||||
}
|
||||
|
||||
MemoryTextureHost::~MemoryTextureHost()
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "mozilla/layers/CompositorTypes.h" // for TextureFlags, etc
|
||||
#include "mozilla/layers/FenceUtils.h" // for FenceHandle
|
||||
#include "mozilla/layers/LayersTypes.h" // for LayerRenderState, etc
|
||||
#include "mozilla/layers/LayersSurfaces.h"
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "mozilla/UniquePtr.h" // for UniquePtr
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
|
@ -37,6 +38,7 @@ class Shmem;
|
|||
|
||||
namespace layers {
|
||||
|
||||
class BufferDescriptor;
|
||||
class Compositor;
|
||||
class CompositableParentManager;
|
||||
class SurfaceDescriptor;
|
||||
|
@ -567,8 +569,7 @@ protected:
|
|||
class BufferTextureHost : public TextureHost
|
||||
{
|
||||
public:
|
||||
BufferTextureHost(gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags);
|
||||
BufferTextureHost(const BufferDescriptor& aDescriptor, TextureFlags aFlags);
|
||||
|
||||
~BufferTextureHost();
|
||||
|
||||
|
@ -605,15 +606,13 @@ protected:
|
|||
bool Upload(nsIntRegion *aRegion = nullptr);
|
||||
bool MaybeUpload(nsIntRegion *aRegion = nullptr);
|
||||
|
||||
void InitSize();
|
||||
|
||||
virtual void UpdatedInternal(const nsIntRegion* aRegion = nullptr) override;
|
||||
|
||||
BufferDescriptor mDescriptor;
|
||||
RefPtr<Compositor> mCompositor;
|
||||
RefPtr<DataTextureSource> mFirstSource;
|
||||
nsIntRegion mMaybeUpdatedRegion;
|
||||
gfx::IntSize mSize;
|
||||
// format of the data that is shared with the content process.
|
||||
gfx::SurfaceFormat mFormat;
|
||||
uint32_t mUpdateSerial;
|
||||
bool mLocked;
|
||||
|
@ -629,7 +628,7 @@ class ShmemTextureHost : public BufferTextureHost
|
|||
{
|
||||
public:
|
||||
ShmemTextureHost(const mozilla::ipc::Shmem& aShmem,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
const BufferDescriptor& aDesc,
|
||||
ISurfaceAllocator* aDeallocator,
|
||||
TextureFlags aFlags);
|
||||
|
||||
|
@ -664,7 +663,7 @@ class MemoryTextureHost : public BufferTextureHost
|
|||
{
|
||||
public:
|
||||
MemoryTextureHost(uint8_t* aBuffer,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
const BufferDescriptor& aDesc,
|
||||
TextureFlags aFlags);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "CompositorD3D11.h"
|
||||
#include "gfxContext.h"
|
||||
#include "Effects.h"
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxPrefs.h"
|
||||
|
@ -665,8 +664,7 @@ CreateTextureHostD3D11(const SurfaceDescriptor& aDesc,
|
|||
{
|
||||
RefPtr<TextureHost> result;
|
||||
switch (aDesc.type()) {
|
||||
case SurfaceDescriptor::TSurfaceDescriptorShmem:
|
||||
case SurfaceDescriptor::TSurfaceDescriptorMemory: {
|
||||
case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
|
||||
result = CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include "gfxContext.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "Effects.h"
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxUtils.h"
|
||||
|
@ -53,8 +52,7 @@ CreateTextureHostD3D9(const SurfaceDescriptor& aDesc,
|
|||
{
|
||||
RefPtr<TextureHost> result;
|
||||
switch (aDesc.type()) {
|
||||
case SurfaceDescriptor::TSurfaceDescriptorShmem:
|
||||
case SurfaceDescriptor::TSurfaceDescriptorMemory: {
|
||||
case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
|
||||
result = CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags);
|
||||
break;
|
||||
}
|
||||
|
@ -192,7 +190,7 @@ TextureSourceD3D9::InitTextures(DeviceManagerD3D9* aDeviceManager,
|
|||
}
|
||||
|
||||
tmpTexture->GetSurfaceLevel(0, getter_AddRefs(aSurface));
|
||||
|
||||
|
||||
HRESULT hr = aSurface->LockRect(&aLockedRect, nullptr, 0);
|
||||
if (FAILED(hr) || !aLockedRect.pBits) {
|
||||
gfxCriticalError() << "Failed to lock rect initialize texture in D3D9 " << hexa(hr);
|
||||
|
|
|
@ -1546,10 +1546,6 @@ CompositorParent::RecvNotifyChildCreated(const uint64_t& child)
|
|||
void
|
||||
CompositorParent::NotifyChildCreated(const uint64_t& aChild)
|
||||
{
|
||||
if (mApzcTreeManager) {
|
||||
NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<uint64_t>(
|
||||
mApzcTreeManager, &APZCTreeManager::InitializeForLayersId, aChild));
|
||||
}
|
||||
sIndirectLayerTreesLock->AssertCurrentThreadOwns();
|
||||
sIndirectLayerTrees[aChild].mParent = this;
|
||||
sIndirectLayerTrees[aChild].mLayerManager = mLayerManager;
|
||||
|
@ -1559,9 +1555,6 @@ bool
|
|||
CompositorParent::RecvAdoptChild(const uint64_t& child)
|
||||
{
|
||||
MonitorAutoLock lock(*sIndirectLayerTreesLock);
|
||||
if (mApzcTreeManager) {
|
||||
mApzcTreeManager->AdoptLayersId(child, sIndirectLayerTrees[child].mParent->mApzcTreeManager.get());
|
||||
}
|
||||
NotifyChildCreated(child);
|
||||
if (sIndirectLayerTrees[child].mLayerTree) {
|
||||
sIndirectLayerTrees[child].mLayerTree->mLayerManager = mLayerManager;
|
||||
|
@ -1633,7 +1626,6 @@ ScopedLayerTreeRegistration::ScopedLayerTreeRegistration(APZCTreeManager* aApzct
|
|||
: mLayersId(aLayersId)
|
||||
{
|
||||
EnsureLayerTreeMapReady();
|
||||
aApzctm->InitializeForLayersId(aLayersId);
|
||||
MonitorAutoLock lock(*sIndirectLayerTreesLock);
|
||||
sIndirectLayerTrees[aLayersId].mRoot = aRoot;
|
||||
sIndirectLayerTrees[aLayersId].mController = aController;
|
||||
|
@ -1649,9 +1641,6 @@ ScopedLayerTreeRegistration::~ScopedLayerTreeRegistration()
|
|||
CompositorParent::SetControllerForLayerTree(uint64_t aLayersId,
|
||||
GeckoContentController* aController)
|
||||
{
|
||||
if (APZCTreeManager* apzctm = GetAPZCTreeManager(aLayersId)) {
|
||||
apzctm->InitializeForLayersId(aLayersId);
|
||||
}
|
||||
// This ref is adopted by UpdateControllerForLayersId().
|
||||
aController->AddRef();
|
||||
CompositorLoop()->PostTask(FROM_HERE,
|
||||
|
|
|
@ -60,38 +60,38 @@ ISurfaceAllocator::Finalize()
|
|||
}
|
||||
|
||||
static inline uint8_t*
|
||||
GetAddressFromDescriptor(const SurfaceDescriptor& aDescriptor, size_t& aSize)
|
||||
GetAddressFromDescriptor(const SurfaceDescriptor& aDescriptor)
|
||||
{
|
||||
MOZ_ASSERT(IsSurfaceDescriptorValid(aDescriptor));
|
||||
MOZ_ASSERT(aDescriptor.type() == SurfaceDescriptor::TSurfaceDescriptorShmem ||
|
||||
aDescriptor.type() == SurfaceDescriptor::TSurfaceDescriptorMemory);
|
||||
if (aDescriptor.type() == SurfaceDescriptor::TSurfaceDescriptorShmem) {
|
||||
Shmem shmem(aDescriptor.get_SurfaceDescriptorShmem().data());
|
||||
aSize = shmem.Size<uint8_t>();
|
||||
return shmem.get<uint8_t>();
|
||||
MOZ_RELEASE_ASSERT(aDescriptor.type() == SurfaceDescriptor::TSurfaceDescriptorBuffer);
|
||||
|
||||
auto memOrShmem = aDescriptor.get_SurfaceDescriptorBuffer().data();
|
||||
if (memOrShmem.type() == MemoryOrShmem::TShmem) {
|
||||
return memOrShmem.get_Shmem().get<uint8_t>();
|
||||
} else {
|
||||
const SurfaceDescriptorMemory& image = aDescriptor.get_SurfaceDescriptorMemory();
|
||||
aSize = std::numeric_limits<size_t>::max();
|
||||
return reinterpret_cast<uint8_t*>(image.data());
|
||||
return reinterpret_cast<uint8_t*>(memOrShmem.get_uintptr_t());
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::DrawTarget>
|
||||
GetDrawTargetForDescriptor(const SurfaceDescriptor& aDescriptor, gfx::BackendType aBackend)
|
||||
{
|
||||
size_t size;
|
||||
uint8_t* data = GetAddressFromDescriptor(aDescriptor, size);
|
||||
ImageDataDeserializer image(data, size);
|
||||
return image.GetAsDrawTarget(aBackend);
|
||||
uint8_t* data = GetAddressFromDescriptor(aDescriptor);
|
||||
auto rgb = aDescriptor.get_SurfaceDescriptorBuffer().desc().get_RGBDescriptor();
|
||||
uint32_t stride = ImageDataSerializer::GetRGBStride(rgb);
|
||||
return gfx::Factory::CreateDrawTargetForData(gfx::BackendType::CAIRO,
|
||||
data, rgb.size(),
|
||||
stride, rgb.format());
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::DataSourceSurface>
|
||||
GetSurfaceForDescriptor(const SurfaceDescriptor& aDescriptor)
|
||||
{
|
||||
size_t size;
|
||||
uint8_t* data = GetAddressFromDescriptor(aDescriptor, size);
|
||||
ImageDataDeserializer image(data, size);
|
||||
return image.GetAsSurface();
|
||||
uint8_t* data = GetAddressFromDescriptor(aDescriptor);
|
||||
auto rgb = aDescriptor.get_SurfaceDescriptorBuffer().desc().get_RGBDescriptor();
|
||||
uint32_t stride = ImageDataSerializer::GetRGBStride(rgb);
|
||||
return gfx::Factory::CreateWrappingDataSourceSurface(data, stride, rgb.size(),
|
||||
rgb.format());
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -116,12 +116,14 @@ ISurfaceAllocator::AllocSurfaceDescriptorWithCaps(const gfx::IntSize& aSize,
|
|||
}
|
||||
gfx::SurfaceFormat format =
|
||||
gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aContent);
|
||||
size_t size = ImageDataSerializer::ComputeMinBufferSize(aSize, format);
|
||||
size_t size = ImageDataSerializer::ComputeRGBBufferSize(aSize, format);
|
||||
if (!size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MemoryOrShmem bufferDesc;
|
||||
if (IsSameProcess()) {
|
||||
uint8_t *data = new (std::nothrow) uint8_t[size];
|
||||
uint8_t* data = new (std::nothrow) uint8_t[size];
|
||||
if (!data) {
|
||||
return false;
|
||||
}
|
||||
|
@ -133,7 +135,7 @@ ISurfaceAllocator::AllocSurfaceDescriptorWithCaps(const gfx::IntSize& aSize,
|
|||
memset(data, 0, size);
|
||||
}
|
||||
#endif
|
||||
*aBuffer = SurfaceDescriptorMemory((uintptr_t)data, format);
|
||||
bufferDesc = reinterpret_cast<uintptr_t>(data);
|
||||
} else {
|
||||
|
||||
mozilla::ipc::SharedMemory::SharedMemoryType shmemType = OptimalShmemType();
|
||||
|
@ -142,19 +144,19 @@ ISurfaceAllocator::AllocSurfaceDescriptorWithCaps(const gfx::IntSize& aSize,
|
|||
return false;
|
||||
}
|
||||
|
||||
*aBuffer = SurfaceDescriptorShmem(shmem, format);
|
||||
bufferDesc = shmem;
|
||||
}
|
||||
|
||||
uint8_t* data = GetAddressFromDescriptor(*aBuffer, size);
|
||||
ImageDataSerializer serializer(data, size);
|
||||
serializer.InitializeBufferInfo(aSize, format);
|
||||
|
||||
*aBuffer = SurfaceDescriptorBuffer(RGBDescriptor(aSize, format), bufferDesc);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
ISurfaceAllocator::IsShmem(SurfaceDescriptor* aSurface)
|
||||
{
|
||||
return aSurface && (aSurface->type() == SurfaceDescriptor::TSurfaceDescriptorShmem);
|
||||
return aSurface && (aSurface->type() == SurfaceDescriptor::TSurfaceDescriptorBuffer)
|
||||
&& (aSurface->get_SurfaceDescriptorBuffer().data().type() == MemoryOrShmem::TShmem);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -172,17 +174,18 @@ ISurfaceAllocator::DestroySharedSurface(SurfaceDescriptor* aSurface)
|
|||
if (!IPCOpen()) {
|
||||
return;
|
||||
}
|
||||
switch (aSurface->type()) {
|
||||
case SurfaceDescriptor::TSurfaceDescriptorShmem:
|
||||
DeallocShmem(aSurface->get_SurfaceDescriptorShmem().data());
|
||||
SurfaceDescriptorBuffer& desc = aSurface->get_SurfaceDescriptorBuffer();
|
||||
switch (desc.data().type()) {
|
||||
case MemoryOrShmem::TShmem: {
|
||||
DeallocShmem(desc.data().get_Shmem());
|
||||
break;
|
||||
case SurfaceDescriptor::TSurfaceDescriptorMemory:
|
||||
GfxMemoryImageReporter::WillFree((uint8_t*)aSurface->get_SurfaceDescriptorMemory().data());
|
||||
delete [] (uint8_t*)aSurface->get_SurfaceDescriptorMemory().data();
|
||||
break;
|
||||
case SurfaceDescriptor::Tnull_t:
|
||||
case SurfaceDescriptor::T__None:
|
||||
}
|
||||
case MemoryOrShmem::Tuintptr_t: {
|
||||
uint8_t* ptr = (uint8_t*)desc.data().get_uintptr_t();
|
||||
GfxMemoryImageReporter::WillFree(ptr);
|
||||
delete [] ptr;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NS_RUNTIMEABORT("surface type not implemented!");
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ using nsIntRegion from "nsRegion.h";
|
|||
using struct mozilla::layers::MagicGrallocBufferHandle from "gfxipc/ShadowLayerUtils.h";
|
||||
using struct mozilla::layers::GrallocBufferRef from "gfxipc/ShadowLayerUtils.h";
|
||||
using struct mozilla::layers::SurfaceDescriptorX11 from "gfxipc/ShadowLayerUtils.h";
|
||||
using mozilla::StereoMode from "ImageTypes.h";
|
||||
using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
|
||||
using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h";
|
||||
using mozilla::gfx::SurfaceFormat from "mozilla/gfx/Types.h";
|
||||
|
@ -95,25 +96,37 @@ struct SurfaceDescriptorGralloc {
|
|||
bool isOpaque;
|
||||
};
|
||||
|
||||
/**
|
||||
* Used for shmem-backed YCbCr and (flavors of) RGBA textures
|
||||
*/
|
||||
struct SurfaceDescriptorShmem {
|
||||
Shmem data;
|
||||
struct RGBDescriptor {
|
||||
IntSize size;
|
||||
SurfaceFormat format;
|
||||
};
|
||||
|
||||
/**
|
||||
* Used for "raw memory"-backed YCbCr and (flavors of) RGBA textures
|
||||
*/
|
||||
struct SurfaceDescriptorMemory {
|
||||
uintptr_t data;
|
||||
SurfaceFormat format;
|
||||
struct YCbCrDescriptor {
|
||||
IntSize ySize;
|
||||
IntSize cbCrSize;
|
||||
uint32_t yOffset;
|
||||
uint32_t cbOffset;
|
||||
uint32_t crOffset;
|
||||
StereoMode stereoMode;
|
||||
};
|
||||
|
||||
union BufferDescriptor {
|
||||
RGBDescriptor;
|
||||
YCbCrDescriptor;
|
||||
};
|
||||
|
||||
union MemoryOrShmem {
|
||||
uintptr_t;
|
||||
Shmem;
|
||||
};
|
||||
|
||||
struct SurfaceDescriptorBuffer {
|
||||
BufferDescriptor desc;
|
||||
MemoryOrShmem data;
|
||||
};
|
||||
|
||||
union SurfaceDescriptor {
|
||||
SurfaceDescriptorShmem;
|
||||
SurfaceDescriptorMemory;
|
||||
SurfaceDescriptorBuffer;
|
||||
SurfaceDescriptorD3D9;
|
||||
SurfaceDescriptorDIB;
|
||||
SurfaceDescriptorD3D10;
|
||||
|
|
|
@ -319,11 +319,12 @@ ShadowLayerForwarder::CheckSurfaceDescriptor(const SurfaceDescriptor* aDescripto
|
|||
return;
|
||||
}
|
||||
|
||||
if (aDescriptor->type() == SurfaceDescriptor::TSurfaceDescriptorShmem) {
|
||||
const SurfaceDescriptorShmem& shmem = aDescriptor->get_SurfaceDescriptorShmem();
|
||||
shmem.data().AssertInvariants();
|
||||
if (aDescriptor->type() == SurfaceDescriptor::TSurfaceDescriptorBuffer &&
|
||||
aDescriptor->get_SurfaceDescriptorBuffer().data().type() == MemoryOrShmem::TShmem) {
|
||||
const Shmem& shmem = aDescriptor->get_SurfaceDescriptorBuffer().data().get_Shmem();
|
||||
shmem.AssertInvariants();
|
||||
MOZ_ASSERT(mShadowManager &&
|
||||
mShadowManager->IsTrackingSharedMemory(shmem.data().mSegment));
|
||||
mShadowManager->IsTrackingSharedMemory(shmem.mSegment));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "mozilla/layers/BufferTexture.h"
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include "mozilla/layers/ImageDataSerializer.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h" // for ImageBridgeChild
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "nsISupportsImpl.h" // for Image::AddRef
|
||||
|
@ -112,14 +112,14 @@ uint8_t*
|
|||
SharedPlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize)
|
||||
{
|
||||
MOZ_ASSERT(!mTextureClient, "This image already has allocated data");
|
||||
size_t size = YCbCrImageDataSerializer::ComputeMinBufferSize(aSize);
|
||||
size_t size = ImageDataSerializer::ComputeYCbCrBufferSize(aSize);
|
||||
if (!size) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mTextureClient = TextureClient::CreateWithBufferSize(mCompositable->GetForwarder(),
|
||||
gfx::SurfaceFormat::YUV, size,
|
||||
mCompositable->GetTextureFlags());
|
||||
mTextureClient = TextureClient::CreateForYCbCrWithBufferSize(mCompositable->GetForwarder(),
|
||||
gfx::SurfaceFormat::YUV, size,
|
||||
mCompositable->GetTextureFlags());
|
||||
|
||||
// get new buffer _without_ setting mBuffer.
|
||||
if (!mTextureClient) {
|
||||
|
@ -132,11 +132,7 @@ SharedPlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize)
|
|||
MappedYCbCrTextureData mapped;
|
||||
if (mTextureClient->BorrowMappedYCbCrData(mapped)) {
|
||||
// The caller expects a pointer to the beginning of the writable part of the
|
||||
// buffer (after the metadata) which is where the y channel starts by default.
|
||||
// The caller might choose to write the y channel at a different offset and
|
||||
// if it does so, it will also update the metadata.
|
||||
// Anyway, we return the y channel here but the intent is to obtain the start of
|
||||
// the writable part of the buffer.
|
||||
// buffer which is where the y channel starts by default.
|
||||
return mapped.y.data;
|
||||
} else {
|
||||
MOZ_CRASH();
|
||||
|
@ -146,35 +142,26 @@ SharedPlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize)
|
|||
bool
|
||||
SharedPlanarYCbCrImage::SetDataNoCopy(const Data &aData)
|
||||
{
|
||||
// SetDataNoCopy is used to update YUV plane offsets without (re)allocating
|
||||
// memory previously allocated with AllocateAndGetNewBuffer().
|
||||
|
||||
MOZ_ASSERT(mTextureClient, "This Image should have already allocated data");
|
||||
if (!mTextureClient) {
|
||||
return false;
|
||||
}
|
||||
mData = aData;
|
||||
mSize = aData.mPicSize;
|
||||
/* SetDataNoCopy is used to update YUV plane offsets without (re)allocating
|
||||
* memory previously allocated with AllocateAndGetNewBuffer().
|
||||
* serializer.GetData() returns the address of the memory previously allocated
|
||||
* with AllocateAndGetNewBuffer(), that we subtract from the Y, Cb, Cr
|
||||
* channels to compute 0-based offsets to pass to InitializeBufferInfo.
|
||||
*/
|
||||
MappedYCbCrTextureData mapped;
|
||||
if(!mTextureClient->BorrowMappedYCbCrData(mapped)) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
YCbCrImageDataSerializer serializer(mapped.metadata, mBufferSize);
|
||||
uint8_t *base = serializer.GetData();
|
||||
|
||||
uint8_t *base = GetBuffer();
|
||||
uint32_t yOffset = aData.mYChannel - base;
|
||||
uint32_t cbOffset = aData.mCbChannel - base;
|
||||
uint32_t crOffset = aData.mCrChannel - base;
|
||||
serializer.InitializeBufferInfo(yOffset,
|
||||
cbOffset,
|
||||
crOffset,
|
||||
aData.mYStride,
|
||||
aData.mCbCrStride,
|
||||
aData.mYSize,
|
||||
aData.mCbCrSize,
|
||||
aData.mStereoMode);
|
||||
|
||||
static_cast<BufferTextureData*>(mTextureClient->GetInternalData())->SetDesciptor(
|
||||
YCbCrDescriptor(aData.mYSize, aData.mCbCrSize, yOffset, cbOffset, crOffset,
|
||||
aData.mStereoMode)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -232,8 +219,7 @@ SharedPlanarYCbCrImage::Allocate(PlanarYCbCrData& aData)
|
|||
// do not set mBuffer like in PlanarYCbCrImage because the later
|
||||
// will try to manage this memory without knowing it belongs to a
|
||||
// shmem.
|
||||
mBufferSize = YCbCrImageDataSerializer::ComputeMinBufferSize(mData.mYSize,
|
||||
mData.mCbCrSize);
|
||||
mBufferSize = ImageDataSerializer::ComputeYCbCrBufferSize(mData.mYSize, mData.mCbCrSize);
|
||||
mSize = mData.mPicSize;
|
||||
|
||||
mTextureClient->Unlock();
|
||||
|
|
|
@ -180,7 +180,6 @@ EXPORTS.mozilla.layers += [
|
|||
'RenderTrace.h',
|
||||
'TextureWrapperImage.h',
|
||||
'TransactionIdAllocator.h',
|
||||
'YCbCrImageDataSerializer.h',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_X11']:
|
||||
|
@ -250,7 +249,6 @@ UNIFIED_SOURCES += [
|
|||
'apz/src/InputBlockState.cpp',
|
||||
'apz/src/InputQueue.cpp',
|
||||
'apz/src/OverscrollHandoffState.cpp',
|
||||
'apz/src/TaskThrottler.cpp',
|
||||
'apz/src/TouchCounter.cpp',
|
||||
'apz/src/WheelScrollAnimation.cpp',
|
||||
'apz/testutil/APZTestData.cpp',
|
||||
|
@ -352,7 +350,6 @@ UNIFIED_SOURCES += [
|
|||
'RenderTrace.cpp',
|
||||
'RotatedBuffer.cpp',
|
||||
'TextureWrapperImage.cpp',
|
||||
'YCbCrImageDataSerializer.cpp',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "mozilla/gfx/BaseSize.h" // for BaseSize
|
||||
#include "mozilla/gfx/Logging.h" // for gfxCriticalError
|
||||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include "mozilla/layers/GrallocTextureHost.h"
|
||||
#include "nsRegion.h" // for nsIntRegion
|
||||
#include "AndroidSurfaceTexture.h"
|
||||
|
@ -52,8 +51,7 @@ CreateTextureHostOGL(const SurfaceDescriptor& aDesc,
|
|||
{
|
||||
RefPtr<TextureHost> result;
|
||||
switch (aDesc.type()) {
|
||||
case SurfaceDescriptor::TSurfaceDescriptorShmem:
|
||||
case SurfaceDescriptor::TSurfaceDescriptorMemory: {
|
||||
case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
|
||||
result = CreateBackendIndependentTextureHost(aDesc,
|
||||
aDeallocator, aFlags);
|
||||
break;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "gfxImageSurface.h"
|
||||
#include "gfxTypes.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include "mozilla/layers/ImageDataSerializer.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
@ -119,31 +119,6 @@ void AssertSurfacesEqual(SourceSurface* surface1,
|
|||
dataSurface2->Unmap();
|
||||
}
|
||||
|
||||
// Same as above, for YCbCr surfaces
|
||||
void AssertYCbCrSurfacesEqual(PlanarYCbCrData* surface1,
|
||||
PlanarYCbCrData* surface2)
|
||||
{
|
||||
ASSERT_EQ(surface1->mYSize, surface2->mYSize);
|
||||
ASSERT_EQ(surface1->mCbCrSize, surface2->mCbCrSize);
|
||||
ASSERT_EQ(surface1->mStereoMode, surface2->mStereoMode);
|
||||
ASSERT_EQ(surface1->mPicSize, surface2->mPicSize);
|
||||
|
||||
for (int y = 0; y < surface1->mYSize.height; ++y) {
|
||||
for (int x = 0; x < surface1->mYSize.width; ++x) {
|
||||
ASSERT_EQ(surface1->mYChannel[y*surface1->mYStride + x*(1+surface1->mYSkip)],
|
||||
surface2->mYChannel[y*surface2->mYStride + x*(1+surface2->mYSkip)]);
|
||||
}
|
||||
}
|
||||
for (int y = 0; y < surface1->mCbCrSize.height; ++y) {
|
||||
for (int x = 0; x < surface1->mCbCrSize.width; ++x) {
|
||||
ASSERT_EQ(surface1->mCbChannel[y*surface1->mCbCrStride + x*(1+surface1->mCbSkip)],
|
||||
surface2->mCbChannel[y*surface2->mCbCrStride + x*(1+surface2->mCbSkip)]);
|
||||
ASSERT_EQ(surface1->mCrChannel[y*surface1->mCbCrStride + x*(1+surface1->mCrSkip)],
|
||||
surface2->mCrChannel[y*surface2->mCbCrStride + x*(1+surface2->mCrSkip)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run the test for a texture client and a surface
|
||||
void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface) {
|
||||
|
||||
|
@ -206,7 +181,13 @@ void TestTextureClientYCbCr(TextureClient* client, PlanarYCbCrData& ycbcrData) {
|
|||
SurfaceDescriptor descriptor;
|
||||
ASSERT_TRUE(client->ToSurfaceDescriptor(descriptor));
|
||||
|
||||
ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t);
|
||||
ASSERT_EQ(descriptor.type(), SurfaceDescriptor::TSurfaceDescriptorBuffer);
|
||||
auto bufferDesc = descriptor.get_SurfaceDescriptorBuffer();
|
||||
ASSERT_EQ(bufferDesc.desc().type(), BufferDescriptor::TYCbCrDescriptor);
|
||||
auto ycbcrDesc = bufferDesc.desc().get_YCbCrDescriptor();
|
||||
ASSERT_EQ(ycbcrDesc.ySize(), ycbcrData.mYSize);
|
||||
ASSERT_EQ(ycbcrDesc.cbCrSize(), ycbcrData.mCbCrSize);
|
||||
ASSERT_EQ(ycbcrDesc.stereoMode(), ycbcrData.mStereoMode);
|
||||
|
||||
// host deserialization
|
||||
RefPtr<TextureHost> textureHost = CreateBackendIndependentTextureHost(descriptor, nullptr,
|
||||
|
@ -222,26 +203,6 @@ void TestTextureClientYCbCr(TextureClient* client, PlanarYCbCrData& ycbcrData) {
|
|||
if (host->Lock()) {
|
||||
// This will work iff the compositor is not BasicCompositor
|
||||
ASSERT_EQ(host->GetFormat(), mozilla::gfx::SurfaceFormat::YUV);
|
||||
|
||||
YCbCrImageDataDeserializer yuvDeserializer(host->GetBuffer(), host->GetBufferSize());
|
||||
ASSERT_TRUE(yuvDeserializer.IsValid());
|
||||
PlanarYCbCrData data;
|
||||
data.mYChannel = yuvDeserializer.GetYData();
|
||||
data.mCbChannel = yuvDeserializer.GetCbData();
|
||||
data.mCrChannel = yuvDeserializer.GetCrData();
|
||||
data.mYStride = yuvDeserializer.GetYStride();
|
||||
data.mCbCrStride = yuvDeserializer.GetCbCrStride();
|
||||
data.mStereoMode = yuvDeserializer.GetStereoMode();
|
||||
data.mYSize = yuvDeserializer.GetYSize();
|
||||
data.mCbCrSize = yuvDeserializer.GetCbCrSize();
|
||||
data.mYSkip = 0;
|
||||
data.mCbSkip = 0;
|
||||
data.mCrSkip = 0;
|
||||
data.mPicSize = data.mYSize;
|
||||
data.mPicX = 0;
|
||||
data.mPicY = 0;
|
||||
|
||||
AssertYCbCrSurfacesEqual(&ycbcrData, &data);
|
||||
host->Unlock();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -167,7 +167,6 @@ private:
|
|||
DECL_GFX_PREF(Once, "apz.max_velocity_queue_size", APZMaxVelocityQueueSize, uint32_t, 5);
|
||||
DECL_GFX_PREF(Live, "apz.min_skate_speed", APZMinSkateSpeed, float, 1.0f);
|
||||
DECL_GFX_PREF(Live, "apz.minimap.enabled", APZMinimap, bool, false);
|
||||
DECL_GFX_PREF(Live, "apz.num_paint_duration_samples", APZNumPaintDurationSamples, int32_t, 3);
|
||||
DECL_GFX_PREF(Live, "apz.overscroll.enabled", APZOverscrollEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "apz.overscroll.min_pan_distance_ratio", APZMinPanDistanceRatio, float, 1.0f);
|
||||
DECL_GFX_PREF(Live, "apz.overscroll.spring_friction", APZOverscrollSpringFriction, float, 0.015f);
|
||||
|
@ -181,7 +180,6 @@ private:
|
|||
DECL_GFX_PREF(Live, "apz.test.logging_enabled", APZTestLoggingEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "apz.touch_move_tolerance", APZTouchMoveTolerance, float, 0.0);
|
||||
DECL_GFX_PREF(Live, "apz.touch_start_tolerance", APZTouchStartTolerance, float, 1.0f/4.5f);
|
||||
DECL_GFX_PREF(Live, "apz.use_paint_duration", APZUsePaintDuration, bool, true);
|
||||
DECL_GFX_PREF(Live, "apz.velocity_bias", APZVelocityBias, float, 1.0f);
|
||||
DECL_GFX_PREF(Live, "apz.velocity_relevance_time_ms", APZVelocityRelevanceTime, uint32_t, 150);
|
||||
DECL_GFX_PREF(Live, "apz.x_skate_highmem_adjust", APZXSkateHighMemAdjust, float, 0.0f);
|
||||
|
|
|
@ -6870,7 +6870,7 @@ Warn(AsmJSParser& parser, int errorNumber, const char* str)
|
|||
static bool
|
||||
EstablishPreconditions(ExclusiveContext* cx, AsmJSParser& parser)
|
||||
{
|
||||
#ifdef JS_CODEGEN_NONE
|
||||
#if defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_ARM64)
|
||||
return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by lack of a JIT compiler");
|
||||
#endif
|
||||
|
||||
|
@ -6980,7 +6980,7 @@ js::IsAsmJSCompilationAvailable(JSContext* cx, unsigned argc, Value* vp)
|
|||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// See EstablishPreconditions.
|
||||
#ifdef JS_CODEGEN_NONE
|
||||
#if defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_ARM64)
|
||||
bool available = false;
|
||||
#else
|
||||
bool available = cx->jitSupportsFloatingPoint() &&
|
||||
|
|
|
@ -2946,7 +2946,7 @@ wasm::CompileFunction(CompileTask* task)
|
|||
MIRGraph graph(&results.alloc());
|
||||
CompileInfo compileInfo(func.numLocals());
|
||||
MIRGenerator mir(nullptr, options, &results.alloc(), &graph, &compileInfo,
|
||||
IonOptimizations.get(Optimization_AsmJS),
|
||||
IonOptimizations.get(OptimizationLevel::AsmJS),
|
||||
args.usesSignalHandlersForOOB);
|
||||
|
||||
// Build MIR graph
|
||||
|
|
|
@ -199,11 +199,7 @@ Reflect_enumerate(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ES6 26.1.6 Reflect.get(target, propertyKey [, receiver])
|
||||
*
|
||||
* Primitive receivers are not supported yet (see bug 603201).
|
||||
*/
|
||||
/* ES6 26.1.6 Reflect.get(target, propertyKey [, receiver]) */
|
||||
static bool
|
||||
Reflect_get(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
|
@ -221,16 +217,10 @@ Reflect_get(JSContext* cx, unsigned argc, Value* vp)
|
|||
return false;
|
||||
|
||||
// Step 4.
|
||||
RootedValue receiver(cx, argc > 2 ? args[2] : args.get(0));
|
||||
|
||||
// Non-standard hack: Throw a TypeError if the receiver isn't an object.
|
||||
// See bug 603201.
|
||||
RootedObject receiverObj(cx, NonNullObject(cx, receiver));
|
||||
if (!receiverObj)
|
||||
return false;
|
||||
RootedValue receiver(cx, args.length() > 2 ? args[2] : args.get(0));
|
||||
|
||||
// Step 5.
|
||||
return GetProperty(cx, obj, receiverObj, key, args.rval());
|
||||
return GetProperty(cx, obj, receiver, key, args.rval());
|
||||
}
|
||||
|
||||
/* ES6 26.1.7 Reflect.getOwnPropertyDescriptor(target, propertyKey) */
|
||||
|
@ -336,7 +326,7 @@ Reflect_set(JSContext* cx, unsigned argc, Value* vp)
|
|||
return false;
|
||||
|
||||
// Step 4.
|
||||
RootedValue receiver(cx, argc > 3 ? args[3] : args.get(0));
|
||||
RootedValue receiver(cx, args.length() > 3 ? args[3] : args.get(0));
|
||||
|
||||
// Step 5.
|
||||
ObjectOpResult result;
|
||||
|
|
|
@ -306,8 +306,8 @@ GC(JSContext* cx, unsigned argc, Value* vp)
|
|||
|
||||
char buf[256] = { '\0' };
|
||||
#ifndef JS_MORE_DETERMINISTIC
|
||||
JS_snprintf(buf, sizeof(buf), "before %lu, after %lu\n",
|
||||
(unsigned long)preBytes, (unsigned long)cx->runtime()->gc.usage.gcBytes());
|
||||
JS_snprintf(buf, sizeof(buf), "before %" PRIuSIZE ", after %" PRIuSIZE "\n",
|
||||
preBytes, cx->runtime()->gc.usage.gcBytes());
|
||||
#endif
|
||||
JSString* str = JS_NewStringCopyZ(cx, buf);
|
||||
if (!str)
|
||||
|
|
|
@ -73,8 +73,8 @@ _PTHREAD_LDFLAGS=""
|
|||
|
||||
dnl Do not allow objdir == srcdir builds
|
||||
dnl ==============================================================
|
||||
_topsrcdir=`cd $srcdir; pwd -W 2>/dev/null || pwd`
|
||||
_objdir=`pwd`
|
||||
_topsrcdir=`cd $srcdir; pwd -W 2>/dev/null || pwd -P`
|
||||
_objdir=`pwd -P`
|
||||
|
||||
if test "$_topsrcdir" = "$_objdir"
|
||||
then
|
||||
|
@ -112,7 +112,7 @@ if test "$_conflict_files"; then
|
|||
exit 1
|
||||
break
|
||||
fi
|
||||
MOZ_BUILD_ROOT=`pwd -W 2>/dev/null || pwd`
|
||||
MOZ_BUILD_ROOT=`pwd -W 2>/dev/null || pwd -P`
|
||||
|
||||
MOZ_BUILD_BACKEND
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
ecma/Date/15.9.5.10-2.js
|
||||
ecma/Date/15.9.5.11-2.js
|
||||
ecma/Date/15.9.5.12-2.js
|
||||
ecma/Date/15.9.5.8.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-01-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-02-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-03-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-04-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-05-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-06-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-07-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-08-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-09-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-10-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-11-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-12-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-13-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-14-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-15-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-16-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-17-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-18-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-19-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-20-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-21-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-22-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-23-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-24-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-25-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-26-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-27-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-30-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-31-of-32.js
|
||||
ecma_5/Object/15.2.3.6-dictionary-redefinition-32-of-32.js
|
||||
ecma_5/Object/15.2.3.6-middle-redefinition-1-of-8.js
|
||||
ecma_5/Object/15.2.3.6-middle-redefinition-2-of-8.js
|
||||
ecma_5/Object/15.2.3.6-middle-redefinition-3-of-8.js
|
||||
ecma_5/Object/15.2.3.6-middle-redefinition-4-of-8.js
|
||||
ecma_5/Object/15.2.3.6-middle-redefinition-5-of-8.js
|
||||
ecma_5/Object/15.2.3.6-middle-redefinition-6-of-8.js
|
||||
ecma_5/Object/15.2.3.6-middle-redefinition-7-of-8.js
|
||||
ecma_5/Object/15.2.3.6-middle-redefinition-8-of-8.js
|
||||
ecma_5/Object/15.2.3.6-redefinition-1-of-4.js
|
||||
ecma_5/Object/15.2.3.6-redefinition-2-of-4.js
|
||||
ecma_5/Object/15.2.3.6-redefinition-3-of-4.js
|
||||
ecma_5/Object/15.2.3.6-redefinition-4-of-4.js
|
||||
ecma_6/Comprehensions/sudoku.js
|
||||
js1_8/extensions/regress-476427.js
|
||||
js1_8_5/extensions/clone-complex-object.js
|
||||
js1_8_5/reflect-parse/classes.js
|
||||
js1_8_5/reflect-parse/destructuring-variable-declarations.js
|
||||
js1_8_5/regress/no-array-comprehension-length-limit.js
|
|
@ -217,10 +217,10 @@ elif [[ "$VARIANT" = "arm-sim" ||
|
|||
"$VARIANT" = "plaindebug" ]]; then
|
||||
export JSTESTS_EXTRA_ARGS=--jitflags=debug
|
||||
elif [[ "$VARIANT" = arm64* ]]; then
|
||||
# The ARM64 JIT is not yet fully functional, and asm.js does not work.
|
||||
# Just run "make check" and jsapi-tests.
|
||||
RUN_JITTEST=false
|
||||
RUN_JSTESTS=false
|
||||
# The ARM64 simulator is slow, so some tests are timing out.
|
||||
# Run a reduced set of test cases so this doesn't take hours.
|
||||
export JSTESTS_EXTRA_ARGS="--exclude-file=$ABSDIR/arm64-jstests-slow.txt"
|
||||
export JITTEST_EXTRA_ARGS="--jitflags=none --args=--baseline-eager -x ion/ -x asm.js/"
|
||||
fi
|
||||
|
||||
$COMMAND_PREFIX $MAKE check || exit 1
|
||||
|
|
|
@ -6780,6 +6780,13 @@ Parser<FullParseHandler>::classDefinition(YieldHandling yieldHandling,
|
|||
if (tt == TOK_NAME && tokenStream.currentName() == context->names().static_) {
|
||||
if (!tokenStream.peekToken(&tt, TokenStream::KeywordIsName))
|
||||
return null();
|
||||
if (tt == TOK_RC) {
|
||||
tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName);
|
||||
report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
|
||||
"property name", TokenKindToDesc(tt));
|
||||
return null();
|
||||
}
|
||||
|
||||
if (tt != TOK_LP) {
|
||||
if (!checkUnescapedName())
|
||||
return null();
|
||||
|
@ -9249,8 +9256,7 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
|
|||
if (!tokenStream.getToken(<ok, TokenStream::KeywordIsName))
|
||||
return null();
|
||||
|
||||
// TOK_RC should be handled in caller.
|
||||
MOZ_ASSERT(ltok != TOK_RC);
|
||||
MOZ_ASSERT(ltok != TOK_RC, "caller should have handled TOK_RC");
|
||||
|
||||
bool isGenerator = false;
|
||||
if (ltok == TOK_MUL) {
|
||||
|
|
|
@ -501,15 +501,15 @@ JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, void* thing,
|
|||
bool willFit = str->length() + strlen("<length > ") +
|
||||
CountDecimalDigits(str->length()) < bufsize;
|
||||
|
||||
n = JS_snprintf(buf, bufsize, "<length %d%s> ",
|
||||
(int)str->length(),
|
||||
n = JS_snprintf(buf, bufsize, "<length %" PRIuSIZE "%s> ",
|
||||
str->length(),
|
||||
willFit ? "" : " (truncated)");
|
||||
buf += n;
|
||||
bufsize -= n;
|
||||
|
||||
PutEscapedString(buf, bufsize, &str->asLinear(), 0);
|
||||
} else {
|
||||
JS_snprintf(buf, bufsize, "<rope: length %d>", (int)str->length());
|
||||
JS_snprintf(buf, bufsize, "<rope: length %" PRIuSIZE ">", str->length());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -122,8 +122,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.Mov(masm.GetStackPointer64(), sp);
|
||||
masm.initStackPtr();
|
||||
#endif
|
||||
|
||||
// Push non-volatile registers which might be modified by jitcode.
|
||||
|
|
|
@ -9,6 +9,12 @@ function jitTogglesMatch(opts) {
|
|||
if (k.indexOf(".enable") > 0 && opts[k] != currentOpts[k])
|
||||
return false;
|
||||
}
|
||||
|
||||
// ARM64 does not yet have an Ion code generator, so return false if
|
||||
// ion.enable is requested.
|
||||
if (getBuildConfiguration()['arm64-simulator'] && opts['ion.enable'])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,5 +19,7 @@ runOffThreadScript();
|
|||
|
||||
var msg = getLastWarning().message;
|
||||
assertEq(msg === "asm.js type error: Disabled by debugger" ||
|
||||
msg === "asm.js type error: Disabled by lack of a JIT compiler" ||
|
||||
msg === "asm.js type error: Disabled by javascript.options.asmjs in about:config" ||
|
||||
msg === "asm.js type error: Disabled by lack of floating point support",
|
||||
true);
|
||||
|
|
|
@ -2108,8 +2108,6 @@ IonCompile(JSContext* cx, JSScript* script,
|
|||
AutoTraceLog logScript(logger, event);
|
||||
AutoTraceLog logCompile(logger, TraceLogger_IonCompilation);
|
||||
|
||||
MOZ_ASSERT(optimizationLevel > Optimization_DontCompile);
|
||||
|
||||
// Make sure the script's canonical function isn't lazy. We can't de-lazify
|
||||
// it in a helper thread.
|
||||
script->ensureNonLazyCanonicalFunction(cx);
|
||||
|
@ -2396,7 +2394,7 @@ Compile(JSContext* cx, HandleScript script, BaselineFrame* osrFrame, jsbytecode*
|
|||
|
||||
bool recompile = false;
|
||||
OptimizationLevel optimizationLevel = GetOptimizationLevel(script, osrPc);
|
||||
if (optimizationLevel == Optimization_DontCompile)
|
||||
if (optimizationLevel == OptimizationLevel::DontCompile)
|
||||
return Method_Skipped;
|
||||
|
||||
if (script->hasIonScript()) {
|
||||
|
|
|
@ -3683,7 +3683,7 @@ jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, JSFunction* fun,
|
|||
script->needsArgsObj(),
|
||||
inlineScriptTree);
|
||||
|
||||
const OptimizationInfo* optimizationInfo = IonOptimizations.get(Optimization_Normal);
|
||||
const OptimizationInfo* optimizationInfo = IonOptimizations.get(OptimizationLevel::Normal);
|
||||
|
||||
CompilerConstraintList* constraints = NewCompilerConstraintList(temp);
|
||||
if (!constraints) {
|
||||
|
@ -3904,7 +3904,7 @@ jit::AnalyzeArgumentsUsage(JSContext* cx, JSScript* scriptArg)
|
|||
/* needsArgsObj = */ true,
|
||||
inlineScriptTree);
|
||||
|
||||
const OptimizationInfo* optimizationInfo = IonOptimizations.get(Optimization_Normal);
|
||||
const OptimizationInfo* optimizationInfo = IonOptimizations.get(OptimizationLevel::Normal);
|
||||
|
||||
CompilerConstraintList* constraints = NewCompilerConstraintList(temp);
|
||||
if (!constraints) {
|
||||
|
|
|
@ -16,27 +16,28 @@ using namespace js::jit;
|
|||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
OptimizationInfos IonOptimizations;
|
||||
OptimizationLevelInfo IonOptimizations;
|
||||
|
||||
void
|
||||
OptimizationInfo::initNormalOptimizationInfo()
|
||||
{
|
||||
level_ = Optimization_Normal;
|
||||
level_ = OptimizationLevel::Normal;
|
||||
|
||||
autoTruncate_ = true;
|
||||
eaa_ = true;
|
||||
eagerSimdUnbox_ = true;
|
||||
edgeCaseAnalysis_ = true;
|
||||
eliminateRedundantChecks_ = true;
|
||||
inlineInterpreted_ = true;
|
||||
inlineNative_ = true;
|
||||
eagerSimdUnbox_ = true;
|
||||
gvn_ = true;
|
||||
licm_ = true;
|
||||
rangeAnalysis_ = true;
|
||||
loopUnrolling_ = true;
|
||||
gvn_ = true;
|
||||
rangeAnalysis_ = true;
|
||||
reordering_ = true;
|
||||
autoTruncate_ = true;
|
||||
sincos_ = true;
|
||||
sink_ = true;
|
||||
|
||||
registerAllocator_ = RegisterAllocator_Backtracking;
|
||||
|
||||
inlineMaxBytecodePerCallSiteMainThread_ = 500;
|
||||
|
@ -61,16 +62,16 @@ OptimizationInfo::initAsmjsOptimizationInfo()
|
|||
// Take normal option values for not specified values.
|
||||
initNormalOptimizationInfo();
|
||||
|
||||
level_ = OptimizationLevel::AsmJS;
|
||||
|
||||
ama_ = true;
|
||||
level_ = Optimization_AsmJS;
|
||||
autoTruncate_ = false;
|
||||
eagerSimdUnbox_ = false; // AsmJS has no boxing / unboxing.
|
||||
edgeCaseAnalysis_ = false;
|
||||
eliminateRedundantChecks_ = false;
|
||||
autoTruncate_ = false;
|
||||
scalarReplacement_ = false; // AsmJS has no objects.
|
||||
sincos_ = false;
|
||||
sink_ = false;
|
||||
registerAllocator_ = RegisterAllocator_Backtracking;
|
||||
scalarReplacement_ = false; // AsmJS has no objects.
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -108,49 +109,51 @@ OptimizationInfo::compilerWarmUpThreshold(JSScript* script, jsbytecode* pc) cons
|
|||
return warmUpThreshold + loopDepth * 100;
|
||||
}
|
||||
|
||||
OptimizationInfos::OptimizationInfos()
|
||||
OptimizationLevelInfo::OptimizationLevelInfo()
|
||||
{
|
||||
infos_[Optimization_Normal - 1].initNormalOptimizationInfo();
|
||||
infos_[Optimization_AsmJS - 1].initAsmjsOptimizationInfo();
|
||||
infos_[OptimizationLevel::Normal].initNormalOptimizationInfo();
|
||||
infos_[OptimizationLevel::AsmJS].initAsmjsOptimizationInfo();
|
||||
|
||||
#ifdef DEBUG
|
||||
OptimizationLevel level = firstLevel();
|
||||
while (!isLastLevel(level)) {
|
||||
OptimizationLevel next = nextLevel(level);
|
||||
MOZ_ASSERT(level < next);
|
||||
MOZ_ASSERT_IF(level != OptimizationLevel::DontCompile, level < next);
|
||||
level = next;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
OptimizationLevel
|
||||
OptimizationInfos::nextLevel(OptimizationLevel level) const
|
||||
OptimizationLevelInfo::nextLevel(OptimizationLevel level) const
|
||||
{
|
||||
MOZ_ASSERT(!isLastLevel(level));
|
||||
switch (level) {
|
||||
case Optimization_DontCompile:
|
||||
return Optimization_Normal;
|
||||
default:
|
||||
MOZ_CRASH("Unknown optimization level.");
|
||||
case OptimizationLevel::DontCompile:
|
||||
return OptimizationLevel::Normal;
|
||||
case OptimizationLevel::Normal:
|
||||
case OptimizationLevel::AsmJS:
|
||||
case OptimizationLevel::Count:;
|
||||
}
|
||||
MOZ_CRASH("Unknown optimization level.");
|
||||
}
|
||||
|
||||
OptimizationLevel
|
||||
OptimizationInfos::firstLevel() const
|
||||
OptimizationLevelInfo::firstLevel() const
|
||||
{
|
||||
return nextLevel(Optimization_DontCompile);
|
||||
return nextLevel(OptimizationLevel::DontCompile);
|
||||
}
|
||||
|
||||
bool
|
||||
OptimizationInfos::isLastLevel(OptimizationLevel level) const
|
||||
OptimizationLevelInfo::isLastLevel(OptimizationLevel level) const
|
||||
{
|
||||
return level == Optimization_Normal;
|
||||
return level == OptimizationLevel::Normal;
|
||||
}
|
||||
|
||||
OptimizationLevel
|
||||
OptimizationInfos::levelForScript(JSScript* script, jsbytecode* pc) const
|
||||
OptimizationLevelInfo::levelForScript(JSScript* script, jsbytecode* pc) const
|
||||
{
|
||||
OptimizationLevel prev = Optimization_DontCompile;
|
||||
OptimizationLevel prev = OptimizationLevel::DontCompile;
|
||||
|
||||
while (!isLastLevel(prev)) {
|
||||
OptimizationLevel level = nextLevel(prev);
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#ifndef jit_IonOptimizationLevels_h
|
||||
#define jit_IonOptimizationLevels_h
|
||||
|
||||
#include "mozilla/EnumeratedArray.h"
|
||||
|
||||
#include "jsbytecode.h"
|
||||
#include "jstypes.h"
|
||||
|
||||
|
@ -16,12 +18,12 @@
|
|||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
enum OptimizationLevel
|
||||
enum class OptimizationLevel : uint8_t
|
||||
{
|
||||
Optimization_DontCompile,
|
||||
Optimization_Normal,
|
||||
Optimization_AsmJS,
|
||||
Optimization_Count
|
||||
Normal,
|
||||
AsmJS,
|
||||
Count,
|
||||
DontCompile
|
||||
};
|
||||
|
||||
#ifdef JS_JITSPEW
|
||||
|
@ -29,15 +31,15 @@ inline const char*
|
|||
OptimizationLevelString(OptimizationLevel level)
|
||||
{
|
||||
switch (level) {
|
||||
case Optimization_DontCompile:
|
||||
case OptimizationLevel::DontCompile:
|
||||
return "Optimization_DontCompile";
|
||||
case Optimization_Normal:
|
||||
case OptimizationLevel::Normal:
|
||||
return "Optimization_Normal";
|
||||
case Optimization_AsmJS:
|
||||
case OptimizationLevel::AsmJS:
|
||||
return "Optimization_AsmJS";
|
||||
default:
|
||||
MOZ_CRASH("Invalid OptimizationLevel");
|
||||
case OptimizationLevel::Count:;
|
||||
}
|
||||
MOZ_CRASH("Invalid OptimizationLevel");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -263,19 +265,16 @@ class OptimizationInfo
|
|||
}
|
||||
};
|
||||
|
||||
class OptimizationInfos
|
||||
class OptimizationLevelInfo
|
||||
{
|
||||
private:
|
||||
OptimizationInfo infos_[Optimization_Count - 1];
|
||||
mozilla::EnumeratedArray<OptimizationLevel, OptimizationLevel::Count, OptimizationInfo> infos_;
|
||||
|
||||
public:
|
||||
OptimizationInfos();
|
||||
OptimizationLevelInfo();
|
||||
|
||||
const OptimizationInfo* get(OptimizationLevel level) const {
|
||||
MOZ_ASSERT(level < Optimization_Count);
|
||||
MOZ_ASSERT(level != Optimization_DontCompile);
|
||||
|
||||
return &infos_[level - 1];
|
||||
return &infos_[level];
|
||||
}
|
||||
|
||||
OptimizationLevel nextLevel(OptimizationLevel level) const;
|
||||
|
@ -284,7 +283,7 @@ class OptimizationInfos
|
|||
OptimizationLevel levelForScript(JSScript* script, jsbytecode* pc = nullptr) const;
|
||||
};
|
||||
|
||||
extern OptimizationInfos IonOptimizations;
|
||||
extern OptimizationLevelInfo IonOptimizations;
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
|
|
@ -407,13 +407,6 @@ MacroAssemblerARMCompat::incrementInt32Value(const Address& addr)
|
|||
asMasm().add32(Imm32(1), ToPayload(addr));
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label)
|
||||
{
|
||||
asMasm().subPtr(imm, lhs);
|
||||
branch32(cond, lhs, Imm32(0), label);
|
||||
}
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
|
|
|
@ -971,7 +971,10 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
|||
void branchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
|
||||
branch32(cond, lhs, imm, label);
|
||||
}
|
||||
inline void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label);
|
||||
void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
|
||||
ma_sub(imm, lhs, SetCC);
|
||||
as_b(label, cond);
|
||||
}
|
||||
void branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp, Label* label);
|
||||
void moveValue(const Value& val, Register type, Register data);
|
||||
|
||||
|
|
|
@ -1346,8 +1346,8 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
|
|||
}
|
||||
void branch(JitCode* target) {
|
||||
syncStackPtr();
|
||||
addPendingJump(nextOffset(), ImmPtr(target->raw()), Relocation::JITCODE);
|
||||
b(-1); // The jump target will be patched by executableCopy().
|
||||
BufferOffset loc = b(-1); // The jump target will be patched by executableCopy().
|
||||
addPendingJump(loc, ImmPtr(target->raw()), Relocation::JITCODE);
|
||||
}
|
||||
|
||||
void branch32(Condition cond, const Operand& lhs, Register rhs, Label* label) {
|
||||
|
|
|
@ -1564,11 +1564,14 @@ void MacroAssembler::Claim(const Operand& size) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!sp.Is(GetStackPointer64())) {
|
||||
BumpSystemStackPointer(size);
|
||||
}
|
||||
|
||||
Sub(GetStackPointer64(), GetStackPointer64(), size);
|
||||
|
||||
// Make sure the real stack pointer reflects the claimed stack space.
|
||||
// We can't use stack memory below the stack pointer, it could be clobbered by
|
||||
// interupts and signal handlers.
|
||||
if (!sp.Is(GetStackPointer64())) {
|
||||
Mov(sp, GetStackPointer64());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -206,11 +206,6 @@ class MozBaseAssembler : public js::jit::AssemblerShared {
|
|||
protected:
|
||||
// The buffer into which code and relocation info are generated.
|
||||
ARMBuffer armbuffer_;
|
||||
|
||||
js::jit::CompactBufferWriter jumpRelocations_;
|
||||
js::jit::CompactBufferWriter dataRelocations_;
|
||||
js::jit::CompactBufferWriter relocations_;
|
||||
js::jit::CompactBufferWriter preBarriers_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -3107,9 +3107,9 @@ SliceBudget::describe(char* buffer, size_t maxlen) const
|
|||
if (isUnlimited())
|
||||
return JS_snprintf(buffer, maxlen, "unlimited");
|
||||
else if (isWorkBudget())
|
||||
return JS_snprintf(buffer, maxlen, "work(%lld)", workBudget.budget);
|
||||
return JS_snprintf(buffer, maxlen, "work(%" PRId64 ")", workBudget.budget);
|
||||
else
|
||||
return JS_snprintf(buffer, maxlen, "%lldms", timeBudget.budget);
|
||||
return JS_snprintf(buffer, maxlen, "%" PRId64 "ms", timeBudget.budget);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче