зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
c0ca77697c
|
@ -1822,8 +1822,8 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(
|
|||
}
|
||||
|
||||
nsEventStatus AsyncPanZoomController::HandleEndOfPan() {
|
||||
MOZ_ASSERT(GetCurrentTouchBlock());
|
||||
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->FlushRepaints();
|
||||
MOZ_ASSERT(GetCurrentTouchBlock() || GetCurrentPanGestureBlock());
|
||||
GetCurrentInputBlock()->GetOverscrollHandoffChain()->FlushRepaints();
|
||||
ParentLayerPoint flingVelocity = GetVelocityVector();
|
||||
|
||||
// Clear our velocities; if DispatchFling() gives the fling to us,
|
||||
|
@ -1845,7 +1845,7 @@ nsEventStatus AsyncPanZoomController::HandleEndOfPan() {
|
|||
if (flingVelocity.Length() < StaticPrefs::APZFlingMinVelocityThreshold()) {
|
||||
// Relieve overscroll now if needed, since we will not transition to a fling
|
||||
// animation and then an overscroll animation, and relieve it then.
|
||||
GetCurrentTouchBlock()
|
||||
GetCurrentInputBlock()
|
||||
->GetOverscrollHandoffChain()
|
||||
->SnapBackOverscrolledApzc(this);
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
|
@ -1856,8 +1856,8 @@ nsEventStatus AsyncPanZoomController::HandleEndOfPan() {
|
|||
// which nulls out mTreeManager, could be called concurrently.
|
||||
if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) {
|
||||
const FlingHandoffState handoffState{
|
||||
flingVelocity, GetCurrentTouchBlock()->GetOverscrollHandoffChain(),
|
||||
false /* not handoff */, GetCurrentTouchBlock()->GetScrolledApzc()};
|
||||
flingVelocity, GetCurrentInputBlock()->GetOverscrollHandoffChain(),
|
||||
false /* not handoff */, GetCurrentInputBlock()->GetScrolledApzc()};
|
||||
treeManagerLocal->DispatchFling(this, handoffState);
|
||||
}
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
|
@ -2556,6 +2556,35 @@ nsEventStatus AsyncPanZoomController::OnPan(const PanGestureInput& aEvent,
|
|||
ScreenPoint physicalPanDisplacement = aEvent.mPanDisplacement;
|
||||
ParentLayerPoint logicalPanDisplacement =
|
||||
aEvent.UserMultipliedLocalPanDisplacement();
|
||||
if (aEvent.mDeltaType == PanGestureInput::PANDELTA_PAGE) {
|
||||
// Pan events with page units are used by Gtk, so this replicates Gtk:
|
||||
// https://gitlab.gnome.org/GNOME/gtk/blob/c734c7e9188b56f56c3a504abee05fa40c5475ac/gtk/gtkrange.c#L3065-3073
|
||||
CSSSize pageScrollSize;
|
||||
CSSToParentLayerScale2D zoom;
|
||||
{
|
||||
// Grab the lock to access the frame metrics.
|
||||
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
||||
pageScrollSize = mScrollMetadata.GetPageScrollAmount() /
|
||||
Metrics().GetDevPixelsPerCSSPixel();
|
||||
zoom = Metrics().GetZoom();
|
||||
}
|
||||
// scrollUnit* is in units of "ParentLayer pixels per page proportion"...
|
||||
auto scrollUnitWidth = std::min(std::pow(pageScrollSize.width, 2.0 / 3.0),
|
||||
pageScrollSize.width / 2.0) *
|
||||
zoom.xScale;
|
||||
auto scrollUnitHeight = std::min(std::pow(pageScrollSize.height, 2.0 / 3.0),
|
||||
pageScrollSize.height / 2.0) *
|
||||
zoom.yScale;
|
||||
// ... and pan displacements are in units of "page proportion count"
|
||||
// here, so the products of them and scrollUnit* are in ParentLayer pixels
|
||||
ParentLayerPoint physicalPanDisplacementPL(
|
||||
physicalPanDisplacement.x * scrollUnitWidth,
|
||||
physicalPanDisplacement.y * scrollUnitHeight);
|
||||
physicalPanDisplacement = ToScreenCoordinates(physicalPanDisplacementPL,
|
||||
aEvent.mLocalPanStartPoint);
|
||||
logicalPanDisplacement.x *= scrollUnitWidth;
|
||||
logicalPanDisplacement.y *= scrollUnitHeight;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(GetCurrentPanGestureBlock());
|
||||
AdjustDeltaForAllowedScrollDirections(
|
||||
|
@ -2609,6 +2638,12 @@ nsEventStatus AsyncPanZoomController::OnPanEnd(const PanGestureInput& aEvent) {
|
|||
mX.EndTouch(aEvent.mTime);
|
||||
mY.EndTouch(aEvent.mTime);
|
||||
|
||||
// Use HandleEndOfPan for fling on platforms that don't
|
||||
// emit momentum events (Gtk).
|
||||
if (aEvent.mSimulateMomentum) {
|
||||
return HandleEndOfPan();
|
||||
}
|
||||
|
||||
// Drop any velocity on axes where we don't have room to scroll anyways
|
||||
// (in this APZC, or an APZC further in the handoff chain).
|
||||
// This ensures that we don't enlarge the display port unnecessarily.
|
||||
|
|
|
@ -167,25 +167,6 @@ struct ParamTraits<mozilla::layers::CompositableHandle> {
|
|||
}
|
||||
};
|
||||
|
||||
// Helper class for reading bitfields.
|
||||
// If T has bitfields members, derive ParamTraits<T> from BitfieldHelper<T>.
|
||||
template <typename ParamType>
|
||||
struct BitfieldHelper {
|
||||
// We need this helper because we can't get the address of a bitfield to
|
||||
// pass directly to ReadParam. So instead we read it into a temporary bool
|
||||
// and set the bitfield using a setter function
|
||||
static bool ReadBoolForBitfield(const Message* aMsg, PickleIterator* aIter,
|
||||
ParamType* aResult,
|
||||
void (ParamType::*aSetter)(bool)) {
|
||||
bool value;
|
||||
if (ReadParam(aMsg, aIter, &value)) {
|
||||
(aResult->*aSetter)(value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::layers::FrameMetrics>
|
||||
: BitfieldHelper<mozilla::layers::FrameMetrics> {
|
||||
|
|
|
@ -1088,6 +1088,25 @@ struct ParamTraits<nsILoadInfo::CrossOriginPolicy>
|
|||
: EnumSerializer<nsILoadInfo::CrossOriginPolicy,
|
||||
CrossOriginPolicyValidator> {};
|
||||
|
||||
// Helper class for reading bitfields.
|
||||
// If T has bitfields members, derive ParamTraits<T> from BitfieldHelper<T>.
|
||||
template <typename ParamType>
|
||||
struct BitfieldHelper {
|
||||
// We need this helper because we can't get the address of a bitfield to
|
||||
// pass directly to ReadParam. So instead we read it into a temporary bool
|
||||
// and set the bitfield using a setter function
|
||||
static bool ReadBoolForBitfield(const Message* aMsg, PickleIterator* aIter,
|
||||
ParamType* aResult,
|
||||
void (ParamType::*aSetter)(bool)) {
|
||||
bool value;
|
||||
if (ReadParam(aMsg, aIter, &value)) {
|
||||
(aResult->*aSetter)(value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace IPC */
|
||||
|
||||
#endif /* __IPC_GLUE_IPCMESSAGEUTILS_H__ */
|
||||
|
|
|
@ -112,7 +112,14 @@ enum class ZealMode {
|
|||
_(RegExpStatics) \
|
||||
_(RegExpSharedBytecode) \
|
||||
_(TypedArrayElements) \
|
||||
_(TypeDescrTraceList)
|
||||
_(TypeDescrTraceList) \
|
||||
_(NativeIterator) \
|
||||
_(JitScript) \
|
||||
_(ObjectGroupAddendum) \
|
||||
_(ScriptDebugScript) \
|
||||
_(BreakpointSite) \
|
||||
_(ForOfPIC) \
|
||||
_(ForOfPICStub)
|
||||
|
||||
#define JS_FOR_EACH_MEMORY_USE(_) \
|
||||
JS_FOR_EACH_PUBLIC_MEMORY_USE(_) \
|
||||
|
|
|
@ -701,7 +701,8 @@ void MemoryTracker::checkEmptyOnDestroy() {
|
|||
inline bool MemoryTracker::allowMultipleAssociations(MemoryUse use) const {
|
||||
// For most uses only one association is possible for each GC thing. Allow a
|
||||
// one-to-many relationship only where necessary.
|
||||
return use == MemoryUse::RegExpSharedBytecode;
|
||||
return use == MemoryUse::RegExpSharedBytecode ||
|
||||
use == MemoryUse::BreakpointSite || use == MemoryUse::ForOfPICStub;
|
||||
}
|
||||
|
||||
void MemoryTracker::trackMemory(Cell* cell, size_t nbytes, MemoryUse use) {
|
||||
|
|
|
@ -1831,7 +1831,7 @@ bool BaselineCacheIRCompiler::emitGuardAndGetIterator() {
|
|||
EmitPreBarrier(masm, iterObjAddr, MIRType::Object);
|
||||
|
||||
// Mark iterator as active.
|
||||
Address iterFlagsAddr(niScratch, NativeIterator::offsetOfFlags());
|
||||
Address iterFlagsAddr(niScratch, NativeIterator::offsetOfFlagsAndCount());
|
||||
masm.storePtr(obj, iterObjAddr);
|
||||
masm.or32(Imm32(NativeIterator::Flags::Active), iterFlagsAddr);
|
||||
|
||||
|
|
|
@ -3145,7 +3145,7 @@ void jit::DestroyJitScripts(FreeOp* fop, JSScript* script) {
|
|||
}
|
||||
|
||||
if (script->hasJitScript()) {
|
||||
JitScript::Destroy(script->zone(), script->jitScript());
|
||||
script->releaseJitScript();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2210,7 +2210,7 @@ bool IonCacheIRCompiler::emitGuardAndGetIterator() {
|
|||
EmitPreBarrier(masm, iterObjAddr, MIRType::Object);
|
||||
|
||||
// Mark iterator as active.
|
||||
Address iterFlagsAddr(niScratch, NativeIterator::offsetOfFlags());
|
||||
Address iterFlagsAddr(niScratch, NativeIterator::offsetOfFlagsAndCount());
|
||||
masm.storePtr(obj, iterObjAddr);
|
||||
masm.or32(Imm32(NativeIterator::Flags::Active), iterFlagsAddr);
|
||||
|
||||
|
|
|
@ -40,9 +40,10 @@ static size_t NumTypeSets(JSScript* script) {
|
|||
}
|
||||
|
||||
JitScript::JitScript(JSScript* script, uint32_t typeSetOffset,
|
||||
uint32_t bytecodeTypeMapOffset)
|
||||
uint32_t bytecodeTypeMapOffset, uint32_t allocBytes)
|
||||
: typeSetOffset_(typeSetOffset),
|
||||
bytecodeTypeMapOffset_(bytecodeTypeMapOffset) {
|
||||
bytecodeTypeMapOffset_(bytecodeTypeMapOffset),
|
||||
allocBytes_(allocBytes) {
|
||||
setTypesGeneration(script->zone()->types.generation);
|
||||
|
||||
uint8_t* base = reinterpret_cast<uint8_t*>(this);
|
||||
|
@ -98,8 +99,8 @@ bool JSScript::createJitScript(JSContext* cx) {
|
|||
uint32_t typeSetOffset = sizeof(JitScript) + numICEntries() * sizeof(ICEntry);
|
||||
uint32_t bytecodeTypeMapOffset =
|
||||
typeSetOffset + numTypeSets * sizeof(StackTypeSet);
|
||||
UniquePtr<JitScript> jitScript(
|
||||
new (raw) JitScript(this, typeSetOffset, bytecodeTypeMapOffset));
|
||||
UniquePtr<JitScript> jitScript(new (raw) JitScript(
|
||||
this, typeSetOffset, bytecodeTypeMapOffset, allocSize.value()));
|
||||
|
||||
// Sanity check the length computations.
|
||||
MOZ_ASSERT(jitScript->numICEntries() == numICEntries());
|
||||
|
@ -116,6 +117,7 @@ bool JSScript::createJitScript(JSContext* cx) {
|
|||
MOZ_ASSERT(!jitScript_);
|
||||
prepareForDestruction.release();
|
||||
jitScript_ = jitScript.release();
|
||||
AddCellMemory(this, allocSize.value(), MemoryUse::JitScript);
|
||||
|
||||
// We have a JitScript so we can set the script's jitCodeRaw_ pointer to the
|
||||
// Baseline Interpreter code.
|
||||
|
@ -150,8 +152,14 @@ void JSScript::maybeReleaseJitScript() {
|
|||
return;
|
||||
}
|
||||
|
||||
releaseJitScript();
|
||||
}
|
||||
|
||||
void JSScript::releaseJitScript() {
|
||||
MOZ_ASSERT(!hasIonScript());
|
||||
|
||||
RemoveCellMemory(this, jitScript_->allocBytes(), MemoryUse::JitScript);
|
||||
|
||||
JitScript::Destroy(zone(), jitScript_);
|
||||
jitScript_ = nullptr;
|
||||
updateJitCodeRaw(runtimeFromMainThread());
|
||||
|
|
|
@ -115,6 +115,9 @@ class alignas(uintptr_t) JitScript final {
|
|||
// bytecode map queries are in linear order.
|
||||
uint32_t bytecodeTypeMapHint_ = 0;
|
||||
|
||||
// The size of this allocation.
|
||||
uint32_t allocBytes_ = 0;
|
||||
|
||||
struct Flags {
|
||||
// Flag set when discarding JIT code to indicate this script is on the stack
|
||||
// and type information and JIT code should not be discarded.
|
||||
|
@ -147,7 +150,7 @@ class alignas(uintptr_t) JitScript final {
|
|||
|
||||
public:
|
||||
JitScript(JSScript* script, uint32_t typeSetOffset,
|
||||
uint32_t bytecodeTypeMapOffset);
|
||||
uint32_t bytecodeTypeMapOffset, uint32_t allocBytes);
|
||||
|
||||
#ifdef DEBUG
|
||||
~JitScript() {
|
||||
|
@ -327,6 +330,8 @@ class alignas(uintptr_t) JitScript final {
|
|||
uint32_t idx);
|
||||
void removeDependentWasmImport(wasm::Instance& instance, uint32_t idx);
|
||||
void unlinkDependentWasmImports();
|
||||
|
||||
size_t allocBytes() const { return allocBytes_; }
|
||||
};
|
||||
|
||||
// Ensures no JitScripts are purged in the current zone.
|
||||
|
|
|
@ -3462,7 +3462,7 @@ void MacroAssembler::debugAssertObjHasFixedSlots(Register obj,
|
|||
void MacroAssembler::branchIfNativeIteratorNotReusable(Register ni,
|
||||
Label* notReusable) {
|
||||
// See NativeIterator::isReusable.
|
||||
Address flagsAddr(ni, NativeIterator::offsetOfFlags());
|
||||
Address flagsAddr(ni, NativeIterator::offsetOfFlagsAndCount());
|
||||
|
||||
#ifdef DEBUG
|
||||
Label niIsInitialized;
|
||||
|
@ -3530,7 +3530,7 @@ void MacroAssembler::iteratorClose(Register obj, Register temp1, Register temp2,
|
|||
|
||||
// Clear active bit.
|
||||
and32(Imm32(~NativeIterator::Flags::Active),
|
||||
Address(temp1, NativeIterator::offsetOfFlags()));
|
||||
Address(temp1, NativeIterator::offsetOfFlagsAndCount()));
|
||||
|
||||
// Reset property cursor.
|
||||
loadPtr(Address(temp1, NativeIterator::offsetOfGuardsEnd()), temp2);
|
||||
|
|
|
@ -592,14 +592,7 @@ static PropertyIteratorObject* NewPropertyIteratorObject(JSContext* cx) {
|
|||
return res;
|
||||
}
|
||||
|
||||
static PropertyIteratorObject* CreatePropertyIterator(
|
||||
JSContext* cx, Handle<JSObject*> objBeingIterated, HandleIdVector props,
|
||||
uint32_t numGuards, uint32_t guardKey) {
|
||||
Rooted<PropertyIteratorObject*> propIter(cx, NewPropertyIteratorObject(cx));
|
||||
if (!propIter) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static inline size_t ExtraStringCount(size_t propertyCount, size_t guardCount) {
|
||||
static_assert(sizeof(ReceiverGuard) == 2 * sizeof(GCPtrFlatString),
|
||||
"NativeIterators are allocated in space for 1) themselves, "
|
||||
"2) the properties a NativeIterator iterates (as "
|
||||
|
@ -608,9 +601,24 @@ static PropertyIteratorObject* CreatePropertyIterator(
|
|||
"this size-relationship when determining the extra space to "
|
||||
"allocate");
|
||||
|
||||
size_t extraCount = props.length() + numGuards * 2;
|
||||
void* mem =
|
||||
cx->pod_malloc_with_extra<NativeIterator, GCPtrFlatString>(extraCount);
|
||||
return propertyCount + guardCount * 2;
|
||||
}
|
||||
|
||||
static inline size_t AllocationSize(size_t propertyCount, size_t guardCount) {
|
||||
return sizeof(NativeIterator) +
|
||||
ExtraStringCount(propertyCount, guardCount) * sizeof(GCPtrFlatString);
|
||||
}
|
||||
|
||||
static PropertyIteratorObject* CreatePropertyIterator(
|
||||
JSContext* cx, Handle<JSObject*> objBeingIterated, HandleIdVector props,
|
||||
uint32_t numGuards, uint32_t guardKey) {
|
||||
Rooted<PropertyIteratorObject*> propIter(cx, NewPropertyIteratorObject(cx));
|
||||
if (!propIter) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* mem = cx->pod_malloc_with_extra<NativeIterator, GCPtrFlatString>(
|
||||
ExtraStringCount(props.length(), numGuards));
|
||||
if (!mem) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -680,7 +688,7 @@ NativeIterator::NativeIterator(JSContext* cx,
|
|||
reinterpret_cast<GCPtrFlatString*>(guardsBegin() + numGuards)),
|
||||
propertiesEnd_(propertyCursor_),
|
||||
guardKey_(guardKey),
|
||||
flags_(0) // note: no Flags::Initialized
|
||||
flagsAndCount_(0) // note: no Flags::Initialized
|
||||
{
|
||||
MOZ_ASSERT(!*hadError);
|
||||
|
||||
|
@ -688,6 +696,15 @@ NativeIterator::NativeIterator(JSContext* cx,
|
|||
// can only free |this| (and not leak it) if this has happened.
|
||||
propIter->setNativeIterator(this);
|
||||
|
||||
if (!setInitialPropertyCount(props.length())) {
|
||||
ReportAllocationOverflow(cx);
|
||||
*hadError = true;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t nbytes = AllocationSize(props.length(), numGuards);
|
||||
AddCellMemory(propIter, nbytes, MemoryUse::NativeIterator);
|
||||
|
||||
for (size_t i = 0, len = props.length(); i < len; i++) {
|
||||
JSFlatString* str = IdToString(cx, props[i]);
|
||||
if (!str) {
|
||||
|
@ -754,6 +771,11 @@ NativeIterator::NativeIterator(JSContext* cx,
|
|||
MOZ_ASSERT(!*hadError);
|
||||
}
|
||||
|
||||
inline size_t NativeIterator::allocationSize() const {
|
||||
size_t numGuards = guardsEnd() - guardsBegin();
|
||||
return AllocationSize(initialPropertyCount(), numGuards);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool IteratorHashPolicy::match(PropertyIteratorObject* obj,
|
||||
const Lookup& lookup) {
|
||||
|
@ -1059,7 +1081,7 @@ void PropertyIteratorObject::trace(JSTracer* trc, JSObject* obj) {
|
|||
void PropertyIteratorObject::finalize(FreeOp* fop, JSObject* obj) {
|
||||
if (NativeIterator* ni =
|
||||
obj->as<PropertyIteratorObject>().getNativeIterator()) {
|
||||
fop->free_(ni);
|
||||
fop->free_(obj, ni, ni->allocationSize(), MemoryUse::NativeIterator);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -87,7 +87,13 @@ struct NativeIterator {
|
|||
};
|
||||
|
||||
private:
|
||||
uint32_t flags_ = 0; // consists of Flags bits
|
||||
static constexpr uint32_t FlagsBits = 3;
|
||||
static constexpr uint32_t FlagsMask = (1 << FlagsBits) - 1;
|
||||
static constexpr uint32_t PropCountLimit = 1 << (32 - FlagsBits);
|
||||
|
||||
// Stores Flags bits in the lower bits and the initial property count above
|
||||
// them.
|
||||
uint32_t flagsAndCount_ = 0;
|
||||
|
||||
/* While in compartment->enumerators, these form a doubly linked list. */
|
||||
NativeIterator* next_ = nullptr;
|
||||
|
@ -223,31 +229,50 @@ struct NativeIterator {
|
|||
|
||||
uint32_t guardKey() const { return guardKey_; }
|
||||
|
||||
bool isInitialized() const { return flags_ & Flags::Initialized; }
|
||||
bool isInitialized() const { return flags() & Flags::Initialized; }
|
||||
|
||||
size_t allocationSize() const;
|
||||
|
||||
private:
|
||||
uint32_t flags() const { return flagsAndCount_ & FlagsMask; }
|
||||
|
||||
uint32_t initialPropertyCount() const { return flagsAndCount_ >> FlagsBits; }
|
||||
|
||||
void setFlags(uint32_t flags) {
|
||||
MOZ_ASSERT((flags & ~FlagsMask) == 0);
|
||||
flagsAndCount_ = (initialPropertyCount() << FlagsBits) | flags;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool setInitialPropertyCount(uint32_t count) {
|
||||
if (count >= PropCountLimit) {
|
||||
return false;
|
||||
}
|
||||
flagsAndCount_ = (count << FlagsBits) | flags();
|
||||
return true;
|
||||
}
|
||||
|
||||
void markInitialized() {
|
||||
MOZ_ASSERT(flags_ == 0);
|
||||
flags_ = Flags::Initialized;
|
||||
MOZ_ASSERT(flags() == 0);
|
||||
setFlags(Flags::Initialized);
|
||||
}
|
||||
|
||||
public:
|
||||
bool isActive() const {
|
||||
MOZ_ASSERT(isInitialized());
|
||||
|
||||
return flags_ & Flags::Active;
|
||||
return flags() & Flags::Active;
|
||||
}
|
||||
|
||||
void markActive() {
|
||||
MOZ_ASSERT(isInitialized());
|
||||
|
||||
flags_ |= Flags::Active;
|
||||
flagsAndCount_ |= Flags::Active;
|
||||
}
|
||||
|
||||
void markInactive() {
|
||||
MOZ_ASSERT(isInitialized());
|
||||
|
||||
flags_ &= ~Flags::Active;
|
||||
flagsAndCount_ &= ~Flags::Active;
|
||||
}
|
||||
|
||||
bool isReusable() const {
|
||||
|
@ -258,13 +283,13 @@ struct NativeIterator {
|
|||
// |Flags::Initialized| is set. Using |Flags::NotReusable| to test
|
||||
// would also work, but this formulation is safer against memory
|
||||
// corruption.
|
||||
return flags_ == Flags::Initialized;
|
||||
return flags() == Flags::Initialized;
|
||||
}
|
||||
|
||||
void markHasUnvisitedPropertyDeletion() {
|
||||
MOZ_ASSERT(isInitialized());
|
||||
|
||||
flags_ |= Flags::HasUnvisitedPropertyDeletion;
|
||||
flagsAndCount_ |= Flags::HasUnvisitedPropertyDeletion;
|
||||
}
|
||||
|
||||
void link(NativeIterator* other) {
|
||||
|
@ -310,8 +335,8 @@ struct NativeIterator {
|
|||
return offsetof(NativeIterator, propertiesEnd_);
|
||||
}
|
||||
|
||||
static constexpr size_t offsetOfFlags() {
|
||||
return offsetof(NativeIterator, flags_);
|
||||
static constexpr size_t offsetOfFlagsAndCount() {
|
||||
return offsetof(NativeIterator, flagsAndCount_);
|
||||
}
|
||||
|
||||
static constexpr size_t offsetOfNext() {
|
||||
|
|
|
@ -4657,24 +4657,25 @@ void JSScript::destroyDebugScript(FreeOp* fop) {
|
|||
if (hasDebugScript()) {
|
||||
#ifdef DEBUG
|
||||
for (jsbytecode* pc = code(); pc < codeEnd(); pc++) {
|
||||
if (BreakpointSite* site = getBreakpointSite(pc)) {
|
||||
/* Breakpoints are swept before finalization. */
|
||||
MOZ_ASSERT(site->firstBreakpoint() == nullptr);
|
||||
MOZ_ASSERT(getBreakpointSite(pc) == nullptr);
|
||||
}
|
||||
MOZ_ASSERT(!getBreakpointSite(pc));
|
||||
}
|
||||
#endif
|
||||
fop->free_(releaseDebugScript());
|
||||
freeDebugScript(fop);
|
||||
}
|
||||
}
|
||||
|
||||
void JSScript::freeDebugScript(FreeOp* fop) {
|
||||
MOZ_ASSERT(hasDebugScript());
|
||||
fop->free_(this, releaseDebugScript(), DebugScript::allocSize(length()),
|
||||
MemoryUse::ScriptDebugScript);
|
||||
}
|
||||
|
||||
DebugScript* JSScript::getOrCreateDebugScript(JSContext* cx) {
|
||||
if (hasDebugScript()) {
|
||||
return debugScript();
|
||||
}
|
||||
|
||||
size_t nbytes =
|
||||
offsetof(DebugScript, breakpoints) + length() * sizeof(BreakpointSite*);
|
||||
size_t nbytes = DebugScript::allocSize(length());
|
||||
UniqueDebugScript debug(
|
||||
reinterpret_cast<DebugScript*>(cx->pod_calloc<uint8_t>(nbytes)));
|
||||
if (!debug) {
|
||||
|
@ -4699,6 +4700,7 @@ DebugScript* JSScript::getOrCreateDebugScript(JSContext* cx) {
|
|||
|
||||
setFlag(MutableFlags::HasDebugScript); // safe to set this; we can't fail
|
||||
// after this point
|
||||
AddCellMemory(this, nbytes, MemoryUse::ScriptDebugScript);
|
||||
|
||||
/*
|
||||
* Ensure that any Interpret() instances running on this script have
|
||||
|
@ -4744,7 +4746,7 @@ void JSScript::decrementGeneratorObserverCount(js::FreeOp* fop) {
|
|||
debug->generatorObserverCount--;
|
||||
|
||||
if (!debug->needed()) {
|
||||
fop->free_(releaseDebugScript());
|
||||
destroyDebugScript(fop);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4783,7 +4785,7 @@ void JSScript::decrementStepperCount(FreeOp* fop) {
|
|||
}
|
||||
|
||||
if (!debug->needed()) {
|
||||
fop->free_(releaseDebugScript());
|
||||
freeDebugScript(fop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4805,6 +4807,7 @@ BreakpointSite* JSScript::getOrCreateBreakpointSite(JSContext* cx,
|
|||
return nullptr;
|
||||
}
|
||||
debug->numSites++;
|
||||
AddCellMemory(this, sizeof(JSBreakpointSite), MemoryUse::BreakpointSite);
|
||||
}
|
||||
|
||||
return site;
|
||||
|
@ -4815,12 +4818,14 @@ void JSScript::destroyBreakpointSite(FreeOp* fop, jsbytecode* pc) {
|
|||
BreakpointSite*& site = debug->breakpoints[pcToOffset(pc)];
|
||||
MOZ_ASSERT(site);
|
||||
|
||||
RemoveCellMemory(this, sizeof(JSBreakpointSite), MemoryUse::BreakpointSite);
|
||||
|
||||
fop->delete_(site);
|
||||
site = nullptr;
|
||||
|
||||
debug->numSites--;
|
||||
if (!debug->needed()) {
|
||||
fop->free_(releaseDebugScript());
|
||||
freeDebugScript(fop);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -298,6 +298,11 @@ class DebugScript {
|
|||
bool needed() const {
|
||||
return generatorObserverCount > 0 || stepperCount > 0 || numSites > 0;
|
||||
}
|
||||
|
||||
static size_t allocSize(size_t codeLength) {
|
||||
return offsetof(DebugScript, breakpoints) +
|
||||
codeLength * sizeof(BreakpointSite*);
|
||||
}
|
||||
};
|
||||
|
||||
using UniqueDebugScript = js::UniquePtr<DebugScript, JS::FreePolicy>;
|
||||
|
@ -2661,6 +2666,7 @@ class JSScript : public js::gc::TenuredCell {
|
|||
js::jit::JitScript* jitScript() { return jitScript_; }
|
||||
|
||||
void maybeReleaseJitScript();
|
||||
void releaseJitScript();
|
||||
|
||||
inline js::GlobalObject& global() const;
|
||||
inline bool hasGlobal(const js::GlobalObject* global) const;
|
||||
|
@ -2958,6 +2964,7 @@ class JSScript : public js::gc::TenuredCell {
|
|||
js::DebugScript* debugScript();
|
||||
js::DebugScript* releaseDebugScript();
|
||||
void destroyDebugScript(js::FreeOp* fop);
|
||||
void freeDebugScript(js::FreeOp* fop);
|
||||
|
||||
bool hasDebugScript() const { return hasFlag(MutableFlags::HasDebugScript); }
|
||||
|
||||
|
|
|
@ -48,14 +48,16 @@ ObjectGroup::ObjectGroup(const Class* clasp, TaggedProto proto,
|
|||
}
|
||||
|
||||
void ObjectGroup::finalize(FreeOp* fop) {
|
||||
if (newScriptDontCheckGeneration()) {
|
||||
newScriptDontCheckGeneration()->clear();
|
||||
if (auto newScript = newScriptDontCheckGeneration()) {
|
||||
newScript->clear();
|
||||
fop->delete_(this, newScript, newScript->gcMallocBytes(),
|
||||
MemoryUse::ObjectGroupAddendum);
|
||||
}
|
||||
fop->delete_(newScriptDontCheckGeneration());
|
||||
if (maybePreliminaryObjectsDontCheckGeneration()) {
|
||||
maybePreliminaryObjectsDontCheckGeneration()->clear();
|
||||
}
|
||||
fop->delete_(maybePreliminaryObjectsDontCheckGeneration());
|
||||
fop->delete_(this, maybePreliminaryObjectsDontCheckGeneration(),
|
||||
MemoryUse::ObjectGroupAddendum);
|
||||
}
|
||||
|
||||
void ObjectGroup::setProtoUnchecked(TaggedProto proto) {
|
||||
|
@ -78,11 +80,27 @@ size_t ObjectGroup::sizeOfExcludingThis(
|
|||
return n;
|
||||
}
|
||||
|
||||
static inline size_t AddendumAllocSize(ObjectGroup::AddendumKind kind,
|
||||
void* addendum) {
|
||||
if (kind == ObjectGroup::Addendum_NewScript) {
|
||||
auto newScript = static_cast<TypeNewScript*>(addendum);
|
||||
return newScript->gcMallocBytes();
|
||||
}
|
||||
if (kind == ObjectGroup::Addendum_PreliminaryObjects) {
|
||||
return sizeof(PreliminaryObjectArrayWithTemplate);
|
||||
}
|
||||
// Other addendum kinds point to GC memory tracked elsewhere.
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ObjectGroup::setAddendum(AddendumKind kind, void* addendum,
|
||||
bool writeBarrier /* = true */) {
|
||||
MOZ_ASSERT(!needsSweep());
|
||||
MOZ_ASSERT(kind <= (OBJECT_FLAG_ADDENDUM_MASK >> OBJECT_FLAG_ADDENDUM_SHIFT));
|
||||
|
||||
RemoveCellMemory(this, AddendumAllocSize(addendumKind(), addendum_),
|
||||
MemoryUse::ObjectGroupAddendum);
|
||||
|
||||
if (writeBarrier) {
|
||||
// Manually trigger barriers if we are clearing new script or
|
||||
// preliminary object information. Other addendums are immutable.
|
||||
|
@ -105,6 +123,9 @@ void ObjectGroup::setAddendum(AddendumKind kind, void* addendum,
|
|||
flags_ &= ~OBJECT_FLAG_ADDENDUM_MASK;
|
||||
flags_ |= kind << OBJECT_FLAG_ADDENDUM_SHIFT;
|
||||
addendum_ = addendum;
|
||||
|
||||
AddCellMemory(this, AddendumAllocSize(kind, addendum),
|
||||
MemoryUse::ObjectGroupAddendum);
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
|
|
@ -19,6 +19,25 @@
|
|||
|
||||
using namespace js;
|
||||
|
||||
template <typename Category>
|
||||
void PICChain<Category>::addStub(JSObject* obj, CatStub* stub) {
|
||||
MOZ_ASSERT(stub);
|
||||
MOZ_ASSERT(!stub->next());
|
||||
|
||||
AddCellMemory(obj, sizeof(CatStub), MemoryUse::ForOfPICStub);
|
||||
|
||||
if (!stubs_) {
|
||||
stubs_ = stub;
|
||||
return;
|
||||
}
|
||||
|
||||
CatStub* cur = stubs_;
|
||||
while (cur->next()) {
|
||||
cur = cur->next();
|
||||
}
|
||||
cur->append(stub);
|
||||
}
|
||||
|
||||
bool js::ForOfPIC::Chain::initialize(JSContext* cx) {
|
||||
MOZ_ASSERT(!initialized_);
|
||||
|
||||
|
@ -106,7 +125,7 @@ bool js::ForOfPIC::Chain::tryOptimizeArray(JSContext* cx,
|
|||
|
||||
} else if (!disabled_ && !isArrayStateStillSane()) {
|
||||
// Otherwise, if array state is no longer sane, reinitialize.
|
||||
reset();
|
||||
reset(cx);
|
||||
|
||||
if (!initialize(cx)) {
|
||||
return false;
|
||||
|
@ -142,7 +161,7 @@ bool js::ForOfPIC::Chain::tryOptimizeArray(JSContext* cx,
|
|||
// existing cache before adding new stubs. We shouldn't really have heavy
|
||||
// churn on these.
|
||||
if (numStubs() >= MAX_STUBS) {
|
||||
eraseChain();
|
||||
eraseChain(cx);
|
||||
}
|
||||
|
||||
// Good to optimize now, create stub to add.
|
||||
|
@ -153,7 +172,7 @@ bool js::ForOfPIC::Chain::tryOptimizeArray(JSContext* cx,
|
|||
}
|
||||
|
||||
// Add the stub.
|
||||
addStub(stub);
|
||||
addStub(picObject_, stub);
|
||||
|
||||
*optimized = true;
|
||||
return true;
|
||||
|
@ -172,7 +191,7 @@ bool js::ForOfPIC::Chain::tryOptimizeArrayIteratorNext(JSContext* cx,
|
|||
}
|
||||
} else if (!disabled_ && !isArrayNextStillSane()) {
|
||||
// Otherwise, if array iterator state is no longer sane, reinitialize.
|
||||
reset();
|
||||
reset(cx);
|
||||
|
||||
if (!initialize(cx)) {
|
||||
return false;
|
||||
|
@ -222,12 +241,12 @@ bool js::ForOfPIC::Chain::isArrayStateStillSane() {
|
|||
return isArrayNextStillSane();
|
||||
}
|
||||
|
||||
void js::ForOfPIC::Chain::reset() {
|
||||
void js::ForOfPIC::Chain::reset(JSContext* cx) {
|
||||
// Should never reset a disabled_ stub.
|
||||
MOZ_ASSERT(!disabled_);
|
||||
|
||||
// Erase the chain.
|
||||
eraseChain();
|
||||
eraseChain(cx);
|
||||
|
||||
arrayProto_ = nullptr;
|
||||
arrayIteratorProto_ = nullptr;
|
||||
|
@ -243,22 +262,16 @@ void js::ForOfPIC::Chain::reset() {
|
|||
initialized_ = false;
|
||||
}
|
||||
|
||||
void js::ForOfPIC::Chain::eraseChain() {
|
||||
void js::ForOfPIC::Chain::eraseChain(JSContext* cx) {
|
||||
// Should never need to clear the chain of a disabled stub.
|
||||
MOZ_ASSERT(!disabled_);
|
||||
|
||||
// Free all stubs.
|
||||
Stub* stub = stubs_;
|
||||
while (stub) {
|
||||
Stub* next = stub->next();
|
||||
js_delete(stub);
|
||||
stub = next;
|
||||
}
|
||||
stubs_ = nullptr;
|
||||
freeAllStubs(cx->defaultFreeOp());
|
||||
}
|
||||
|
||||
// Trace the pointers stored directly on the stub.
|
||||
void js::ForOfPIC::Chain::trace(JSTracer* trc) {
|
||||
TraceEdge(trc, &picObject_, "ForOfPIC object");
|
||||
|
||||
if (!initialized_ || disabled_) {
|
||||
return;
|
||||
}
|
||||
|
@ -274,30 +287,35 @@ void js::ForOfPIC::Chain::trace(JSTracer* trc) {
|
|||
TraceEdge(trc, &canonicalNextFunc_,
|
||||
"ForOfPIC ArrayIterator.prototype.next builtin.");
|
||||
|
||||
// Free all the stubs in the chain.
|
||||
while (stubs_) {
|
||||
removeStub(stubs_, nullptr);
|
||||
if (trc->isMarkingTracer()) {
|
||||
// Free all the stubs in the chain.
|
||||
freeAllStubs(trc->runtime()->defaultFreeOp());
|
||||
}
|
||||
}
|
||||
|
||||
void js::ForOfPIC::Chain::sweep(FreeOp* fop) {
|
||||
// Free all the stubs in the chain.
|
||||
while (stubs_) {
|
||||
Stub* next = stubs_->next();
|
||||
fop->delete_(stubs_);
|
||||
stubs_ = next;
|
||||
}
|
||||
fop->delete_(this);
|
||||
}
|
||||
|
||||
static void ForOfPIC_finalize(FreeOp* fop, JSObject* obj) {
|
||||
MOZ_ASSERT(fop->maybeOnHelperThread());
|
||||
if (ForOfPIC::Chain* chain =
|
||||
ForOfPIC::fromJSObject(&obj->as<NativeObject>())) {
|
||||
chain->sweep(fop);
|
||||
chain->finalize(fop, obj);
|
||||
}
|
||||
}
|
||||
|
||||
void js::ForOfPIC::Chain::finalize(FreeOp* fop, JSObject* obj) {
|
||||
freeAllStubs(fop);
|
||||
fop->delete_(obj, this, MemoryUse::ForOfPIC);
|
||||
}
|
||||
|
||||
void js::ForOfPIC::Chain::freeAllStubs(FreeOp* fop) {
|
||||
Stub* stub = stubs_;
|
||||
while (stub) {
|
||||
Stub* next = stub->next();
|
||||
fop->delete_(picObject_, stub, MemoryUse::ForOfPICStub);
|
||||
stub = next;
|
||||
}
|
||||
stubs_ = nullptr;
|
||||
}
|
||||
|
||||
static void ForOfPIC_traceObject(JSTracer* trc, JSObject* obj) {
|
||||
if (ForOfPIC::Chain* chain =
|
||||
ForOfPIC::fromJSObject(&obj->as<NativeObject>())) {
|
||||
|
@ -330,10 +348,11 @@ NativeObject* js::ForOfPIC::createForOfPICObject(JSContext* cx,
|
|||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
ForOfPIC::Chain* chain = cx->new_<ForOfPIC::Chain>();
|
||||
ForOfPIC::Chain* chain = cx->new_<ForOfPIC::Chain>(obj);
|
||||
if (!chain) {
|
||||
return nullptr;
|
||||
}
|
||||
InitObjectPrivate(obj, chain, MemoryUse::ForOfPIC);
|
||||
obj->setPrivate(chain);
|
||||
return obj;
|
||||
}
|
||||
|
|
|
@ -64,20 +64,7 @@ class PICChain {
|
|||
public:
|
||||
CatStub* stubs() const { return stubs_; }
|
||||
|
||||
void addStub(CatStub* stub) {
|
||||
MOZ_ASSERT(stub);
|
||||
MOZ_ASSERT(!stub->next());
|
||||
if (!stubs_) {
|
||||
stubs_ = stub;
|
||||
return;
|
||||
}
|
||||
|
||||
CatStub* cur = stubs_;
|
||||
while (cur->next()) {
|
||||
cur = cur->next();
|
||||
}
|
||||
cur->append(stub);
|
||||
}
|
||||
void addStub(JSObject* obj, CatStub* stub);
|
||||
|
||||
unsigned numStubs() const {
|
||||
unsigned count = 0;
|
||||
|
@ -86,17 +73,6 @@ class PICChain {
|
|||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void removeStub(CatStub* stub, CatStub* previous) {
|
||||
if (previous) {
|
||||
MOZ_ASSERT(previous->next() == stub);
|
||||
previous->next_ = stub->next();
|
||||
} else {
|
||||
MOZ_ASSERT(stub == stubs_);
|
||||
stubs_ = stub->next();
|
||||
}
|
||||
js_delete(stub);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -158,6 +134,9 @@ struct ForOfPIC {
|
|||
*/
|
||||
class Chain : public BaseChain {
|
||||
private:
|
||||
// Pointer to owning JSObject for memory accounting purposes.
|
||||
GCPtrObject picObject_;
|
||||
|
||||
// Pointer to canonical Array.prototype and ArrayIterator.prototype
|
||||
GCPtrNativeObject arrayProto_;
|
||||
GCPtrNativeObject arrayIteratorProto_;
|
||||
|
@ -184,8 +163,9 @@ struct ForOfPIC {
|
|||
static const unsigned MAX_STUBS = 10;
|
||||
|
||||
public:
|
||||
Chain()
|
||||
explicit Chain(JSObject* picObject)
|
||||
: BaseChain(),
|
||||
picObject_(picObject),
|
||||
arrayProto_(nullptr),
|
||||
arrayIteratorProto_(nullptr),
|
||||
arrayProtoShape_(nullptr),
|
||||
|
@ -207,7 +187,7 @@ struct ForOfPIC {
|
|||
bool tryOptimizeArrayIteratorNext(JSContext* cx, bool* optimized);
|
||||
|
||||
void trace(JSTracer* trc);
|
||||
void sweep(FreeOp* fop);
|
||||
void finalize(FreeOp* fop, JSObject* obj);
|
||||
|
||||
private:
|
||||
// Check if the global array-related objects have not been messed with
|
||||
|
@ -226,10 +206,12 @@ struct ForOfPIC {
|
|||
bool hasMatchingStub(ArrayObject* obj);
|
||||
|
||||
// Reset the PIC and all info associated with it.
|
||||
void reset();
|
||||
void reset(JSContext* cx);
|
||||
|
||||
// Erase the stub chain.
|
||||
void eraseChain();
|
||||
void eraseChain(JSContext* cx);
|
||||
|
||||
void freeAllStubs(FreeOp* fop);
|
||||
};
|
||||
|
||||
// Class for object that holds ForOfPIC chain.
|
||||
|
|
|
@ -282,6 +282,12 @@ static inline const char* TypeIdString(jsid id) {
|
|||
// complex ways which can't be understood statically.
|
||||
class TypeNewScript {
|
||||
private:
|
||||
// Variable-length list of TypeNewScriptInitializer pointers.
|
||||
struct InitializerList {
|
||||
size_t length;
|
||||
TypeNewScriptInitializer entries[1];
|
||||
};
|
||||
|
||||
// Scripted function which this information was computed for.
|
||||
HeapPtr<JSFunction*> function_ = {};
|
||||
|
||||
|
@ -303,7 +309,7 @@ class TypeNewScript {
|
|||
// shape. Property assignments in inner frames are preceded by a series of
|
||||
// SETPROP_FRAME entries specifying the stack down to the frame containing
|
||||
// the write.
|
||||
TypeNewScriptInitializer* initializerList = nullptr;
|
||||
InitializerList* initializerList = nullptr;
|
||||
|
||||
// If there are additional properties found by the acquired properties
|
||||
// analysis which were not found by the definite properties analysis, this
|
||||
|
@ -356,9 +362,13 @@ class TypeNewScript {
|
|||
|
||||
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
|
||||
size_t gcMallocBytes() const;
|
||||
|
||||
static size_t offsetOfPreliminaryObjects() {
|
||||
return offsetof(TypeNewScript, preliminaryObjects);
|
||||
}
|
||||
|
||||
static size_t sizeOfInitializerList(size_t length);
|
||||
};
|
||||
|
||||
inline bool ObjectGroup::hasUnanalyzedPreliminaryObjects() {
|
||||
|
|
|
@ -3679,6 +3679,26 @@ size_t TypeNewScript::sizeOfIncludingThis(
|
|||
return n;
|
||||
}
|
||||
|
||||
/* static */ size_t TypeNewScript::sizeOfInitializerList(size_t length) {
|
||||
// TypeNewScriptInitializer struct contains [1] element in its size.
|
||||
size_t size = sizeof(TypeNewScript::InitializerList);
|
||||
if (length > 0) {
|
||||
size += (length - 1) * sizeof(TypeNewScriptInitializer);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t TypeNewScript::gcMallocBytes() const {
|
||||
size_t size = sizeof(TypeNewScript);
|
||||
if (preliminaryObjects) {
|
||||
size += sizeof(PreliminaryObjectArray);
|
||||
}
|
||||
if (initializerList) {
|
||||
size += sizeOfInitializerList(initializerList->length);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void TypeNewScript::registerNewObject(PlainObject* res) {
|
||||
MOZ_ASSERT(!analyzed());
|
||||
|
||||
|
@ -3835,6 +3855,8 @@ bool TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group,
|
|||
|
||||
MOZ_ASSERT(OnlyHasDataProperties(templateObject()->lastProperty()));
|
||||
|
||||
MOZ_ASSERT(!initializerList);
|
||||
InitializerList* newInitializerList = nullptr;
|
||||
if (templateObject()->slotSpan() != 0) {
|
||||
// Make sure that all definite properties found are reflected in the
|
||||
// prefix shape. Otherwise, the constructor behaved differently before
|
||||
|
@ -3866,25 +3888,27 @@ bool TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group,
|
|||
}
|
||||
}
|
||||
|
||||
TypeNewScriptInitializer done(TypeNewScriptInitializer::DONE, 0);
|
||||
|
||||
if (!initializerVector.append(done)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
initializerList = group->zone()->pod_calloc<TypeNewScriptInitializer>(
|
||||
initializerVector.length());
|
||||
if (!initializerList) {
|
||||
size_t nbytes = sizeOfInitializerList(initializerVector.length());
|
||||
newInitializerList = reinterpret_cast<InitializerList*>(
|
||||
group->zone()->pod_calloc<uint8_t>(nbytes));
|
||||
if (!newInitializerList) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
PodCopy(initializerList, initializerVector.begin(),
|
||||
newInitializerList->length = initializerVector.length();
|
||||
PodCopy(newInitializerList->entries, initializerVector.begin(),
|
||||
initializerVector.length());
|
||||
}
|
||||
|
||||
RemoveCellMemory(group, gcMallocBytes(), MemoryUse::ObjectGroupAddendum);
|
||||
|
||||
initializerList = newInitializerList;
|
||||
|
||||
js_delete(preliminaryObjects);
|
||||
preliminaryObjects = nullptr;
|
||||
|
||||
AddCellMemory(group, gcMallocBytes(), MemoryUse::ObjectGroupAddendum);
|
||||
|
||||
if (prefixShape->slotSpan() == templateObject()->slotSpan()) {
|
||||
// The definite properties analysis found exactly the properties that
|
||||
// are held in common by the preliminary objects. No further analysis
|
||||
|
@ -4006,9 +4030,10 @@ bool TypeNewScript::rollbackPartiallyInitializedObjects(JSContext* cx,
|
|||
// Index in pcOffsets of the frame currently being checked for a SETPROP.
|
||||
int setpropDepth = callDepth;
|
||||
|
||||
for (TypeNewScriptInitializer* init = initializerList;; init++) {
|
||||
if (init->kind == TypeNewScriptInitializer::SETPROP) {
|
||||
if (!pastProperty && pcOffsets[setpropDepth] < init->offset) {
|
||||
for (size_t i = 0; i < initializerList->length; i++) {
|
||||
const TypeNewScriptInitializer init = initializerList->entries[i];
|
||||
if (init.kind == TypeNewScriptInitializer::SETPROP) {
|
||||
if (!pastProperty && pcOffsets[setpropDepth] < init.offset) {
|
||||
// Have not yet reached this setprop.
|
||||
break;
|
||||
}
|
||||
|
@ -4016,12 +4041,12 @@ bool TypeNewScript::rollbackPartiallyInitializedObjects(JSContext* cx,
|
|||
numProperties++;
|
||||
pastProperty = false;
|
||||
setpropDepth = callDepth;
|
||||
} else if (init->kind == TypeNewScriptInitializer::SETPROP_FRAME) {
|
||||
} else if (init.kind == TypeNewScriptInitializer::SETPROP_FRAME) {
|
||||
if (!pastProperty) {
|
||||
if (pcOffsets[setpropDepth] < init->offset) {
|
||||
if (pcOffsets[setpropDepth] < init.offset) {
|
||||
// Have not yet reached this inner call.
|
||||
break;
|
||||
} else if (pcOffsets[setpropDepth] > init->offset) {
|
||||
} else if (pcOffsets[setpropDepth] > init.offset) {
|
||||
// Have advanced past this inner call.
|
||||
pastProperty = true;
|
||||
} else if (setpropDepth == 0) {
|
||||
|
@ -4033,7 +4058,7 @@ bool TypeNewScript::rollbackPartiallyInitializedObjects(JSContext* cx,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(init->kind == TypeNewScriptInitializer::DONE);
|
||||
MOZ_ASSERT(init.kind == TypeNewScriptInitializer::DONE);
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -808,7 +808,7 @@ struct nsGridContainerFrame::UsedTrackSizes {
|
|||
/** Helper function for the above method */
|
||||
void ResolveSubgridTrackSizesForAxis(nsGridContainerFrame* aFrame,
|
||||
LogicalAxis aAxis, Subgrid* aSubgrid,
|
||||
gfxContext& aRC, nscoord aCBSize);
|
||||
gfxContext& aRC, nscoord aContentBoxSize);
|
||||
|
||||
// This only has valid sizes when mCanResolveLineRangeSize is true in
|
||||
// the same axis. It may have zero tracks (a grid with only abs.pos.
|
||||
|
@ -2021,7 +2021,7 @@ struct nsGridContainerFrame::Tracks {
|
|||
void CalculateSizes(GridReflowInput& aState,
|
||||
nsTArray<GridItemInfo>& aGridItems,
|
||||
const TrackSizingFunctions& aFunctions,
|
||||
nscoord aContentSize, LineRange GridArea::*aRange,
|
||||
nscoord aContentBoxSize, LineRange GridArea::*aRange,
|
||||
SizingConstraint aConstraint);
|
||||
|
||||
/**
|
||||
|
@ -2029,7 +2029,7 @@ struct nsGridContainerFrame::Tracks {
|
|||
* https://drafts.csswg.org/css-align-3/#propdef-align-content
|
||||
*/
|
||||
void AlignJustifyContent(const nsStylePosition* aStyle, WritingMode aWM,
|
||||
nscoord aContentSize, bool aIsSubgridded);
|
||||
nscoord aContentBoxSize, bool aIsSubgridded);
|
||||
|
||||
nscoord GridLineEdge(uint32_t aLine, GridLineSide aSide) const {
|
||||
if (MOZ_UNLIKELY(mSizes.IsEmpty())) {
|
||||
|
@ -3010,20 +3010,23 @@ void nsGridContainerFrame::UsedTrackSizes::ResolveTrackSizesForAxis(
|
|||
mCanResolveLineRangeSize[aAxis] = true;
|
||||
} else {
|
||||
const auto& range = subgrid->mArea.LineRangeForAxis(parentAxis);
|
||||
nscoord cbSize = range.ToLength(parentSizes->mSizes[parentAxis]);
|
||||
ResolveSubgridTrackSizesForAxis(aFrame, aAxis, subgrid, aRC, cbSize);
|
||||
nscoord contentBoxSize = range.ToLength(parentSizes->mSizes[parentAxis]);
|
||||
auto parentWM = aFrame->GetParent()->GetWritingMode();
|
||||
contentBoxSize -= subgrid->mMarginBorderPadding.StartEnd(parentAxis, parentWM);
|
||||
contentBoxSize = std::max(nscoord(0), contentBoxSize);
|
||||
ResolveSubgridTrackSizesForAxis(aFrame, aAxis, subgrid, aRC, contentBoxSize);
|
||||
}
|
||||
}
|
||||
|
||||
void nsGridContainerFrame::UsedTrackSizes::ResolveSubgridTrackSizesForAxis(
|
||||
nsGridContainerFrame* aFrame, LogicalAxis aAxis, Subgrid* aSubgrid,
|
||||
gfxContext& aRC, nscoord aCBSize) {
|
||||
gfxContext& aRC, nscoord aContentBoxSize) {
|
||||
GridReflowInput state(aFrame, aRC);
|
||||
state.mGridItems = aSubgrid->mGridItems;
|
||||
Grid grid;
|
||||
grid.mGridColEnd = aSubgrid->mGridColEnd;
|
||||
grid.mGridRowEnd = aSubgrid->mGridRowEnd;
|
||||
state.CalculateTrackSizesForAxis(aAxis, grid, aCBSize,
|
||||
state.CalculateTrackSizesForAxis(aAxis, grid, aContentBoxSize,
|
||||
SizingConstraint::NoConstraint);
|
||||
const auto& tracks = aAxis == eLogicalAxisInline ? state.mCols : state.mRows;
|
||||
mSizes[aAxis] = tracks.mSizes;
|
||||
|
@ -3032,7 +3035,7 @@ void nsGridContainerFrame::UsedTrackSizes::ResolveSubgridTrackSizesForAxis(
|
|||
}
|
||||
|
||||
void nsGridContainerFrame::GridReflowInput::CalculateTrackSizesForAxis(
|
||||
LogicalAxis aAxis, const Grid& aGrid, nscoord aContentSize,
|
||||
LogicalAxis aAxis, const Grid& aGrid, nscoord aContentBoxSize,
|
||||
SizingConstraint aConstraint) {
|
||||
auto& tracks = aAxis == eLogicalAxisInline ? mCols : mRows;
|
||||
const auto& sizingFunctions =
|
||||
|
@ -3046,10 +3049,10 @@ void nsGridContainerFrame::GridReflowInput::CalculateTrackSizesForAxis(
|
|||
bool useParentGaps = false;
|
||||
const bool isSubgriddedAxis = mFrame->IsSubgrid(aAxis);
|
||||
if (MOZ_LIKELY(!isSubgriddedAxis)) {
|
||||
tracks.Initialize(sizingFunctions, gapStyle, gridEnd, aContentSize);
|
||||
tracks.Initialize(sizingFunctions, gapStyle, gridEnd, aContentBoxSize);
|
||||
} else {
|
||||
tracks.mGridGap = nsLayoutUtils::ResolveGapToLength(gapStyle, aContentSize);
|
||||
tracks.mContentBoxSize = aContentSize;
|
||||
tracks.mGridGap = nsLayoutUtils::ResolveGapToLength(gapStyle, aContentBoxSize);
|
||||
tracks.mContentBoxSize = aContentBoxSize;
|
||||
const auto* subgrid = mFrame->GetProperty(Subgrid::Prop());
|
||||
tracks.mSizes.SetLength(gridEnd);
|
||||
auto* parent = mFrame->ParentGridContainerForSubgrid();
|
||||
|
@ -3068,7 +3071,7 @@ void nsGridContainerFrame::GridReflowInput::CalculateTrackSizesForAxis(
|
|||
*fallbackTrackSizing->mAutoMaxSizing,
|
||||
fallbackTrackSizing->mHasRepeatAuto,
|
||||
fallbackTrackSizing->mRepeatAutoIndex),
|
||||
gapStyle, gridEnd, aContentSize);
|
||||
gapStyle, gridEnd, aContentBoxSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3089,7 +3092,7 @@ void nsGridContainerFrame::GridReflowInput::CalculateTrackSizesForAxis(
|
|||
fallbackTrackSizing->mHasRepeatAuto,
|
||||
fallbackTrackSizing->mRepeatAutoIndex)
|
||||
: sizingFunctions,
|
||||
aContentSize,
|
||||
aContentBoxSize,
|
||||
aAxis == eLogicalAxisInline ? &GridArea::mCols : &GridArea::mRows,
|
||||
aConstraint);
|
||||
// XXXmats we're losing the baseline state of subgrid descendants that
|
||||
|
@ -3098,8 +3101,8 @@ void nsGridContainerFrame::GridReflowInput::CalculateTrackSizesForAxis(
|
|||
mGridItems.TruncateLength(origGridItemCount);
|
||||
}
|
||||
|
||||
if (aContentSize != NS_UNCONSTRAINEDSIZE) {
|
||||
tracks.AlignJustifyContent(mGridStyle, mWM, aContentSize, isSubgriddedAxis);
|
||||
if (aContentBoxSize != NS_UNCONSTRAINEDSIZE) {
|
||||
tracks.AlignJustifyContent(mGridStyle, mWM, aContentBoxSize, isSubgriddedAxis);
|
||||
} else if (!useParentGaps) {
|
||||
const nscoord gridGap = tracks.mGridGap;
|
||||
nscoord pos = 0;
|
||||
|
@ -5612,7 +5615,7 @@ void nsGridContainerFrame::Tracks::StretchFlexibleTracks(
|
|||
}
|
||||
|
||||
void nsGridContainerFrame::Tracks::AlignJustifyContent(
|
||||
const nsStylePosition* aStyle, WritingMode aWM, nscoord aContentSize,
|
||||
const nsStylePosition* aStyle, WritingMode aWM, nscoord aContentBoxSize,
|
||||
bool aIsSubgriddedAxis) {
|
||||
const bool isAlign = mAxis == eLogicalAxisBlock;
|
||||
// Align-/justify-content doesn't apply in a subgridded axis.
|
||||
|
@ -5702,7 +5705,7 @@ void nsGridContainerFrame::Tracks::AlignJustifyContent(
|
|||
}
|
||||
}
|
||||
}
|
||||
space = aContentSize - trackSizeSum - SumOfGridGaps();
|
||||
space = aContentBoxSize - trackSizeSum - SumOfGridGaps();
|
||||
// Use the fallback value instead when applicable.
|
||||
if (space < 0 ||
|
||||
(alignment == NS_STYLE_ALIGN_SPACE_BETWEEN && mSizes.Length() == 1)) {
|
||||
|
|
|
@ -406,6 +406,15 @@ VARCACHE_PREF(
|
|||
RelaxedAtomicBool, false
|
||||
)
|
||||
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
VARCACHE_PREF(
|
||||
Live,
|
||||
"apz.gtk.kinetic_scroll.enabled",
|
||||
APZGTKKineticScrollEnabled,
|
||||
RelaxedAtomicBool, false
|
||||
)
|
||||
#endif
|
||||
|
||||
#if !defined(MOZ_WIDGET_ANDROID)
|
||||
# define PREF_VALUE true
|
||||
#else
|
||||
|
|
|
@ -340,7 +340,7 @@ Classes = [
|
|||
{
|
||||
'cid': '{a181af0d-68b8-4308-94db-d4f859058215}',
|
||||
'contract_ids': ['@mozilla.org/network/safe-file-output-stream;1'],
|
||||
'type': 'nsAtomicFileOutputStream',
|
||||
'type': 'nsSafeFileOutputStream',
|
||||
'headers': ['nsFileStreams.h'],
|
||||
},
|
||||
{
|
||||
|
|
|
@ -3,3 +3,4 @@
|
|||
if os == "win": FAIL
|
||||
disabled:
|
||||
if debug and os == "win" and version == "6.1.7601": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
if os == "win" and processor == "aarch64": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[appearance-button-bevel-001.html]
|
||||
disabled:
|
||||
if debug and os == "win" and version == "6.1.7601": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
if os == "win" and processor == "aarch64": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
expected:
|
||||
if (os == "win") and debug and (processor == "x86_64"): FAIL
|
||||
if (os == "win") and not debug: FAIL
|
||||
|
|
|
@ -3,3 +3,4 @@
|
|||
if os == "win": FAIL
|
||||
disabled:
|
||||
if debug and os == "win" and version == "6.1.7601": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
if os == "win" and processor == "aarch64": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
|
|
|
@ -3,3 +3,4 @@
|
|||
if os == "win": FAIL
|
||||
disabled:
|
||||
if debug and os == "win" and version == "6.1.7601": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
if os == "win" and processor == "aarch64": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
|
|
|
@ -3,3 +3,4 @@
|
|||
if os == "win": FAIL
|
||||
disabled:
|
||||
if debug and os == "win" and version == "6.1.7601": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
if os == "win" and processor == "aarch64": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[appearance-menulist-button-001.html]
|
||||
disabled:
|
||||
if debug and os == "win" and version == "6.1.7601": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
if os == "win" and processor == "aarch64": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
expected:
|
||||
if (os == "win") and debug and (processor == "x86_64"): FAIL
|
||||
if (os == "win") and not debug: FAIL
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[appearance-menulist-button-002.html]
|
||||
disabled:
|
||||
if debug and os == "win" and version == "6.1.7601": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
if os == "win" and processor == "aarch64": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
expected:
|
||||
if os == "win": PASS
|
||||
FAIL
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[appearance-meter-001.html]
|
||||
disabled:
|
||||
if debug and os == "win" and version == "6.1.7601": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
if os == "win" and processor == "aarch64": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
expected:
|
||||
if os == "win": FAIL
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[appearance-progress-bar-001.html]
|
||||
disabled:
|
||||
if debug and os == "win" and version == "6.1.7601": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
if os == "win" and processor == "aarch64": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
expected:
|
||||
if os == "win": FAIL
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
[appearance-push-button-001.html]
|
||||
disabled:
|
||||
if debug and os == "win" and version == "6.1.7601": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
if os == "win" and processor == "aarch64": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
expected:
|
||||
if os == "win": FAIL
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
[appearance-radio-001.html]
|
||||
disabled:
|
||||
if debug and os == "win" and version == "6.1.7601": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
if os == "win" and processor == "aarch64": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
expected:
|
||||
if (os == "win") and debug and (processor == "x86_64"): FAIL
|
||||
if (os == "win") and not debug: FAIL
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
[appearance-searchfield-001.html]
|
||||
disabled:
|
||||
if debug and os == "win" and version == "6.1.7601": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
if os == "win" and processor == "aarch64": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
expected:
|
||||
if (os == "win") and debug and (processor == "x86_64"): FAIL
|
||||
if (os == "win") and not debug: FAIL
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
[appearance-slider-horizontal-001.html]
|
||||
disabled:
|
||||
if debug and os == "win" and version == "6.1.7601": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
if os == "win" and processor == "aarch64": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
expected:
|
||||
if (os == "win") and debug and (processor == "x86_64"): FAIL
|
||||
if (os == "win") and not debug: FAIL
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
[appearance-square-button-001.html]
|
||||
disabled:
|
||||
if debug and os == "win" and version == "6.1.7601": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
if os == "win" and processor == "aarch64": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
expected:
|
||||
if (os == "win") and debug and (processor == "x86_64"): FAIL
|
||||
if (os == "win") and not debug: FAIL
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
[appearance-textarea-001.html]
|
||||
disabled:
|
||||
if debug and os == "win" and version == "6.1.7601": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
if os == "win" and processor == "aarch64": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
|
||||
expected:
|
||||
if (os == "win") and debug and (processor == "x86_64"): FAIL
|
||||
if (os == "win") and not debug: FAIL
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html><head>
|
||||
<meta charset="utf-8">
|
||||
<title>Reference: subgrid auto track sizing</title>
|
||||
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1558705">
|
||||
<style>
|
||||
html,body {
|
||||
color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
max-width: 260px;
|
||||
padding: 1px 5px;
|
||||
border: 1px solid;
|
||||
}
|
||||
.subgrid {
|
||||
display: grid;
|
||||
padding: 3px 5px 7px 11px;
|
||||
border-style: solid;
|
||||
border-width: 5px 7px 11px 3px;
|
||||
margin: 7px 11px 3px 5px;
|
||||
background: grey;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<article class="grid">
|
||||
<div class="subgrid">
|
||||
The cat can not be separated from milk
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="grid" style="grid-template-columns: 100px auto">
|
||||
<div class="subgrid">
|
||||
The cat can not be separated from milk
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="grid" style="grid-template-columns: auto 100px">
|
||||
<div class="subgrid" style="grid-column:2">
|
||||
The cat can not be separated from milk
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="grid" style="grid-template-columns: auto 100px auto">
|
||||
<div class="subgrid" style="grid-column:2 span 2">
|
||||
The cat can not be separated from milk
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="grid" style="grid-template-columns: auto 100px auto">
|
||||
<div class="subgrid" style="grid-column:1 span 3">
|
||||
The cat can not be separated from milk
|
||||
</div>
|
||||
</article>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,68 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html><head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test: subgrid auto track sizing</title>
|
||||
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1558705">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-grid-2">
|
||||
<link rel="match" href="auto-track-sizing-001-ref.html">
|
||||
<style>
|
||||
html,body {
|
||||
color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
max-width: 260px;
|
||||
padding: 1px 5px;
|
||||
border: 1px solid;
|
||||
}
|
||||
.subgrid {
|
||||
display: grid;
|
||||
grid-template-rows: subgrid;
|
||||
padding: 3px 5px 7px 11px;
|
||||
border-style: solid;
|
||||
border-width: 5px 7px 11px 3px;
|
||||
margin: 7px 11px 3px 5px;
|
||||
background: grey;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<article class="grid">
|
||||
<div class="subgrid">
|
||||
The cat can not be separated from milk
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="grid" style="grid-template-columns: 100px auto">
|
||||
<div class="subgrid">
|
||||
The cat can not be separated from milk
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="grid" style="grid-template-columns: auto 100px">
|
||||
<div class="subgrid" style="grid-column:2">
|
||||
The cat can not be separated from milk
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="grid" style="grid-template-columns: auto 100px auto">
|
||||
<div class="subgrid" style="grid-column:2 span 2">
|
||||
The cat can not be separated from milk
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="grid" style="grid-template-columns: auto 100px auto">
|
||||
<div class="subgrid" style="grid-column:1 span 3">
|
||||
The cat can not be separated from milk
|
||||
</div>
|
||||
</article>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -18,29 +18,56 @@ var EXPORTED_SYMBOLS = ["ContentDOMReference"];
|
|||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
|
||||
"@mozilla.org/uuid-generator;1",
|
||||
"nsIUUIDGenerator");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "finalizationService",
|
||||
"@mozilla.org/toolkit/finalizationwitness;1",
|
||||
"nsIFinalizationWitnessService");
|
||||
|
||||
/**
|
||||
* @typedef {number} ElementID
|
||||
* @typedef {Object} ElementIdentifier
|
||||
*/
|
||||
|
||||
const FINALIZATION_TOPIC = "content-dom-reference-finalized";
|
||||
|
||||
// A WeakMap which ties finalization witness objects to the lifetime of the DOM
|
||||
// nodes they're meant to witness. When the DOM node in the map key is
|
||||
// finalized, the WeakMap stops holding the finalization witness in its value
|
||||
// alive, which alerts our observer that the element has been destroyed.
|
||||
const finalizerRoots = new WeakMap();
|
||||
|
||||
/**
|
||||
* An identifier generated by ContentDOMReference is a unique pair of BrowsingContext
|
||||
* ID and a UUID. gRegistry maps BrowsingContext's to an object with the following
|
||||
* ID and a numeric ID. gRegistry maps BrowsingContext's to an object with the following
|
||||
* properties:
|
||||
*
|
||||
* UUIDToElement:
|
||||
* A Map of UUID strings to WeakReference's to the elements they refer to.
|
||||
* IDToElement:
|
||||
* A Map of IDs to WeakReference's to the elements they refer to.
|
||||
*
|
||||
* elementToUUID:
|
||||
* A WeakMap from a DOM element to a UUID that refers to it.
|
||||
* elementToID:
|
||||
* A WeakMap from a DOM element to an ID that refers to it.
|
||||
*/
|
||||
var gRegistry = new WeakMap();
|
||||
|
||||
var ContentDOMReference = {
|
||||
_init() {
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
Services.obs.addObserver(this, FINALIZATION_TOPIC);
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
if (topic !== FINALIZATION_TOPIC) {
|
||||
throw new Error("Unexpected observer topic");
|
||||
}
|
||||
|
||||
let identifier = JSON.parse(data);
|
||||
this._revoke(identifier);
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate and return an identifier for a given DOM element.
|
||||
*
|
||||
* @param {Element} element The DOM element to generate the identifier for.
|
||||
* @return {Object} The identifier for the DOM element that can be passed between
|
||||
* @return {ElementIdentifier} The identifier for the DOM element that can be passed between
|
||||
* processes as a message.
|
||||
*/
|
||||
get(element) {
|
||||
|
@ -53,85 +80,85 @@ var ContentDOMReference = {
|
|||
let mappings = gRegistry.get(browsingContext);
|
||||
if (!mappings) {
|
||||
mappings = {
|
||||
UUIDToElement: new Map(),
|
||||
elementToUUID: new WeakMap(),
|
||||
IDToElement: new Map(),
|
||||
elementToID: new WeakMap(),
|
||||
};
|
||||
gRegistry.set(browsingContext, mappings);
|
||||
}
|
||||
|
||||
let uuid = mappings.elementToUUID.get(element);
|
||||
if (uuid) {
|
||||
// We already had this element registered, so return the pre-existing UUID.
|
||||
return { browsingContextId: browsingContext.id, uuid };
|
||||
let id = mappings.elementToID.get(element);
|
||||
if (id) {
|
||||
// We already had this element registered, so return the pre-existing ID.
|
||||
return { browsingContextId: browsingContext.id, id };
|
||||
}
|
||||
|
||||
// We must be registering a new element at this point.
|
||||
uuid = gUUIDGenerator.generateUUID().toString();
|
||||
mappings.elementToUUID.set(element, uuid);
|
||||
mappings.UUIDToElement.set(uuid, Cu.getWeakReference(element));
|
||||
id = Math.random();
|
||||
mappings.elementToID.set(element, id);
|
||||
mappings.IDToElement.set(id, Cu.getWeakReference(element));
|
||||
|
||||
return { browsingContextId: browsingContext.id, uuid };
|
||||
let identifier = { browsingContextId: browsingContext.id, id };
|
||||
|
||||
finalizerRoots.set(
|
||||
element,
|
||||
finalizationService.make(FINALIZATION_TOPIC,
|
||||
JSON.stringify(identifier)));
|
||||
|
||||
return identifier;
|
||||
},
|
||||
|
||||
/**
|
||||
* Resolves an identifier back into the DOM Element that it was generated from.
|
||||
*
|
||||
* @param {Object} The identifier generated via ContentDOMReference.get for a
|
||||
* @param {ElementIdentifier} The identifier generated via ContentDOMReference.get for a
|
||||
* DOM element.
|
||||
* @return {Element} The DOM element that the identifier was generated for, or
|
||||
* null if the element does not still exist.
|
||||
*/
|
||||
resolve(identifier) {
|
||||
let browsingContext = BrowsingContext.get(identifier.browsingContextId);
|
||||
let uuid = identifier.uuid;
|
||||
return this._resolveUUIDToElement(browsingContext, uuid);
|
||||
let {id} = identifier;
|
||||
return this._resolveIDToElement(browsingContext, id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes an identifier from the registry so that subsequent attempts
|
||||
* to resolve it will result in null. This is generally a good idea to avoid
|
||||
* identifiers lying around taking up space (identifiers don't keep the
|
||||
* DOM element alive, but the weak pointers themselves consume memory, and
|
||||
* that's what we reclaim when revoking).
|
||||
* to resolve it will result in null. This is done automatically when the
|
||||
* target node is GCed.
|
||||
*
|
||||
* @param {Object} The identifier to revoke, issued by ContentDOMReference.get for
|
||||
* @param {ElementIdentifier} The identifier to revoke, issued by ContentDOMReference.get for
|
||||
* a DOM element.
|
||||
*/
|
||||
revoke(identifier) {
|
||||
_revoke(identifier) {
|
||||
let browsingContext = BrowsingContext.get(identifier.browsingContextId);
|
||||
let uuid = identifier.uuid;
|
||||
let {id} = identifier;
|
||||
|
||||
let mappings = gRegistry.get(browsingContext);
|
||||
if (!mappings) {
|
||||
return;
|
||||
}
|
||||
|
||||
let element = this._resolveUUIDToElement(browsingContext, uuid);
|
||||
if (element) {
|
||||
mappings.elementToUUID.delete(element);
|
||||
}
|
||||
|
||||
mappings.UUIDToElement.delete(uuid);
|
||||
mappings.IDToElement.delete(id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Private helper function that resolves a BrowsingContext and UUID (the
|
||||
* Private helper function that resolves a BrowsingContext and ID (the
|
||||
* pair that makes up an identifier) to a DOM element.
|
||||
*
|
||||
* @param {BrowsingContext} browsingContext The BrowsingContext that was hosting
|
||||
* the DOM element at the time that the identifier was generated.
|
||||
* @param {String} uuid The UUID generated for the DOM element.
|
||||
* @param {ElementID} id The ID generated for the DOM element.
|
||||
*
|
||||
* @return {Element} The DOM element that the identifier was generated for, or
|
||||
* null if the element does not still exist.
|
||||
*/
|
||||
_resolveUUIDToElement(browsingContext, uuid) {
|
||||
_resolveIDToElement(browsingContext, id) {
|
||||
let mappings = gRegistry.get(browsingContext);
|
||||
if (!mappings) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let weakReference = mappings.UUIDToElement.get(uuid);
|
||||
let weakReference = mappings.IDToElement.get(id);
|
||||
if (!weakReference) {
|
||||
return null;
|
||||
}
|
||||
|
@ -139,3 +166,5 @@ var ContentDOMReference = {
|
|||
return weakReference.get();
|
||||
},
|
||||
};
|
||||
|
||||
ContentDOMReference._init();
|
||||
|
|
|
@ -437,7 +437,8 @@ PanGestureInput::PanGestureInput()
|
|||
mHandledByAPZ(false),
|
||||
mFollowedByMomentum(false),
|
||||
mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection(false),
|
||||
mOverscrollBehaviorAllowsSwipe(false) {}
|
||||
mOverscrollBehaviorAllowsSwipe(false),
|
||||
mSimulateMomentum(false) {}
|
||||
|
||||
PanGestureInput::PanGestureInput(PanGestureType aType, uint32_t aTime,
|
||||
TimeStamp aTimeStamp,
|
||||
|
@ -455,7 +456,8 @@ PanGestureInput::PanGestureInput(PanGestureType aType, uint32_t aTime,
|
|||
mHandledByAPZ(false),
|
||||
mFollowedByMomentum(false),
|
||||
mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection(false),
|
||||
mOverscrollBehaviorAllowsSwipe(false) {}
|
||||
mOverscrollBehaviorAllowsSwipe(false),
|
||||
mSimulateMomentum(false) {}
|
||||
|
||||
bool PanGestureInput::IsMomentum() const {
|
||||
switch (mType) {
|
||||
|
@ -477,7 +479,6 @@ WidgetWheelEvent PanGestureInput::ToWidgetWheelEvent(nsIWidget* aWidget) const {
|
|||
mPanStartPoint,
|
||||
PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
|
||||
wheelEvent.mButtons = 0;
|
||||
wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL;
|
||||
wheelEvent.mMayHaveMomentum = true; // pan inputs may have momentum
|
||||
wheelEvent.mIsMomentum = IsMomentum();
|
||||
wheelEvent.mLineOrPageDeltaX = mLineOrPageDeltaX;
|
||||
|
@ -486,6 +487,16 @@ WidgetWheelEvent PanGestureInput::ToWidgetWheelEvent(nsIWidget* aWidget) const {
|
|||
wheelEvent.mDeltaY = mPanDisplacement.y;
|
||||
wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
|
||||
wheelEvent.mFocusSequenceNumber = mFocusSequenceNumber;
|
||||
if (mDeltaType == PanGestureInput::PANDELTA_PAGE) {
|
||||
// Emulate legacy widget/gtk behavior
|
||||
wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_LINE;
|
||||
wheelEvent.mIsNoLineOrPageDelta = true;
|
||||
wheelEvent.mScrollType = WidgetWheelEvent::SCROLL_ASYNCHRONOUSELY;
|
||||
wheelEvent.mDeltaX *= 3;
|
||||
wheelEvent.mDeltaY *= 3;
|
||||
} else {
|
||||
wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL;
|
||||
}
|
||||
return wheelEvent;
|
||||
}
|
||||
|
||||
|
@ -498,6 +509,14 @@ bool PanGestureInput::TransformToLocal(
|
|||
}
|
||||
mLocalPanStartPoint = *panStartPoint;
|
||||
|
||||
if (mDeltaType == PanGestureInput::PANDELTA_PAGE) {
|
||||
// Skip transforming the pan displacement because we want
|
||||
// raw page proportion counts.
|
||||
mLocalPanDisplacement.x = mPanDisplacement.x;
|
||||
mLocalPanDisplacement.y = mPanDisplacement.y;
|
||||
return true;
|
||||
}
|
||||
|
||||
Maybe<ParentLayerPoint> panDisplacement =
|
||||
UntransformVector(aTransform, mPanDisplacement, mPanStartPoint);
|
||||
if (!panDisplacement) {
|
||||
|
|
|
@ -332,6 +332,17 @@ class PanGestureInput : public InputData {
|
|||
// user has stopped the animation by putting their fingers on a touchpad.
|
||||
PANGESTURE_MOMENTUMEND
|
||||
));
|
||||
|
||||
MOZ_DEFINE_ENUM_AT_CLASS_SCOPE(
|
||||
PanDeltaType, (
|
||||
// There are three kinds of scroll delta modes in Gecko: "page", "line"
|
||||
// and "pixel". Touchpad pan gestures only support "page" and "pixel".
|
||||
//
|
||||
// NOTE: PANDELTA_PAGE currently replicates Gtk behavior
|
||||
// (see AsyncPanZoomController::OnPan).
|
||||
PANDELTA_PAGE,
|
||||
PANDELTA_PIXEL
|
||||
));
|
||||
// clang-format on
|
||||
|
||||
PanGestureInput(PanGestureType aType, uint32_t aTime, TimeStamp aTimeStamp,
|
||||
|
@ -368,11 +379,13 @@ class PanGestureInput : public InputData {
|
|||
double mUserDeltaMultiplierX;
|
||||
double mUserDeltaMultiplierY;
|
||||
|
||||
bool mHandledByAPZ;
|
||||
PanDeltaType mDeltaType = PANDELTA_PIXEL;
|
||||
|
||||
bool mHandledByAPZ: 1;
|
||||
|
||||
// true if this is a PANGESTURE_END event that will be followed by a
|
||||
// PANGESTURE_MOMENTUMSTART event.
|
||||
bool mFollowedByMomentum;
|
||||
bool mFollowedByMomentum: 1;
|
||||
|
||||
// If this is true, and this event started a new input block that couldn't
|
||||
// find a scrollable target which is scrollable in the horizontal component
|
||||
|
@ -380,15 +393,25 @@ class PanGestureInput : public InputData {
|
|||
// hold until a content response has arrived, even if the block has a
|
||||
// confirmed target.
|
||||
// This is used by events that can result in a swipe instead of a scroll.
|
||||
bool mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection;
|
||||
bool mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection: 1;
|
||||
|
||||
// This is used by APZ to communicate to the macOS widget code whether
|
||||
// the overscroll-behavior of the scroll frame handling this swipe allows
|
||||
// non-local overscroll behaviors in the horizontal direction (such as
|
||||
// swipe navigation).
|
||||
bool mOverscrollBehaviorAllowsSwipe;
|
||||
bool mOverscrollBehaviorAllowsSwipe: 1;
|
||||
|
||||
// XXX: If adding any more bools, switch to using bitfields instead.
|
||||
// true if APZ should do a fling animation after this pan ends, like
|
||||
// it would with touchscreens. (For platforms that don't emit momentum events.)
|
||||
bool mSimulateMomentum: 1;
|
||||
|
||||
void SetHandledByAPZ(bool aHandled) { mHandledByAPZ = aHandled; }
|
||||
void SetFollowedByMomentum(bool aFollowed) { mFollowedByMomentum = aFollowed; }
|
||||
void SetRequiresContentResponseIfCannotScrollHorizontallyInStartDirection(bool aRequires) {
|
||||
mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection = aRequires;
|
||||
}
|
||||
void SetOverscrollBehaviorAllowsSwipe(bool aAllows) { mOverscrollBehaviorAllowsSwipe = aAllows; }
|
||||
void SetSimulateMomentum(bool aSimulate) { mSimulateMomentum = aSimulate; }
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -119,6 +119,9 @@ using namespace mozilla::widget;
|
|||
#include "mozilla/layers/CompositorThread.h"
|
||||
#include "mozilla/layers/KnowsCompositor.h"
|
||||
|
||||
#include "mozilla/layers/APZInputBridge.h"
|
||||
#include "mozilla/layers/IAPZCTreeManager.h"
|
||||
|
||||
#ifdef MOZ_X11
|
||||
# include "GLContextGLX.h" // for GLContextGLX::FindVisual()
|
||||
# include "GtkCompositorWidget.h"
|
||||
|
@ -3034,8 +3037,11 @@ void nsWindow::OnScrollEvent(GdkEventScroll* aEvent) {
|
|||
#if GTK_CHECK_VERSION(3, 4, 0)
|
||||
// check for duplicate legacy scroll event, see GNOME bug 726878
|
||||
if (aEvent->direction != GDK_SCROLL_SMOOTH &&
|
||||
mLastScrollEventTime == aEvent->time)
|
||||
mLastScrollEventTime == aEvent->time) {
|
||||
LOG(("[%d] duplicate legacy scroll event %d\n", aEvent->time,
|
||||
aEvent->direction));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
WidgetWheelEvent wheelEvent(true, eWheel, this);
|
||||
wheelEvent.mDeltaMode = dom::WheelEvent_Binding::DOM_DELTA_LINE;
|
||||
|
@ -3043,21 +3049,56 @@ void nsWindow::OnScrollEvent(GdkEventScroll* aEvent) {
|
|||
#if GTK_CHECK_VERSION(3, 4, 0)
|
||||
case GDK_SCROLL_SMOOTH: {
|
||||
// As of GTK 3.4, all directional scroll events are provided by
|
||||
// the GDK_SCROLL_SMOOTH direction on XInput2 devices.
|
||||
// the GDK_SCROLL_SMOOTH direction on XInput2 and Wayland devices.
|
||||
mLastScrollEventTime = aEvent->time;
|
||||
|
||||
// Special handling for touchpads to support flings
|
||||
// (also known as kinetic/inertial/momentum scrolling)
|
||||
GdkDevice* device = gdk_event_get_source_device((GdkEvent*)aEvent);
|
||||
GdkInputSource source = gdk_device_get_source(device);
|
||||
if (source == GDK_SOURCE_TOUCHSCREEN || source == GDK_SOURCE_TOUCHPAD) {
|
||||
if (StaticPrefs::APZGTKKineticScrollEnabled() &&
|
||||
gtk_check_version(3, 20, 0) == nullptr) {
|
||||
static auto sGdkEventIsScrollStopEvent =
|
||||
(gboolean(*)(const GdkEvent*))dlsym(
|
||||
RTLD_DEFAULT, "gdk_event_is_scroll_stop_event");
|
||||
|
||||
LOG(("[%d] pan smooth event dx=%f dy=%f inprogress=%d\n",
|
||||
aEvent->time, aEvent->delta_x, aEvent->delta_y, mPanInProgress));
|
||||
PanGestureInput::PanGestureType eventType =
|
||||
PanGestureInput::PANGESTURE_PAN;
|
||||
if (sGdkEventIsScrollStopEvent((GdkEvent*)aEvent)) {
|
||||
eventType = PanGestureInput::PANGESTURE_END;
|
||||
mPanInProgress = false;
|
||||
} else if (!mPanInProgress) {
|
||||
eventType = PanGestureInput::PANGESTURE_START;
|
||||
mPanInProgress = true;
|
||||
}
|
||||
|
||||
LayoutDeviceIntPoint touchPoint = GetRefPoint(this, aEvent);
|
||||
PanGestureInput panEvent(
|
||||
eventType, aEvent->time, GetEventTimeStamp(aEvent->time),
|
||||
ScreenPoint(touchPoint.x, touchPoint.y),
|
||||
ScreenPoint(aEvent->delta_x, aEvent->delta_y),
|
||||
KeymapWrapper::ComputeKeyModifiers(aEvent->state));
|
||||
panEvent.mDeltaType = PanGestureInput::PANDELTA_PAGE;
|
||||
panEvent.mSimulateMomentum = true;
|
||||
|
||||
DispatchPanGestureInput(panEvent);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Older GTK doesn't support stop events, so we can't support fling
|
||||
wheelEvent.mScrollType = WidgetWheelEvent::SCROLL_ASYNCHRONOUSELY;
|
||||
}
|
||||
|
||||
// TODO - use a more appropriate scrolling unit than lines.
|
||||
// Multiply event deltas by 3 to emulate legacy behaviour.
|
||||
wheelEvent.mDeltaX = aEvent->delta_x * 3;
|
||||
wheelEvent.mDeltaY = aEvent->delta_y * 3;
|
||||
wheelEvent.mIsNoLineOrPageDelta = true;
|
||||
// This next step manually unsets smooth scrolling for touch devices
|
||||
// that trigger GDK_SCROLL_SMOOTH. We use the slave device, which
|
||||
// represents the actual input.
|
||||
GdkDevice* device = gdk_event_get_source_device((GdkEvent*)aEvent);
|
||||
GdkInputSource source = gdk_device_get_source(device);
|
||||
if (source == GDK_SOURCE_TOUCHSCREEN || source == GDK_SOURCE_TOUCHPAD) {
|
||||
wheelEvent.mScrollType = WidgetWheelEvent::SCROLL_ASYNCHRONOUSELY;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -492,6 +492,8 @@ class nsWindow final : public nsBaseWidget {
|
|||
// This field omits duplicate scroll events caused by GNOME bug 726878.
|
||||
guint32 mLastScrollEventTime;
|
||||
|
||||
bool mPanInProgress = false;
|
||||
|
||||
// for touch event handling
|
||||
nsRefPtrHashtable<nsPtrHashKey<GdkEventSequence>, mozilla::dom::Touch>
|
||||
mTouches;
|
||||
|
|
|
@ -1132,6 +1132,29 @@ void nsBaseWidget::DispatchTouchInput(MultiTouchInput& aInput) {
|
|||
}
|
||||
}
|
||||
|
||||
void nsBaseWidget::DispatchPanGestureInput(PanGestureInput& aInput) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mAPZC) {
|
||||
MOZ_ASSERT(APZThreadUtils::IsControllerThread());
|
||||
uint64_t inputBlockId = 0;
|
||||
ScrollableLayerGuid guid;
|
||||
|
||||
nsEventStatus result =
|
||||
mAPZC->InputBridge()->ReceiveInputEvent(aInput, &guid, &inputBlockId);
|
||||
if (result == nsEventStatus_eConsumeNoDefault) {
|
||||
return;
|
||||
}
|
||||
|
||||
WidgetWheelEvent event = aInput.ToWidgetWheelEvent(this);
|
||||
ProcessUntransformedAPZEvent(&event, guid, inputBlockId, result);
|
||||
} else {
|
||||
WidgetWheelEvent event = aInput.ToWidgetWheelEvent(this);
|
||||
|
||||
nsEventStatus status;
|
||||
DispatchEvent(&event, status);
|
||||
}
|
||||
}
|
||||
|
||||
nsEventStatus nsBaseWidget::DispatchInputEvent(WidgetInputEvent* aEvent) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mAPZC) {
|
||||
|
|
|
@ -619,6 +619,14 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference {
|
|||
*/
|
||||
void DispatchTouchInput(mozilla::MultiTouchInput& aInput);
|
||||
|
||||
/**
|
||||
* Dispatch the given PanGestureInput through APZ to Gecko (if APZ is enabled)
|
||||
* or directly to gecko (if APZ is not enabled). This function must only
|
||||
* be called from the main thread, and if APZ is enabled, that must also be
|
||||
* the APZ controller thread.
|
||||
*/
|
||||
void DispatchPanGestureInput(mozilla::PanGestureInput& aInput);
|
||||
|
||||
#if defined(XP_WIN)
|
||||
void UpdateScrollCapture() override;
|
||||
|
||||
|
|
|
@ -1211,7 +1211,15 @@ struct ParamTraits<mozilla::PanGestureInput::PanGestureType>
|
|||
mozilla::PanGestureInput::sHighestPanGestureType> {};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::PanGestureInput> {
|
||||
struct ParamTraits<mozilla::PanGestureInput::PanDeltaType>
|
||||
: public ContiguousEnumSerializerInclusive<
|
||||
mozilla::PanGestureInput::PanDeltaType,
|
||||
mozilla::PanGestureInput::PanDeltaType::PANDELTA_PAGE,
|
||||
mozilla::PanGestureInput::sHighestPanDeltaType> {};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::PanGestureInput>
|
||||
: BitfieldHelper<mozilla::PanGestureInput> {
|
||||
typedef mozilla::PanGestureInput paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam) {
|
||||
|
@ -1225,6 +1233,7 @@ struct ParamTraits<mozilla::PanGestureInput> {
|
|||
WriteParam(aMsg, aParam.mLineOrPageDeltaY);
|
||||
WriteParam(aMsg, aParam.mUserDeltaMultiplierX);
|
||||
WriteParam(aMsg, aParam.mUserDeltaMultiplierY);
|
||||
WriteParam(aMsg, aParam.mDeltaType);
|
||||
WriteParam(aMsg, aParam.mHandledByAPZ);
|
||||
WriteParam(aMsg, aParam.mFollowedByMomentum);
|
||||
WriteParam(
|
||||
|
@ -1232,6 +1241,7 @@ struct ParamTraits<mozilla::PanGestureInput> {
|
|||
aParam
|
||||
.mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection);
|
||||
WriteParam(aMsg, aParam.mOverscrollBehaviorAllowsSwipe);
|
||||
WriteParam(aMsg, aParam.mSimulateMomentum);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter,
|
||||
|
@ -1246,13 +1256,19 @@ struct ParamTraits<mozilla::PanGestureInput> {
|
|||
ReadParam(aMsg, aIter, &aResult->mLineOrPageDeltaY) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mUserDeltaMultiplierX) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mUserDeltaMultiplierY) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mHandledByAPZ) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFollowedByMomentum) &&
|
||||
ReadParam(
|
||||
aMsg, aIter,
|
||||
&aResult
|
||||
->mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mOverscrollBehaviorAllowsSwipe);
|
||||
ReadParam(aMsg, aIter, &aResult->mDeltaType) &&
|
||||
ReadBoolForBitfield(aMsg, aIter, aResult,
|
||||
¶mType::SetHandledByAPZ) &&
|
||||
ReadBoolForBitfield(aMsg, aIter, aResult,
|
||||
¶mType::SetFollowedByMomentum) &&
|
||||
ReadBoolForBitfield(
|
||||
aMsg, aIter, aResult,
|
||||
¶mType::
|
||||
SetRequiresContentResponseIfCannotScrollHorizontallyInStartDirection) &&
|
||||
ReadBoolForBitfield(aMsg, aIter, aResult,
|
||||
¶mType::SetOverscrollBehaviorAllowsSwipe) &&
|
||||
ReadBoolForBitfield(aMsg, aIter, aResult,
|
||||
¶mType::SetSimulateMomentum);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче