Merge mozilla-central to fx-team

This commit is contained in:
Carsten "Tomcat" Book 2016-01-25 12:46:11 +01:00
Родитель 0088ac397e 90df1090b1
Коммит fc178273c4
141 изменённых файлов: 5629 добавлений и 639 удалений

Просмотреть файл

@ -1124,6 +1124,9 @@ pref("dom.audiochannel.mutedByDefault", true);
// requests.
pref("dom.bluetooth.app-origin", "app://bluetooth.gaiamobile.org");
// Enable W3C WebBluetooth API and disable B2G only GATT client API.
pref("dom.bluetooth.webbluetooth.enabled", false);
// Default device name for Presentation API
pref("dom.presentation.device.name", "Firefox OS");

Просмотреть файл

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

Просмотреть файл

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

Просмотреть файл

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

Просмотреть файл

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

Просмотреть файл

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

Просмотреть файл

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
@ -139,7 +139,7 @@
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="72ffdf71c68a96309212eb13d63560d66db14c9e"/>
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="566810728cd485ff2f30766499d32ada7cbd487a"/>
<project name="platform_bionic" path="bionic" remote="b2g" revision="3e85c4683c121530c1c3a48c696a569bf5f587e2"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="39bdda3051dd1d96da3ab369bc654290cb8d463c"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="3e4affc1794fef1ad96d6fcc727cca92b032a429"/>
<project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="f37bd545063039e30a92f2550ae78c0e6e4e2d08"/>
<project name="platform_external_wpa_supplicant_8" path="external/wpa_supplicant_8" remote="b2g" revision="0c6a6547cd1fd302fa2b0f6e375654df36bf0ec4"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="c0dd0098328f3992e1ca09d6d4355729243863d5"/>

Просмотреть файл

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

Просмотреть файл

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

Просмотреть файл

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

Просмотреть файл

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "385ec34c8fe447342e81a40b4e1cc9a80f37fc33",
"git_revision": "4023297b16fdc46de3ddb04be4f3c575313d1cde",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "c53c24531e4d32550f37c5ff5359eb70af822a73",
"revision": "1520b4ebcfc727b7153be5242339b8f577ab65b4",
"repo_path": "integration/gaia-central"
}

Просмотреть файл

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

Просмотреть файл

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

Просмотреть файл

@ -21,7 +21,7 @@
<!--
B2G repositories for all targets
-->
<project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

Просмотреть файл

@ -1692,15 +1692,6 @@ if test -n "$MOZ_USE_SYSTRACE"; then
AC_DEFINE(MOZ_USE_SYSTRACE)
fi
# For profiling builds keep the symbol information
if test "$MOZ_PROFILING" -a -z "$STRIP_FLAGS"; then
case "$OS_TARGET" in
Linux|DragonFly|FreeBSD|NetBSD|OpenBSD)
STRIP_FLAGS="--strip-debug"
;;
esac
fi
dnl ========================================================
dnl = Use Valgrind
dnl ========================================================
@ -1799,6 +1790,38 @@ if test -n "$MOZ_VTUNE"; then
AC_DEFINE(MOZ_VTUNE)
fi
# For profiling builds keep the symbol information
if test "$MOZ_PROFILING" -a -z "$STRIP_FLAGS"; then
case "$OS_TARGET" in
Linux|DragonFly|FreeBSD|NetBSD|OpenBSD)
STRIP_FLAGS="--strip-debug"
;;
esac
fi
dnl ========================================================
dnl = Enable DMD
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(dmd,
[ --enable-dmd Enable DMD; also enables jemalloc, replace-malloc and profiling],
MOZ_DMD=1,
MOZ_DMD= )
if test "$MOZ_DMD"; then
AC_DEFINE(MOZ_DMD)
if test "${CPU_ARCH}" = "arm"; then
CFLAGS="$CFLAGS -funwind-tables"
CXXFLAGS="$CXXFLAGS -funwind-tables"
fi
MOZ_MEMORY=1 # DMD enables jemalloc
MOZ_REPLACE_MALLOC=1 # DMD enables replace-malloc
MOZ_PROFILING=1 # DMD enables profiling
fi
AC_SUBST(MOZ_DMD)
dnl ========================================================
dnl Profiling
dnl ========================================================
@ -7062,28 +7085,6 @@ if test -n "$MOZ_DEBUG"; then
AC_DEFINE(MOZ_DUMP_PAINTING)
fi
dnl ========================================================
dnl = Enable DMD
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(dmd,
[ --enable-dmd Enable DMD; also enables jemalloc and replace-malloc],
MOZ_DMD=1,
MOZ_DMD= )
if test "$MOZ_DMD"; then
AC_DEFINE(MOZ_DMD)
if test "${CPU_ARCH}" = "arm"; then
CFLAGS="$CFLAGS -funwind-tables"
CXXFLAGS="$CXXFLAGS -funwind-tables"
fi
MOZ_MEMORY=1 # DMD enables jemalloc
MOZ_REPLACE_MALLOC=1 # DMD enables replace-malloc
fi
AC_SUBST(MOZ_DMD)
dnl ========================================================
dnl = Enable jemalloc
dnl ========================================================

Просмотреть файл

@ -5880,7 +5880,6 @@ private:
RefPtr<FullscreenTransitionTask> mTask;
};
static const uint32_t kNextPaintTimeout = 1000; // ms
static const char* const kPaintedTopic;
RefPtr<nsGlobalWindow> mWindow;
@ -5940,8 +5939,14 @@ FullscreenTransitionTask::Run()
// Completely fixing those cases seems to be tricky, and since they
// should rarely happen, it probably isn't worth to fix. Hence we
// simply add a timeout here to ensure we never hang forever.
// In addition, if the page is complicated or the machine is less
// powerful, layout could take a long time, in which case, staying
// in black screen for that long could hurt user experience even
// more than exposing an intermediate state.
mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
mTimer->Init(observer, kNextPaintTimeout, nsITimer::TYPE_ONE_SHOT);
uint32_t timeout =
Preferences::GetUint("full-screen-api.transition.timeout", 500);
mTimer->Init(observer, timeout, nsITimer::TYPE_ONE_SHOT);
} else if (stage == eAfterToggle) {
mWidget->PerformFullscreenTransition(nsIWidget::eAfterFullscreenToggle,
mDuration.mFadeOut, mTransitionData,

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/dom/bluetooth/BluetoothManager.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
#include "mozilla/dom/BluetoothManagerBinding.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "nsContentUtils.h"
#include "nsDOMClassInfo.h"
@ -284,3 +285,10 @@ BluetoothManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return BluetoothManagerBinding::Wrap(aCx, this, aGivenProto);
}
// static
bool
BluetoothManager::B2GGattClientEnabled(JSContext* cx, JSObject* aGlobal)
{
return !Preferences::GetBool("dom.bluetooth.webbluetooth.enabled");
}

Просмотреть файл

@ -77,6 +77,12 @@ public:
*/
void AppendAdapter(const BluetoothValue& aValue);
/**
* Check whether B2G only GATT client API is enabled (true) or W3C
* WebBluetooth API is enabled (false).
*/
static bool B2GGattClientEnabled(JSContext* cx, JSObject* aGlobal);
private:
BluetoothManager(nsPIDOMWindow* aWindow);
~BluetoothManager();

Просмотреть файл

@ -542,7 +542,42 @@ WebGLContext::FramebufferTexture2D(GLenum target,
return;
}
if (!IsWebGL2() && level != 0) {
if (textarget != LOCAL_GL_TEXTURE_2D &&
(textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
{
return ErrorInvalidEnumInfo("framebufferTexture2D: textarget:",
textarget);
}
if (IsWebGL2()) {
/* GLES 3.0.4 p208:
* If textarget is one of TEXTURE_CUBE_MAP_POSITIVE_X,
* TEXTURE_CUBE_MAP_POSITIVE_Y, TEXTURE_CUBE_MAP_POSITIVE_Z,
* TEXTURE_CUBE_MAP_NEGATIVE_X, TEXTURE_CUBE_MAP_NEGATIVE_Y,
* or TEXTURE_CUBE_MAP_NEGATIVE_Z, then level must be greater
* than or equal to zero and less than or equal to log2 of the
* value of MAX_CUBE_MAP_TEXTURE_SIZE. If textarget is TEXTURE_2D,
* level must be greater than or equal to zero and no larger than
* log2 of the value of MAX_TEXTURE_SIZE. Otherwise, an
* INVALID_VALUE error is generated.
*/
if (textarget == LOCAL_GL_TEXTURE_2D) {
if (uint32_t(level) > FloorLog2(mImplMaxTextureSize)) {
ErrorInvalidValue("framebufferTexture2D: level is too large.");
return;
}
} else {
MOZ_ASSERT(textarget >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
textarget <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
if (uint32_t(level) > FloorLog2(mImplMaxCubeMapTextureSize)) {
ErrorInvalidValue("framebufferTexture2D: level is too large.");
return;
}
}
} else if (level != 0) {
ErrorInvalidValue("framebufferTexture2D: level must be 0.");
return;
}
@ -567,14 +602,6 @@ WebGLContext::FramebufferTexture2D(GLenum target,
" framebuffer 0.");
}
if (textarget != LOCAL_GL_TEXTURE_2D &&
(textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
{
return ErrorInvalidEnumInfo("framebufferTexture2D: textarget:",
textarget);
}
if (!ValidateFramebufferAttachment(fb, attachment, "framebufferTexture2D"))
return;

Просмотреть файл

@ -1157,6 +1157,8 @@ WebGLFramebuffer::GetAttachmentParameter(const char* funcName, JSContext* cx,
attachPoint = GetAttachPoint(LOCAL_GL_DEPTH_ATTACHMENT);
}
FinalizeAttachments();
return attachPoint->GetParameter(funcName, mContext, cx, target, attachment, pname,
out_error);
}

Просмотреть файл

@ -737,6 +737,7 @@ void HTMLMediaElement::AbortExistingLoads()
}
mError = nullptr;
mCurrentPlayRangeStart = -1.0;
mLoadedDataFired = false;
mAutoplaying = true;
mIsLoadingFromSourceChildren = false;

Просмотреть файл

@ -96,8 +96,7 @@ MediaFormatReader::Shutdown()
mAudio.RejectPromise(CANCELED, __func__);
}
mAudio.mInitPromise.DisconnectIfExists();
mAudio.mDecoder->Shutdown();
mAudio.mDecoder = nullptr;
mAudio.ShutdownDecoder();
}
if (mAudio.mTrackDemuxer) {
mAudio.ResetDemuxer();
@ -117,8 +116,7 @@ MediaFormatReader::Shutdown()
mVideo.RejectPromise(CANCELED, __func__);
}
mVideo.mInitPromise.DisconnectIfExists();
mVideo.mDecoder->Shutdown();
mVideo.mDecoder = nullptr;
mVideo.ShutdownDecoder();
}
if (mVideo.mTrackDemuxer) {
mVideo.ResetDemuxer();
@ -381,6 +379,8 @@ MediaFormatReader::EnsureDecoderCreated(TrackType aTrack)
decoder.mDecoderInitialized = false;
MonitorAutoLock mon(decoder.mMonitor);
switch (aTrack) {
case TrackType::kAudioTrack:
decoder.mDecoder =
@ -406,6 +406,11 @@ MediaFormatReader::EnsureDecoderCreated(TrackType aTrack)
default:
break;
}
if (decoder.mDecoder ) {
decoder.mDescription = decoder.mDecoder->GetDescriptionName();
} else {
decoder.mDescription = "error creating decoder";
}
return decoder.mDecoder != nullptr;
}
@ -429,13 +434,14 @@ MediaFormatReader::EnsureDecoderInitialized(TrackType aTrack)
auto& decoder = self->GetDecoderData(aTrack);
decoder.mInitPromise.Complete();
decoder.mDecoderInitialized = true;
MonitorAutoLock mon(decoder.mMonitor);
decoder.mDescription = decoder.mDecoder->GetDescriptionName();
self->ScheduleUpdate(aTrack);
},
[self, aTrack] (MediaDataDecoder::DecoderFailureReason aResult) {
auto& decoder = self->GetDecoderData(aTrack);
decoder.mInitPromise.Complete();
decoder.mDecoder->Shutdown();
decoder.mDecoder = nullptr;
decoder.ShutdownDecoder();
self->NotifyError(aTrack);
}));
return false;
@ -465,8 +471,7 @@ MediaFormatReader::DisableHardwareAcceleration()
if (HasVideo() && !mHardwareAccelerationDisabled) {
mHardwareAccelerationDisabled = true;
Flush(TrackInfo::kVideoTrack);
mVideo.mDecoder->Shutdown();
mVideo.mDecoder = nullptr;
mVideo.ShutdownDecoder();
if (!EnsureDecoderCreated(TrackType::kVideoTrack)) {
LOG("Unable to re-create decoder, aborting");
NotifyError(TrackInfo::kVideoTrack);
@ -919,8 +924,7 @@ MediaFormatReader::HandleDemuxedSamples(TrackType aTrack,
// Flush will clear our array of queued samples. So make a copy now.
nsTArray<RefPtr<MediaRawData>> samples{decoder.mQueuedSamples};
Flush(aTrack);
decoder.mDecoder->Shutdown();
decoder.mDecoder = nullptr;
decoder.ShutdownDecoder();
if (sample->mKeyframe) {
decoder.mQueuedSamples.AppendElements(Move(samples));
NotifyDecodingRequested(aTrack);
@ -1604,11 +1608,8 @@ void MediaFormatReader::ReleaseMediaResources()
if (mVideoFrameContainer) {
mVideoFrameContainer->ClearCurrentFrame();
}
if (mVideo.mDecoder) {
mVideo.mInitPromise.DisconnectIfExists();
mVideo.mDecoder->Shutdown();
mVideo.mDecoder = nullptr;
}
mVideo.mInitPromise.DisconnectIfExists();
mVideo.ShutdownDecoder();
}
bool
@ -1666,12 +1667,25 @@ void
MediaFormatReader::GetMozDebugReaderData(nsAString& aString)
{
nsAutoCString result;
const char* audioName = "unavailable";
const char* videoName = audioName;
if (HasAudio()) {
MonitorAutoLock mon(mAudio.mMonitor);
audioName = mAudio.mDescription;
}
if (HasVideo()) {
MonitorAutoLock mon(mVideo.mMonitor);
videoName = mVideo.mDescription;
}
result += nsPrintfCString("audio decoder: %s\n", audioName);
result += nsPrintfCString("audio frames decoded: %lld\n",
mAudio.mNumSamplesOutputTotal);
result += nsPrintfCString("video decoder: %s\n", videoName);
result += nsPrintfCString("hardware video decoding: %s\n",
VideoIsHardwareAccelerated() ? "enabled" : "disabled");
result += nsPrintfCString("audio frames decoded: %lld (skipped:%lld)\n"
"video frames decoded: %lld (skipped:%lld)\n",
mAudio.mNumSamplesOutputTotal,
mAudio.mNumSamplesSkippedTotal,
result += nsPrintfCString("video frames decoded: %lld (skipped:%lld)\n",
mVideo.mNumSamplesOutputTotal,
mVideo.mNumSamplesSkippedTotal);
aString += NS_ConvertUTF8toUTF16(result);

Просмотреть файл

@ -10,6 +10,7 @@
#include "mozilla/Atomics.h"
#include "mozilla/Maybe.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/Monitor.h"
#include "MediaDataDemuxer.h"
#include "MediaDecoderReader.h"
@ -213,6 +214,8 @@ private:
uint32_t aDecodeAhead)
: mOwner(aOwner)
, mType(aType)
, mMonitor("DecoderData")
, mDescription("shutdown")
, mDecodeAhead(aDecodeAhead)
, mUpdateScheduled(false)
, mDemuxEOS(false)
@ -240,14 +243,27 @@ private:
// Disambiguate Audio vs Video.
MediaData::Type mType;
RefPtr<MediaTrackDemuxer> mTrackDemuxer;
// The platform decoder.
RefPtr<MediaDataDecoder> mDecoder;
// TaskQueue on which decoder can choose to decode.
// Only non-null up until the decoder is created.
RefPtr<FlushableTaskQueue> mTaskQueue;
// Callback that receives output and error notifications from the decoder.
nsAutoPtr<DecoderCallback> mCallback;
// Monitor protecting mDescription and mDecoder.
Monitor mMonitor;
// The platform decoder.
RefPtr<MediaDataDecoder> mDecoder;
const char* mDescription;
void ShutdownDecoder()
{
MonitorAutoLock mon(mMonitor);
if (mDecoder) {
mDecoder->Shutdown();
}
mDescription = "shutdown";
mDecoder = nullptr;
}
// Only accessed from reader's task queue.
uint32_t mDecodeAhead;
bool mUpdateScheduled;

Просмотреть файл

@ -202,12 +202,18 @@ DecodedAudioDataSink::PopFrames(uint32_t aFrames)
UniquePtr<AudioDataValue[]> mData;
};
if (!mCurrentData) {
while (!mCurrentData) {
// No data in the queue. Return an empty chunk.
if (AudioQueue().GetSize() == 0) {
return MakeUnique<Chunk>();
}
// Ignore the element with 0 frames and try next.
if (AudioQueue().PeekFront()->mFrames == 0) {
RefPtr<MediaData> releaseMe = AudioQueue().PopFront();
continue;
}
// See if there's a gap in the audio. If there is, push silence into the
// audio hardware, so we can play across the gap.
// Calculate the timestamp of the next chunk of audio in numbers of
@ -239,6 +245,7 @@ DecodedAudioDataSink::PopFrames(uint32_t aFrames)
mCursor = MakeUnique<AudioBufferCursor>(mCurrentData->mAudioData.get(),
mCurrentData->mChannels,
mCurrentData->mFrames);
MOZ_ASSERT(mCurrentData->mFrames > 0);
}
auto framesToPop = std::min(aFrames, mCursor->Available());

Просмотреть файл

@ -220,6 +220,11 @@ public:
{
return NS_OK;
}
// Return the name of the MediaDataDecoder, only used for decoding.
// Only return a static const string, as the information may be accessed
// in a non thread-safe fashion.
virtual const char* GetDescriptionName() const = 0;
};
} // namespace mozilla

Просмотреть файл

@ -93,6 +93,11 @@ public:
return NS_OK;
}
const char* GetDescriptionName() const override
{
return "blank media data decoder";
}
private:
nsAutoPtr<BlankMediaDataCreator> mCreator;
RefPtr<FlushableTaskQueue> mTaskQueue;

Просмотреть файл

@ -27,6 +27,10 @@ public:
nsresult Flush() override;
nsresult Drain() override;
nsresult Shutdown() override;
const char* GetDescriptionName() const override
{
return "opus audio decoder";
}
// Return true if mimetype is Opus
static bool IsOpus(const nsACString& aMimeType);

Просмотреть файл

@ -33,6 +33,10 @@ public:
nsresult Flush() override;
nsresult Drain() override;
nsresult Shutdown() override;
const char* GetDescriptionName() const override
{
return "libvpx video decoder";
}
// Return true if mimetype is a VPX codec
static bool IsVPX(const nsACString& aMimeType);

Просмотреть файл

@ -30,6 +30,10 @@ public:
nsresult Flush() override;
nsresult Drain() override;
nsresult Shutdown() override;
const char* GetDescriptionName() const override
{
return "vorbis audio decoder";
}
// Return true if mimetype is Vorbis
static bool IsVorbis(const nsACString& aMimeType);

Просмотреть файл

@ -137,6 +137,10 @@ public:
return rv;
}
const char* GetDescriptionName() const override {
return mDecoder->GetDescriptionName();
}
private:
RefPtr<MediaDataDecoder> mDecoder;

Просмотреть файл

@ -74,6 +74,10 @@ public:
nsresult Flush() override;
nsresult Drain() override;
nsresult Shutdown() override;
const char* GetDescriptionName() const override
{
return "GMP audio decoder";
}
protected:
virtual void InitTags(nsTArray<nsCString>& aTags);

Просмотреть файл

@ -89,6 +89,10 @@ public:
nsresult Flush() override;
nsresult Drain() override;
nsresult Shutdown() override;
const char* GetDescriptionName() const override
{
return "GMP video decoder";
}
protected:
virtual void InitTags(nsTArray<nsCString>& aTags);

Просмотреть файл

@ -138,6 +138,11 @@ public:
nsresult Drain() override;
nsresult Shutdown() override;
const char* GetDescriptionName() const override
{
return "GMP proxy data decoder";
}
// Called by MediaDataDecoderCallbackProxy.
void FlushComplete();

Просмотреть файл

@ -85,6 +85,11 @@ public:
}
const char* GetDescriptionName() const override
{
return "android video decoder";
}
RefPtr<InitPromise> Init() override
{
mSurfaceTexture = AndroidSurfaceTexture::Create();
@ -189,6 +194,11 @@ public:
}
}
const char* GetDescriptionName() const override
{
return "android audio decoder";
}
nsresult Output(BufferInfo::Param aInfo, void* aBuffer,
MediaFormat::Param aFormat, const TimeUnit& aDuration)
{

Просмотреть файл

@ -57,6 +57,10 @@ public:
nsresult Drain() override;
nsresult Shutdown() override;
nsresult Input(MediaRawData* aSample) override;
const char* GetDescriptionName() const override
{
return "android decoder";
}
protected:
enum ModuleState {

Просмотреть файл

@ -31,6 +31,11 @@ public:
nsresult Drain() override;
nsresult Shutdown() override;
const char* GetDescriptionName() const override
{
return "apple CoreMedia decoder";
}
// Callbacks also need access to the config.
const AudioInfo& mConfig;

Просмотреть файл

@ -81,6 +81,11 @@ public:
return true;
}
const char* GetDescriptionName() const override
{
return "apple VDA decoder";
}
// Access from the taskqueue and the decoder's thread.
// OutputFrame is thread-safe.
nsresult OutputFrame(CVPixelBufferRef aImage,

Просмотреть файл

@ -27,6 +27,13 @@ public:
return mIsHardwareAccelerated;
}
const char* GetDescriptionName() const override
{
return mIsHardwareAccelerated
? "apple hardware VT decoder"
: "apple software VT decoder";
}
protected:
void ProcessFlush() override;
void ProcessDrain() override;
@ -43,7 +50,7 @@ private:
nsresult WaitForAsynchronousFrames();
CFDictionaryRef CreateDecoderSpecification();
CFDictionaryRef CreateDecoderExtensions();
bool mIsHardwareAccelerated;
Atomic<bool> mIsHardwareAccelerated;
};
} // namespace mozilla

Просмотреть файл

@ -31,6 +31,10 @@ public:
void ProcessDrain() override;
void InitCodecContext() override;
static AVCodecID GetCodecId(const nsACString& aMimeType);
const char* GetDescriptionName() const override
{
return "ffmpeg audio decoder";
}
private:
void DecodePacket(MediaRawData* aSample);

Просмотреть файл

@ -44,6 +44,14 @@ public:
void ProcessDrain() override;
void ProcessFlush() override;
void InitCodecContext() override;
const char* GetDescriptionName() const override
{
#ifdef USING_MOZFFVPX
return "ffvpx video decoder";
#else
return "ffmpeg video decoder";
#endif
}
static AVCodecID GetCodecId(const nsACString& aMimeType);
private:

Просмотреть файл

@ -33,6 +33,11 @@ public:
void ProcessFlush() override;
const char* GetDescriptionName() const override
{
return "gonk audio decoder";
}
private:
bool InitMediaCodecProxy();

Просмотреть файл

@ -28,6 +28,7 @@ public:
virtual ~GonkDecoderManager() {}
virtual RefPtr<InitPromise> Init() = 0;
virtual const char* GetDescriptionName() const = 0;
// Asynchronously send sample into mDecoder. If out of input buffer, aSample
// will be queued for later re-send.
@ -199,6 +200,11 @@ public:
nsresult Shutdown() override;
const char* GetDescriptionName() const override
{
return "gonk decoder";
}
private:
android::sp<GonkDecoderManager> mManager;

Просмотреть файл

@ -50,6 +50,11 @@ public:
nsresult Shutdown() override;
const char* GetDescriptionName() const override
{
return "gonk video decoder";
}
static void RecycleCallback(TextureClient* aClient, void* aClosure);
protected:

Просмотреть файл

@ -71,6 +71,11 @@ public:
nsresult Shutdown() override;
const char* GetDescriptionName() const override
{
return "omx decoder";
}
// Return true if event is handled.
bool Event(OMX_EVENTTYPE aEvent, OMX_U32 aData1, OMX_U32 aData2);

Просмотреть файл

@ -236,7 +236,9 @@ MFTDecoder::Output(RefPtr<IMFSample>* aOutput)
// Treat other errors as unexpected, and warn.
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
MOZ_ASSERT(output.pSample);
if (!output.pSample) {
return S_OK;
}
if (mDiscontinuity) {
output.pSample->SetUINT32(MFSampleExtension_Discontinuity, TRUE);

Просмотреть файл

@ -10,7 +10,7 @@
#include "WMFUtils.h"
#include "nsTArray.h"
#include "TimeUnits.h"
#include "mozilla/Telemetry.h"
#include "mozilla/Logging.h"
extern mozilla::LogModule* GetPDMLog();
@ -226,6 +226,16 @@ WMFAudioMFTManager::Output(int64_t aStreamOffset,
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
if (!sample) {
LOG("Audio MFTDecoder returned success but null output.");
nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction([]() -> void {
LOG("Reporting telemetry AUDIO_MFT_OUTPUT_NULL_SAMPLES");
Telemetry::Accumulate(Telemetry::ID::AUDIO_MFT_OUTPUT_NULL_SAMPLES, 1);
});
AbstractThread::MainThread()->Dispatch(task.forget());
return E_FAIL;
}
RefPtr<IMFMediaBuffer> buffer;
hr = sample->ConvertToContiguousBuffer(getter_AddRefs(buffer));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

Просмотреть файл

@ -38,6 +38,11 @@ public:
return TrackInfo::kAudioTrack;
}
const char* GetDescriptionName() const override
{
return "wmf audio decoder";
}
private:
HRESULT UpdateOutputType();

Просмотреть файл

@ -54,6 +54,8 @@ public:
virtual void ConfigurationChanged(const TrackInfo& aConfig) {}
virtual const char* GetDescriptionName() const = 0;
protected:
// IMFTransform wrapper that performs the decoding.
RefPtr<MFTDecoder> mDecoder;
@ -85,6 +87,11 @@ public:
nsresult ConfigurationChanged(const TrackInfo& aConfig) override;
const char* GetDescriptionName() const override
{
return mMFTManager ? mMFTManager->GetDescriptionName() : "";
}
private:
// Called on the task queue. Inserts the sample into the decoder, and

Просмотреть файл

@ -21,6 +21,7 @@
#include "IMFYCbCrImage.h"
#include "mozilla/WindowsVersion.h"
#include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h"
#include "nsPrintfCString.h"
extern mozilla::LogModule* GetPDMLog();
@ -78,6 +79,9 @@ WMFVideoMFTManager::WMFVideoMFTManager(
, mImageContainer(aImageContainer)
, mDXVAEnabled(aDXVAEnabled)
, mLayersBackend(aLayersBackend)
, mNullOutputCount(0)
, mGotValidOutputAfterNullOutput(false)
, mGotExcessiveNullOutput(false)
// mVideoStride, mVideoWidth, mVideoHeight, mUseHwAccel are initialized in
// Init().
{
@ -103,6 +107,20 @@ WMFVideoMFTManager::~WMFVideoMFTManager()
if (mDXVA2Manager) {
DeleteOnMainThread(mDXVA2Manager);
}
// Record whether the video decoder successfully decoded, or output null
// samples but did/didn't recover.
uint32_t telemetry = (mNullOutputCount == 0) ? 0 :
(mGotValidOutputAfterNullOutput && mGotExcessiveNullOutput) ? 1 :
mGotExcessiveNullOutput ? 2 :
mGotValidOutputAfterNullOutput ? 3 :
4;
nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction([=]() -> void {
LOG(nsPrintfCString("Reporting telemetry VIDEO_MFT_OUTPUT_NULL_SAMPLES=%d", telemetry).get());
Telemetry::Accumulate(Telemetry::ID::VIDEO_MFT_OUTPUT_NULL_SAMPLES, telemetry);
});
AbstractThread::MainThread()->Dispatch(task.forget());
}
const GUID&
@ -575,6 +593,23 @@ WMFVideoMFTManager::Output(int64_t aStreamOffset,
continue;
}
if (SUCCEEDED(hr)) {
if (!sample) {
LOG("Video MFTDecoder returned success but no output!");
// On some machines/input the MFT returns success but doesn't output
// a video frame. If we detect this, try again, but only up to a
// point; after 250 failures, give up. Note we count all failures
// over the life of the decoder, as we may end up exiting with a
// NEED_MORE_INPUT and coming back to hit the same error. So just
// counting with a local variable (like typeChangeCount does) may
// not work in this situation.
++mNullOutputCount;
if (mNullOutputCount > 250) {
LOG("Excessive Video MFTDecoder returning success but no output; giving up");
mGotExcessiveNullOutput = true;
return E_FAIL;
}
continue;
}
break;
}
// Else unexpected error, assert, and bail.
@ -595,6 +630,10 @@ WMFVideoMFTManager::Output(int64_t aStreamOffset,
aOutData = frame;
if (mNullOutputCount) {
mGotValidOutputAfterNullOutput = true;
}
return S_OK;
}

Просмотреть файл

@ -41,6 +41,13 @@ public:
void ConfigurationChanged(const TrackInfo& aConfig) override;
const char* GetDescriptionName() const override
{
nsCString failureReason;
return IsHardwareAccelerated(failureReason)
? "wmf hardware video decoder" : "wmf software video decoder";
}
private:
bool InitializeDXVA(bool aForceD3D9);
@ -88,6 +95,10 @@ private:
const GUID& GetMFTGUID();
const GUID& GetMediaSubtypeGUID();
uint32_t mNullOutputCount;
bool mGotValidOutputAfterNullOutput;
bool mGotExcessiveNullOutput;
};
} // namespace mozilla

Просмотреть файл

@ -111,6 +111,10 @@ private:
nsresult Shutdown() override;
bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
nsresult ConfigurationChanged(const TrackInfo& aConfig) override;
const char* GetDescriptionName() const override
{
return mDecoder->GetDescriptionName();
}
RefPtr<MediaDataDecoder> mDecoder;
RefPtr<DecoderCallbackFuzzingWrapper> mCallbackWrapper;

Просмотреть файл

@ -35,6 +35,13 @@ public:
nsresult Drain() override;
nsresult Shutdown() override;
bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
const char* GetDescriptionName() const override
{
if (mDecoder) {
return mDecoder->GetDescriptionName();
}
return "H264Converter decoder (pending)";
}
// Return true if mimetype is H.264.
static bool IsH264(const TrackInfo& aConfig);

Просмотреть файл

@ -789,7 +789,13 @@ nsSynthVoiceRegistry::SpeakImpl(VoiceData* aVoice,
aTask->InitDirectAudio();
}
aVoice->mService->Speak(aText, aVoice->mUri, aVolume, aRate, aPitch, aTask);
if (NS_FAILED(aVoice->mService->Speak(aText, aVoice->mUri, aVolume, aRate,
aPitch, aTask))) {
if (serviceType == nsISpeechService::SERVICETYPE_INDIRECT_AUDIO) {
aTask->DispatchError(0, 0);
}
// XXX When using direct audio, no way to dispatch error
}
}
} // namespace dom

Просмотреть файл

