Merge autoland to mozilla-central. a=merge

This commit is contained in:
Cosmin Sabou 2019-03-02 23:46:22 +02:00
commit d503a7df4f
52 changed files with 685 additions and 533 deletions

View File

@ -86,7 +86,6 @@ const whitelist = {
"data:,ChromeUtils.import('resource://gre/modules/ExtensionProcessScript.jsm')",
"resource://devtools/client/jsonview/converter-observer.js",
"resource://gre/modules/WebRequestContent.js",
"resource://webcompat/aboutPageProcessScript.js",
]),
};
@ -98,11 +97,16 @@ const intermittently_loaded_whitelist = {
"resource://gre/modules/nsAsyncShutdown.jsm",
"resource://gre/modules/sessionstore/Utils.jsm",
// Webcompat about:config front-end
// Webcompat about:config front-end. This is presently nightly-only and
// part of a system add-on which may not load early enough for the test.
"resource://webcompat/AboutCompat.jsm",
]),
frameScripts: new Set([]),
processScripts: new Set([]),
processScripts: new Set([
// Webcompat about:config front-end. This is presently nightly-only and
// part of a system add-on which may not load early enough for the test.
"resource://webcompat/aboutPageProcessScript.js",
]),
};
const blacklist = {

View File

@ -1,193 +0,0 @@
Index: include/clang/Basic/BuiltinsAArch64.def
===================================================================
--- a/clang/include/clang/Basic/BuiltinsAArch64.def
+++ b/clang/include/clang/Basic/BuiltinsAArch64.def
@@ -203,8 +203,8 @@
TARGET_HEADER_BUILTIN(_ReadWriteBarrier, "v", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__getReg, "ULLii", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_ReadStatusReg, "ii", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_WriteStatusReg, "vii", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_ReadStatusReg, "LLii", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_WriteStatusReg, "viLLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_AddressOfReturnAddress, "v*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
#undef BUILTIN
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -7062,19 +7062,16 @@
llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
llvm::Type *RegisterType = Int64Ty;
- llvm::Type *ValueType = Int32Ty;
llvm::Type *Types[] = { RegisterType };
if (BuiltinID == AArch64::BI_ReadStatusReg) {
llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::read_register, Types);
- llvm::Value *Call = Builder.CreateCall(F, Metadata);
- return Builder.CreateTrunc(Call, ValueType);
+ return Builder.CreateCall(F, Metadata);
}
llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::write_register, Types);
llvm::Value *ArgValue = EmitScalarExpr(E->getArg(1));
- ArgValue = Builder.CreateZExt(ArgValue, RegisterType);
return Builder.CreateCall(F, { Metadata, ArgValue });
}
Index: lib/Headers/intrin.h
===================================================================
--- a/clang/lib/Headers/intrin.h
+++ b/clang/lib/Headers/intrin.h
@@ -554,8 +554,8 @@
#if defined(__aarch64__)
unsigned __int64 __getReg(int);
long _InterlockedAdd(long volatile *Addend, long Value);
-int _ReadStatusReg(int);
-void _WriteStatusReg(int, int);
+__int64 _ReadStatusReg(int);
+void _WriteStatusReg(int, __int64);
static inline unsigned short _byteswap_ushort (unsigned short val) {
return __builtin_bswap16(val);
Index: test/CodeGen/arm64-microsoft-status-reg.cpp
===================================================================
--- a/clang/test/CodeGen/arm64-microsoft-status-reg.cpp
+++ b/clang/test/CodeGen/arm64-microsoft-status-reg.cpp
@@ -23,87 +23,101 @@
#define ARM64_TPIDRRO_EL0 ARM64_SYSREG(3,3,13, 0,3) // Thread ID Register, User Read Only [CP15_TPIDRURO]
#define ARM64_TPIDR_EL1 ARM64_SYSREG(3,0,13, 0,4) // Thread ID Register, Privileged Only [CP15_TPIDRPRW]
-void check_ReadWriteStatusReg(int v) {
- int ret;
+// From intrin.h
+__int64 _ReadStatusReg(int);
+void _WriteStatusReg(int, __int64);
+
+void check_ReadWriteStatusReg(__int64 v) {
+ __int64 ret;
ret = _ReadStatusReg(ARM64_CNTVCT);
-// CHECK-ASM: mrs x8, CNTVCT_EL0
-// CHECK-IR: call i64 @llvm.read_register.i64(metadata ![[MD2:.*]])
+// CHECK-ASM: mrs x0, CNTVCT_EL0
+// CHECK-IR: %[[VAR:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD2:.*]])
+// CHECK-IR-NEXT: store i64 %[[VAR]]
ret = _ReadStatusReg(ARM64_PMCCNTR_EL0);
-// CHECK-ASM: mrs x8, PMCCNTR_EL0
-// CHECK-IR: call i64 @llvm.read_register.i64(metadata ![[MD3:.*]])
+// CHECK-ASM: mrs x0, PMCCNTR_EL0
+// CHECK-IR: %[[VAR:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD3:.*]])
+// CHECK-IR-NEXT: store i64 %[[VAR]]
ret = _ReadStatusReg(ARM64_PMSELR_EL0);
-// CHECK-ASM: mrs x8, PMSELR_EL0
-// CHECK-IR: call i64 @llvm.read_register.i64(metadata ![[MD4:.*]])
+// CHECK-ASM: mrs x0, PMSELR_EL0
+// CHECK-IR: %[[VAR:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD4:.*]])
+// CHECK-IR-NEXT: store i64 %[[VAR]]
ret = _ReadStatusReg(ARM64_PMXEVCNTR_EL0);
-// CHECK-ASM: mrs x8, PMXEVCNTR_EL0
-// CHECK-IR: call i64 @llvm.read_register.i64(metadata ![[MD5:.*]])
+// CHECK-ASM: mrs x0, PMXEVCNTR_EL0
+// CHECK-IR: %[[VAR:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD5:.*]])
+// CHECK-IR-NEXT: store i64 %[[VAR]]
ret = _ReadStatusReg(ARM64_PMXEVCNTRn_EL0(0));
-// CHECK-ASM: mrs x8, PMEVCNTR0_EL0
-// CHECK-IR: call i64 @llvm.read_register.i64(metadata ![[MD6:.*]])
+// CHECK-ASM: mrs x0, PMEVCNTR0_EL0
+// CHECK-IR: %[[VAR:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD6:.*]])
+// CHECK-IR-NEXT: store i64 %[[VAR]]
ret = _ReadStatusReg(ARM64_PMXEVCNTRn_EL0(1));
-// CHECK-ASM: mrs x8, PMEVCNTR1_EL0
-// CHECK-IR: call i64 @llvm.read_register.i64(metadata ![[MD7:.*]])
+// CHECK-ASM: mrs x0, PMEVCNTR1_EL0
+// CHECK-IR: %[[VAR:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD7:.*]])
+// CHECK-IR-NEXT: store i64 %[[VAR]]
ret = _ReadStatusReg(ARM64_PMXEVCNTRn_EL0(30));
-// CHECK-ASM: mrs x8, PMEVCNTR30_EL0
-// CHECK-IR: call i64 @llvm.read_register.i64(metadata ![[MD8:.*]])
+// CHECK-ASM: mrs x0, PMEVCNTR30_EL0
+// CHECK-IR: %[[VAR:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD8:.*]])
+// CHECK-IR-NEXT: store i64 %[[VAR]]
ret = _ReadStatusReg(ARM64_TPIDR_EL0);
-// CHECK-ASM: mrs x8, TPIDR_EL0
-// CHECK-IR: call i64 @llvm.read_register.i64(metadata ![[MD9:.*]])
+// CHECK-ASM: mrs x0, TPIDR_EL0
+// CHECK-IR: %[[VAR:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD9:.*]])
+// CHECK-IR-NEXT: store i64 %[[VAR]]
ret = _ReadStatusReg(ARM64_TPIDRRO_EL0);
-// CHECK-ASM: mrs x8, TPIDRRO_EL0
-// CHECK-IR: call i64 @llvm.read_register.i64(metadata ![[MD10:.*]])
+// CHECK-ASM: mrs x0, TPIDRRO_EL0
+// CHECK-IR: %[[VAR:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD10:.*]])
+// CHECK-IR-NEXT: store i64 %[[VAR]]
ret = _ReadStatusReg(ARM64_TPIDR_EL1);
-// CHECK-ASM: mrs x8, TPIDR_EL1
-// CHECK-IR: call i64 @llvm.read_register.i64(metadata ![[MD11:.*]])
+// CHECK-ASM: mrs x0, TPIDR_EL1
+// CHECK-IR: %[[VAR:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD11:.*]])
+// CHECK-IR-NEXT: store i64 %[[VAR]]
_WriteStatusReg(ARM64_CNTVCT, v);
-// CHECK-ASM: msr S3_3_C14_C0_2, x8
+// CHECK-ASM: msr S3_3_C14_C0_2, x0
// CHECK-IR: call void @llvm.write_register.i64(metadata ![[MD2:.*]], i64 {{%.*}})
_WriteStatusReg(ARM64_PMCCNTR_EL0, v);
-// CHECK-ASM: msr PMCCNTR_EL0, x8
+// CHECK-ASM: msr PMCCNTR_EL0, x0
// CHECK-IR: call void @llvm.write_register.i64(metadata ![[MD3:.*]], i64 {{%.*}})
_WriteStatusReg(ARM64_PMSELR_EL0, v);
-// CHECK-ASM: msr PMSELR_EL0, x8
+// CHECK-ASM: msr PMSELR_EL0, x0
// CHECK-IR: call void @llvm.write_register.i64(metadata ![[MD4:.*]], i64 {{%.*}})
_WriteStatusReg(ARM64_PMXEVCNTR_EL0, v);
-// CHECK-ASM: msr PMXEVCNTR_EL0, x8
+// CHECK-ASM: msr PMXEVCNTR_EL0, x0
// CHECK-IR: call void @llvm.write_register.i64(metadata ![[MD5:.*]], i64 {{%.*}})
_WriteStatusReg(ARM64_PMXEVCNTRn_EL0(0), v);
-// CHECK-ASM: msr PMEVCNTR0_EL0, x8
+// CHECK-ASM: msr PMEVCNTR0_EL0, x0
// CHECK-IR: call void @llvm.write_register.i64(metadata ![[MD6:.*]], i64 {{%.*}})
_WriteStatusReg(ARM64_PMXEVCNTRn_EL0(1), v);
-// CHECK-ASM: msr PMEVCNTR1_EL0, x8
+// CHECK-ASM: msr PMEVCNTR1_EL0, x0
// CHECK-IR: call void @llvm.write_register.i64(metadata ![[MD7:.*]], i64 {{%.*}})
_WriteStatusReg(ARM64_PMXEVCNTRn_EL0(30), v);
-// CHECK-ASM: msr PMEVCNTR30_EL0, x8
+// CHECK-ASM: msr PMEVCNTR30_EL0, x0
// CHECK-IR: call void @llvm.write_register.i64(metadata ![[MD8:.*]], i64 {{%.*}})
_WriteStatusReg(ARM64_TPIDR_EL0, v);
-// CHECK-ASM: msr TPIDR_EL0, x8
+// CHECK-ASM: msr TPIDR_EL0, x0
// CHECK-IR: call void @llvm.write_register.i64(metadata ![[MD9:.*]], i64 {{%.*}})
_WriteStatusReg(ARM64_TPIDRRO_EL0, v);
-// CHECK-ASM: msr TPIDRRO_EL0, x8
+// CHECK-ASM: msr TPIDRRO_EL0, x0
// CHECK-IR: call void @llvm.write_register.i64(metadata ![[MD10:.*]], i64 {{%.*}})
_WriteStatusReg(ARM64_TPIDR_EL1, v);
-// CHECK-ASM: msr TPIDR_EL1, x8
+// CHECK-ASM: msr TPIDR_EL1, x0
// CHECK-IR: call void @llvm.write_register.i64(metadata ![[MD11:.*]], i64 {{%.*}})
}

View File

@ -1,14 +1,14 @@
{
"llvm_revision": "353414",
"llvm_revision": "355016",
"stages": "3",
"build_libcxx": false,
"build_type": "Release",
"assertions": false,
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_800/rc2",
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_800/rc2",
"lld_repo": "https://llvm.org/svn/llvm-project/lld/tags/RELEASE_800/rc2",
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_800/rc2",
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_800/rc2",
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_800/rc3",
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_800/rc3",
"lld_repo": "https://llvm.org/svn/llvm-project/lld/tags/RELEASE_800/rc3",
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_800/rc3",
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_800/rc3",
"python_path": "c:/mozilla-build/python/python.exe",
"cc": "cl.exe",
"cxx": "cl.exe",
@ -17,7 +17,6 @@
"workaround-issue38586.patch",
"unpoison-thread-stacks.patch",
"downgrade-mangling-error.patch",
"loosen-msvc-detection.patch",
"D57636.diff"
"loosen-msvc-detection.patch"
]
}

View File

@ -7500,20 +7500,17 @@ void nsContentUtils::TransferableToIPCTransferable(
} else if (nsCOMPtr<nsISupportsCString> ctext = do_QueryInterface(data)) {
nsAutoCString dataAsString;
ctext->GetData(dataAsString);
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
item->flavor() = flavorStr;
Shmem dataAsShmem = ConvertToShmem(aChild, aParent, dataAsString);
if (!dataAsShmem.IsReadable() || !dataAsShmem.Size<char>()) {
continue;
}
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
item->flavor() = flavorStr;
item->data() = dataAsShmem;
} else if (nsCOMPtr<nsIInputStream> stream = do_QueryInterface(data)) {
// Images to be pasted on the clipboard are nsIInputStreams
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
item->flavor() = flavorStr;
nsCString imageData;
NS_ConsumeStream(stream, UINT32_MAX, imageData);
@ -7522,6 +7519,8 @@ void nsContentUtils::TransferableToIPCTransferable(
continue;
}
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
item->flavor() = flavorStr;
item->data() = imageDataShmem;
} else if (nsCOMPtr<imgIContainer> image = do_QueryInterface(data)) {
// Images to be placed on the clipboard are imgIContainers.
@ -7570,13 +7569,17 @@ void nsContentUtils::TransferableToIPCTransferable(
if (aInSyncMessage) {
nsAutoCString type;
if (IsFileImage(file, type)) {
IPCDataTransferItem* item =
aIPCDataTransfer->items().AppendElement();
item->flavor() = type;
nsAutoCString data;
SlurpFileToString(file, data);
Shmem dataAsShmem = ConvertToShmem(aChild, aParent, data);
if (!dataAsShmem.IsReadable() || !dataAsShmem.Size<char>()) {
continue;
}
IPCDataTransferItem* item =
aIPCDataTransfer->items().AppendElement();
item->flavor() = type;
item->data() = dataAsShmem;
}

View File

@ -409,10 +409,6 @@ Index::Index(const IndiceWrapper& aIndices, ByteStream* aSource,
if (!haveSync) {
continue;
}
if (indice.start_composition == indice.end_composition) {
// Ignore this sample as it doesn't account for the buffered range.
continue;
}
Sample sample;
sample.mByteRange =
MediaByteRange(indice.start_offset, indice.end_offset);
@ -561,9 +557,11 @@ TimeIntervals Index::ConvertByteRangesToTimeRanges(
}
}
if (end > start) {
timeRanges += TimeInterval(
TimeUnit::FromMicroseconds(mDataOffset[start].mTime.start),
TimeUnit::FromMicroseconds(mDataOffset[end - 1].mTime.end));
for (uint32_t i = start; i < end; i++) {
timeRanges += TimeInterval(
TimeUnit::FromMicroseconds(mDataOffset[i].mTime.start),
TimeUnit::FromMicroseconds(mDataOffset[i].mTime.end));
}
}
if (end < mDataOffset.Length()) {
// Find samples in partial block contained in the byte range.

View File

@ -20,12 +20,12 @@
#include "mozilla/layers/IAPZCTreeManager.h" // for IAPZCTreeManager
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/layers/KeyboardMap.h" // for KeyboardMap
#include "mozilla/layers/TouchCounter.h" // for TouchCounter
#include "mozilla/RecursiveMutex.h" // for RecursiveMutex
#include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/TimeStamp.h" // for mozilla::TimeStamp
#include "mozilla/UniquePtr.h" // for UniquePtr
#include "nsCOMPtr.h" // for already_AddRefed
#include "TouchCounter.h" // for TouchCounter
#if defined(MOZ_WIDGET_ANDROID)
# include "mozilla/layers/AndroidDynamicToolbarAnimator.h"

View File

@ -14,9 +14,9 @@
#include "mozilla/layers/APZUtils.h"
#include "mozilla/layers/LayersTypes.h" // for TouchBehaviorFlags
#include "mozilla/layers/AsyncDragMetrics.h"
#include "mozilla/layers/TouchCounter.h"
#include "mozilla/TimeStamp.h" // for TimeStamp
#include "nsTArray.h" // for nsTArray
#include "TouchCounter.h"
namespace mozilla {
namespace layers {

View File

@ -11,10 +11,10 @@
#include "DragTracker.h"
#include "InputData.h"
#include "mozilla/EventForwards.h"
#include "mozilla/layers/TouchCounter.h"
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
#include "nsTArray.h"
#include "TouchCounter.h"
namespace mozilla {

View File

@ -0,0 +1,81 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Checking prevent-default for zooming</title>
<script type="application/javascript" src="apz_test_native_event_utils.js"></script>
<script type="application/javascript" src="apz_test_utils.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
<script type="application/javascript">
function* testPreventDefault(testDriver, aTouchStartToCancel) {
var initial_resolution = getResolution();
ok(initial_resolution > 0,
"The initial_resolution is " + initial_resolution + ", which is some sane value");
// preventDefault exactly one touchstart based on the value of aTouchStartToCancel
var touchStartCount = 0;
var canceller = function(e) {
dump("touchstart listener hit, count: " + touchStartCount + "\n");
touchStartCount++;
if (touchStartCount == aTouchStartToCancel) {
dump("calling preventDefault on touchstart\n");
e.preventDefault();
document.documentElement.removeEventListener("touchstart", canceller, {passive: false});
}
};
document.documentElement.addEventListener("touchstart", canceller, {passive: false});
var waitForTouchEnd = function(e) {
dump("touchend listener hit\n");
setTimeout(testDriver, 0);
};
document.documentElement.addEventListener("touchend", waitForTouchEnd, {passive: true, once: true});
// Ensure that APZ gets updated hit-test info
yield waitForAllPaints(testDriver);
var zoom_in = [
[ { x: 125, y: 250 }, { x: 175, y: 350 } ],
[ { x: 120, y: 220 }, { x: 180, y: 380 } ],
[ { x: 115, y: 190 }, { x: 185, y: 410 } ],
[ { x: 110, y: 160 }, { x: 190, y: 440 } ],
[ { x: 105, y: 130 }, { x: 195, y: 470 } ],
[ { x: 100, y: 100 }, { x: 200, y: 500 } ],
];
var touchIds = [0, 1];
yield* synthesizeNativeTouchSequences(document.body, zoom_in, null, touchIds);
yield; // wait for the touchend listener to fire
// Flush state and get the resolution we're at now
yield waitForApzFlushedRepaints(testDriver);
let final_resolution = getResolution();
is(final_resolution, initial_resolution, "The final resolution (" + final_resolution + ") matches the initial resolution");
}
function* test(testDriver) {
// Register a listener that fails the test if the APZ:TransformEnd event fires,
// because this test shouldn't actually be triggering any transforms
SpecialPowers.Services.obs.addObserver(function() {
ok(false, "The test fired an unexpected APZ:TransformEnd");
}, "APZ:TransformEnd");
yield* testPreventDefault(testDriver, 1);
yield* testPreventDefault(testDriver, 2);
}
waitUntilApzStable()
.then(runContinuation(test))
.then(subtestDone);
</script>
</head>
<body>
Here is some text to stare at as the test runs. It serves no functional
purpose, but gives you an idea of the zoom level. It's harder to tell what
the zoom level is when the page is just solid white.
</body>
</html>

View File

@ -32,6 +32,9 @@ var prefs = [
// Pinch-zooming currently requires meta viewport support (this requirement
// will eventually be removed).
["dom.meta-viewport.enabled", true],
// Increase the content response timeout because some tests do preventDefault
// and we want to make sure APZ actually waits for them.
["apz.content_response_timeout", 60000],
];
// Increase the tap timeouts so the double-tap is still detected in case of
@ -45,6 +48,7 @@ var doubletap_prefs = [
var subtests = [
{"file": "helper_bug1280013.html", "prefs": prefs},
{"file": "helper_basic_zoom.html", "prefs": prefs},
{"file": "helper_zoom_prevented.html", "prefs": prefs},
{"file": "helper_zoomed_pan.html", "prefs": prefs},
{"file": "helper_fixed_position_scroll_hittest.html", "prefs": prefs},
{"file": "helper_basic_doubletap_zoom.html", "prefs": doubletap_prefs},

View File

@ -104,6 +104,7 @@ APZEventState::APZEventState(nsIWidget* aWidget,
mPendingTouchPreventedResponse(false),
mPendingTouchPreventedBlockId(0),
mEndTouchIsClick(false),
mFirstTouchCancelled(false),
mTouchEndCancelled(false),
mLastTouchIdentifier(0) {
nsresult rv;
@ -337,6 +338,22 @@ void APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
// for events that went through APZ (which should be all of them).
MOZ_ASSERT(aEvent.mFlags.mHandledByAPZ);
// If the first touchstart event was preventDefaulted, ensure that any
// subsequent additional touchstart events also get preventDefaulted. This
// ensures that e.g. pinch zooming is prevented even if just the first
// touchstart was prevented by content.
if (mTouchCounter.GetActiveTouchCount() == 0) {
mFirstTouchCancelled = isTouchPrevented;
} else {
if (mFirstTouchCancelled && !isTouchPrevented) {
APZES_LOG(
"Propagating prevent-default from first-touch for block %" PRIu64
"\n",
aInputBlockId);
}
isTouchPrevented |= mFirstTouchCancelled;
}
if (isTouchPrevented) {
mContentReceivedInputBlockCallback(aGuid, aInputBlockId,
isTouchPrevented);
@ -373,6 +390,11 @@ void APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
break;
}
mTouchCounter.Update(aEvent);
if (mTouchCounter.GetActiveTouchCount() == 0) {
mFirstTouchCancelled = false;
}
if (sentContentResponse && !isTouchPrevented &&
aApzResponse == nsEventStatus_eConsumeDoDefault &&
gfxPrefs::PointerEventsEnabled()) {

View File

@ -13,6 +13,7 @@
#include "mozilla/EventForwards.h"
#include "mozilla/layers/GeckoContentController.h" // for APZStateChange
#include "mozilla/layers/ScrollableLayerGuid.h" // for ScrollableLayerGuid
#include "mozilla/layers/TouchCounter.h" // for TouchCounter
#include "mozilla/RefPtr.h"
#include "nsCOMPtr.h"
#include "nsISupportsImpl.h" // for NS_INLINE_DECL_REFCOUNTING
@ -94,10 +95,12 @@ class APZEventState {
nsWeakPtr mWidget;
RefPtr<ActiveElementManager> mActiveElementManager;
ContentReceivedInputBlockCallback mContentReceivedInputBlockCallback;
TouchCounter mTouchCounter;
bool mPendingTouchPreventedResponse;
ScrollableLayerGuid mPendingTouchPreventedGuid;
uint64_t mPendingTouchPreventedBlockId;
bool mEndTouchIsClick;
bool mFirstTouchCancelled;
bool mTouchEndCancelled;
int32_t mLastTouchIdentifier;

View File

@ -7,6 +7,7 @@
#include "TouchCounter.h"
#include "InputData.h"
#include "mozilla/TouchEvents.h"
namespace mozilla {
namespace layers {
@ -24,7 +25,7 @@ void TouchCounter::Update(const MultiTouchInput& aInput) {
// touch-end event contains only released touches
mActiveTouchCount -= aInput.mTouches.Length();
} else {
NS_WARNING("Got an unexpected touchend/touchcancel");
NS_WARNING("Got an unexpected touchend");
mActiveTouchCount = 0;
}
break;
@ -36,6 +37,37 @@ void TouchCounter::Update(const MultiTouchInput& aInput) {
}
}
void TouchCounter::Update(const WidgetTouchEvent& aEvent) {
switch (aEvent.mMessage) {
case eTouchStart:
// touch-start event contains all active touches of the current session
mActiveTouchCount = aEvent.mTouches.Length();
break;
case eTouchEnd: {
// touch-end contains all touches, but ones being lifted are marked as
// changed
uint32_t liftedTouches = 0;
for (const auto& touch : aEvent.mTouches) {
if (touch->mChanged) {
liftedTouches++;
}
}
if (mActiveTouchCount >= liftedTouches) {
mActiveTouchCount -= liftedTouches;
} else {
NS_WARNING("Got an unexpected touchend");
mActiveTouchCount = 0;
}
break;
}
case eTouchCancel:
mActiveTouchCount = 0;
break;
default:
break;
}
}
uint32_t TouchCounter::GetActiveTouchCount() const { return mActiveTouchCount; }
} // namespace layers

View File

@ -16,11 +16,14 @@ class MultiTouchInput;
namespace layers {
// TouchCounter simply tracks the number of active touch points. Feed it
// your input events to update the internal state.
// your input events to update the internal state. Generally you should
// only be calling one of the Update functions, depending on which type
// of touch inputs you have access to.
class TouchCounter {
public:
TouchCounter();
void Update(const MultiTouchInput& aInput);
void Update(const WidgetTouchEvent& aEvent);
uint32_t GetActiveTouchCount() const;
private:

View File

@ -118,6 +118,7 @@ EXPORTS.mozilla.layers += [
'apz/util/InputAPZContext.h',
'apz/util/ScrollLinkedEffectDetector.h',
'apz/util/TouchActionHelper.h',
'apz/util/TouchCounter.h',
'AsyncCanvasRenderer.h',
'AtomicRefCountedWithFinalize.h',
'AxisPhysicsModel.h',
@ -336,7 +337,6 @@ UNIFIED_SOURCES += [
'apz/src/PotentialCheckerboardDurationTracker.cpp',
'apz/src/QueuedInput.cpp',
'apz/src/SimpleVelocityTracker.cpp',
'apz/src/TouchCounter.cpp',
'apz/src/WheelScrollAnimation.cpp',
'apz/testutil/APZTestData.cpp',
'apz/util/ActiveElementManager.cpp',
@ -350,6 +350,7 @@ UNIFIED_SOURCES += [
'apz/util/InputAPZContext.cpp',
'apz/util/ScrollLinkedEffectDetector.cpp',
'apz/util/TouchActionHelper.cpp',
'apz/util/TouchCounter.cpp',
'AsyncCanvasRenderer.cpp',
'AxisPhysicsModel.cpp',
'AxisPhysicsMSDModel.cpp',

View File

@ -1209,6 +1209,24 @@ static bool StartGC(JSContext* cx, unsigned argc, Value* vp) {
return true;
}
static bool FinishGC(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() > 0) {
RootedObject callee(cx, &args.callee());
ReportUsageErrorASCII(cx, callee, "Wrong number of arguments");
return false;
}
JSRuntime* rt = cx->runtime();
if (rt->gc.isIncrementalGCInProgress()) {
rt->gc.finishGC(JS::GCReason::DEBUG_GC);
}
args.rval().setUndefined();
return true;
}
static bool GCSlice(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
@ -5853,6 +5871,10 @@ gc::ZealModeHelpText),
" If 'shrinking' is passesd as the optional second argument, perform a\n"
" shrinking GC rather than a normal GC."),
JS_FN_HELP("finishgc", FinishGC, 0, 0,
"finishgc()",
" Finish an in-progress incremental GC, if none is running then do nothing."),
JS_FN_HELP("gcslice", GCSlice, 1, 0,
"gcslice([n])",
" Start or continue an an incremental GC, running a slice that processes about n objects."),

View File

@ -13,6 +13,7 @@ function basicSweeping() {
wm1.set(hold, {'name': 'val2'});
wm1.set({'name': 'obj3'}, {'name': 'val3'});
finishgc();
startgc(100000, 'shrinking');
gcslice();
@ -36,6 +37,7 @@ function weakGraph() {
wm1.set(obj4, obj1); // This edge will be cleared
obj1 = obj3 = obj4 = undefined;
finishgc();
startgc(100000, 'shrinking');
gcslice();
@ -64,6 +66,7 @@ function deadWeakMap() {
obj1 = obj3 = obj4 = undefined;
wm1 = undefined;
finishgc();
startgc(100000, 'shrinking');
gcslice();
@ -91,6 +94,7 @@ function deadKeys() {
obj1 = obj3 = undefined;
var initialCount = finalizeCount();
finishgc();
startgc(100000, 'shrinking');
gcslice();
@ -124,6 +128,7 @@ function weakKeysRealloc() {
obj2 = undefined;
var initialCount = finalizeCount();
finishgc();
startgc(100000, 'shrinking');
gcslice();
assertEq(finalizeCount(), initialCount + 1);
@ -142,6 +147,7 @@ function deletedKeys() {
for (var i = 0; i < 1000; i++)
wm.set(g.Object.create(null), i);
finishgc();
startgc(100, 'shrinking');
for (var key of nondeterministicGetWeakMapKeys(wm)) {
if (wm.get(key) % 2)
@ -171,6 +177,7 @@ function incrementalAdds() {
obj2 = undefined;
var obj3 = [];
finishgc();
startgc(100, 'shrinking');
var M = 10;
var N = 800;

View File

@ -2091,12 +2091,6 @@ JSObject* BaselineCompilerHandler::maybeNoCloneSingletonObject() {
return script()->getObject(pc());
}
typedef JSObject* (*SingletonObjectLiteralFn)(JSContext*, HandleScript,
jsbytecode*);
static const VMFunction SingletonObjectLiteralInfo =
FunctionInfo<SingletonObjectLiteralFn>(SingletonObjectLiteralOperation,
"SingletonObjectLiteralOperation");
template <typename Handler>
bool BaselineCodeGen<Handler>::emit_JSOP_OBJECT() {
// If we know we don't have to clone the object literal, just push it
@ -2112,7 +2106,8 @@ bool BaselineCodeGen<Handler>::emit_JSOP_OBJECT() {
pushBytecodePCArg();
pushScriptArg(R2.scratchReg());
if (!callVM(SingletonObjectLiteralInfo)) {
using Fn = JSObject* (*)(JSContext*, HandleScript, jsbytecode*);
if (!callVM<Fn, SingletonObjectLiteralOperation>()) {
return false;
}
@ -2134,12 +2129,6 @@ bool BaselineCompilerCodeGen::emit_JSOP_CALLSITEOBJ() {
return true;
}
typedef ArrayObject* (*ProcessCallSiteObjFn)(JSContext*, HandleScript,
jsbytecode*);
static const VMFunction ProcessCallSiteObjInfo =
FunctionInfo<ProcessCallSiteObjFn>(ProcessCallSiteObjOperation,
"ProcessCallSiteObjOperation");
template <>
bool BaselineInterpreterCodeGen::emit_JSOP_CALLSITEOBJ() {
prepareVMCall();
@ -2147,7 +2136,8 @@ bool BaselineInterpreterCodeGen::emit_JSOP_CALLSITEOBJ() {
pushBytecodePCArg();
pushScriptArg(R2.scratchReg());
if (!callVM(ProcessCallSiteObjInfo)) {
using Fn = ArrayObject* (*)(JSContext*, HandleScript, jsbytecode*);
if (!callVM<Fn, ProcessCallSiteObjOperation>()) {
return false;
}
@ -2157,15 +2147,13 @@ bool BaselineInterpreterCodeGen::emit_JSOP_CALLSITEOBJ() {
return true;
}
typedef JSObject* (*CloneRegExpObjectFn)(JSContext*, Handle<RegExpObject*>);
static const VMFunction CloneRegExpObjectInfo =
FunctionInfo<CloneRegExpObjectFn>(CloneRegExpObject, "CloneRegExpObject");
template <typename Handler>
bool BaselineCodeGen<Handler>::emit_JSOP_REGEXP() {
prepareVMCall();
pushScriptObjectArg(ScriptObjectType::RegExp);
if (!callVM(CloneRegExpObjectInfo)) {
using Fn = JSObject* (*)(JSContext*, Handle<RegExpObject*>);
if (!callVM<Fn, CloneRegExpObject>()) {
return false;
}
@ -2175,10 +2163,6 @@ bool BaselineCodeGen<Handler>::emit_JSOP_REGEXP() {
return true;
}
typedef JSObject* (*LambdaFn)(JSContext*, HandleFunction, HandleObject);
static const VMFunction LambdaInfo =
FunctionInfo<LambdaFn>(js::Lambda, "Lambda");
template <typename Handler>
bool BaselineCodeGen<Handler>::emit_JSOP_LAMBDA() {
prepareVMCall();
@ -2187,7 +2171,8 @@ bool BaselineCodeGen<Handler>::emit_JSOP_LAMBDA() {
pushArg(R0.scratchReg());
pushScriptObjectArg(ScriptObjectType::Function);
if (!callVM(LambdaInfo)) {
using Fn = JSObject* (*)(JSContext*, HandleFunction, HandleObject);
if (!callVM<Fn, js::Lambda>()) {
return false;
}
@ -2197,11 +2182,6 @@ bool BaselineCodeGen<Handler>::emit_JSOP_LAMBDA() {
return true;
}
typedef JSObject* (*LambdaArrowFn)(JSContext*, HandleFunction, HandleObject,
HandleValue);
static const VMFunction LambdaArrowInfo =
FunctionInfo<LambdaArrowFn>(js::LambdaArrow, "LambdaArrow");
template <typename Handler>
bool BaselineCodeGen<Handler>::emit_JSOP_LAMBDA_ARROW() {
// Keep pushed newTarget in R0.
@ -2214,7 +2194,9 @@ bool BaselineCodeGen<Handler>::emit_JSOP_LAMBDA_ARROW() {
pushArg(R2.scratchReg());
pushScriptObjectArg(ScriptObjectType::Function);
if (!callVM(LambdaArrowInfo)) {
using Fn =
JSObject* (*)(JSContext*, HandleFunction, HandleObject, HandleValue);
if (!callVM<Fn, js::LambdaArrow>()) {
return false;
}
@ -2224,11 +2206,6 @@ bool BaselineCodeGen<Handler>::emit_JSOP_LAMBDA_ARROW() {
return true;
}
typedef bool (*SetFunNameFn)(JSContext*, HandleFunction, HandleValue,
FunctionPrefixKind);
static const VMFunction SetFunNameInfo =
FunctionInfo<SetFunNameFn>(js::SetFunctionName, "SetFunName");
template <typename Handler>
bool BaselineCodeGen<Handler>::emit_JSOP_SETFUNNAME() {
frame.popRegsAndSync(2);
@ -2243,7 +2220,10 @@ bool BaselineCodeGen<Handler>::emit_JSOP_SETFUNNAME() {
pushUint8BytecodeOperandArg();
pushArg(R1);
pushArg(R0.scratchReg());
return callVM(SetFunNameInfo);
using Fn =
bool (*)(JSContext*, HandleFunction, HandleValue, FunctionPrefixKind);
return callVM<Fn, SetFunctionName>();
}
template <typename Handler>
@ -2469,11 +2449,6 @@ bool BaselineInterpreterCodeGen::emit_JSOP_NEWARRAY() {
MOZ_CRASH("NYI: interpreter JSOP_NEWARRAY");
}
typedef ArrayObject* (*NewArrayCopyOnWriteFn)(JSContext*, HandleArrayObject,
gc::InitialHeap);
const VMFunction NewArrayCopyOnWriteInfo = FunctionInfo<NewArrayCopyOnWriteFn>(
js::NewDenseCopyOnWriteArray, "NewDenseCopyOnWriteArray");
template <>
bool BaselineCompilerCodeGen::emit_JSOP_NEWARRAY_COPYONWRITE() {
// This is like the interpreter implementation, but we can call
@ -2491,7 +2466,8 @@ bool BaselineCompilerCodeGen::emit_JSOP_NEWARRAY_COPYONWRITE() {
pushArg(Imm32(gc::DefaultHeap));
pushArg(ImmGCPtr(obj));
if (!callVM(NewArrayCopyOnWriteInfo)) {
using Fn = ArrayObject* (*)(JSContext*, HandleArrayObject, gc::InitialHeap);
if (!callVM<Fn, js::NewDenseCopyOnWriteArray>()) {
return false;
}
@ -2501,12 +2477,6 @@ bool BaselineCompilerCodeGen::emit_JSOP_NEWARRAY_COPYONWRITE() {
return true;
}
typedef ArrayObject* (*NewArrayCopyOnWriteOperationFn)(JSContext*, HandleScript,
jsbytecode*);
const VMFunction NewArrayCopyOnWriteOperationInfo =
FunctionInfo<NewArrayCopyOnWriteOperationFn>(
NewArrayCopyOnWriteOperation, "NewArrayCopyOnWriteOperation");
template <>
bool BaselineInterpreterCodeGen::emit_JSOP_NEWARRAY_COPYONWRITE() {
prepareVMCall();
@ -2514,7 +2484,8 @@ bool BaselineInterpreterCodeGen::emit_JSOP_NEWARRAY_COPYONWRITE() {
pushBytecodePCArg();
pushScriptArg(R2.scratchReg());
if (!callVM(NewArrayCopyOnWriteOperationInfo)) {
using Fn = ArrayObject* (*)(JSContext*, HandleScript, jsbytecode*);
if (!callVM<Fn, NewArrayCopyOnWriteOperation>()) {
return false;
}
@ -2608,11 +2579,6 @@ bool BaselineCodeGen<Handler>::emit_JSOP_INITHIDDENELEM() {
return emit_JSOP_INITELEM();
}
typedef bool (*MutateProtoFn)(JSContext* cx, HandlePlainObject obj,
HandleValue newProto);
static const VMFunction MutateProtoInfo =
FunctionInfo<MutateProtoFn>(MutatePrototype, "MutatePrototype");
template <typename Handler>
bool BaselineCodeGen<Handler>::emit_JSOP_MUTATEPROTO() {
// Keep values on the stack for the decompiler.
@ -2626,7 +2592,8 @@ bool BaselineCodeGen<Handler>::emit_JSOP_MUTATEPROTO() {
pushArg(R1);
pushArg(R0.scratchReg());
if (!callVM(MutateProtoInfo)) {
using Fn = bool (*)(JSContext*, HandlePlainObject, HandleValue);
if (!callVM<Fn, MutatePrototype>()) {
return false;
}
@ -2765,13 +2732,6 @@ bool BaselineCodeGen<Handler>::emit_JSOP_STRICTSETELEM_SUPER() {
return emitSetElemSuper(/* strict = */ true);
}
typedef bool (*DeleteElementFn)(JSContext*, HandleValue, HandleValue, bool*);
static const VMFunction DeleteElementStrictInfo = FunctionInfo<DeleteElementFn>(
DeleteElementJit<true>, "DeleteElementStrict");
static const VMFunction DeleteElementNonStrictInfo =
FunctionInfo<DeleteElementFn>(DeleteElementJit<false>,
"DeleteElementNonStrict");
template <typename Handler>
bool BaselineCodeGen<Handler>::emitDelElem(bool strict) {
// Keep values on the stack for the decompiler.
@ -2783,8 +2743,16 @@ bool BaselineCodeGen<Handler>::emitDelElem(bool strict) {
pushArg(R1);
pushArg(R0);
if (!callVM(strict ? DeleteElementStrictInfo : DeleteElementNonStrictInfo)) {
return false;
using Fn = bool (*)(JSContext*, HandleValue, HandleValue, bool*);
if (strict) {
if (!callVM<Fn, DeleteElementJit<true>>()) {
return false;
}
} else {
if (!callVM<Fn, DeleteElementJit<false>>()) {
return false;
}
}
masm.boxNonDouble(JSVAL_TYPE_BOOLEAN, ReturnReg, R1);
@ -2930,10 +2898,6 @@ bool BaselineCodeGen<Handler>::emit_JSOP_BINDGNAME() {
return emitBindName(JSOP_BINDGNAME);
}
typedef JSObject* (*BindVarFn)(JSContext*, JSObject*);
static const VMFunction BindVarInfo =
FunctionInfo<BindVarFn>(BindVarOperation, "BindVarOperation");
template <typename Handler>
bool BaselineCodeGen<Handler>::emit_JSOP_BINDVAR() {
frame.syncStack(0);
@ -2942,7 +2906,8 @@ bool BaselineCodeGen<Handler>::emit_JSOP_BINDVAR() {
prepareVMCall();
pushArg(R0.scratchReg());
if (!callVM(BindVarInfo)) {
using Fn = JSObject* (*)(JSContext*, JSObject*);
if (!callVM<Fn, BindVarOperation>()) {
return false;
}
@ -2993,11 +2958,6 @@ bool BaselineCodeGen<Handler>::emit_JSOP_STRICTSETGNAME() {
return emit_JSOP_SETPROP();
}
typedef bool (*SetPropertySuperFn)(JSContext*, HandleObject, HandleValue,
HandlePropertyName, HandleValue, bool);
static const VMFunction SetPropertySuperInfo =
FunctionInfo<SetPropertySuperFn>(js::SetPropertySuper, "SetPropertySuper");
template <typename Handler>
bool BaselineCodeGen<Handler>::emitSetPropSuper(bool strict) {
// Incoming stack is |receiver, obj, rval|. We need to shuffle stack to
@ -3017,7 +2977,9 @@ bool BaselineCodeGen<Handler>::emitSetPropSuper(bool strict) {
masm.unboxObject(frame.addressOfStackValue(-1), R0.scratchReg());
pushArg(R0.scratchReg()); // obj
if (!callVM(SetPropertySuperInfo)) {
using Fn = bool (*)(JSContext*, HandleObject, HandleValue, HandlePropertyName,
HandleValue, bool);
if (!callVM<Fn, js::SetPropertySuper>()) {
return false;
}
@ -3080,15 +3042,6 @@ bool BaselineCodeGen<Handler>::emit_JSOP_GETPROP_SUPER() {
return true;
}
typedef bool (*DeletePropertyFn)(JSContext*, HandleValue, HandlePropertyName,
bool*);
static const VMFunction DeletePropertyStrictInfo =
FunctionInfo<DeletePropertyFn>(DeletePropertyJit<true>,
"DeletePropertyStrict");
static const VMFunction DeletePropertyNonStrictInfo =
FunctionInfo<DeletePropertyFn>(DeletePropertyJit<false>,
"DeletePropertyNonStrict");
template <typename Handler>
bool BaselineCodeGen<Handler>::emitDelProp(bool strict) {
// Keep value on the stack for the decompiler.
@ -3100,9 +3053,15 @@ bool BaselineCodeGen<Handler>::emitDelProp(bool strict) {
pushScriptNameArg();
pushArg(R0);
if (!callVM(strict ? DeletePropertyStrictInfo
: DeletePropertyNonStrictInfo)) {
return false;
using Fn = bool (*)(JSContext*, HandleValue, HandlePropertyName, bool*);
if (strict) {
if (!callVM<Fn, DeletePropertyJit<true>>()) {
return false;
}
} else {
if (!callVM<Fn, DeletePropertyJit<false>>()) {
return false;
}
}
masm.boxNonDouble(JSVAL_TYPE_BOOLEAN, ReturnReg, R1);
@ -3273,11 +3232,6 @@ bool BaselineCodeGen<Handler>::emit_JSOP_BINDNAME() {
return emitBindName(JSOP_BINDNAME);
}
typedef bool (*DeleteNameFn)(JSContext*, HandlePropertyName, HandleObject,
MutableHandleValue);
static const VMFunction DeleteNameInfo =
FunctionInfo<DeleteNameFn>(DeleteNameOperation, "DeleteNameOperation");
template <typename Handler>
bool BaselineCodeGen<Handler>::emit_JSOP_DELNAME() {
frame.syncStack(0);
@ -3288,7 +3242,9 @@ bool BaselineCodeGen<Handler>::emit_JSOP_DELNAME() {
pushArg(R0.scratchReg());
pushScriptNameArg();
if (!callVM(DeleteNameInfo)) {
using Fn = bool (*)(JSContext*, HandlePropertyName, HandleObject,
MutableHandleValue);
if (!callVM<Fn, js::DeleteNameOperation>()) {
return false;
}
@ -3343,12 +3299,6 @@ bool BaselineCompilerCodeGen::emit_JSOP_GETIMPORT() {
return true;
}
typedef bool (*GetImportOperationFn)(JSContext*, HandleObject, HandleScript,
jsbytecode*, MutableHandleValue);
static const VMFunction GetImportOperationInfo =
FunctionInfo<GetImportOperationFn>(GetImportOperation,
"GetImportOperation");
template <>
bool BaselineInterpreterCodeGen::emit_JSOP_GETIMPORT() {
frame.syncStack(0);
@ -3361,7 +3311,9 @@ bool BaselineInterpreterCodeGen::emit_JSOP_GETIMPORT() {
pushScriptArg(R2.scratchReg());
pushArg(R0.scratchReg());
if (!callVM(GetImportOperationInfo)) {
using Fn = bool (*)(JSContext*, HandleObject, HandleScript, jsbytecode*,
MutableHandleValue);
if (!callVM<Fn, GetImportOperation>()) {
return false;
}
@ -3386,10 +3338,6 @@ bool BaselineCodeGen<Handler>::emit_JSOP_GETINTRINSIC() {
return true;
}
typedef bool (*SetIntrinsicFn)(JSContext*, JSScript*, jsbytecode*, HandleValue);
static const VMFunction SetIntrinsicInfo = FunctionInfo<SetIntrinsicFn>(
SetIntrinsicOperation, "SetIntrinsicOperation");
template <typename Handler>
bool BaselineCodeGen<Handler>::emit_JSOP_SETINTRINSIC() {
frame.syncStack(0);
@ -3401,13 +3349,10 @@ bool BaselineCodeGen<Handler>::emit_JSOP_SETINTRINSIC() {
pushBytecodePCArg();
pushScriptArg(R2.scratchReg());
return callVM(SetIntrinsicInfo);
using Fn = bool (*)(JSContext*, JSScript*, jsbytecode*, HandleValue);
return callVM<Fn, SetIntrinsicOperation>();
}
typedef bool (*DefVarFn)(JSContext*, HandleObject, HandleScript, jsbytecode*);
static const VMFunction DefVarInfo =
FunctionInfo<DefVarFn>(DefVarOperation, "DefVarOperation");
template <typename Handler>
bool BaselineCodeGen<Handler>::emit_JSOP_DEFVAR() {
frame.syncStack(0);
@ -3420,14 +3365,10 @@ bool BaselineCodeGen<Handler>::emit_JSOP_DEFVAR() {
pushScriptArg(R2.scratchReg());
pushArg(R0.scratchReg());
return callVM(DefVarInfo);
using Fn = bool (*)(JSContext*, HandleObject, HandleScript, jsbytecode*);
return callVM<Fn, DefVarOperation>();
}
typedef bool (*DefLexicalFn)(JSContext*, HandleObject, HandleScript,
jsbytecode*);
static const VMFunction DefLexicalInfo =
FunctionInfo<DefLexicalFn>(DefLexicalOperation, "DefLexicalOperation");
template <typename Handler>
bool BaselineCodeGen<Handler>::emitDefLexical(JSOp op) {
MOZ_ASSERT(op == JSOP_DEFCONST || op == JSOP_DEFLET);
@ -3442,7 +3383,8 @@ bool BaselineCodeGen<Handler>::emitDefLexical(JSOp op) {
pushScriptArg(R2.scratchReg());
pushArg(R0.scratchReg());
return callVM(DefLexicalInfo);
using Fn = bool (*)(JSContext*, HandleObject, HandleScript, jsbytecode*);
return callVM<Fn, DefLexicalOperation>();
}
template <typename Handler>
@ -3455,11 +3397,6 @@ bool BaselineCodeGen<Handler>::emit_JSOP_DEFLET() {
return emitDefLexical(JSOP_DEFLET);
}
typedef bool (*DefFunOperationFn)(JSContext*, HandleScript, HandleObject,
HandleFunction);
static const VMFunction DefFunOperationInfo =
FunctionInfo<DefFunOperationFn>(DefFunOperation, "DefFunOperation");
template <typename Handler>
bool BaselineCodeGen<Handler>::emit_JSOP_DEFFUN() {
frame.popRegsAndSync(1);
@ -3472,15 +3409,10 @@ bool BaselineCodeGen<Handler>::emit_JSOP_DEFFUN() {
pushArg(R1.scratchReg());
pushScriptArg(R2.scratchReg());
return callVM(DefFunOperationInfo);
using Fn = bool (*)(JSContext*, HandleScript, HandleObject, HandleFunction);
return callVM<Fn, DefFunOperation>();
}
typedef bool (*InitPropGetterSetterFn)(JSContext*, jsbytecode*, HandleObject,
HandlePropertyName, HandleObject);
static const VMFunction InitPropGetterSetterInfo =
FunctionInfo<InitPropGetterSetterFn>(InitGetterSetterOperation,
"InitPropGetterSetterOperation");
template <typename Handler>
bool BaselineCodeGen<Handler>::emitInitPropGetterSetter() {
// Keep values on the stack for the decompiler.
@ -3496,7 +3428,9 @@ bool BaselineCodeGen<Handler>::emitInitPropGetterSetter() {
pushArg(R1.scratchReg());
pushBytecodePCArg();
if (!callVM(InitPropGetterSetterInfo)) {
using Fn = bool (*)(JSContext*, jsbytecode*, HandleObject, HandlePropertyName,
HandleObject);
if (!callVM<Fn, InitPropGetterSetterOperation>()) {
return false;
}
@ -3524,12 +3458,6 @@ bool BaselineCodeGen<Handler>::emit_JSOP_INITHIDDENPROP_SETTER() {
return emitInitPropGetterSetter();
}
typedef bool (*InitElemGetterSetterFn)(JSContext*, jsbytecode*, HandleObject,
HandleValue, HandleObject);
static const VMFunction InitElemGetterSetterInfo =
FunctionInfo<InitElemGetterSetterFn>(InitGetterSetterOperation,
"InitElemGetterSetterOperation");
template <typename Handler>
bool BaselineCodeGen<Handler>::emitInitElemGetterSetter() {
// Load index and value in R0 and R1, but keep values on the stack for the
@ -3546,7 +3474,9 @@ bool BaselineCodeGen<Handler>::emitInitElemGetterSetter() {
pushArg(R0.scratchReg());
pushBytecodePCArg();
if (!callVM(InitElemGetterSetterInfo)) {
using Fn = bool (*)(JSContext*, jsbytecode*, HandleObject, HandleValue,
HandleObject);
if (!callVM<Fn, InitElemGetterSetterOperation>()) {
return false;
}
@ -3800,16 +3730,13 @@ bool BaselineInterpreterCodeGen::emit_JSOP_NEWTARGET() {
MOZ_CRASH("NYI: interpreter JSOP_NEWTARGET");
}
typedef bool (*ThrowRuntimeLexicalErrorFn)(JSContext* cx, unsigned);
static const VMFunction ThrowRuntimeLexicalErrorInfo =
FunctionInfo<ThrowRuntimeLexicalErrorFn>(jit::ThrowRuntimeLexicalError,
"ThrowRuntimeLexicalError");
template <typename Handler>
bool BaselineCodeGen<Handler>::emitThrowConstAssignment() {
prepareVMCall();
pushArg(Imm32(JSMSG_BAD_CONST_ASSIGN));
return callVM(ThrowRuntimeLexicalErrorInfo);
using Fn = bool (*)(JSContext*, unsigned);
return callVM<Fn, jit::ThrowRuntimeLexicalError>();
}
template <typename Handler>
@ -3836,7 +3763,9 @@ bool BaselineCodeGen<Handler>::emitUninitializedLexicalCheck(
prepareVMCall();
pushArg(Imm32(JSMSG_UNINITIALIZED_LEXICAL));
if (!callVM(ThrowRuntimeLexicalErrorInfo)) {
using Fn = bool (*)(JSContext*, unsigned);
if (!callVM<Fn, jit::ThrowRuntimeLexicalError>()) {
return false;
}
@ -4002,11 +3931,6 @@ bool BaselineCodeGen<Handler>::emit_JSOP_STRICTSPREADEVAL() {
return emitSpreadCall(JSOP_STRICTSPREADEVAL);
}
typedef bool (*OptimizeSpreadCallFn)(JSContext*, HandleValue, bool*);
static const VMFunction OptimizeSpreadCallInfo =
FunctionInfo<OptimizeSpreadCallFn>(OptimizeSpreadCall,
"OptimizeSpreadCall");
template <typename Handler>
bool BaselineCodeGen<Handler>::emit_JSOP_OPTIMIZE_SPREADCALL() {
frame.syncStack(0);
@ -4015,7 +3939,8 @@ bool BaselineCodeGen<Handler>::emit_JSOP_OPTIMIZE_SPREADCALL() {
prepareVMCall();
pushArg(R0);
if (!callVM(OptimizeSpreadCallInfo)) {
using Fn = bool (*)(JSContext*, HandleValue, bool*);
if (!callVM<Fn, OptimizeSpreadCall>()) {
return false;
}

View File

@ -667,7 +667,6 @@ class BaselineInterpreterGenerator final : private BaselineInterpreterCodeGen {
explicit BaselineInterpreterGenerator(JSContext* cx);
};
extern const VMFunction NewArrayCopyOnWriteInfo;
extern const VMFunction ImplicitThisInfo;
} // namespace jit

View File

@ -6212,6 +6212,12 @@ void CodeGenerator::visitOutOfLineNewArray(OutOfLineNewArray* ool) {
masm.jump(ool->rejoin());
}
typedef ArrayObject* (*NewArrayCopyOnWriteFn)(JSContext*, HandleArrayObject,
gc::InitialHeap);
static const VMFunction NewArrayCopyOnWriteInfo =
FunctionInfo<NewArrayCopyOnWriteFn>(js::NewDenseCopyOnWriteArray,
"NewDenseCopyOnWriteArray");
void CodeGenerator::visitNewArrayCopyOnWrite(LNewArrayCopyOnWrite* lir) {
Register objReg = ToRegister(lir->output());
Register tempReg = ToRegister(lir->temp());
@ -6725,7 +6731,7 @@ void CodeGenerator::visitInitElem(LInitElem* lir) {
typedef bool (*InitElemGetterSetterFn)(JSContext*, jsbytecode*, HandleObject,
HandleValue, HandleObject);
static const VMFunction InitElemGetterSetterInfo =
FunctionInfo<InitElemGetterSetterFn>(InitGetterSetterOperation,
FunctionInfo<InitElemGetterSetterFn>(InitElemGetterSetterOperation,
"InitElemGetterSetterOperation");
void CodeGenerator::visitInitElemGetterSetter(LInitElemGetterSetter* lir) {
@ -6757,7 +6763,7 @@ void CodeGenerator::visitMutateProto(LMutateProto* lir) {
typedef bool (*InitPropGetterSetterFn)(JSContext*, jsbytecode*, HandleObject,
HandlePropertyName, HandleObject);
static const VMFunction InitPropGetterSetterInfo =
FunctionInfo<InitPropGetterSetterFn>(InitGetterSetterOperation,
FunctionInfo<InitPropGetterSetterFn>(InitPropGetterSetterOperation,
"InitPropGetterSetterOperation");
void CodeGenerator::visitInitPropGetterSetter(LInitPropGetterSetter* lir) {

View File

@ -23,13 +23,38 @@ namespace jit {
_(BaselineGetFunctionThis, js::jit::BaselineGetFunctionThis) \
_(BaselineThrowInitializedThis, js::jit::BaselineThrowInitializedThis) \
_(BaselineThrowUninitializedThis, js::jit::BaselineThrowUninitializedThis) \
_(BindVarOperation, js::BindVarOperation) \
_(CheckIsCallable, js::jit::CheckIsCallable) \
_(CheckOverRecursedBaseline, js::jit::CheckOverRecursedBaseline) \
_(CloneRegExpObject, js::CloneRegExpObject) \
_(DefFunOperation, js::DefFunOperation) \
_(DefLexicalOperation, js::DefLexicalOperation) \
_(DefVarOperation, js::DefVarOperation) \
_(DeleteElementNonStrict, js::DeleteElementJit<false>) \
_(DeleteElementStrict, js::DeleteElementJit<true>) \
_(DeleteNameOperation, js::DeleteNameOperation) \
_(DeletePropertyNonStrict, js::DeletePropertyJit<false>) \
_(DeletePropertyStrict, js::DeletePropertyJit<true>) \
_(GetImportOperation, js::GetImportOperation) \
_(GetNonSyntacticGlobalThis, js::GetNonSyntacticGlobalThis) \
_(InitElemGetterSetterOperation, js::InitElemGetterSetterOperation) \
_(InitPropGetterSetterOperation, js::InitPropGetterSetterOperation) \
_(InterruptCheck, js::jit::InterruptCheck) \
_(IonCompileScriptForBaseline, js::jit::IonCompileScriptForBaseline) \
_(Lambda, js::Lambda) \
_(LambdaArrow, js::LambdaArrow) \
_(MutatePrototype, js::jit::MutatePrototype) \
_(NewArrayCopyOnWriteOperation, js::NewArrayCopyOnWriteOperation) \
_(NewDenseCopyOnWriteArray, js::NewDenseCopyOnWriteArray) \
_(OptimizeSpreadCall, js::OptimizeSpreadCall) \
_(ProcessCallSiteObjOperation, js::ProcessCallSiteObjOperation) \
_(SetFunctionName, js::SetFunctionName) \
_(SetIntrinsicOperation, js::SetIntrinsicOperation) \
_(SetPropertySuper, js::SetPropertySuper) \
_(SingletonObjectLiteralOperation, js::SingletonObjectLiteralOperation) \
_(ThrowBadDerivedReturn, js::jit::ThrowBadDerivedReturn) \
_(ThrowCheckIsObject, js::ThrowCheckIsObject)
_(ThrowCheckIsObject, js::ThrowCheckIsObject) \
_(ThrowRuntimeLexicalError, js::jit::ThrowRuntimeLexicalError)
enum class VMFunctionId {
#define DEF_ID(name, fp) name,

View File

@ -26,6 +26,7 @@
#include "jit/arm64/vixl/Disasm-vixl.h"
#include "mozilla/Sprintf.h"
#include <cstdlib>
namespace vixl {

View File

@ -3678,7 +3678,7 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
ReservedRooted<JSObject*> val(&rootObject1, &REGS.sp[-1].toObject());
if (!InitGetterSetterOperation(cx, REGS.pc, obj, name, val)) {
if (!InitPropGetterSetterOperation(cx, REGS.pc, obj, name, val)) {
goto error;
}
@ -3696,7 +3696,7 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
ReservedRooted<Value> idval(&rootValue0, REGS.sp[-2]);
ReservedRooted<JSObject*> val(&rootObject1, &REGS.sp[-1].toObject());
if (!InitGetterSetterOperation(cx, REGS.pc, obj, idval, val)) {
if (!InitElemGetterSetterOperation(cx, REGS.pc, obj, idval, val)) {
goto error;
}
@ -4932,9 +4932,9 @@ unsigned js::GetInitDataPropAttrs(JSOp op) {
MOZ_CRASH("Unknown data initprop");
}
bool js::InitGetterSetterOperation(JSContext* cx, jsbytecode* pc,
HandleObject obj, HandleId id,
HandleObject val) {
static bool InitGetterSetterOperation(JSContext* cx, jsbytecode* pc,
HandleObject obj, HandleId id,
HandleObject val) {
MOZ_ASSERT(val->isCallable());
JSOp op = JSOp(*pc);
@ -4957,16 +4957,17 @@ bool js::InitGetterSetterOperation(JSContext* cx, jsbytecode* pc,
return DefineAccessorProperty(cx, obj, id, nullptr, val, attrs);
}
bool js::InitGetterSetterOperation(JSContext* cx, jsbytecode* pc,
HandleObject obj, HandlePropertyName name,
HandleObject val) {
bool js::InitPropGetterSetterOperation(JSContext* cx, jsbytecode* pc,
HandleObject obj,
HandlePropertyName name,
HandleObject val) {
RootedId id(cx, NameToId(name));
return InitGetterSetterOperation(cx, pc, obj, id, val);
}
bool js::InitGetterSetterOperation(JSContext* cx, jsbytecode* pc,
HandleObject obj, HandleValue idval,
HandleObject val) {
bool js::InitElemGetterSetterOperation(JSContext* cx, jsbytecode* pc,
HandleObject obj, HandleValue idval,
HandleObject val) {
RootedId id(cx);
if (!ToPropertyKey(cx, idval, &id)) {
return false;

View File

@ -515,19 +515,18 @@ bool DeleteNameOperation(JSContext* cx, HandlePropertyName name,
bool ImplicitThisOperation(JSContext* cx, HandleObject scopeObj,
HandlePropertyName name, MutableHandleValue res);
bool InitGetterSetterOperation(JSContext* cx, jsbytecode* pc, HandleObject obj,
HandleId id, HandleObject val);
bool InitGetterSetterOperation(JSContext* cx, jsbytecode* pc, HandleObject obj,
HandlePropertyName name, HandleObject val);
bool InitPropGetterSetterOperation(JSContext* cx, jsbytecode* pc,
HandleObject obj, HandlePropertyName name,
HandleObject val);
unsigned GetInitDataPropAttrs(JSOp op);
bool EnterWithOperation(JSContext* cx, AbstractFramePtr frame, HandleValue val,
Handle<WithScope*> scope);
bool InitGetterSetterOperation(JSContext* cx, jsbytecode* pc, HandleObject obj,
HandleValue idval, HandleObject val);
bool InitElemGetterSetterOperation(JSContext* cx, jsbytecode* pc,
HandleObject obj, HandleValue idval,
HandleObject val);
bool SpreadCallOperation(JSContext* cx, HandleScript script, jsbytecode* pc,
HandleValue thisv, HandleValue callee, HandleValue arr,

View File

@ -6659,22 +6659,10 @@ nsresult PresShell::EventHandler::HandleEvent(nsIFrame* aFrame,
}
// frame could be null after dispatching pointer events.
if (aGUIEvent->mClass == eTouchEventClass) {
if (aGUIEvent->mMessage == eTouchStart) {
WidgetTouchEvent* touchEvent = aGUIEvent->AsTouchEvent();
if (nsIFrame* newFrame =
TouchManager::SuppressInvalidPointsAndGetTargetedFrame(
touchEvent)) {
eventTargetData.SetFrameAndComputePresShellAndContent(newFrame,
aGUIEvent);
}
} else if (PresShell* newShell =
PresShell::GetShellForTouchEvent(aGUIEvent)) {
// Touch events (except touchstart) are dispatching to the captured
// element. Get correct shell from it.
eventTargetData.mPresShell = newShell;
}
}
// XXX Despite of this comment, we update the event target data outside
// DispatchPrecedingPointerEvent(). Can we make it call
// UpdateTouchEventTarget()?
eventTargetData.UpdateTouchEventTarget(aGUIEvent);
// Handle the event in the correct shell.
// We pass the subshell's root frame as the frame to start from. This is
@ -10865,3 +10853,32 @@ bool PresShell::EventHandler::EventTargetData::ComputeElementFromFrame(
// If we found an element, target it. Otherwise, target *nothing*.
return !!mContent;
}
void PresShell::EventHandler::EventTargetData::UpdateTouchEventTarget(
WidgetGUIEvent* aGUIEvent) {
MOZ_ASSERT(aGUIEvent);
if (aGUIEvent->mClass != eTouchEventClass) {
return;
}
if (aGUIEvent->mMessage == eTouchStart) {
WidgetTouchEvent* touchEvent = aGUIEvent->AsTouchEvent();
nsIFrame* newFrame =
TouchManager::SuppressInvalidPointsAndGetTargetedFrame(touchEvent);
if (!newFrame) {
return; // XXX Why don't we stop handling the event in this case?
}
SetFrameAndComputePresShellAndContent(newFrame, aGUIEvent);
return;
}
PresShell* newPresShell = PresShell::GetShellForTouchEvent(aGUIEvent);
if (!newPresShell) {
return; // XXX Why don't we stop handling the event in this case?
}
// Touch events (except touchstart) are dispatching to the captured
// element. Get correct shell from it.
mPresShell = newPresShell;
}

View File

@ -639,6 +639,15 @@ class PresShell final : public nsIPresShell,
*/
bool ComputeElementFromFrame(WidgetGUIEvent* aGUIEvent);
/**
* UpdateTouchEventTarget() updates mFrame, mPresShell and mContent if
* aGUIEvent is a touch event and there is new proper target.
*
* @param aGUIEvent The handled event. If it's not a touch event,
* this method does nothing.
*/
void UpdateTouchEventTarget(WidgetGUIEvent* aGUIEvent);
RefPtr<PresShell> mPresShell;
nsIFrame* mFrame;
nsCOMPtr<nsIContent> mContent;

View File

@ -35,16 +35,11 @@ package org.mozilla.geckoview {
method public void addDrawCallback(@android.support.annotation.NonNull java.lang.Runnable);
method public int getClearColor();
method @android.support.annotation.Nullable public java.lang.Runnable getFirstPaintCallback();
method public void getPixels(@android.support.annotation.NonNull org.mozilla.geckoview.CompositorController.GetPixelsCallback);
method public void removeDrawCallback(@android.support.annotation.NonNull java.lang.Runnable);
method public void setClearColor(int);
method public void setFirstPaintCallback(@android.support.annotation.Nullable java.lang.Runnable);
}
public static interface CompositorController.GetPixelsCallback {
method @android.support.annotation.UiThread public void onPixelsResult(int, int, @android.support.annotation.Nullable java.nio.IntBuffer);
}
@android.support.annotation.AnyThread public class ContentBlocking {
ctor public ContentBlocking();
field public static final int AT_AD = 2;
@ -136,6 +131,7 @@ package org.mozilla.geckoview {
public class GeckoDisplay {
ctor protected GeckoDisplay(org.mozilla.geckoview.GeckoSession);
method @android.support.annotation.UiThread @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoResult<android.graphics.Bitmap> capturePixels();
method @android.support.annotation.UiThread public void screenOriginChanged(int, int);
method @android.support.annotation.UiThread public boolean shouldPinOnScreen();
method @android.support.annotation.UiThread public void surfaceChanged(@android.support.annotation.NonNull android.view.Surface, int, int);
@ -735,6 +731,7 @@ package org.mozilla.geckoview {
@android.support.annotation.UiThread public class GeckoView extends android.widget.FrameLayout {
ctor public GeckoView(android.content.Context);
ctor public GeckoView(android.content.Context, android.util.AttributeSet);
method @android.support.annotation.UiThread @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoResult<android.graphics.Bitmap> capturePixels();
method public void coverUntilFirstPaint(int);
method @android.support.annotation.NonNull public org.mozilla.geckoview.DynamicToolbarAnimator getDynamicToolbarAnimator();
method @android.support.annotation.AnyThread @android.support.annotation.NonNull public org.mozilla.gecko.EventDispatcher getEventDispatcher();

View File

@ -86,6 +86,9 @@
# GeckoView specific rules.
# Keep everthing in org.mozilla.geckoview
-keep class org.mozilla.geckoview.** { *; }
-keep class org.mozilla.gecko.SysInfo {
*;
}

View File

@ -0,0 +1,6 @@
<html>
<head><title>Colours</title></head>
<body style="background-color:green;">
<div id="fullscreen" style="width:100%;height:100%;position:fixed;top:0;left:0;z-index:100;"></div>
</body>
</html>

View File

@ -53,6 +53,7 @@ open class BaseSessionTest(noErrorCollector: Boolean = false) {
const val IFRAME_REDIRECT_AUTOMATION = "/assets/www/iframe_redirect_automation.html"
const val AUTOPLAY_PATH = "/assets/www/autoplay.html"
const val SCROLL_TEST_PATH = "/assets/www/scroll.html"
const val COLORS_HTML_PATH = "/assets/www/colors.html"
}
@get:Rule val sessionRule = GeckoSessionTestRule()

View File

@ -0,0 +1,106 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
package org.mozilla.geckoview.test
import android.graphics.*
import android.support.test.filters.MediumTest
import android.support.test.runner.AndroidJUnit4
import android.view.Surface
import org.hamcrest.Matchers.notNullValue
import org.hamcrest.Matchers.nullValue
import org.junit.Assert.fail
import org.junit.Rule
import org.junit.Test
import org.junit.rules.ExpectedException
import org.junit.runner.RunWith
import org.mozilla.geckoview.GeckoResult
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.ReuseSession
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.WithDisplay
const val SCREEN_HEIGHT = 100
const val SCREEN_WIDTH = 100
@RunWith(AndroidJUnit4::class)
@MediumTest
@ReuseSession(false)
class ScreenshotTest : BaseSessionTest() {
@get:Rule
val expectedEx: ExpectedException = ExpectedException.none()
private fun getComparisonScreenshot(width: Int, height: Int): Bitmap {
val screenshotFile = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(screenshotFile)
val paint = Paint()
paint.color = Color.rgb(0, 128, 0)
canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint)
return screenshotFile
}
private fun assertScreenshotResult(result: GeckoResult<Bitmap>, comparisonImage: Bitmap) {
sessionRule.waitForResult(result).let {
assertThat("Screenshot is not null",
it, notNullValue())
assert(it.sameAs(comparisonImage)) { "Screenshots are the same" }
}
}
@WithDisplay(height = SCREEN_HEIGHT, width = SCREEN_WIDTH)
@Test
fun capturePixelsSucceeds() {
val screenshotFile = getComparisonScreenshot(SCREEN_WIDTH, SCREEN_HEIGHT)
sessionRule.session.loadTestPath(COLORS_HTML_PATH)
sessionRule.waitForPageStop()
sessionRule.display?.let {
assertScreenshotResult(it.capturePixels(), screenshotFile)
}
}
@WithDisplay(height = SCREEN_HEIGHT, width = SCREEN_WIDTH)
@Test
fun capturePixelsCanBeCalledMultipleTimes() {
val screenshotFile = getComparisonScreenshot(SCREEN_WIDTH, SCREEN_HEIGHT)
sessionRule.session.loadTestPath(COLORS_HTML_PATH)
sessionRule.waitForPageStop()
sessionRule.display?.let {
val call1 = it.capturePixels()
val call2 = it.capturePixels()
val call3 = it.capturePixels()
assertScreenshotResult(call1, screenshotFile)
assertScreenshotResult(call2, screenshotFile)
assertScreenshotResult(call3, screenshotFile)
}
}
@WithDisplay(height = SCREEN_HEIGHT, width = SCREEN_WIDTH)
@Test
fun capturePixelsCompletesCompositorPausedRestarted() {
sessionRule.display?.let {
it.surfaceDestroyed()
val result = it.capturePixels()
val texture = SurfaceTexture(0)
texture.setDefaultBufferSize(SCREEN_WIDTH, SCREEN_HEIGHT)
val surface = Surface(texture)
it.surfaceChanged(surface, SCREEN_WIDTH, SCREEN_HEIGHT)
sessionRule.waitForResult(result)
}
}
@Test
fun capturePixelsThrowsCompositorNotReady() {
expectedEx.expect(IllegalStateException::class.java)
expectedEx.expectMessage("Compositor must be ready before pixels can be captured")
val session = sessionRule.createClosedSession()
val display = session.acquireDisplay()
sessionRule.waitForResult(display.capturePixels())
fail("IllegalStateException expected to be thrown")
}
}

View File

@ -36,6 +36,7 @@ import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import android.app.Instrumentation;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.SurfaceTexture;
import android.net.LocalSocketAddress;
@ -958,6 +959,10 @@ public class GeckoSessionTestRule implements TestRule {
return RuntimeCreator.getRuntime();
}
public @Nullable GeckoDisplay getDisplay() {
return mDisplay;
}
protected static Object setDelegate(final @NonNull Class<?> cls,
final @NonNull GeckoSession session,
final @Nullable Object delegate)
@ -1211,9 +1216,10 @@ public class GeckoSessionTestRule implements TestRule {
prepareSession(mMainSession);
if (mDisplaySize != null) {
mDisplayTexture = new SurfaceTexture(0);
mDisplaySurface = new Surface(mDisplayTexture);
mDisplay = mMainSession.acquireDisplay();
mDisplayTexture = new SurfaceTexture(0);
mDisplayTexture.setDefaultBufferSize(mDisplaySize.x, mDisplaySize.y);
mDisplaySurface = new Surface(mDisplayTexture);
mDisplay.surfaceChanged(mDisplaySurface, mDisplaySize.x, mDisplaySize.y);
}
@ -1288,7 +1294,6 @@ public class GeckoSessionTestRule implements TestRule {
// We cannot detect initial page load without progress delegate.
assertThat("ProgressDelegate cannot be null-delegate when opening session",
GeckoSession.ProgressDelegate.class, not(isIn(mNullDelegates)));
mCallRecordHandler = new CallRecordHandler() {
private boolean mIsAboutBlank = !lookForAboutBlank;

View File

@ -8,11 +8,13 @@ package org.mozilla.geckoview;
import org.mozilla.gecko.annotation.RobocopTarget;
import org.mozilla.gecko.util.ThreadUtils;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;
@ -21,13 +23,7 @@ import java.util.List;
public final class CompositorController {
private final GeckoSession.Compositor mCompositor;
public interface GetPixelsCallback {
@UiThread
void onPixelsResult(int width, int height, @Nullable IntBuffer pixels);
}
private List<Runnable> mDrawCallbacks;
private GetPixelsCallback mGetPixelsCallback;
private int mDefaultClearColor = Color.WHITE;
private Runnable mFirstPaintCallback;
@ -93,32 +89,6 @@ public final class CompositorController {
}
}
/* package */ void recvScreenPixels(final int width, final int height,
final int[] pixels) {
if (mGetPixelsCallback != null) {
mGetPixelsCallback.onPixelsResult(width, height, IntBuffer.wrap(pixels));
mGetPixelsCallback = null;
}
}
/**
* Request current pixel values from the compositor. May be called on any thread. Must
* not be called again until the callback is invoked.
*
* @param callback Callback for getting pixels.
*/
@RobocopTarget
public void getPixels(final @NonNull GetPixelsCallback callback) {
ThreadUtils.assertOnUiThread();
if (mCompositor.isReady()) {
mGetPixelsCallback = callback;
mCompositor.requestScreenPixels();
} else {
callback.onPixelsResult(0, 0, null);
}
}
/**
* Get the current clear color when drawing.
*

View File

@ -6,6 +6,7 @@
package org.mozilla.geckoview;
import android.graphics.Bitmap;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
import android.view.Surface;
@ -118,4 +119,31 @@ public class GeckoDisplay {
ThreadUtils.assertOnUiThread();
return session.getDisplay() == this && session.shouldPinOnScreen();
}
/**
* Request a {@link Bitmap} of the visible portion of the web page currently being
* rendered.
*
* Returned {@link Bitmap} will have the same dimensions as the {@link Surface} the
* {@link GeckoDisplay} is currently using.
*
* If the {@link GeckoSession#isCompositorReady} is false the {@link GeckoResult} will complete
* with an {@link IllegalStateException}.
*
* This function must be called on the UI thread.
*
* @return A {@link GeckoResult} that completes with a {@link Bitmap} containing
* the pixels and size information of the currently visible rendered web page.
*/
@UiThread
public @NonNull GeckoResult<Bitmap> capturePixels() {
ThreadUtils.assertOnUiThread();
if (!session.isCompositorReady()) {
return GeckoResult.fromException(
new IllegalStateException("Compositor must be ready before pixels can be captured"));
}
GeckoResult<Bitmap> result = new GeckoResult<>();
session.mCompositor.requestScreenPixels(result);
return result;
}
}

View File

@ -1,5 +1,6 @@
package org.mozilla.geckoview;
import org.mozilla.gecko.annotation.RobocopTarget;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.util.ThreadUtils;

View File

@ -9,9 +9,6 @@ package org.mozilla.geckoview;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.UUID;
import org.mozilla.gecko.annotation.WrapForJNI;
@ -31,6 +28,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
@ -216,12 +214,7 @@ public class GeckoSession implements Parcelable {
public native void setDefaultClearColor(int color);
@WrapForJNI(calledFrom = "ui", dispatchTo = "current")
public native void requestScreenPixels();
@WrapForJNI(calledFrom = "ui")
private void recvScreenPixels(int width, int height, int[] pixels) {
GeckoSession.this.recvScreenPixels(width, height, pixels);
}
/* package */ native void requestScreenPixels(final GeckoResult<Bitmap> result);
@WrapForJNI(calledFrom = "ui", dispatchTo = "current")
public native void enableLayerUpdateNotifications(boolean enable);
@ -4364,12 +4357,6 @@ public class GeckoSession implements Parcelable {
}
}
/* package */ void recvScreenPixels(int width, int height, int[] pixels) {
if (mController != null) {
mController.recvScreenPixels(width, height, pixels);
}
}
/* package */ boolean isCompositorReady() {
return mCompositorReady;
}

View File

@ -9,6 +9,7 @@ package org.mozilla.geckoview;
import org.mozilla.gecko.AndroidGamepadManager;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.InputMethods;
import org.mozilla.gecko.annotation.RobocopTarget;
import org.mozilla.gecko.util.ActivityUtils;
import org.mozilla.gecko.util.ThreadUtils;
@ -17,6 +18,7 @@ import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
@ -166,6 +168,22 @@ public class GeckoView extends FrameLayout {
public boolean shouldPinOnScreen() {
return mDisplay != null ? mDisplay.shouldPinOnScreen() : false;
}
/**
* Request a {@link Bitmap} of the visible portion of the web page currently being
* rendered.
*
* @return A {@link GeckoResult} that completes with a {@link Bitmap} containing
* the pixels and size information of the currently visible rendered web page.
*/
@UiThread
@NonNull GeckoResult<Bitmap> capturePixels() {
if (mDisplay == null) {
return GeckoResult.fromException(new IllegalStateException("Display must be created before pixels can be captured"));
}
return mDisplay.capturePixels();
}
}
public GeckoView(final Context context) {
@ -709,4 +727,18 @@ public class GeckoView extends FrameLayout {
}
mSession.getTextInput().autofill(strValues);
}
/**
* Request a {@link Bitmap} of the visible portion of the web page currently being
* rendered.
*
* See {@link GeckoDisplay#capturePixels} for more details.
*
* @return A {@link GeckoResult} that completes with a {@link Bitmap} containing
* the pixels and size information of the currently visible rendered web page.
*/
@UiThread
public @NonNull GeckoResult<Bitmap> capturePixels() {
return mDisplay.capturePixels();
}
}

View File

@ -73,6 +73,18 @@ exclude: true
[67.15]: ../GeckoRuntime.html#registerWebExtension-org.mozilla.geckoview.WebExtension-
- Added API to [`GeckoView`][65.5] to take screenshot of the visible page. Calling [`capturePixels`][67.16] returns a ['GeckoResult'][65.25] that completes to a [`Bitmap`][67.17] of the current [`Surface`][67.18] contents, or an [`IllegalStateException`][67.19] if the [`GeckoSession`][65.9] is not ready to render content.
[67.16]: ../GeckoView.html#capturePixels
[67.17]: https://developer.android.com/reference/android/graphics/Bitmap
[67.18]: https://developer.android.com/reference/android/view/Surface
[67.19]: https://developer.android.com/reference/java/lang/IllegalStateException
- Added API to capture a screenshot to [`GeckoDisplay`][67.20]. [`capturePixels`][67.21] returns a ['GeckoResult'][65.25] that completes to a [`Bitmap`][67.16] of the current [`Surface`][67.17] contents, or an [`IllegalStateException`][67.18] if the [`GeckoSession`][65.9] is not ready to render content.
[67.20]: ../GeckoDisplay.html
[67.21]: ../GeckoDisplay.html#capturePixels
## v66
- Removed redundant field `trackingMode` from [`SecurityInformation`][66.6].
Use `TrackingProtectionDelegate.onTrackerBlocked` for notification of blocked
@ -192,4 +204,4 @@ exclude: true
[65.24]: ../CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
[65.25]: ../GeckoResult.html
[api-version]: df89fa914cfd095b37e696f3e767b55fc03a4835
[api-version]: 0bcb9f0f763b746bb6f27f5d275c351818ab971b

View File

@ -43,7 +43,6 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Locale;

View File

@ -13,6 +13,7 @@ import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.List;
@ -20,7 +21,6 @@ import java.util.Map;
import java.lang.StringBuffer;
import java.lang.Math;
import org.mozilla.geckoview.CompositorController;
import org.mozilla.gecko.gfx.PanningPerfAPI;
import org.mozilla.gecko.util.BundleEventListener;
import org.mozilla.gecko.util.EventCallback;
@ -29,12 +29,13 @@ import org.mozilla.gecko.util.StrictModeContext;
import org.mozilla.geckoview.GeckoView;
import android.app.Activity;
import android.graphics.Bitmap;
import android.util.Log;
import android.view.View;
import com.robotium.solo.Solo;
public class FennecNativeDriver implements Driver, CompositorController.GetPixelsCallback {
public class FennecNativeDriver implements Driver {
private static final int FRAME_TIME_THRESHOLD = 25; // allow 25ms per frame (40fps)
private final Activity mActivity;
@ -191,15 +192,10 @@ public class FennecNativeDriver implements Driver, CompositorController.GetPixel
}
private volatile boolean mGotPixelsResult;
private int mPixelsWidth;
private int mPixelsHeight;
private IntBuffer mPixelsResult;
private Bitmap mPixelsResult;
@Override
public synchronized void onPixelsResult(int aWidth, int aHeight, IntBuffer aPixels) {
mPixelsWidth = aWidth;
mPixelsHeight = aHeight;
mPixelsResult = aPixels;
public synchronized void onPixelsResult(final Bitmap aResult) {
mPixelsResult = aResult;
mGotPixelsResult = true;
notifyAll();
}
@ -259,7 +255,10 @@ public class FennecNativeDriver implements Driver, CompositorController.GetPixel
view.post(new Runnable() {
@Override
public void run() {
view.getSession().getCompositorController().getPixels(FennecNativeDriver.this);
view.capturePixels().then( value -> {
FennecNativeDriver.this.onPixelsResult(value);
return null;
});
}
});
@ -272,13 +271,12 @@ public class FennecNativeDriver implements Driver, CompositorController.GetPixel
}
}
final IntBuffer pixelBuffer = mPixelsResult;
int w = mPixelsWidth;
int h = mPixelsHeight;
final ByteBuffer pixelBuffer = ByteBuffer.allocate(mPixelsResult.getByteCount());
mPixelsResult.copyPixelsToBuffer(pixelBuffer);
int w = mPixelsResult.getWidth();
int h = mPixelsResult.getHeight();
mGotPixelsResult = false;
mPixelsWidth = 0;
mPixelsHeight = 0;
mPixelsResult = null;
@ -291,9 +289,7 @@ public class FennecNativeDriver implements Driver, CompositorController.GetPixel
// This allows the screen capture to be examined in the log output in a human
// readable format.
// logPixels(pixelBuffer, w, h);
// now we need to (1) flip the image, because GL likes to do things up-side-down,
// and (2) rearrange the bits from AGBR-8888 to ARGB-8888.
pixelBuffer.position(0);
String mapFile = mRootPath + "/pixels.map";
@ -304,13 +300,7 @@ public class FennecNativeDriver implements Driver, CompositorController.GetPixel
fos = new FileOutputStream(mapFile);
bos = new BufferedOutputStream(fos);
dos = new DataOutputStream(bos);
for (int y = h - 1; y >= 0; y--) {
for (int x = 0; x < w; x++) {
int agbr = pixelBuffer.get();
dos.writeInt((agbr & 0xFF00FF00) | ((agbr >> 16) & 0x000000FF) | ((agbr << 16) & 0x00FF0000));
}
}
dos.write(pixelBuffer.array());
} catch (IOException e) {
throw new RoboCopException("exception with pixel writer on file: " + mapFile);
} finally {

View File

@ -38,9 +38,6 @@ NS_IMETHODIMP
nsCryptoHash::Init(uint32_t algorithm) {
HASH_HashType hashType;
switch (algorithm) {
case nsICryptoHash::MD2:
hashType = HASH_AlgMD2;
break;
case nsICryptoHash::MD5:
hashType = HASH_AlgMD5;
break;
@ -85,8 +82,6 @@ nsCryptoHash::Init(uint32_t algorithm) {
NS_IMETHODIMP
nsCryptoHash::InitWithString(const nsACString &aAlgorithm) {
if (aAlgorithm.LowerCaseEqualsLiteral("md2")) return Init(nsICryptoHash::MD2);
if (aAlgorithm.LowerCaseEqualsLiteral("md5")) return Init(nsICryptoHash::MD5);
if (aAlgorithm.LowerCaseEqualsLiteral("sha1"))

View File

@ -16,10 +16,11 @@ interface nsICryptoHash : nsISupports
/**
* Hashing Algorithms. These values are to be used by the
* |init| method to indicate which hashing function to
* use. These values map directly onto the values defined
* in mozilla/security/nss/lib/cryptohi/hasht.h.
* use. These values must be identical to the values defined
* in security/nss/lib/util/hasht.h in type HASH_HashType.
* This allows us to use NSS mapping functions like
* HASH_GetHashOidTagByHashType with these values.
*/
const short MD2 = 1; /* String value: "md2" */
const short MD5 = 2; /* String value: "md5" */
const short SHA1 = 3; /* String value: "sha1" */
const short SHA256 = 4; /* String value: "sha256" */

View File

@ -8,18 +8,6 @@ const messages = [
"",
];
const ALGORITHMS = [
{
initString: "md2",
initConstant: Ci.nsICryptoHash.MD2,
hexHashes: [
"03d85a0d629d2c442e987525319fc471",
"8350e5a3e24c153df2275c9f80692773",
],
b64Hashes: [
"A9haDWKdLEQumHUlMZ/EcQ==",
"g1Dlo+JMFT3yJ1yfgGkncw==",
],
},
{
initString: "md5",
initConstant: Ci.nsICryptoHash.MD5,

View File

@ -9,6 +9,15 @@ Unreleased
### Removed
- Dropped support for legacy Selenium web element references
The legacy way of serialising web elements, using `{"ELEMENT": <UUID>}`,
has been removed in this release. This may break older Selenium
clients and clients which are otherwise not compatible with the
WebDriver standard.
Thanks to Shivam Singhal for this patch.
- Removed `--webdriver-port` command-line option
`--webdriver-port <PORT>` was an undocumented alias for `--port`,

View File

@ -14,7 +14,6 @@ use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult};
use webdriver::httpapi::WebDriverExtensionRoute;
pub const CHROME_ELEMENT_KEY: &'static str = "chromeelement-9fc5-4b51-a3c8-01716eedeb04";
pub const LEGACY_ELEMENT_KEY: &'static str = "ELEMENT";
pub fn extension_routes() -> Vec<(Method, &'static str, GeckoExtensionRoute)> {
return vec![

View File

@ -1,7 +1,6 @@
use crate::command::{
AddonInstallParameters, AddonUninstallParameters, GeckoContextParameters,
GeckoExtensionCommand, GeckoExtensionRoute, XblLocatorParameters, CHROME_ELEMENT_KEY,
LEGACY_ELEMENT_KEY,
};
use mozprofile::preferences::Pref;
use mozprofile::profile::Profile;
@ -393,12 +392,10 @@ impl MarionetteSession {
let chrome_element = data.get(CHROME_ELEMENT_KEY);
let element = data.get(ELEMENT_KEY);
let frame = data.get(FRAME_KEY);
let legacy_element = data.get(LEGACY_ELEMENT_KEY);
let window = data.get(WINDOW_KEY);
let value = try_opt!(
element
.or(legacy_element)
.or(chrome_element)
.or(frame)
.or(window),

View File

@ -929,7 +929,6 @@ mod test {
"type":"pointerMove",
"duration":100,
"origin":{
"ELEMENT":"elem",
"element-6066-11e4-a52e-4f735466cecf":"elem"
},
"x":5,
@ -951,7 +950,7 @@ mod test {
"type":"pointerMove",
"duration":100,
"origin":{
"ELEMENT":"elem"
"element-6066-11e4-a52e-4f735466cecf":"elem"
},
"x":5,
"y":10

View File

@ -474,6 +474,10 @@ button.warning {
-moz-box-align: center;
}
.addon-view[type="theme"] .icon:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
.content-container {
-moz-box-align: center;
}

View File

@ -0,0 +1,10 @@
[android.graphics.Bitmap = skip:true]
copyPixelsFromBuffer(Ljava/nio/Buffer;)V =
createBitmap(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap; =
[android.graphics.Bitmap$Config = skip:true]
valueOf(Ljava/lang/String;)Landroid/graphics/Bitmap$Config; =
ALPHA_8 =
ARGB_8888 =
RGBA_F16 =
RGB_565 =

View File

@ -0,0 +1,2 @@
[java.lang.IllegalStateException = skip:true]
<init>(Ljava/lang/String;)V =

View File

@ -12,10 +12,12 @@ with Files("**"):
generated = [
'AccessibilityEvent',
'AndroidBuild',
'AndroidGraphics',
'AndroidInputType',
'AndroidRect',
'InetAddress',
'JavaBuiltins',
'JavaExceptions',
'KeyEvent',
'MediaCodec',
'MotionEvent',

View File

@ -8,6 +8,7 @@
#include <android/native_window.h>
#include <android/native_window_jni.h>
#include <math.h>
#include <queue>
#include <unistd.h>
#include "mozilla/MiscEvents.h"
@ -24,6 +25,8 @@
#include "mozilla/Unused.h"
#include "mozilla/Preferences.h"
#include "mozilla/layers/RenderTrace.h"
#include "mozilla/gfx/DataSurfaceHelpers.h"
#include "mozilla/gfx/2D.h"
#include <algorithm>
using mozilla::Unused;
@ -32,6 +35,9 @@ using mozilla::dom::ContentParent;
#include "nsWindow.h"
#include "AndroidGraphics.h"
#include "JavaExceptions.h"
#include "nsIBaseWindow.h"
#include "nsIBrowserDOMWindow.h"
#include "nsIDOMChromeWindow.h"
@ -797,6 +803,7 @@ class nsWindow::LayerViewSupport final
GeckoSession::Compositor::WeakRef mCompositor;
Atomic<bool, ReleaseAcquire> mCompositorPaused;
jni::Object::GlobalRef mSurface;
std::queue<java::GeckoResult::GlobalRef> mCapturePixelsResults;
// In order to use Event::HasSameTypeAs in PostTo(), we cannot make
// LayerViewEvent a template because each template instantiation is
@ -857,7 +864,11 @@ class nsWindow::LayerViewSupport final
uiThread->Dispatch(NS_NewRunnableFunction(
"LayerViewSupport::OnDetach",
[compositor, disposer = RefPtr<Runnable>(aDisposer)] {
[compositor, disposer = RefPtr<Runnable>(aDisposer), result = &mCapturePixelsResults] {
while (!result->empty()) {
result->front()->CompleteExceptionally(java::sdk::IllegalStateException::New("The compositor has detached from the session").Cast<jni::Throwable>());
result->pop();
}
compositor->OnCompositorDetached();
disposer->Run();
}));
@ -882,6 +893,27 @@ class nsWindow::LayerViewSupport final
return child.forget();
}
int8_t* FlipScreenPixels(Shmem& aMem, const ScreenIntSize& aSize) {
const IntSize size(aSize.width, aSize.height);
RefPtr<DataSourceSurface> image = gfx::CreateDataSourceSurfaceFromData(
size,
SurfaceFormat::B8G8R8A8,
aMem.get<uint8_t>(),
StrideForFormatAndWidth(SurfaceFormat::B8G8R8A8, aSize.width));
RefPtr<DrawTarget> drawTarget = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
size, SurfaceFormat::B8G8R8A8);
drawTarget->SetTransform(Matrix::Scaling(1.0, -1.0) * Matrix::Translation(0, aSize.height));
gfx::Rect drawRect(0, 0, aSize.width, aSize.height);
drawTarget->DrawSurface(image, drawRect, drawRect);
RefPtr<SourceSurface> snapshot = drawTarget->Snapshot();
RefPtr<DataSourceSurface> data = snapshot->GetDataSurface();
DataSourceSurface::ScopedMap* smap =
new DataSourceSurface::ScopedMap(data, DataSourceSurface::READ);
return reinterpret_cast<int8_t*>(smap->GetData());
}
/**
* Compositor methods
*/
@ -1078,28 +1110,37 @@ class nsWindow::LayerViewSupport final
}
}
void RequestScreenPixels() {
void RequestScreenPixels(jni::Object::Param aResult) {
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
if (RefPtr<UiCompositorControllerChild> child =
GetUiCompositorControllerChild()) {
child->RequestScreenPixels();
mCapturePixelsResults.push(java::GeckoResult::GlobalRef(java::GeckoResult::LocalRef(aResult)));
if (mCapturePixelsResults.size() == 1) {
if (RefPtr<UiCompositorControllerChild> child =
GetUiCompositorControllerChild()) {
child->RequestScreenPixels();
}
}
}
}
void RecvScreenPixels(Shmem&& aMem, const ScreenIntSize& aSize) {
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
auto pixels =
mozilla::jni::IntArray::New(aMem.get<int>(), aMem.Size<int>());
auto compositor = GeckoSession::Compositor::LocalRef(mCompositor);
if (compositor) {
compositor->RecvScreenPixels(aSize.width, aSize.height, pixels);
auto aResult = java::GeckoResult::LocalRef(mCapturePixelsResults.front());
if (aResult) {
auto pixels =
mozilla::jni::ByteBuffer::New(FlipScreenPixels(aMem, aSize), aMem.Size<int8_t>());
auto bitmap = java::sdk::Bitmap::CreateBitmap(aSize.width, aSize.height, java::sdk::Config::ARGB_8888());
bitmap->CopyPixelsFromBuffer(pixels);
aResult->Complete(bitmap);
mCapturePixelsResults.pop();
}
// Pixels have been copied, so Dealloc Shmem
if (RefPtr<UiCompositorControllerChild> child =
GetUiCompositorControllerChild()) {
child->DeallocPixelBuffer(aMem);
if (!mCapturePixelsResults.empty()) {
child->RequestScreenPixels();
}
}
}