@ -268,8 +268,7 @@ FakeIndirectAudioSynth::Speak(const nsAString& aText, const nsAString& aUri,
}
if (flags & eFailAtStart) {
aTask->DispatchError(0, 0);
return NS_OK;
return NS_ERROR_FAILURE;
}
RefPtr<FakeSynthCallback> cb = new FakeSynthCallback(

Просмотреть файл

@ -72,6 +72,7 @@ skip-if = e10s || buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'androi
[test_for_of.html]
[test_frameElementWrapping.html]
[test_pointerPreserves3D.html]
[test_pointerPreserves3DClip.html]
[test_framedhistoryframes.html]
[test_idleapi_permissions.html]
skip-if = buildapp == 'b2g' || buildapp == 'mulet'

Просмотреть файл

@ -0,0 +1,55 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for pointer events with preserve-3d and clips</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<style type="text/css">
.outer {
transform-style: preserve-3d;
}
.container {
overflow-y: scroll;
overflow-x: hidden;
width: 200px;
height: 300px;
}
.content {
width: 200px;
height: 1000px;
transform-style: preserve-3d;
}
#container1 {
background-color: green;
transform: translateZ(2px);
}
#container2 {
height: 100px;
transform: translateY(-200px) translateZ(10px);
background-color: red;
}
</style>
</head>
<body onload="runTest();">
<div class="outer" id="outer">
<div class="container" id="container1">
<div class="content"></div>
</div>
<div class="container" id="container2">
<div class="content"></div>
</div>
</div>
<script class="testbody" type="text/javascript">
function runTest() {
var outer = document.getElementById("outer");
var x = outer.offsetLeft;
var y = outer.offsetTop;
var target = document.elementFromPoint(x + 100, y + 250);
ok(target.parentNode == document.getElementById("container1"), "Find the right target.");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
</script>
</body>
</html>

Просмотреть файл

@ -128,10 +128,17 @@ interface BluetoothAdapter : EventTarget {
sequence<BluetoothDevice> getPairedDevices();
[NewObject]
/**
* [B2G only GATT client API]
* |startLeScan| and |stopLeScan| methods are exposed only if
* "dom.bluetooth.webbluetooth.enabled" preference is false.
*/
[NewObject,
Func="mozilla::dom::bluetooth::BluetoothManager::B2GGattClientEnabled"]
Promise<BluetoothDiscoveryHandle> startLeScan(sequence<DOMString> serviceUuids);
[NewObject]
[NewObject,
Func="mozilla::dom::bluetooth::BluetoothManager::B2GGattClientEnabled"]
Promise<void> stopLeScan(BluetoothDiscoveryHandle discoveryHandle);
[NewObject, Throws, AvailableIn=CertifiedApps]

Просмотреть файл

@ -16,7 +16,12 @@ interface BluetoothDevice : EventTarget
/**
* Retrieve the BluetoothGatt interface to interact with remote BLE devices.
* This attribute is null if the device type is not dual or le.
*
* [B2G only GATT client API]
* gatt attribute is exposed only if "dom.bluetooth.webbluetooth.enabled"
* preference is false.
*/
[Func="mozilla::dom::bluetooth::BluetoothManager::B2GGattClientEnabled"]
readonly attribute BluetoothGatt? gatt;
[Cached, Pure]

Просмотреть файл

@ -4,7 +4,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
[CheckAnyPermissions="bluetooth"]
/**
* [B2G only GATT client API]
* BluetoothGatt interface is exposed only if
* "dom.bluetooth.webbluetooth.enabled" preference is false.
*/
[CheckAnyPermissions="bluetooth",
Func="mozilla::dom::bluetooth::BluetoothManager::B2GGattClientEnabled"]
interface BluetoothGatt : EventTarget
{
[Cached, Pure]

Просмотреть файл

@ -4,7 +4,13 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/**
* [B2G only GATT client API]
* BluetoothGattCharacteristicEvent interface is exposed only if
* "dom.bluetooth.webbluetooth.enabled" preference is false.
*/
[CheckAnyPermissions="bluetooth",
Func="mozilla::dom::bluetooth::BluetoothManager::B2GGattClientEnabled",
Constructor(DOMString type,
optional BluetoothGattCharacteristicEventInit eventInitDict)]
interface BluetoothGattCharacteristicEvent : Event

Просмотреть файл

@ -4,7 +4,13 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/**
* [B2G only GATT client API]
* BluetoothLeDeviceEvent interface is exposed only if
* "dom.bluetooth.webbluetooth.enabled" preference is false.
*/
[CheckAnyPermissions="bluetooth",
Func="mozilla::dom::bluetooth::BluetoothManager::B2GGattClientEnabled",
Constructor(DOMString type, optional BluetoothLeDeviceEventInit eventInitDict)]
interface BluetoothLeDeviceEvent : Event
{

Просмотреть файл

@ -1339,7 +1339,13 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
if (CurrentTouchBlock()->GetActiveTouchCount() == 0) {
// It's possible we may be overscrolled if the user tapped during a
// previous overscroll pan. Make sure to snap back in this situation.
if (!SnapBackIfOverscrolled()) {
// An ancestor APZC could be overscrolled instead of this APZC, so
// walk the handoff chain as well.
CurrentTouchBlock()->GetOverscrollHandoffChain()->SnapBackOverscrolledApzc(this);
// SnapBackOverscrolledApzc() will put any APZC it causes to snap back
// into the OVERSCROLL_ANIMATION state. If that's not us, since we're
// done TOUCHING enter the NOTHING state.
if (mState != OVERSCROLL_ANIMATION) {
SetState(NOTHING);
}
}
@ -3558,6 +3564,11 @@ AsyncPanZoomController::ResetTouchInputState()
listener->HandleInputEvent(cancel);
}
CancelAnimationAndGestureState();
// Clear overscroll along the entire handoff chain, in case an APZC
// later in the chain is overscrolled.
if (TouchBlockState* block = CurrentTouchBlock()) {
block->GetOverscrollHandoffChain()->ClearOverscroll();
}
}
void

Просмотреть файл

@ -32,21 +32,28 @@
// (which expects an untransformed point). We handle both cases by setting both
// the transformed and untransformed fields to the same value.
SingleTouchData
CreateSingleTouchData(int32_t aIdentifier, int aX, int aY)
CreateSingleTouchData(int32_t aIdentifier, const ScreenIntPoint& aPoint)
{
SingleTouchData touch(aIdentifier, ScreenIntPoint(aX, aY), ScreenSize(0, 0), 0, 0);
touch.mLocalScreenPoint = ParentLayerPoint(aX, aY);
SingleTouchData touch(aIdentifier, aPoint, ScreenSize(0, 0), 0, 0);
touch.mLocalScreenPoint = ParentLayerPoint(aPoint.x, aPoint.y);
return touch;
}
// Convenience wrapper for CreateSingleTouchData() that takes loose coordinates.
SingleTouchData
CreateSingleTouchData(int32_t aIdentifier, ScreenIntCoord aX, ScreenIntCoord aY)
{
return CreateSingleTouchData(aIdentifier, ScreenIntPoint(aX, aY));
}
PinchGestureInput
CreatePinchGestureInput(PinchGestureInput::PinchGestureType aType,
int aFocusX, int aFocusY,
const ScreenIntPoint& aFocus,
float aCurrentSpan, float aPreviousSpan)
{
PinchGestureInput result(aType, 0, TimeStamp(), ScreenPoint(aFocusX, aFocusY),
PinchGestureInput result(aType, 0, TimeStamp(), aFocus,
aCurrentSpan, aPreviousSpan, 0);
result.mLocalFocusPoint = ParentLayerPoint(aFocusX, aFocusY);
result.mLocalFocusPoint = ParentLayerPoint(aFocus.x, aFocus.y);
return result;
}
@ -76,34 +83,38 @@ CreateMultiTouchInput(MultiTouchInput::MultiTouchType aType, TimeStamp aTime)
template<class InputReceiver>
nsEventStatus
TouchDown(const RefPtr<InputReceiver>& aTarget, int aX, int aY, TimeStamp aTime, uint64_t* aOutInputBlockId = nullptr)
TouchDown(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint,
TimeStamp aTime, uint64_t* aOutInputBlockId = nullptr)
{
MultiTouchInput mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, aTime);
mti.mTouches.AppendElement(CreateSingleTouchData(0, aX, aY));
mti.mTouches.AppendElement(CreateSingleTouchData(0, aPoint));
return aTarget->ReceiveInputEvent(mti, nullptr, aOutInputBlockId);
}
template<class InputReceiver>
nsEventStatus
TouchMove(const RefPtr<InputReceiver>& aTarget, int aX, int aY, TimeStamp aTime)
TouchMove(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint,
TimeStamp aTime)
{
MultiTouchInput mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, aTime);
mti.mTouches.AppendElement(CreateSingleTouchData(0, aX, aY));
mti.mTouches.AppendElement(CreateSingleTouchData(0, aPoint));
return aTarget->ReceiveInputEvent(mti, nullptr, nullptr);
}
template<class InputReceiver>
nsEventStatus
TouchUp(const RefPtr<InputReceiver>& aTarget, int aX, int aY, TimeStamp aTime)
TouchUp(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint,
TimeStamp aTime)
{
MultiTouchInput mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_END, aTime);
mti.mTouches.AppendElement(CreateSingleTouchData(0, aX, aY));
mti.mTouches.AppendElement(CreateSingleTouchData(0, aPoint));
return aTarget->ReceiveInputEvent(mti, nullptr, nullptr);
}
template<class InputReceiver>
void
Tap(const RefPtr<InputReceiver>& aTarget, int aX, int aY, MockContentControllerDelayed* aMcc,
Tap(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint,
MockContentControllerDelayed* aMcc,
TimeDuration aTapLength,
nsEventStatus (*aOutEventStatuses)[2] = nullptr,
uint64_t* aOutInputBlockId = nullptr)
@ -115,7 +126,7 @@ Tap(const RefPtr<InputReceiver>& aTarget, int aX, int aY, MockContentControllerD
aOutInputBlockId = &blockId;
}
nsEventStatus status = TouchDown(aTarget, aX, aY, aMcc->Time(), aOutInputBlockId);
nsEventStatus status = TouchDown(aTarget, aPoint, aMcc->Time(), aOutInputBlockId);
if (aOutEventStatuses) {
(*aOutEventStatuses)[0] = status;
}
@ -127,7 +138,7 @@ Tap(const RefPtr<InputReceiver>& aTarget, int aX, int aY, MockContentControllerD
SetDefaultAllowedTouchBehavior(aTarget, *aOutInputBlockId);
}
status = TouchUp(aTarget, aX, aY, aMcc->Time());
status = TouchUp(aTarget, aPoint, aMcc->Time());
if (aOutEventStatuses) {
(*aOutEventStatuses)[1] = status;
}
@ -135,11 +146,12 @@ Tap(const RefPtr<InputReceiver>& aTarget, int aX, int aY, MockContentControllerD
template<class InputReceiver>
void
TapAndCheckStatus(const RefPtr<InputReceiver>& aTarget, int aX, int aY,
MockContentControllerDelayed* aMcc, TimeDuration aTapLength)
TapAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
const ScreenIntPoint& aPoint, MockContentControllerDelayed* aMcc,
TimeDuration aTapLength)
{
nsEventStatus statuses[2];
Tap(aTarget, aX, aY, aMcc, aTapLength, &statuses);
Tap(aTarget, aPoint, aMcc, aTapLength, &statuses);
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]);
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[1]);
}
@ -148,8 +160,8 @@ template<class InputReceiver>
void
Pan(const RefPtr<InputReceiver>& aTarget,
MockContentControllerDelayed* aMcc,
const ScreenPoint& aTouchStart,
const ScreenPoint& aTouchEnd,
const ScreenIntPoint& aTouchStart,
const ScreenIntPoint& aTouchEnd,
bool aKeepFingerDown = false,
nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr,
nsEventStatus (*aOutEventStatuses)[4] = nullptr,
@ -173,7 +185,9 @@ Pan(const RefPtr<InputReceiver>& aTarget,
}
// Make sure the move is large enough to not be handled as a tap
nsEventStatus status = TouchDown(aTarget, aTouchStart.x, aTouchStart.y + OVERCOME_TOUCH_TOLERANCE, aMcc->Time(), aOutInputBlockId);
nsEventStatus status = TouchDown(aTarget,
ScreenIntPoint(aTouchStart.x, aTouchStart.y + OVERCOME_TOUCH_TOLERANCE),
aMcc->Time(), aOutInputBlockId);
if (aOutEventStatuses) {
(*aOutEventStatuses)[0] = status;
}
@ -190,14 +204,14 @@ Pan(const RefPtr<InputReceiver>& aTarget,
}
}
status = TouchMove(aTarget, aTouchStart.x, aTouchStart.y, aMcc->Time());
status = TouchMove(aTarget, aTouchStart, aMcc->Time());
if (aOutEventStatuses) {
(*aOutEventStatuses)[1] = status;
}
aMcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
status = TouchMove(aTarget, aTouchEnd.x, aTouchEnd.y, aMcc->Time());
status = TouchMove(aTarget, aTouchEnd, aMcc->Time());
if (aOutEventStatuses) {
(*aOutEventStatuses)[2] = status;
}
@ -205,7 +219,7 @@ Pan(const RefPtr<InputReceiver>& aTarget,
aMcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
if (!aKeepFingerDown) {
status = TouchUp(aTarget, aTouchEnd.x, aTouchEnd.y, aMcc->Time());
status = TouchUp(aTarget, aTouchEnd, aMcc->Time());
} else {
status = nsEventStatus_eIgnore;
}
@ -232,7 +246,7 @@ Pan(const RefPtr<InputReceiver>& aTarget,
nsEventStatus (*aOutEventStatuses)[4] = nullptr,
uint64_t* aOutInputBlockId = nullptr)
{
::Pan(aTarget, aMcc, ScreenPoint(10, aTouchStartY), ScreenPoint(10, aTouchEndY),
::Pan(aTarget, aMcc, ScreenIntPoint(10, aTouchStartY), ScreenIntPoint(10, aTouchEndY),
aKeepFingerDown, aAllowedTouchBehaviors, aOutEventStatuses, aOutInputBlockId);
}
@ -279,19 +293,20 @@ ApzcPanNoFling(const RefPtr<TestAsyncPanZoomController>& aApzc,
template<class InputReceiver>
void
PinchWithPinchInput(const RefPtr<InputReceiver>& aTarget,
int aFocusX, int aFocusY, int aSecondFocusX, int aSecondFocusY, float aScale,
const ScreenIntPoint& aFocus,
const ScreenIntPoint& aSecondFocus, float aScale,
nsEventStatus (*aOutEventStatuses)[3] = nullptr)
{
nsEventStatus actualStatus = aTarget->ReceiveInputEvent(
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_START,
aFocusX, aFocusY, 10.0, 10.0),
aFocus, 10.0, 10.0),
nullptr);
if (aOutEventStatuses) {
(*aOutEventStatuses)[0] = actualStatus;
}
actualStatus = aTarget->ReceiveInputEvent(
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE,
aSecondFocusX, aSecondFocusY, 10.0 * aScale, 10.0),
aSecondFocus, 10.0 * aScale, 10.0),
nullptr);
if (aOutEventStatuses) {
(*aOutEventStatuses)[1] = actualStatus;
@ -300,7 +315,7 @@ PinchWithPinchInput(const RefPtr<InputReceiver>& aTarget,
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_END,
// note: negative values here tell APZC
// not to turn the pinch into a pan
aFocusX, aFocusY, -1.0, -1.0),
aFocus, -1.0, -1.0),
nullptr);
if (aOutEventStatuses) {
(*aOutEventStatuses)[2] = actualStatus;
@ -310,11 +325,11 @@ PinchWithPinchInput(const RefPtr<InputReceiver>& aTarget,
template<class InputReceiver>
void
PinchWithPinchInputAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
int aFocusX, int aFocusY, float aScale,
const ScreenIntPoint& aFocus, float aScale,
bool aShouldTriggerPinch)
{
nsEventStatus statuses[3]; // scalebegin, scale, scaleend
PinchWithPinchInput(aTarget, aFocusX, aFocusY, aFocusX, aFocusY, aScale, &statuses);
PinchWithPinchInput(aTarget, aFocus, aFocus, aScale, &statuses);
nsEventStatus expectedStatus = aShouldTriggerPinch
? nsEventStatus_eConsumeNoDefault
@ -326,7 +341,7 @@ PinchWithPinchInputAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
template<class InputReceiver>
void
PinchWithTouchInput(const RefPtr<InputReceiver>& aTarget,
int aFocusX, int aFocusY, float aScale,
const ScreenIntPoint& aFocus, float aScale,
int& inputId,
nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr,
nsEventStatus (*aOutEventStatuses)[4] = nullptr,
@ -345,8 +360,8 @@ PinchWithTouchInput(const RefPtr<InputReceiver>& aTarget,
}
MultiTouchInput mtiStart = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0);
mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocusX, aFocusY));
mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocusX, aFocusY));
mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocus));
mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocus));
nsEventStatus status = aTarget->ReceiveInputEvent(mtiStart, aOutInputBlockId);
if (aOutEventStatuses) {
(*aOutEventStatuses)[0] = status;
@ -360,24 +375,24 @@ PinchWithTouchInput(const RefPtr<InputReceiver>& aTarget,
}
MultiTouchInput mtiMove1 = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0);
mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocusX - pinchLength, aFocusY));
mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocusX + pinchLength, aFocusY));
mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocus.x - pinchLength, aFocus.y));
mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocus.x + pinchLength, aFocus.y));
status = aTarget->ReceiveInputEvent(mtiMove1, nullptr);
if (aOutEventStatuses) {
(*aOutEventStatuses)[1] = status;
}
MultiTouchInput mtiMove2 = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0);
mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocusX - pinchLengthScaled, aFocusY));
mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocusX + pinchLengthScaled, aFocusY));
mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocus.x - pinchLengthScaled, aFocus.y));
mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocus.x + pinchLengthScaled, aFocus.y));
status = aTarget->ReceiveInputEvent(mtiMove2, nullptr);
if (aOutEventStatuses) {
(*aOutEventStatuses)[2] = status;
}
MultiTouchInput mtiEnd = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, TimeStamp(), 0);
mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocusX - pinchLengthScaled, aFocusY));
mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocusX + pinchLengthScaled, aFocusY));
mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocus.x - pinchLengthScaled, aFocus.y));
mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocus.x + pinchLengthScaled, aFocus.y));
status = aTarget->ReceiveInputEvent(mtiEnd, nullptr);
if (aOutEventStatuses) {
(*aOutEventStatuses)[3] = status;
@ -389,12 +404,12 @@ PinchWithTouchInput(const RefPtr<InputReceiver>& aTarget,
template<class InputReceiver>
void
PinchWithTouchInputAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
int aFocusX, int aFocusY, float aScale,
const ScreenIntPoint& aFocus, float aScale,
int& inputId, bool aShouldTriggerPinch,
nsTArray<uint32_t>* aAllowedTouchBehaviors)
{
nsEventStatus statuses[4]; // down, move, move, up
PinchWithTouchInput(aTarget, aFocusX, aFocusY, aScale, inputId, aAllowedTouchBehaviors, &statuses);
PinchWithTouchInput(aTarget, aFocus, aScale, inputId, aAllowedTouchBehaviors, &statuses);
nsEventStatus expectedMoveStatus = aShouldTriggerPinch
? nsEventStatus_eConsumeDoDefault
@ -406,12 +421,13 @@ PinchWithTouchInputAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
template<class InputReceiver>
void
DoubleTap(const RefPtr<InputReceiver>& aTarget, int aX, int aY, MockContentControllerDelayed* aMcc,
DoubleTap(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint,
MockContentControllerDelayed* aMcc,
nsEventStatus (*aOutEventStatuses)[4] = nullptr,
uint64_t (*aOutInputBlockIds)[2] = nullptr)
{
uint64_t blockId;
nsEventStatus status = TouchDown(aTarget, aX, aY, aMcc->Time(), &blockId);
nsEventStatus status = TouchDown(aTarget, aPoint, aMcc->Time(), &blockId);
if (aOutEventStatuses) {
(*aOutEventStatuses)[0] = status;
}
@ -426,12 +442,12 @@ DoubleTap(const RefPtr<InputReceiver>& aTarget, int aX, int aY, MockContentContr
SetDefaultAllowedTouchBehavior(aTarget, blockId);
}
status = TouchUp(aTarget, aX, aY, aMcc->Time());
status = TouchUp(aTarget, aPoint, aMcc->Time());
if (aOutEventStatuses) {
(*aOutEventStatuses)[1] = status;
}
aMcc->AdvanceByMillis(10);
status = TouchDown(aTarget, aX, aY, aMcc->Time(), &blockId);
status = TouchDown(aTarget, aPoint, aMcc->Time(), &blockId);
if (aOutEventStatuses) {
(*aOutEventStatuses)[2] = status;
}
@ -444,7 +460,7 @@ DoubleTap(const RefPtr<InputReceiver>& aTarget, int aX, int aY, MockContentContr
SetDefaultAllowedTouchBehavior(aTarget, blockId);
}
status = TouchUp(aTarget, aX, aY, aMcc->Time());
status = TouchUp(aTarget, aPoint, aMcc->Time());
if (aOutEventStatuses) {
(*aOutEventStatuses)[3] = status;
}
@ -452,11 +468,12 @@ DoubleTap(const RefPtr<InputReceiver>& aTarget, int aX, int aY, MockContentContr
template<class InputReceiver>
void
DoubleTapAndCheckStatus(const RefPtr<InputReceiver>& aTarget, int aX, int aY,
MockContentControllerDelayed* aMcc, uint64_t (*aOutInputBlockIds)[2] = nullptr)
DoubleTapAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
const ScreenIntPoint& aPoint, MockContentControllerDelayed* aMcc,
uint64_t (*aOutInputBlockIds)[2] = nullptr)
{
nsEventStatus statuses[4];
DoubleTap(aTarget, aX, aY, aMcc, &statuses, aOutInputBlockIds);
DoubleTap(aTarget, aPoint, aMcc, &statuses, aOutInputBlockIds);
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]);
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[1]);
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[2]);

Просмотреть файл

@ -22,7 +22,7 @@ TEST_F(APZCBasicTester, Overzoom) {
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
PinchWithPinchInputAndCheckStatus(apzc, 50, 50, 0.5, true);
PinchWithPinchInputAndCheckStatus(apzc, ScreenIntPoint(50, 50), 0.5, true);
fm = apzc->GetFrameMetrics();
EXPECT_EQ(0.8f, fm.GetZoom().ToScaleFactor().scale);
@ -295,8 +295,8 @@ TEST_F(APZCBasicTester, OverScroll_Bug1152051b) {
// to schedule a new one since we're still overscrolled. We don't pan because
// panning can trigger functions that clear the overscroll animation state
// in other ways.
TouchDown(apzc, 10, 10, mcc->Time(), nullptr);
TouchUp(apzc, 10, 10, mcc->Time());
TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time(), nullptr);
TouchUp(apzc, ScreenIntPoint(10, 10), mcc->Time());
// Sample the second overscroll animation to its end.
// If the ending of the first overscroll animation fails to clear state

Просмотреть файл

@ -186,18 +186,18 @@ TEST_F(APZEventRegionsTester, HitRegionImmediateResponse) {
// Tap in the exposed hit regions of each of the layers once and ensure
// the clicks are dispatched right away
Tap(manager, 10, 10, mcc, tapDuration);
Tap(manager, ScreenIntPoint(10, 10), mcc, tapDuration);
mcc->RunThroughDelayedTasks(); // this runs the tap event
check.Call("Tapped on left");
Tap(manager, 110, 110, mcc, tapDuration);
Tap(manager, ScreenIntPoint(110, 110), mcc, tapDuration);
mcc->RunThroughDelayedTasks(); // this runs the tap event
check.Call("Tapped on bottom");
Tap(manager, 110, 10, mcc, tapDuration);
Tap(manager, ScreenIntPoint(110, 10), mcc, tapDuration);
mcc->RunThroughDelayedTasks(); // this runs the tap event
check.Call("Tapped on root");
// Now tap on the dispatch-to-content region where the layers overlap
Tap(manager, 10, 110, mcc, tapDuration);
Tap(manager, ScreenIntPoint(10, 110), mcc, tapDuration);
mcc->RunThroughDelayedTasks(); // this runs the main-thread timeout
check.Call("Tap pending on d-t-c region");
mcc->RunThroughDelayedTasks(); // this runs the tap event
@ -205,7 +205,7 @@ TEST_F(APZEventRegionsTester, HitRegionImmediateResponse) {
// Now let's do that again, but simulate a main-thread response
uint64_t inputBlockId = 0;
Tap(manager, 10, 110, mcc, tapDuration, nullptr, &inputBlockId);
Tap(manager, ScreenIntPoint(10, 110), mcc, tapDuration, nullptr, &inputBlockId);
nsTArray<ScrollableLayerGuid> targets;
targets.AppendElement(left->GetGuid());
manager->SetTargetAPZC(inputBlockId, targets);
@ -221,7 +221,7 @@ TEST_F(APZEventRegionsTester, HitRegionAccumulatesChildren) {
// content controller, which indicates the input events got routed correctly
// to the APZC.
EXPECT_CALL(*mcc, HandleSingleTap(_, _, rootApzc->GetGuid())).Times(1);
Tap(manager, 10, 160, mcc, TimeDuration::FromMilliseconds(100));
Tap(manager, ScreenIntPoint(10, 160), mcc, TimeDuration::FromMilliseconds(100));
}
TEST_F(APZEventRegionsTester, Obscuration) {
@ -260,7 +260,7 @@ TEST_F(APZEventRegionsTester, Bug1117712) {
// These touch events should hit the dispatch-to-content region of layers[3]
// and so get queued with that APZC as the tentative target.
uint64_t inputBlockId = 0;
Tap(manager, 55, 5, mcc, TimeDuration::FromMilliseconds(100), nullptr, &inputBlockId);
Tap(manager, ScreenIntPoint(55, 5), mcc, TimeDuration::FromMilliseconds(100), nullptr, &inputBlockId);
// But now we tell the APZ that really it hit layers[2], and expect the tap
// to be delivered at the correct coordinates.
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(55, 5), 0, apzc2->GetGuid())).Times(1);

Просмотреть файл

@ -210,12 +210,12 @@ protected:
// Deliver a tap to abort the fling. Ensure that we get a HandleSingleTap
// call out of it if and only if the fling is slow.
EXPECT_CALL(*mcc, HandleSingleTap(_, 0, apzc->GetGuid())).Times(tapCallsExpected);
Tap(apzc, 10, 10, mcc, 0);
Tap(apzc, ScreenIntPoint(10, 10), mcc, 0);
while (mcc->RunThroughDelayedTasks());
// Deliver another tap, to make sure that taps are flowing properly once
// the fling is aborted.
Tap(apzc, 100, 100, mcc, 0);
Tap(apzc, ScreenIntPoint(100, 100), mcc, 0);
while (mcc->RunThroughDelayedTasks());
// Verify that we didn't advance any further after the fling was aborted, in either case.
@ -247,7 +247,7 @@ protected:
EXPECT_GT(finalPoint.y, point.y);
// Now we put our finger down to stop the fling
TouchDown(apzc, 10, 10, mcc->Time(), &blockId);
TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time(), &blockId);
// Re-sample to make sure it hasn't moved
apzc->SampleContentTransformForFrame(&viewTransform, point, TimeDuration::FromMilliseconds(10));
@ -264,7 +264,7 @@ protected:
EXPECT_EQ(finalPoint.y, point.y);
// clean up
TouchUp(apzc, 10, 10, mcc->Time());
TouchUp(apzc, ScreenIntPoint(10, 10), mcc->Time());
apzc->AssertStateIsReset();
}
@ -300,7 +300,7 @@ TEST_F(APZCGestureDetectorTester, ShortPress) {
}
check.Call("pre-tap");
TapAndCheckStatus(apzc, 10, 10, mcc, TimeDuration::FromMilliseconds(100));
TapAndCheckStatus(apzc, ScreenIntPoint(10, 10), mcc, TimeDuration::FromMilliseconds(100));
check.Call("post-tap");
apzc->AssertStateIsReset();
@ -320,7 +320,7 @@ TEST_F(APZCGestureDetectorTester, MediumPress) {
}
check.Call("pre-tap");
TapAndCheckStatus(apzc, 10, 10, mcc, TimeDuration::FromMilliseconds(400));
TapAndCheckStatus(apzc, ScreenIntPoint(10, 10), mcc, TimeDuration::FromMilliseconds(400));
check.Call("post-tap");
apzc->AssertStateIsReset();
@ -333,7 +333,7 @@ protected:
uint64_t blockId = 0;
nsEventStatus status = TouchDown(apzc, 10, 10, mcc->Time(), &blockId);
nsEventStatus status = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time(), &blockId);
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status);
if (gfxPrefs::TouchActionEnabled() && status != nsEventStatus_eConsumeNoDefault) {
@ -376,7 +376,7 @@ protected:
// Finally, simulate lifting the finger. Since the long-press wasn't
// prevent-defaulted, we should get a long-tap-up event.
check.Call("preHandleSingleTap");
status = TouchUp(apzc, 10, 10, mcc->Time());
status = TouchUp(apzc, ScreenIntPoint(10, 10), mcc->Time());
mcc->RunThroughDelayedTasks();
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status);
check.Call("postHandleSingleTap");
@ -394,7 +394,7 @@ protected:
touchEndY = 50;
uint64_t blockId = 0;
nsEventStatus status = TouchDown(apzc, touchX, touchStartY, mcc->Time(), &blockId);
nsEventStatus status = TouchDown(apzc, ScreenIntPoint(touchX, touchStartY), mcc->Time(), &blockId);
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status);
if (gfxPrefs::TouchActionEnabled() && status != nsEventStatus_eConsumeNoDefault) {
@ -436,7 +436,7 @@ protected:
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status);
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(touchX, touchEndY), 0, apzc->GetGuid())).Times(0);
status = TouchUp(apzc, touchX, touchEndY, mcc->Time());
status = TouchUp(apzc, ScreenIntPoint(touchX, touchEndY), mcc->Time());
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status);
ParentLayerPoint pointOut;
@ -482,7 +482,7 @@ TEST_F(APZCGestureDetectorTester, DoubleTap) {
EXPECT_CALL(*mcc, HandleDoubleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
uint64_t blockIds[2];
DoubleTapAndCheckStatus(apzc, 10, 10, mcc, &blockIds);
DoubleTapAndCheckStatus(apzc, ScreenIntPoint(10, 10), mcc, &blockIds);
// responses to the two touchstarts
apzc->ContentReceivedInputBlock(blockIds[0], false);
@ -499,7 +499,7 @@ TEST_F(APZCGestureDetectorTester, DoubleTapNotZoomable) {
EXPECT_CALL(*mcc, HandleDoubleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(0);
uint64_t blockIds[2];
DoubleTapAndCheckStatus(apzc, 10, 10, mcc, &blockIds);
DoubleTapAndCheckStatus(apzc, ScreenIntPoint(10, 10), mcc, &blockIds);
// responses to the two touchstarts
apzc->ContentReceivedInputBlock(blockIds[0], false);
@ -516,7 +516,7 @@ TEST_F(APZCGestureDetectorTester, DoubleTapPreventDefaultFirstOnly) {
EXPECT_CALL(*mcc, HandleDoubleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(0);
uint64_t blockIds[2];
DoubleTapAndCheckStatus(apzc, 10, 10, mcc, &blockIds);
DoubleTapAndCheckStatus(apzc, ScreenIntPoint(10, 10), mcc, &blockIds);
// responses to the two touchstarts
apzc->ContentReceivedInputBlock(blockIds[0], true);
@ -533,7 +533,7 @@ TEST_F(APZCGestureDetectorTester, DoubleTapPreventDefaultBoth) {
EXPECT_CALL(*mcc, HandleDoubleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(0);
uint64_t blockIds[2];
DoubleTapAndCheckStatus(apzc, 10, 10, mcc, &blockIds);
DoubleTapAndCheckStatus(apzc, ScreenIntPoint(10, 10), mcc, &blockIds);
// responses to the two touchstarts
apzc->ContentReceivedInputBlock(blockIds[0], true);
@ -549,7 +549,7 @@ TEST_F(APZCGestureDetectorTester, TapFollowedByPinch) {
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
Tap(apzc, 10, 10, mcc, TimeDuration::FromMilliseconds(100));
Tap(apzc, ScreenIntPoint(10, 10), mcc, TimeDuration::FromMilliseconds(100));
int inputId = 0;
MultiTouchInput mti;
@ -571,7 +571,7 @@ TEST_F(APZCGestureDetectorTester, TapFollowedByMultipleTouches) {
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
Tap(apzc, 10, 10, mcc, TimeDuration::FromMilliseconds(100));
Tap(apzc, ScreenIntPoint(10, 10), mcc, TimeDuration::FromMilliseconds(100));
int inputId = 0;
MultiTouchInput mti;

Просмотреть файл

@ -465,12 +465,12 @@ TEST_F(APZHitTestingTester, Bug1148350) {
EXPECT_CALL(check, Call("Tapped with interleaved transform"));
}
Tap(manager, 100, 100, mcc, TimeDuration::FromMilliseconds(100));
Tap(manager, ScreenIntPoint(100, 100), mcc, TimeDuration::FromMilliseconds(100));
mcc->RunThroughDelayedTasks();
check.Call("Tapped without transform");
uint64_t blockId;
TouchDown(manager, 100, 100, mcc->Time(), &blockId);
TouchDown(manager, ScreenIntPoint(100, 100), mcc->Time(), &blockId);
if (gfxPrefs::TouchActionEnabled()) {
SetDefaultAllowedTouchBehavior(manager, blockId);
}
@ -480,7 +480,7 @@ TEST_F(APZHitTestingTester, Bug1148350) {
layers[0]->SetBaseTransform(Matrix4x4::Translation(0, 50, 0));
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
TouchUp(manager, 100, 100, mcc->Time());
TouchUp(manager, ScreenIntPoint(100, 100), mcc->Time());
mcc->RunThroughDelayedTasks();
check.Call("Tapped with interleaved transform");
}

Просмотреть файл

@ -44,9 +44,11 @@ protected:
int touchInputId = 0;
if (mGestureBehavior == AsyncPanZoomController::USE_GESTURE_DETECTOR) {
PinchWithTouchInputAndCheckStatus(apzc, 250, 300, 1.25, touchInputId, aShouldTriggerPinch, aAllowedTouchBehaviors);
PinchWithTouchInputAndCheckStatus(apzc, ScreenIntPoint(250, 300), 1.25,
touchInputId, aShouldTriggerPinch, aAllowedTouchBehaviors);
} else {
PinchWithPinchInputAndCheckStatus(apzc, 250, 300, 1.25, aShouldTriggerPinch);
PinchWithPinchInputAndCheckStatus(apzc, ScreenIntPoint(250, 300), 1.25,
aShouldTriggerPinch);
}
FrameMetrics fm = apzc->GetFrameMetrics();
@ -72,9 +74,11 @@ protected:
// the visible area of the document in CSS pixels is x=930 y=5 w=50 h=100
if (mGestureBehavior == AsyncPanZoomController::USE_GESTURE_DETECTOR) {
PinchWithTouchInputAndCheckStatus(apzc, 250, 300, 0.5, touchInputId, aShouldTriggerPinch, aAllowedTouchBehaviors);
PinchWithTouchInputAndCheckStatus(apzc, ScreenIntPoint(250, 300), 0.5,
touchInputId, aShouldTriggerPinch, aAllowedTouchBehaviors);
} else {
PinchWithPinchInputAndCheckStatus(apzc, 250, 300, 0.5, aShouldTriggerPinch);
PinchWithPinchInputAndCheckStatus(apzc, ScreenIntPoint(250, 300), 0.5,
aShouldTriggerPinch);
}
fm = apzc->GetFrameMetrics();
@ -142,7 +146,8 @@ TEST_F(APZCPinchGestureDetectorTester, Pinch_PreventDefault) {
int touchInputId = 0;
uint64_t blockId = 0;
PinchWithTouchInput(apzc, 250, 300, 1.25, touchInputId, nullptr, nullptr, &blockId);
PinchWithTouchInput(apzc, ScreenIntPoint(250, 300), 1.25, touchInputId,
nullptr, nullptr, &blockId);
// Send the prevent-default notification for the touch block
apzc->ContentReceivedInputBlock(blockId, true);
@ -162,7 +167,8 @@ TEST_F(APZCPinchTester, Panning_TwoFinger_ZoomDisabled) {
MakeApzcUnzoomable();
nsEventStatus statuses[3]; // scalebegin, scale, scaleend
PinchWithPinchInput(apzc, 250, 350, 200, 300, 10, &statuses);
PinchWithPinchInput(apzc, ScreenIntPoint(250, 350), ScreenIntPoint(200, 300),
10, &statuses);
FrameMetrics fm = apzc->GetFrameMetrics();

Просмотреть файл

@ -8,12 +8,12 @@
#include "APZTestCommon.h"
#include "InputUtils.h"
class APZOverscrollHandoffTester : public APZCTreeManagerTester {
class APZScrollHandoffTester : public APZCTreeManagerTester {
protected:
UniquePtr<ScopedLayerTreeRegistration> registration;
TestAsyncPanZoomController* rootApzc;
void CreateOverscrollHandoffLayerTree1() {
void CreateScrollHandoffLayerTree1() {
const char* layerTreeSyntax = "c(t)";
nsIntRegion layerVisibleRegion[] = {
nsIntRegion(IntRect(0, 0, 100, 100)),
@ -26,9 +26,10 @@ protected:
registration = MakeUnique<ScopedLayerTreeRegistration>(manager, 0, root, mcc);
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
rootApzc = ApzcOf(root);
rootApzc->GetFrameMetrics().SetIsRootContent(true); // make root APZC zoomable
}
void CreateOverscrollHandoffLayerTree2() {
void CreateScrollHandoffLayerTree2() {
const char* layerTreeSyntax = "c(c(t))";
nsIntRegion layerVisibleRegion[] = {
nsIntRegion(IntRect(0, 0, 100, 100)),
@ -48,7 +49,7 @@ protected:
rootApzc = ApzcOf(root);
}
void CreateOverscrollHandoffLayerTree3() {
void CreateScrollHandoffLayerTree3() {
const char* layerTreeSyntax = "c(c(t)c(t))";
nsIntRegion layerVisibleRegion[] = {
nsIntRegion(IntRect(0, 0, 100, 100)), // root
@ -126,9 +127,9 @@ protected:
// Here we test that if the processing of a touch block is deferred while we
// wait for content to send a prevent-default message, overscroll is still
// handed off correctly when the block is processed.
TEST_F(APZOverscrollHandoffTester, DeferredInputEventProcessing) {
TEST_F(APZScrollHandoffTester, DeferredInputEventProcessing) {
// Set up the APZC tree.
CreateOverscrollHandoffLayerTree1();
CreateScrollHandoffLayerTree1();
TestAsyncPanZoomController* childApzc = ApzcOf(layers[1]);
@ -154,9 +155,9 @@ TEST_F(APZOverscrollHandoffTester, DeferredInputEventProcessing) {
// one has been queued, overscroll handoff for the first block follows
// the original layer structure while overscroll handoff for the second block
// follows the new layer structure.
TEST_F(APZOverscrollHandoffTester, LayerStructureChangesWhileEventsArePending) {
TEST_F(APZScrollHandoffTester, LayerStructureChangesWhileEventsArePending) {
// Set up an initial APZC tree.
CreateOverscrollHandoffLayerTree1();
CreateScrollHandoffLayerTree1();
TestAsyncPanZoomController* childApzc = ApzcOf(layers[1]);
@ -170,7 +171,7 @@ TEST_F(APZOverscrollHandoffTester, LayerStructureChangesWhileEventsArePending) {
// Modify the APZC tree to insert a new APZC 'middle' into the handoff chain
// between the child and the root.
CreateOverscrollHandoffLayerTree2();
CreateScrollHandoffLayerTree2();
RefPtr<Layer> middle = layers[1];
childApzc->SetWaitForMainThread();
TestAsyncPanZoomController* middleApzc = ApzcOf(middle);
@ -202,11 +203,11 @@ TEST_F(APZOverscrollHandoffTester, LayerStructureChangesWhileEventsArePending) {
// Test that putting a second finger down on an APZC while a down-chain APZC
// is overscrolled doesn't result in being stuck in overscroll.
TEST_F(APZOverscrollHandoffTester, StuckInOverscroll_Bug1073250) {
TEST_F(APZScrollHandoffTester, StuckInOverscroll_Bug1073250) {
// Enable overscrolling.
SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
CreateOverscrollHandoffLayerTree1();
CreateScrollHandoffLayerTree1();
TestAsyncPanZoomController* child = ApzcOf(layers[1]);
@ -239,11 +240,11 @@ TEST_F(APZOverscrollHandoffTester, StuckInOverscroll_Bug1073250) {
// This is almost exactly like StuckInOverscroll_Bug1073250, except the
// APZC receiving the input events for the first touch block is the child
// (and thus not the same APZC that overscrolls, which is the parent).
TEST_F(APZOverscrollHandoffTester, StuckInOverscroll_Bug1231228) {
TEST_F(APZScrollHandoffTester, StuckInOverscroll_Bug1231228) {
// Enable overscrolling.
SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
CreateOverscrollHandoffLayerTree1();
CreateScrollHandoffLayerTree1();
TestAsyncPanZoomController* child = ApzcOf(layers[1]);
@ -273,17 +274,95 @@ TEST_F(APZOverscrollHandoffTester, StuckInOverscroll_Bug1231228) {
EXPECT_FALSE(rootApzc->IsOverscrolled());
}
TEST_F(APZScrollHandoffTester, StuckInOverscroll_Bug1240202a) {
// Enable overscrolling.
SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
CreateScrollHandoffLayerTree1();
TestAsyncPanZoomController* child = ApzcOf(layers[1]);
// Pan, causing the parent APZC to overscroll.
Pan(manager, mcc, 60, 90, true /* keep finger down */);
EXPECT_FALSE(child->IsOverscrolled());
EXPECT_TRUE(rootApzc->IsOverscrolled());
// Lift the finger, triggering an overscroll animation
// (but don't allow it to run).
TouchUp(manager, ScreenIntPoint(10, 90), mcc->Time());
// Put the finger down again, interrupting the animation
// and entering the TOUCHING state.
TouchDown(manager, ScreenIntPoint(10, 90), mcc->Time());
// Lift the finger once again.
TouchUp(manager, ScreenIntPoint(10, 90), mcc->Time());
// Allow any animations to run their course.
child->AdvanceAnimationsUntilEnd();
rootApzc->AdvanceAnimationsUntilEnd();
// Make sure nothing is overscrolled.
EXPECT_FALSE(child->IsOverscrolled());
EXPECT_FALSE(rootApzc->IsOverscrolled());
}
TEST_F(APZScrollHandoffTester, StuckInOverscroll_Bug1240202b) {
// Enable overscrolling.
SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
CreateScrollHandoffLayerTree1();
TestAsyncPanZoomController* child = ApzcOf(layers[1]);
// Pan, causing the parent APZC to overscroll.
Pan(manager, mcc, 60, 90, true /* keep finger down */);
EXPECT_FALSE(child->IsOverscrolled());
EXPECT_TRUE(rootApzc->IsOverscrolled());
// Lift the finger, triggering an overscroll animation
// (but don't allow it to run).
TouchUp(manager, ScreenIntPoint(10, 90), mcc->Time());
// Put the finger down again, interrupting the animation
// and entering the TOUCHING state.
TouchDown(manager, ScreenIntPoint(10, 90), mcc->Time());
// Put a second finger down. Since we're in the TOUCHING state,
// the "are we panned into overscroll" check will fail and we
// will not ignore the second finger, instead entering the
// PINCHING state.
MultiTouchInput secondFingerDown(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0);
// Use the same touch identifier for the first touch (0) as TouchDown(). (A bit hacky.)
secondFingerDown.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, 90), ScreenSize(0, 0), 0, 0));
secondFingerDown.mTouches.AppendElement(SingleTouchData(1, ScreenIntPoint(10, 80), ScreenSize(0, 0), 0, 0));
manager->ReceiveInputEvent(secondFingerDown, nullptr, nullptr);
// Release the fingers.
MultiTouchInput fingersUp = secondFingerDown;
fingersUp.mType = MultiTouchInput::MULTITOUCH_END;
manager->ReceiveInputEvent(fingersUp, nullptr, nullptr);
// Allow any animations to run their course.
child->AdvanceAnimationsUntilEnd();
rootApzc->AdvanceAnimationsUntilEnd();
// Make sure nothing is overscrolled.
EXPECT_FALSE(child->IsOverscrolled());
EXPECT_FALSE(rootApzc->IsOverscrolled());
}
// Test that flinging in a direction where one component of the fling goes into
// overscroll but the other doesn't, results in just the one component being
// handed off to the parent, while the original APZC continues flinging in the
// other direction.
TEST_F(APZOverscrollHandoffTester, PartialFlingHandoff) {
CreateOverscrollHandoffLayerTree1();
TEST_F(APZScrollHandoffTester, PartialFlingHandoff) {
CreateScrollHandoffLayerTree1();
// Fling up and to the left. The child APZC has room to scroll up, but not
// to the left, so the horizontal component of the fling should be handed
// off to the parent APZC.
Pan(manager, mcc, ScreenPoint(90, 90), ScreenPoint(55, 55));
Pan(manager, mcc, ScreenIntPoint(90, 90), ScreenIntPoint(55, 55));
RefPtr<TestAsyncPanZoomController> parent = ApzcOf(root);
RefPtr<TestAsyncPanZoomController> child = ApzcOf(layers[1]);
@ -300,9 +379,9 @@ TEST_F(APZOverscrollHandoffTester, PartialFlingHandoff) {
// Here we test that if two flings are happening simultaneously, overscroll
// is handed off correctly for each.
TEST_F(APZOverscrollHandoffTester, SimultaneousFlings) {
TEST_F(APZScrollHandoffTester, SimultaneousFlings) {
// Set up an initial APZC tree.
CreateOverscrollHandoffLayerTree3();
CreateScrollHandoffLayerTree3();
RefPtr<TestAsyncPanZoomController> parent1 = ApzcOf(layers[1]);
RefPtr<TestAsyncPanZoomController> child1 = ApzcOf(layers[2]);
@ -330,7 +409,7 @@ TEST_F(APZOverscrollHandoffTester, SimultaneousFlings) {
parent2->AssertStateIsFling();
}
TEST_F(APZOverscrollHandoffTester, Scrollgrab) {
TEST_F(APZScrollHandoffTester, Scrollgrab) {
// Set up the layer tree
CreateScrollgrabLayerTree();
@ -345,7 +424,7 @@ TEST_F(APZOverscrollHandoffTester, Scrollgrab) {
EXPECT_EQ(15, childApzc->GetFrameMetrics().GetScrollOffset().y);
}
TEST_F(APZOverscrollHandoffTester, ScrollgrabFling) {
TEST_F(APZScrollHandoffTester, ScrollgrabFling) {
// Set up the layer tree
CreateScrollgrabLayerTree();
@ -359,20 +438,20 @@ TEST_F(APZOverscrollHandoffTester, ScrollgrabFling) {
childApzc->AssertStateIsReset();
}
TEST_F(APZOverscrollHandoffTester, ScrollgrabFlingAcceleration1) {
TEST_F(APZScrollHandoffTester, ScrollgrabFlingAcceleration1) {
CreateScrollgrabLayerTree(true /* make parent scrollable */);
TestFlingAcceleration();
}
TEST_F(APZOverscrollHandoffTester, ScrollgrabFlingAcceleration2) {
TEST_F(APZScrollHandoffTester, ScrollgrabFlingAcceleration2) {
CreateScrollgrabLayerTree(false /* do not make parent scrollable */);
TestFlingAcceleration();
}
TEST_F(APZOverscrollHandoffTester, ImmediateHandoffDisallowed_Pan) {
TEST_F(APZScrollHandoffTester, ImmediateHandoffDisallowed_Pan) {
SCOPED_GFX_PREF(APZAllowImmediateHandoff, bool, false);
CreateOverscrollHandoffLayerTree1();
CreateScrollHandoffLayerTree1();
RefPtr<TestAsyncPanZoomController> parentApzc = ApzcOf(root);
RefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);
@ -394,10 +473,10 @@ TEST_F(APZOverscrollHandoffTester, ImmediateHandoffDisallowed_Pan) {
EXPECT_EQ(10, parentApzc->GetFrameMetrics().GetScrollOffset().y);
}
TEST_F(APZOverscrollHandoffTester, ImmediateHandoffDisallowed_Fling) {
TEST_F(APZScrollHandoffTester, ImmediateHandoffDisallowed_Fling) {
SCOPED_GFX_PREF(APZAllowImmediateHandoff, bool, false);
CreateOverscrollHandoffLayerTree1();
CreateScrollHandoffLayerTree1();
RefPtr<TestAsyncPanZoomController> parentApzc = ApzcOf(root);
RefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);

Просмотреть файл

@ -9,9 +9,9 @@ UNIFIED_SOURCES += [
'TestEventRegions.cpp',
'TestGestureDetector.cpp',
'TestHitTesting.cpp',
'TestOverscrollHandoff.cpp',
'TestPanning.cpp',
'TestPinching.cpp',
'TestScrollHandoff.cpp',
'TestTreeManager.cpp',
]

Просмотреть файл

@ -324,6 +324,7 @@ MessageChannel::MessageChannel(MessageListener *aListener)
mDispatchingAsyncMessagePriority(0),
mCurrentTransaction(0),
mTimedOutMessageSeqno(0),
mTimedOutMessagePriority(0),
mRecvdErrors(0),
mRemoteStackDepthGuess(false),
mSawInterruptOutMsg(false),
@ -1039,6 +1040,7 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
}
mTimedOutMessageSeqno = seqno;
mTimedOutMessagePriority = prio;
return false;
}
}
@ -1408,7 +1410,22 @@ MessageChannel::DispatchSyncMessage(const Message& aMsg, Message*& aReply)
MessageChannel*& blockingVar = ShouldBlockScripts() ? gParentProcessBlocker : dummy;
Result rv;
{
if (mTimedOutMessageSeqno && mTimedOutMessagePriority >= prio) {
// If the other side sends a message in response to one of our messages
// that we've timed out, then we reply with an error.
//
// We do this because want to avoid a situation where we process an
// incoming message from the child here while it simultaneously starts
// processing our timed-out CPOW. It's very bad for both sides to
// be processing sync messages concurrently.
//
// The only exception is if the incoming message has urgent priority and
// our timed-out message had only high priority. In that case it's safe
// to process the incoming message because we know that the child won't
// process anything (the child will defer incoming messages when waiting
// for a response to its urgent message).
rv = MsgNotAllowed;
} else {
AutoSetValue<MessageChannel*> blocked(blockingVar, this);
AutoSetValue<bool> sync(mDispatchingSyncMessage, true);
AutoSetValue<int> prioSet(mDispatchingSyncMessagePriority, prio);
@ -2117,8 +2134,10 @@ MessageChannel::CancelCurrentTransaction()
{
MonitorAutoLock lock(*mMonitor);
if (mCurrentTransaction) {
CancelMessage *cancel = new CancelMessage();
cancel->set_transaction_id(mCurrentTransaction);
mLink->SendMessage(cancel);
CancelCurrentTransactionInternal();
mLink->SendMessage(new CancelMessage());
}
}

Просмотреть файл

@ -630,6 +630,7 @@ class MessageChannel : HasResultCodes
// hitting a lot of corner cases with message nesting that we don't really
// care about.
int32_t mTimedOutMessageSeqno;
int mTimedOutMessagePriority;
// If waiting for the reply to a sync out-message, it will be saved here
// on the I/O thread and then read and cleared by the worker thread.

Просмотреть файл

@ -195,6 +195,36 @@ function ArrayStaticSome(list, callbackfn/*, thisArg*/) {
return callFunction(ArraySome, list, callbackfn, T);
}
/* ES6 draft 2016-1-15 22.1.3.25 Array.prototype.sort (comparefn) */
function ArraySort(comparefn) {
/* Step 1. */
var O = ToObject(this);
/* Step 2. */
var len = TO_UINT32(O.length);
/* 22.1.3.25.1 Runtime Semantics: SortCompare( x, y ) */
var wrappedCompareFn = comparefn;
comparefn = function(x, y) {
/* Steps 1-3. */
if (x === undefined) {
if (y === undefined)
return 0;
return 1;
}
if (y === undefined)
return -1;
/* Step 4.a. */
var v = ToNumber(wrappedCompareFn(x, y));
/* Step 4.b-c. */
return v !== v ? 0 : v;
}
return MergeSort(O, len, comparefn);
}
/* ES5 15.4.4.18. */
function ArrayForEach(callbackfn/*, thisArg*/) {
/* Step 1. */

185
js/src/builtin/Sorting.js Normal file
Просмотреть файл

@ -0,0 +1,185 @@
/* 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/. */
// We use varying sorts across the self-hosted codebase. All sorts are
// consolidated here to avoid confusion and re-implementation of existing
// algorithms.
// For sorting small arrays.
function InsertionSort(array, from, to, comparefn) {
var item, swap;
for (var i = from + 1; i <= to; i++) {
item = array[i];
for (var j = i - 1; j >= from; j--) {
swap = array[j];
if (comparefn(swap, item) <= 0)
break;
array[j + 1] = swap;
}
array[j + 1] = item;
}
}
function SwapArrayElements(array, i, j) {
var swap = array[i];
array[i] = array[j];
array[j] = swap;
}
// A helper function for MergeSort.
function Merge(array, start, mid, end, lBuffer, rBuffer, comparefn) {
var i, j, k;
var sizeLeft = mid - start + 1;
var sizeRight = end - mid;
// Copy our virtual arrays into separate buffers.
for (i = 0; i < sizeLeft; i++)
lBuffer[i] = array[start + i];
for (j = 0; j < sizeRight; j++)
rBuffer[j] = array[mid + 1 + j];
i = 0;
j = 0;
k = start;
while (i < sizeLeft && j < sizeRight) {
if (comparefn(lBuffer[i], rBuffer[j]) <= 0) {
array[k] = lBuffer[i];
i++;
} else {
array[k] = rBuffer[j];
j++;
}
k++;
}
// Empty out any remaining elements in the buffer.
while (i < sizeLeft) {
array[k] = lBuffer[i];
i++;
k++;
}
while (j < sizeRight) {
array[k] = rBuffer[j];
j++;
k++;
}
}
// Iterative, bottom up, mergesort.
function MergeSort(array, len, comparefn) {
// Insertion sort for small arrays, where "small" is defined by performance
// testing.
if (len < 24) {
InsertionSort(array, 0, len - 1, comparefn);
return array;
}
// We do all of our allocating up front
var lBuffer = new List();
var rBuffer = new List();
var mid, end, endOne, endTwo;
for (var windowSize = 1; windowSize < len; windowSize = 2*windowSize) {
for (var start = 0; start < len - 1; start += 2*windowSize) {
assert(windowSize < len, "The window size is larger than the array length!");
// The midpoint between the two subarrays.
mid = start + windowSize - 1;
// To keep from going over the edge.
end = start + 2 * windowSize - 1;
end = end < len - 1 ? end : len - 1;
// Skip lopsided runs to avoid doing useless work
if (mid > end)
continue;
Merge(array, start, mid, end, lBuffer, rBuffer, comparefn);
}
}
return array;
}
// Rearranges the elements in array[from:to + 1] and returns an index j such that:
// - from < j < to
// - each element in array[from:j] is less than or equal to array[j]
// - each element in array[j + 1:to + 1] greater than or equal to array[j].
function Partition(array, from, to, comparefn) {
assert(to - from >= 3, "Partition will not work with less than three elements");
var medianIndex = (from + to) >> 1;
var i = from + 1;
var j = to;
SwapArrayElements(array, medianIndex, i);
// Median of three pivot selection.
if (comparefn(array[from], array[to]) > 0)
SwapArrayElements(array, from, to);
if (comparefn(array[i], array[to]) > 0)
SwapArrayElements(array, i, to);
if (comparefn(array[from], array[i]) > 0)
SwapArrayElements(array, from, i);
var pivotIndex = i;
// Hoare partition method.
for(;;) {
do i++; while (comparefn(array[i], array[pivotIndex]) < 0);
do j--; while (comparefn(array[j], array[pivotIndex]) > 0);
if (i > j)
break;
SwapArrayElements(array, i, j);
}
SwapArrayElements(array, pivotIndex, j);
return j;
}
// In-place QuickSort.
function QuickSort(array, len, comparefn) {
// Managing the stack ourselves seems to provide a small performance boost.
var stack = new List();
var top = 0;
var start = 0;
var end = len - 1;
var pivotIndex, i, j, leftLen, rightLen;
for (;;) {
// Insertion sort for the first N elements where N is some value
// determined by performance testing.
if (end - start <= 23) {
InsertionSort(array, start, end, comparefn);
if (top < 1)
break;
end = stack[--top];
start = stack[--top];
} else {
pivotIndex = Partition(array, start, end, comparefn);
// Calculate the left and right sub-array lengths and save
// stack space by directly modifying start/end so that
// we sort the longest of the two during the next iteration.
// This reduces the maximum stack size to log2(len).
leftLen = (pivotIndex - 1) - start;
rightLen = end - (pivotIndex + 1);
if (rightLen > leftLen) {
stack[top++] = start;
stack[top++] = pivotIndex - 1;
start = pivotIndex + 1;
} else {
stack[top++] = pivotIndex + 1;
stack[top++] = end;
end = pivotIndex - 1;
}
}
}
return array;
}

Просмотреть файл

@ -939,112 +939,6 @@ function TypedArraySome(callbackfn, thisArg = undefined) {
return false;
}
// For sorting small arrays
function InsertionSort(array, from, to, comparefn) {
var item, swap;
for (var i = from + 1; i <= to; i++) {
item = array[i];
for (var j = i - 1; j >= from; j--) {
swap = array[j];
if (comparefn(swap, item) <= 0)
break
array[j + 1] = swap;
}
array[j + 1] = item;
}
}
function SwapArrayElements(array, i, j) {
var swap = array[i];
array[i] = array[j];
array[j] = swap;
}
// Rearranges the elements in array[from:to + 1] and returns an index j such that:
// - from < j < to
// - each element in array[from:j] is less than or equal to array[j]
// - each element in array[j + 1:to + 1] greater than or equal to array[j].
function Partition(array, from, to, comparefn) {
assert(to - from >= 3,
"Partition will not work with less than three elements");
var median_i = (from + to) >> 1;
var i = from + 1;
var j = to;
SwapArrayElements(array, median_i, i);
// Median of three pivot selection
if (comparefn(array[from], array[to]) > 0)
SwapArrayElements(array, from, to);
if (comparefn(array[i], array[to]) > 0)
SwapArrayElements(array, i, to);
if (comparefn(array[from], array[i]) > 0)
SwapArrayElements(array, from, i);
var pivot_i = i;
// Hoare partition method
for(;;) {
do i++; while (comparefn(array[i], array[pivot_i]) < 0);
do j--; while (comparefn(array[j], array[pivot_i]) > 0);
if (i > j)
break;
SwapArrayElements(array, i, j);
}
SwapArrayElements(array, pivot_i, j);
return j;
}
// In-place QuickSort
function QuickSort(array, len, comparefn) {
// Managing the stack ourselves seems to provide a small performance boost
var stack = new List();
var top = 0;
var start = 0;
var end = len - 1;
var pivot_i, i, j, l_len, r_len;
for (;;) {
// Insertion sort for the first N elements where N is some value
// determined by performance testing.
if (end - start <= 23) {
InsertionSort(array, start, end, comparefn);
if (top < 1)
break;
end = stack[--top];
start = stack[--top];
} else {
pivot_i = Partition(array, start, end, comparefn);
// Calculate the left and right sub-array lengths and save
// stack space by directly modifying start/end so that
// we sort the longest of the two during the next iteration.
// This reduces the maximum stack size to log2(len)
l_len = (pivot_i - 1) - start;
r_len = end - (pivot_i + 1);
if (r_len > l_len) {
stack[top++] = start;
stack[top++] = pivot_i - 1;
start = pivot_i + 1;
} else {
stack[top++] = pivot_i + 1;
stack[top++] = end;
end = pivot_i - 1;
}
}
}
return array;
}
// ES6 draft 20151210 22.2.3.26
// Cases are ordered according to likelihood of occurrence
// as opposed to the ordering in the spec.

Просмотреть файл

@ -2901,24 +2901,6 @@ elif test "$GNU_CC"; then
fi
fi
dnl ========================================================
dnl = Enable DMD
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(dmd,
[ --enable-dmd Enable DMD; also enables jemalloc and replace-malloc],
MOZ_DMD=1,
MOZ_DMD= )
if test "$MOZ_DMD"; then
AC_DEFINE(MOZ_DMD)
if test "${CPU_ARCH}" = "arm"; then
CFLAGS="$CFLAGS -funwind-tables"
CXXFLAGS="$CXXFLAGS -funwind-tables"
fi
fi
dnl ========================================================
dnl = Enable jemalloc
dnl ========================================================

Просмотреть файл

@ -18,11 +18,6 @@
#include "gc/StoreBuffer.h"
#include "gc/Tracer.h"
/* Perform validation of incremental marking in debug builds but not on B2G. */
#if defined(DEBUG) && !defined(MOZ_B2G)
#define JS_GC_MARKING_VALIDATION
#endif
namespace js {
class AutoLockGC;
@ -1182,7 +1177,7 @@ class GCRuntime
js::gc::ZoneList zonesToMaybeCompact;
ArenaHeader* relocatedArenasToRelease;
#ifdef JS_GC_MARKING_VALIDATION
#ifdef JS_GC_ZEAL
js::gc::MarkingValidator* markingValidator;
#endif

Просмотреть файл

@ -2,6 +2,6 @@ try {
[0,0].sort(Array.some)
"".replace(RegExp(), Array.reduce)
} catch (error) {
if (!(error instanceof TypeError && error.message == "0 is not a function"))
if (!(error instanceof TypeError && /^\w is not a function$/.test(error.message)))
throw error;
}
}

Просмотреть файл

@ -1817,6 +1817,43 @@ js::array_sort(JSContext* cx, unsigned argc, Value* vp)
if (!obj)
return false;
ComparatorMatchResult comp = MatchNumericComparator(cx, fval);
if (comp == Match_Failure)
return false;
if (!fval.isNull() && comp == Match_None) {
/*
* Non-optimized user supplied comparators perform much better when
* called from within a self-hosted sorting function.
*/
RootedAtom selfHostedSortAtom(cx, Atomize(cx, "ArraySort", 9));
RootedPropertyName selfHostedSortName(cx, selfHostedSortAtom->asPropertyName());
RootedValue selfHostedSortValue(cx);
if (!GlobalObject::getIntrinsicValue(cx, cx->global(), selfHostedSortName,
&selfHostedSortValue)) {
return false;
}
MOZ_ASSERT(selfHostedSortValue.isObject());
MOZ_ASSERT(selfHostedSortValue.toObject().is<JSFunction>());
InvokeArgs iargs(cx);
if (!iargs.init(1))
return false;
iargs.setCallee(selfHostedSortValue);
iargs.setThis(args.thisv());
iargs[0].set(fval);
if (!Invoke(cx, iargs))
return false;
args.rval().set(iargs.rval());
return true;
}
uint32_t len;
if (!GetLengthProperty(cx, obj, &len))
return false;
@ -1917,27 +1954,13 @@ js::array_sort(JSContext* cx, unsigned argc, Value* vp)
return false;
}
} else {
ComparatorMatchResult comp = MatchNumericComparator(cx, fval);
if (comp == Match_Failure)
return false;
if (comp != Match_None) {
if (allInts) {
JS_ALWAYS_TRUE(vec.resize(n * 2));
if (!MergeSort(vec.begin(), n, vec.begin() + n, SortComparatorInt32s[comp]))
return false;
} else {
if (!SortNumerically(cx, &vec, n, comp))
return false;
}
} else {
FastInvokeGuard fig(cx, fval);
if (allInts) {
JS_ALWAYS_TRUE(vec.resize(n * 2));
if (!MergeSort(vec.begin(), n, vec.begin() + n,
SortComparatorFunction(cx, fval, fig)))
{
if (!MergeSort(vec.begin(), n, vec.begin() + n, SortComparatorInt32s[comp]))
return false;
} else {
if (!SortNumerically(cx, &vec, n, comp))
return false;
}
}
}

Просмотреть файл

@ -1150,7 +1150,7 @@ GCRuntime::GCRuntime(JSRuntime* rt) :
arenasAllocatedDuringSweep(nullptr),
startedCompacting(false),
relocatedArenasToRelease(nullptr),
#ifdef JS_GC_MARKING_VALIDATION
#ifdef JS_GC_ZEAL
markingValidator(nullptr),
#endif
interFrameGC(false),

Просмотреть файл

@ -711,6 +711,7 @@ selfhosted.inputs = [
'builtin/RegExp.js',
'builtin/String.js',
'builtin/Set.js',
'builtin/Sorting.js',
'builtin/TypedArray.js',
'builtin/TypedObject.js',
'builtin/WeakSet.js'

Просмотреть файл

@ -0,0 +1,34 @@
// Note: failed runs should include their "SEED" value in error messages,
// setting "const SEED" to that value will recreate the data from any such run.
const SEED = (Math.random() * 10) + 1;
// Create an array filled with random values, 'size' is the desired length of
// the array and 'seed' is an initial value supplied to a pseudo-random number
// generator.
function genRandomArray(size, seed) {
return Array.from(XorShiftGenerator(seed, size));
}
function SortTest(size, seed) {
let arrOne = genRandomArray(size, seed);
let arrTwo = Array.from(arrOne);
let arrThree = Array.from(arrOne);
// Test numeric comparators against typed array sort.
assertDeepEq(Array.from((Int32Array.from(arrOne)).sort()),
arrTwo.sort((x, y) => (x - y)),
`The arr is not properly sorted! seed: ${SEED}`);
// Use multiplication to kill comparator optimization and trigger
// self-hosted sorting.
assertDeepEq(Array.from((Int32Array.from(arrOne)).sort()),
arrThree.sort((x, y) => (1*x - 1*y)),
`The arr is not properly sorted! seed: ${SEED}`);
}
SortTest(2048, SEED);
SortTest(16, SEED);
SortTest(0, SEED);
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,33 @@
// Sort every possible permutation of some arrays.
function sortAllPermutations(data, comparefn) {
for (let permutation of Permutations(Array.from(data))) {
let sorted = (Array.from(permutation)).sort(comparefn);
for (let i in sorted) {
assertEq(sorted[i], data[i],
[`[${permutation}].sort(${comparefn})`,
`returned ${sorted}, expected ${data}`].join(' '));
}
}
}
let lex = [2112, "bob", "is", "my", "name"];
let nans = [1/undefined, NaN, Number.NaN]
let num1 = [-11, 0, 0, 100, 101];
let num2 = [-11, 100, 201234.23, undefined, undefined];
sortAllPermutations(lex);
sortAllPermutations(nans);
sortAllPermutations(nans, (x, y) => x - y);
// Multiplication kills comparator optimization.
sortAllPermutations(nans, (x, y) => (1*x - 1*y));
sortAllPermutations(num1, (x, y) => x - y);
sortAllPermutations(num1, (x, y) => (1*x - 1*y));
sortAllPermutations(num2, (x, y) => x - y);
sortAllPermutations(num2, (x, y) => (1*x - 1*y));
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -2,20 +2,6 @@
// setting "const SEED" to that value will recreate the data from any such run.
const SEED = (Math.random() * 10) + 1;
// An xorshift pseudo-random number generator see:
// https://en.wikipedia.org/wiki/Xorshift#xorshift.2A
// This generator will always produce a value, n, where
// 0 <= n <= 255
function *xorShiftGenerator(seed, size) {
let x = seed;
for (let i = 0; i < size; i++) {
x ^= x >> 12;
x ^= x << 25;
x ^= x >> 27;
yield x % 256;
}
}
// Fill up an array buffer with random values and return it in raw form.
// 'size' is the desired length of the view we will place atop the buffer,
// 'width' is the bit-width of the view we plan on placing atop the buffer,
@ -26,7 +12,7 @@ function genRandomArrayBuffer(size, width, seed) {
let len = 0;
// We generate a random number, n, where 0 <= n <= 255 for every space
// available in our buffer.
for (let n of xorShiftGenerator(seed, buf.byteLength))
for (let n of XorShiftGenerator(seed, buf.byteLength))
arr[len++] = n;
return buf;
}

Просмотреть файл

@ -1,22 +1,3 @@
function swapElements(arr, i, j) {
var swap = arr[i];
arr[i] = arr[j];
arr[j] = swap;
}
// Yield every permutation of the elements in some iterable.
function *permutations(items) {
if (items.length == 0) {
yield [];
} else {
for (let i = 0; i < items.length; i++) {
swapElements(items, 0, i);
for (let e of permutations(items.slice(1, items.length)))
yield [items[0]].concat(e);
}
}
}
// Pre-sorted test data, it's important that these arrays remain in ascending order.
let i32 = [-2147483648, -320000, -244000, 2147483647]
let u32 = [0, 987632, 4294967295]
@ -35,7 +16,7 @@ let nans = [1/undefined, NaN, Number.NaN]
// Sort every possible permutation of an arrays
function sortAllPermutations(dataType, testData) {
let reference = new dataType(testData);
for (let permutation of permutations(testData))
for (let permutation of Permutations(testData))
assertDeepEq((new dataType(permutation)).sort(), reference);
}

Просмотреть файл

@ -372,6 +372,40 @@ function enterFunc (funcName)
callStack.push(funcName);
}
/*
* An xorshift pseudo-random number generator see:
* https://en.wikipedia.org/wiki/Xorshift#xorshift.2A
* This generator will always produce a value, n, where
* 0 <= n <= 255
*/
function *XorShiftGenerator(seed, size) {
let x = seed;
for (let i = 0; i < size; i++) {
x ^= x >> 12;
x ^= x << 25;
x ^= x >> 27;
yield x % 256;
}
}
/*
* Yield every permutation of the elements in some iterable.
*/
function *Permutations(items) {
if (items.length == 0) {
yield [];
} else {
let swap;
for (let i = 0; i < items.length; i++) {
swap = items[0];
items[0] = items[i];
items[i] = swap;
for (let e of Permutations(items.slice(1, items.length)))
yield [items[0]].concat(e);
}
}
}
/*
* Pops the top funcName off the call stack. funcName is optional, and can be
* used to check push-pop balance.

Просмотреть файл

@ -1066,7 +1066,8 @@ SavedStacks::clear()
size_t
SavedStacks::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
{
return frames.sizeOfExcludingThis(mallocSizeOf);
return frames.sizeOfExcludingThis(mallocSizeOf) +
pcLocationMap.sizeOfExcludingThis(mallocSizeOf);
}
bool

Просмотреть файл

@ -1856,7 +1856,7 @@ struct FramesWithDepth
{}
bool operator<(const FramesWithDepth& aOther) const {
if (mDepth != aOther.mDepth) {
if (!FuzzyEqual(mDepth, aOther.mDepth, 0.1f)) {
// We want to sort so that the shallowest item (highest depth value) is first
return mDepth > aOther.mDepth;
}
@ -1919,13 +1919,16 @@ void nsDisplayList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
bool snap;
nsRect r = item->GetBounds(aBuilder, &snap).Intersect(aRect);
auto itemType = item->GetType();
bool alwaysIntersect =
bool same3DContext =
(itemType == nsDisplayItem::TYPE_TRANSFORM &&
static_cast<nsDisplayTransform*>(item)->IsParticipating3DContext()) ||
(itemType == nsDisplayItem::TYPE_PERSPECTIVE &&
static_cast<nsDisplayPerspective*>(item)->Frame()->Extend3DContext());
if (alwaysIntersect &&
if (same3DContext &&
!static_cast<nsDisplayTransform*>(item)->IsLeafOf3DContext()) {
if (!item->GetClip().MayIntersect(aRect)) {
continue;
}
nsAutoTArray<nsIFrame*, 1> neverUsed;
// Start gethering leaves of the 3D rendering context, and
// append leaves at the end of mItemBuffer. Leaves are
@ -1936,7 +1939,7 @@ void nsDisplayList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
i = aState->mItemBuffer.Length();
continue;
}
if (alwaysIntersect || item->GetClip().MayIntersect(r)) {
if (same3DContext || item->GetClip().MayIntersect(r)) {
nsAutoTArray<nsIFrame*, 16> outFrames;
item->HitTest(aBuilder, aRect, aState, &outFrames);

Просмотреть файл

@ -5,6 +5,7 @@ support-files =
Ahem.ttf
border_radius_hit_testing_iframe.html
preserve3d_sorting_hit_testing_iframe.html
preserve3d_sorting_hit_testing2_iframe.html
image_rgrg-256x256.png
image_rrgg-256x256.png
bug369950-subframe.xml
@ -41,6 +42,7 @@ support-files =
multi-range-script-select-ref.html
[test_preserve3d_sorting_hit_testing.html]
[test_preserve3d_sorting_hit_testing2.html]
[test_after_paint_pref.html]
[test_bug993936.html]
skip-if = e10s

Просмотреть файл

@ -0,0 +1,97 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body {
background: #333;
overflow: hidden;
}
::-webkit-scrollbar {
display: none;
}
div {
margin: 0;
padding: 0;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
position: absolute;
}
#container {
font-family: UnifrakturMaguntia;
width: 350px;
height: 70%;
max-height: 500px;
-webkit-perspective: 5000px;
perspective: 5000px;
transform: translate(-50%, -50%) rotateY(20deg);
}
#container p {
padding: 0 5px 0 5px;
}
#container hr {
margin: 0 20px 0 20px;
}
#content {
-ms-overflow-style: none;
overflow: -moz-scrollbars-none;
overflow-y: scroll;
height: 100%;
background: #fefee0;
}
#lorem {
font-size: 7em;
float: left;
color: red;
border: 1px solid black;
margin-right: 5px;
}
#tree {
float: right;
width: 10em;
height: 10em;
border: 1px solid black;
margin: 0 5px 0 2px;
}
</style>
</head>
<body>
<div id="container">
<div id="content">
<p>
<span id="lorem">L</span>orem ipsum dolor sit amet, consectetur adipiscing elit. Integer sagittis nisi urna, a ultrices est facilisis a. Morbi porttitor vulputate odio, eu lacinia nisi. Suspendisse felis sapien, facilisis nec ex in, blandit tincidunt tellus. Sed at commodo nunc. In nibh lectus, facilisis nec magna nec, bibendum egestas nunc. Nam varius lorem in fringilla cursus. Integer dignissim, lectus vitae sodales molestie, libero purus malesuada arcu, vitae facilisis nunc dolor non mi. In nunc tortor, tempor non pharetra vitae, mattis a purus. Nulla rhoncus vitae metus vel ornare. Nunc augue dui, suscipit ac urna vel, consectetur volutpat ipsum. Nunc ac nulla ut enim laoreet placerat. Sed luctus aliquam purus, sollicitudin blandit dui blandit id. Aenean venenatis risus dolor, at viverra urna aliquam non. Morbi sit amet pellentesque justo, eget viverra augue.
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;
Praesent posuere ultricies orci sit amet lacinia. Suspendisse lacinia scelerisque risus, sodales egestas turpis cursus sed. Proin sed mollis mauris, vitae ultricies nibh. Nulla bibendum leo a mauris luctus, sit amet iaculis arcu blandit. Etiam pulvinar, odio et rutrum egestas, elit mi maximus ex, id elementum est tortor id turpis. Duis rhoncus et lorem vel maximus. Aenean at justo sagittis, aliquet eros eget, iaculis magna. Nam non orci congue, dapibus dui eget, sagittis nisl. Phasellus venenatis id est et tempor. Aenean condimentum tristique nibh sit amet varius. Vestibulum et lectus quis eros dapibus consectetur nec auctor dolor. Sed euismod eu felis aliquam fermentum. Donec lacinia fringilla erat, at eleifend velit tempus at.
</p>
<hr>
<p>&nbsp;&nbsp;&nbsp;&nbsp;
Cras justo turpis, vulputate eget venenatis sit amet, bibendum quis dolor. Cras at interdum libero. Quisque convallis rutrum magna in ultrices. Donec ut magna dolor. Mauris pulvinar ut sapien a posuere. Sed nisi elit, tincidunt vitae magna eu, dapibus suscipit purus. Maecenas tincidunt mollis eros et dictum. Duis est nulla, rhoncus tincidunt velit at, venenatis elementum velit. Phasellus lobortis sem tellus, id sodales quam dignissim nec. Phasellus pulvinar metus ex, nec gravida nunc elementum vel. Ut mattis varius fringilla. Phasellus imperdiet sit amet risus a elementum. Donec pulvinar ante sit amet massa blandit ullamcorper. Donec vitae malesuada nisl, et laoreet sem.
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;
Suspendisse bibendum elit blandit arcu vulputate, nec hendrerit dui vehicula. Vestibulum porta finibus odio vitae maximus. Duis in vulputate risus. Donec mattis turpis ex, vitae semper sem ultrices eu. Aliquam in ex blandit erat ultrices sollicitudin. Vestibulum porta nisl in porttitor rutrum. Integer consectetur porttitor ligula facilisis malesuada. Proin placerat enim sed lacus commodo mollis nec eu arcu. In hac habitasse platea dictumst. Curabitur luctus est risus, sit amet fringilla nunc condimentum vel. Integer mauris lorem, molestie ut nisl sit amet, pellentesque mollis quam. Aliquam posuere purus non nisi molestie semper.
</p>
<hr>
<p>&nbsp;&nbsp;&nbsp;&nbsp;
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Mauris facilisis nisi diam, eu pulvinar ex sollicitudin sed. Maecenas sed eros id quam suscipit ultricies ut tincidunt quam. Donec iaculis, justo at fringilla laoreet, quam sem dapibus urna, ut eleifend odio eros et ligula. Proin urna ante, condimentum vitae sollicitudin sit amet, egestas ac nunc. Aenean sapien velit, porta a eros quis, iaculis dignissim felis. Suspendisse mollis vulputate metus vel interdum. Aliquam hendrerit elementum erat, sit amet commodo velit suscipit et. Sed semper sem at mauris rhoncus, id efficitur arcu molestie. Nam feugiat lorem pretium, consectetur felis et, fringilla dolor. Nunc dui velit, elementum non hendrerit nec, sagittis vitae odio. Curabitur nec leo tincidunt, pellentesque metus at, condimentum risus.
</p>
</div>
</div>
</body>
<script type="application/javascript">
window.onload = function() {
opener.child_opened(document);
};
</script>
</html>

Просмотреть файл

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1241394
-->
<head>
<title>Test for Bug 1241394</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body onload="run()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1241394">Mozilla Bug 1241394</a>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 1241394 **/
SimpleTest.waitForExplicitFinish();
function run() {
var win;
window.child_opened = function(doc) {
var container= doc.getElementById("container");
isnot(doc.elementFromPoint(60, 50).id, container.id,
"point (50, 50): should not hit background");
win.close();
SimpleTest.finish();
}
win = window.open("preserve3d_sorting_hit_testing2_iframe.html");
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -65,7 +65,7 @@ static void nr_ice_socket_readable_cb(NR_SOCKET s, int how, void *cb_arg)
NR_ASYNC_WAIT(s,how,nr_ice_socket_readable_cb,cb_arg);
if(r=nr_socket_recvfrom(sock->sock,buf,sizeof(buf),&len_s,0,&addr)){
if (r != R_WOULDBLOCK && (sock->type == NR_ICE_SOCKET_TYPE_STREAM_TURN)) {
if (r != R_WOULDBLOCK && (sock->type != NR_ICE_SOCKET_TYPE_DGRAM)) {
/* Report this error upward. Bug 946423 */
r_log(LOG_ICE,LOG_ERR,"ICE(%s): Error %d on reliable socket. Abandoning.",sock->ctx->label, r);
NR_ASYNC_CANCEL(s, NR_ASYNC_WAIT_READ);

Просмотреть файл

@ -47,13 +47,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endif
#define END_HEADERS CRLF CRLF
typedef enum {
PROXY_TUNNEL_NONE=0,
PROXY_TUNNEL_REQUESTED,
PROXY_TUNNEL_CONNECTED,
PROXY_TUNNEL_CLOSED,
PROXY_TUNNEL_FAILED
} nr_socket_proxy_tunnel_state;
typedef struct nr_socket_proxy_tunnel_ {
nr_proxy_tunnel_config *config;
nr_socket *inner;
nr_transport_addr remote_addr;
int connect_requested;
int connect_answered;
int connect_failed;
nr_socket_proxy_tunnel_state state;
char buffer[MAX_HTTP_CONNECT_BUFFER_SIZE];
size_t buffered_bytes;
void *resolver_handle;
@ -143,7 +149,7 @@ static int send_http_connect(nr_socket_proxy_tunnel *sock)
ABORT(R_IO_ERROR);
}
sock->connect_requested = 1;
sock->state = PROXY_TUNNEL_REQUESTED;
_status = 0;
abort:
@ -173,6 +179,9 @@ static int parse_http_response(char *begin, char *end, unsigned int *status)
// len should *never* be greater than nr_socket_proxy_tunnel::buffered_bytes.
// Which in turn should never be greater nr_socket_proxy_tunnel::buffer size.
assert(len <= MAX_HTTP_CONNECT_BUFFER_SIZE);
if (len > MAX_HTTP_CONNECT_BUFFER_SIZE) {
return R_BAD_DATA;
}
memcpy(response, begin, len);
response[len] = '\0';
@ -249,6 +258,10 @@ static int nr_socket_proxy_tunnel_resolved_cb(void *obj, nr_transport_addr *prox
else {
r_log(LOG_GENERIC,LOG_WARNING,"Failed to resolve proxy %s",
sock->config->proxy_host);
/* TODO: Mozilla bug 1241758: because of the callback the return value goes
* nowhere, so we can't mark the candidate as failed, so everything depends
* on the overall timeouts in this case. */
sock->state = PROXY_TUNNEL_FAILED;
ABORT(R_NOT_FOUND);
}
@ -336,13 +349,20 @@ int nr_socket_proxy_tunnel_write(void *obj, const void *msg, size_t len,
r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_write");
if (!sock->connect_requested) {
if (sock->state >= PROXY_TUNNEL_CLOSED) {
return R_FAILED;
}
if (sock->state == PROXY_TUNNEL_NONE) {
if ((r=send_http_connect(sock))) {
ABORT(r);
}
}
/* TODO (bug 1117984): we cannot assume it's safe to write until we receive a response. */
if (sock->state != PROXY_TUNNEL_CONNECTED) {
return R_WOULDBLOCK;
}
if ((r=nr_socket_write(sock->inner, msg, len, written, 0))) {
ABORT(r);
}
@ -366,11 +386,11 @@ int nr_socket_proxy_tunnel_read(void *obj, void * restrict buf, size_t maxlen,
*len = 0;
if (sock->connect_failed) {
if (sock->state >= PROXY_TUNNEL_CLOSED) {
return R_FAILED;
}
if (sock->connect_answered) {
if (sock->state == PROXY_TUNNEL_CONNECTED) {
return nr_socket_read(sock->inner, buf, maxlen, len, 0);
}
@ -391,8 +411,6 @@ int nr_socket_proxy_tunnel_read(void *obj, void * restrict buf, size_t maxlen,
sock->buffered_bytes += bytes_read;
if (http_term = find_http_terminator(sock->buffer, sock->buffered_bytes)) {
sock->connect_answered = 1;
if ((r = parse_http_response(sock->buffer, http_term, &http_status))) {
ABORT(r);
}
@ -404,6 +422,8 @@ int nr_socket_proxy_tunnel_read(void *obj, void * restrict buf, size_t maxlen,
ABORT(R_FAILED);
}
sock->state = PROXY_TUNNEL_CONNECTED;
ptr = http_term + strlen(END_HEADERS);
pending = sock->buffered_bytes - (ptr - sock->buffer);
@ -420,7 +440,7 @@ int nr_socket_proxy_tunnel_read(void *obj, void * restrict buf, size_t maxlen,
_status=0;
abort:
if (_status && _status != R_WOULDBLOCK) {
sock->connect_failed = 1;
sock->state = PROXY_TUNNEL_FAILED;
}
return(_status);
}
@ -436,6 +456,8 @@ int nr_socket_proxy_tunnel_close(void *obj)
sock->resolver_handle = 0;
}
sock->state = PROXY_TUNNEL_CLOSED;
return nr_socket_close(sock->inner);
}

Просмотреть файл

@ -524,6 +524,10 @@ static void nr_socket_buffered_stun_writable_cb(NR_SOCKET s, int how, void *arg)
int r,_status;
nr_p_buf *n1, *n2;
if (sock->read_state == NR_ICE_SOCKET_READ_FAILED) {
ABORT(R_FAILED);
}
/* Try to flush */
STAILQ_FOREACH_SAFE(n1, &sock->pending_writes, entry, n2) {
size_t written = 0;

Просмотреть файл

@ -49,19 +49,4 @@ void TransportLayer::SetState(State state, const char *file, unsigned line) {
}
}
nsresult TransportLayer::RunOnThread(nsIRunnable *event) {
if (target_) {
nsIThread *thr;
DebugOnly<nsresult> rv = NS_GetCurrentThread(&thr);
MOZ_ASSERT(NS_SUCCEEDED(rv));
if (target_ != thr) {
return target_->Dispatch(event, NS_DISPATCH_SYNC);
}
}
return event->Run();
}
} // close namespace

Просмотреть файл

@ -57,10 +57,6 @@ class TransportLayer : public sigslot::has_slots<> {
// Downward interface
TransportLayer *downward() { return downward_; }
// Dispatch a call onto our thread (or run on the same thread if
// thread is not set). This is always synchronous.
nsresult RunOnThread(nsIRunnable *event);
// Get the state
State state() const { return state_; }
// Must be implemented by derived classes

Просмотреть файл

@ -2088,16 +2088,7 @@ JsepSessionImpl::SetupDefaultCodecs()
));
// Supported video codecs.
JsepVideoCodecDescription* vp8 = new JsepVideoCodecDescription(
"120",
"VP8",
90000
);
// Defaults for mandatory params
vp8->mConstraints.maxFs = 12288; // Enough for 2048x1536
vp8->mConstraints.maxFps = 60;
mSupportedCodecs.values.push_back(vp8);
// Note: order here implies priority for building offers!
JsepVideoCodecDescription* vp9 = new JsepVideoCodecDescription(
"121",
"VP9",
@ -2108,6 +2099,16 @@ JsepSessionImpl::SetupDefaultCodecs()
vp9->mConstraints.maxFps = 60;
mSupportedCodecs.values.push_back(vp9);
JsepVideoCodecDescription* vp8 = new JsepVideoCodecDescription(
"120",
"VP8",
90000
);
// Defaults for mandatory params
vp8->mConstraints.maxFs = 12288; // Enough for 2048x1536
vp8->mConstraints.maxFps = 60;
mSupportedCodecs.values.push_back(vp8);
JsepVideoCodecDescription* h264_1 = new JsepVideoCodecDescription(
"126",
"H264",

Просмотреть файл

@ -2656,8 +2656,8 @@ TEST_F(JsepSessionTest, ValidateOfferedCodecParams)
ASSERT_EQ(SdpDirectionAttribute::kSendrecv, video_attrs.GetDirection());
ASSERT_EQ(4U, video_section.GetFormats().size());
ASSERT_EQ("120", video_section.GetFormats()[0]);
ASSERT_EQ("121", video_section.GetFormats()[1]);
ASSERT_EQ("121", video_section.GetFormats()[0]);
ASSERT_EQ("120", video_section.GetFormats()[1]);
ASSERT_EQ("126", video_section.GetFormats()[2]);
ASSERT_EQ("97", video_section.GetFormats()[3]);
@ -2790,22 +2790,24 @@ TEST_F(JsepSessionTest, ValidateAnsweredCodecParams)
// TODO(bug 1099351): Once fixed, this stuff will need to be updated.
ASSERT_EQ(1U, video_section.GetFormats().size());
// ASSERT_EQ(3U, video_section.GetFormats().size());
ASSERT_EQ("120", video_section.GetFormats()[0]);
ASSERT_EQ("121", video_section.GetFormats()[0]);
// ASSERT_EQ("126", video_section.GetFormats()[1]);
// ASSERT_EQ("97", video_section.GetFormats()[2]);
// Validate rtpmap
ASSERT_TRUE(video_attrs.HasAttribute(SdpAttribute::kRtpmapAttribute));
auto& rtpmaps = video_attrs.GetRtpmap();
ASSERT_TRUE(rtpmaps.HasEntry("120"));
ASSERT_TRUE(rtpmaps.HasEntry("121"));
// ASSERT_TRUE(rtpmaps.HasEntry("126"));
// ASSERT_TRUE(rtpmaps.HasEntry("97"));
auto& vp8_entry = rtpmaps.GetEntry("120");
//auto& vp8_entry = rtpmaps.GetEntry("120");
auto& vp9_entry = rtpmaps.GetEntry("121");
// auto& h264_1_entry = rtpmaps.GetEntry("126");
// auto& h264_0_entry = rtpmaps.GetEntry("97");
ASSERT_EQ("VP8", vp8_entry.name);
//ASSERT_EQ("VP8", vp8_entry.name);
ASSERT_EQ("VP9", vp9_entry.name);
// ASSERT_EQ("H264", h264_1_entry.name);
// ASSERT_EQ("H264", h264_0_entry.name);
@ -2816,17 +2818,17 @@ TEST_F(JsepSessionTest, ValidateAnsweredCodecParams)
ASSERT_EQ(1U, fmtps.size());
// ASSERT_EQ(3U, fmtps.size());
// VP8
ASSERT_EQ("120", fmtps[0].format);
// VP9
ASSERT_EQ("121", fmtps[0].format);
ASSERT_TRUE(!!fmtps[0].parameters);
ASSERT_EQ(SdpRtpmapAttributeList::kVP8, fmtps[0].parameters->codec_type);
ASSERT_EQ(SdpRtpmapAttributeList::kVP9, fmtps[0].parameters->codec_type);
auto& parsed_vp8_params =
auto& parsed_vp9_params =
*static_cast<const SdpFmtpAttributeList::VP8Parameters*>(
fmtps[0].parameters.get());
ASSERT_EQ((uint32_t)12288, parsed_vp8_params.max_fs);
ASSERT_EQ((uint32_t)60, parsed_vp8_params.max_fr);
ASSERT_EQ((uint32_t)12288, parsed_vp9_params.max_fs);
ASSERT_EQ((uint32_t)60, parsed_vp9_params.max_fr);
SetLocalAnswer(answer);

Просмотреть файл

@ -29,8 +29,13 @@
'target_name': 'rtc_base_approved',
'type': 'static_library',
'sources': [
'bitbuffer.cc',
'bitbuffer.h',
'buffer.cc',
'buffer.h',
'checks.cc',
'checks.h',
'constructormagic.h',
'event.cc',
'event.h',
'event_tracer.cc',

Просмотреть файл

@ -0,0 +1,296 @@
/*
* Copyright 2015 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/base/bitbuffer.h"
#include <algorithm>
#include <limits>
#include "webrtc/base/checks.h"
namespace {
// Returns the lowest (right-most) |bit_count| bits in |byte|.
uint8_t LowestBits(uint8_t byte, size_t bit_count) {
RTC_DCHECK_LE(bit_count, 8u);
return byte & ((1 << bit_count) - 1);
}
// Returns the highest (left-most) |bit_count| bits in |byte|, shifted to the
// lowest bits (to the right).
uint8_t HighestBits(uint8_t byte, size_t bit_count) {
RTC_DCHECK_LE(bit_count, 8u);
uint8_t shift = 8 - static_cast<uint8_t>(bit_count);
uint8_t mask = 0xFF << shift;
return (byte & mask) >> shift;
}
// Returns the highest byte of |val| in a uint8_t.
uint8_t HighestByte(uint64_t val) {
return static_cast<uint8_t>(val >> 56);
}
// Returns the result of writing partial data from |source|, of
// |source_bit_count| size in the highest bits, to |target| at
// |target_bit_offset| from the highest bit.
uint8_t WritePartialByte(uint8_t source,
size_t source_bit_count,
uint8_t target,
size_t target_bit_offset) {
RTC_DCHECK(target_bit_offset < 8);
RTC_DCHECK(source_bit_count < 9);
RTC_DCHECK(source_bit_count <= (8 - target_bit_offset));
// Generate a mask for just the bits we're going to overwrite, so:
uint8_t mask =
// The number of bits we want, in the most significant bits...
static_cast<uint8_t>(0xFF << (8 - source_bit_count))
// ...shifted over to the target offset from the most signficant bit.
>> target_bit_offset;
// We want the target, with the bits we'll overwrite masked off, or'ed with
// the bits from the source we want.
return (target & ~mask) | (source >> target_bit_offset);
}
// Counts the number of bits used in the binary representation of val.
size_t CountBits(uint64_t val) {
size_t bit_count = 0;
while (val != 0) {
bit_count++;
val >>= 1;
}
return bit_count;
}
} // namespace
namespace rtc {
BitBuffer::BitBuffer(const uint8_t* bytes, size_t byte_count)
: bytes_(bytes), byte_count_(byte_count), byte_offset_(), bit_offset_() {
RTC_DCHECK(static_cast<uint64_t>(byte_count_) <=
std::numeric_limits<uint32_t>::max());
}
uint64_t BitBuffer::RemainingBitCount() const {
return (static_cast<uint64_t>(byte_count_) - byte_offset_) * 8 - bit_offset_;
}
bool BitBuffer::ReadUInt8(uint8_t* val) {
uint32_t bit_val;
if (!ReadBits(&bit_val, sizeof(uint8_t) * 8)) {
return false;
}
RTC_DCHECK(bit_val <= std::numeric_limits<uint8_t>::max());
*val = static_cast<uint8_t>(bit_val);
return true;
}
bool BitBuffer::ReadUInt16(uint16_t* val) {
uint32_t bit_val;
if (!ReadBits(&bit_val, sizeof(uint16_t) * 8)) {
return false;
}
RTC_DCHECK(bit_val <= std::numeric_limits<uint16_t>::max());
*val = static_cast<uint16_t>(bit_val);
return true;
}
bool BitBuffer::ReadUInt32(uint32_t* val) {
return ReadBits(val, sizeof(uint32_t) * 8);
}
bool BitBuffer::PeekBits(uint32_t* val, size_t bit_count) {
if (!val || bit_count > RemainingBitCount() || bit_count > 32) {
return false;
}
const uint8_t* bytes = bytes_ + byte_offset_;
size_t remaining_bits_in_current_byte = 8 - bit_offset_;
uint32_t bits = LowestBits(*bytes++, remaining_bits_in_current_byte);
// If we're reading fewer bits than what's left in the current byte, just
// return the portion of this byte that we need.
if (bit_count < remaining_bits_in_current_byte) {
*val = HighestBits(bits, bit_offset_ + bit_count);
return true;
}
// Otherwise, subtract what we've read from the bit count and read as many
// full bytes as we can into bits.
bit_count -= remaining_bits_in_current_byte;
while (bit_count >= 8) {
bits = (bits << 8) | *bytes++;
bit_count -= 8;
}
// Whatever we have left is smaller than a byte, so grab just the bits we need
// and shift them into the lowest bits.
if (bit_count > 0) {
bits <<= bit_count;
bits |= HighestBits(*bytes, bit_count);
}
*val = bits;
return true;
}
bool BitBuffer::ReadBits(uint32_t* val, size_t bit_count) {
return PeekBits(val, bit_count) && ConsumeBits(bit_count);
}
bool BitBuffer::ConsumeBytes(size_t byte_count) {
return ConsumeBits(byte_count * 8);
}
bool BitBuffer::ConsumeBits(size_t bit_count) {
if (bit_count > RemainingBitCount()) {
return false;
}
byte_offset_ += (bit_offset_ + bit_count) / 8;
bit_offset_ = (bit_offset_ + bit_count) % 8;
return true;
}
bool BitBuffer::ReadExponentialGolomb(uint32_t* val) {
if (!val) {
return false;
}
// Store off the current byte/bit offset, in case we want to restore them due
// to a failed parse.
size_t original_byte_offset = byte_offset_;
size_t original_bit_offset = bit_offset_;
// Count the number of leading 0 bits by peeking/consuming them one at a time.
size_t zero_bit_count = 0;
uint32_t peeked_bit;
while (PeekBits(&peeked_bit, 1) && peeked_bit == 0) {
zero_bit_count++;
ConsumeBits(1);
}
// We should either be at the end of the stream, or the next bit should be 1.
RTC_DCHECK(!PeekBits(&peeked_bit, 1) || peeked_bit == 1);
// The bit count of the value is the number of zeros + 1. Make sure that many
// bits fits in a uint32_t and that we have enough bits left for it, and then
// read the value.
size_t value_bit_count = zero_bit_count + 1;
if (value_bit_count > 32 || !ReadBits(val, value_bit_count)) {
RTC_CHECK(Seek(original_byte_offset, original_bit_offset));
return false;
}
*val -= 1;
return true;
}
bool BitBuffer::ReadSignedExponentialGolomb(int32_t* val) {
uint32_t unsigned_val;
if (!ReadExponentialGolomb(&unsigned_val)) {
return false;
}
if ((unsigned_val & 1) == 0) {
*val = -static_cast<int32_t>(unsigned_val / 2);
} else {
*val = (unsigned_val + 1) / 2;
}
return true;
}
void BitBuffer::GetCurrentOffset(
size_t* out_byte_offset, size_t* out_bit_offset) {
RTC_CHECK(out_byte_offset != NULL);
RTC_CHECK(out_bit_offset != NULL);
*out_byte_offset = byte_offset_;
*out_bit_offset = bit_offset_;
}
bool BitBuffer::Seek(size_t byte_offset, size_t bit_offset) {
if (byte_offset > byte_count_ || bit_offset > 7 ||
(byte_offset == byte_count_ && bit_offset > 0)) {
return false;
}
byte_offset_ = byte_offset;
bit_offset_ = bit_offset;
return true;
}
BitBufferWriter::BitBufferWriter(uint8_t* bytes, size_t byte_count)
: BitBuffer(bytes, byte_count), writable_bytes_(bytes) {
}
bool BitBufferWriter::WriteUInt8(uint8_t val) {
return WriteBits(val, sizeof(uint8_t) * 8);
}
bool BitBufferWriter::WriteUInt16(uint16_t val) {
return WriteBits(val, sizeof(uint16_t) * 8);
}
bool BitBufferWriter::WriteUInt32(uint32_t val) {
return WriteBits(val, sizeof(uint32_t) * 8);
}
bool BitBufferWriter::WriteBits(uint64_t val, size_t bit_count) {
if (bit_count > RemainingBitCount()) {
return false;
}
size_t total_bits = bit_count;
// For simplicity, push the bits we want to read from val to the highest bits.
val <<= (sizeof(uint64_t) * 8 - bit_count);
uint8_t* bytes = writable_bytes_ + byte_offset_;
// The first byte is relatively special; the bit offset to write to may put us
// in the middle of the byte, and the total bit count to write may require we
// save the bits at the end of the byte.
size_t remaining_bits_in_current_byte = 8 - bit_offset_;
size_t bits_in_first_byte =
std::min(bit_count, remaining_bits_in_current_byte);
*bytes = WritePartialByte(
HighestByte(val), bits_in_first_byte, *bytes, bit_offset_);
if (bit_count <= remaining_bits_in_current_byte) {
// Nothing left to write, so quit early.
return ConsumeBits(total_bits);
}
// Subtract what we've written from the bit count, shift it off the value, and
// write the remaining full bytes.
val <<= bits_in_first_byte;
bytes++;
bit_count -= bits_in_first_byte;
while (bit_count >= 8) {
*bytes++ = HighestByte(val);
val <<= 8;
bit_count -= 8;
}
// Last byte may also be partial, so write the remaining bits from the top of
// val.
if (bit_count > 0) {
*bytes = WritePartialByte(HighestByte(val), bit_count, *bytes, 0);
}
// All done! Consume the bits we've written.
return ConsumeBits(total_bits);
}
bool BitBufferWriter::WriteExponentialGolomb(uint32_t val) {
// We don't support reading UINT32_MAX, because it doesn't fit in a uint32_t
// when encoded, so don't support writing it either.
if (val == std::numeric_limits<uint32_t>::max()) {
return false;
}
uint64_t val_to_encode = static_cast<uint64_t>(val) + 1;
// We need to write CountBits(val+1) 0s and then val+1. Since val (as a
// uint64_t) has leading zeros, we can just write the total golomb encoded
// size worth of bits, knowing the value will appear last.
return WriteBits(val_to_encode, CountBits(val_to_encode) * 2 - 1);
}
} // namespace rtc

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше