зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
Коммит
006d377043
|
@ -16,10 +16,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#light-theme-focus:target ~ #light-theme {
|
#light-theme-focus:target ~ #light-theme {
|
||||||
fill: #4A90E2;
|
fill: #0060DF;
|
||||||
}
|
}
|
||||||
#dark-theme-focus:target ~ #dark-theme {
|
#dark-theme-focus:target ~ #dark-theme {
|
||||||
fill: #00FF7F;
|
fill: #75BFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unfocused states */
|
/* Unfocused states */
|
||||||
|
|
До Ширина: | Высота: | Размер: 1.4 KiB После Ширина: | Высота: | Размер: 1.4 KiB |
|
@ -846,6 +846,16 @@ a.learn-more-link.webconsole-learn-more-link {
|
||||||
|
|
||||||
.webconsole-filterbar-primary .devtools-plaininput {
|
.webconsole-filterbar-primary .devtools-plaininput {
|
||||||
flex: 1 1 100%;
|
flex: 1 1 100%;
|
||||||
|
align-self: stretch;
|
||||||
|
margin-left: 1px;
|
||||||
|
padding-inline-start: 4px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.devtools-plaininput:focus {
|
||||||
|
border: 1px solid var(--blue-50);
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.webconsole-filterbar-primary .filter-checkbox {
|
.webconsole-filterbar-primary .filter-checkbox {
|
||||||
|
|
|
@ -841,10 +841,11 @@ class CssGridHighlighter extends AutoRefreshHighlighter {
|
||||||
let row = fragment.rows.tracks[rowNumber - 1];
|
let row = fragment.rows.tracks[rowNumber - 1];
|
||||||
let column = fragment.cols.tracks[columnNumber - 1];
|
let column = fragment.cols.tracks[columnNumber - 1];
|
||||||
|
|
||||||
// Check if the font size is exceeds the bounds of the containing grid cell.
|
// If the font size exceeds the bounds of the containing grid cell, size it its
|
||||||
|
// row or column dimension, whichever is smallest.
|
||||||
if (fontSize > (column.breadth * displayPixelRatio) ||
|
if (fontSize > (column.breadth * displayPixelRatio) ||
|
||||||
fontSize > (row.breadth * displayPixelRatio)) {
|
fontSize > (row.breadth * displayPixelRatio)) {
|
||||||
fontSize = (column.breadth + row.breadth) / 2;
|
fontSize = Math.min([column.breadth, row.breadth]);
|
||||||
this.ctx.font = fontSize + "px " + GRID_FONT_FAMILY;
|
this.ctx.font = fontSize + "px " + GRID_FONT_FAMILY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -804,21 +804,12 @@ Animation::CancelNoUpdate()
|
||||||
mHoldTime.SetNull();
|
mHoldTime.SetNull();
|
||||||
mStartTime.SetNull();
|
mStartTime.SetNull();
|
||||||
|
|
||||||
|
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
|
||||||
|
|
||||||
if (mTimeline) {
|
if (mTimeline) {
|
||||||
mTimeline->RemoveAnimation(this);
|
mTimeline->RemoveAnimation(this);
|
||||||
}
|
}
|
||||||
MaybeQueueCancelEvent(activeTime);
|
MaybeQueueCancelEvent(activeTime);
|
||||||
|
|
||||||
// When an animation is cancelled it no longer needs further ticks from the
|
|
||||||
// timeline. However, if we queued a cancel event and this was the last
|
|
||||||
// animation attached to the timeline, the timeline will stop observing the
|
|
||||||
// refresh driver and there may be no subsequent refresh driver tick for
|
|
||||||
// dispatching the queued event.
|
|
||||||
//
|
|
||||||
// By calling UpdateTiming *after* removing ourselves from our timeline, we
|
|
||||||
// ensure the timeline will register with the refresh driver for at least one
|
|
||||||
// more tick.
|
|
||||||
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "mozilla/AnimationEventDispatcher.h"
|
||||||
|
|
||||||
|
#include "mozilla/EventDispatcher.h"
|
||||||
|
#include "nsRefreshDriver.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(AnimationEventDispatcher)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AnimationEventDispatcher)
|
||||||
|
tmp->ClearEventQueue();
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AnimationEventDispatcher)
|
||||||
|
for (auto& info : tmp->mPendingEvents) {
|
||||||
|
ImplCycleCollectionTraverse(cb, info.mElement,
|
||||||
|
"mozilla::AnimationEventDispatcher.mPendingEvents.mElement");
|
||||||
|
ImplCycleCollectionTraverse(cb, info.mAnimation,
|
||||||
|
"mozilla::AnimationEventDispatcher.mPendingEvents.mAnimation");
|
||||||
|
}
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AnimationEventDispatcher, AddRef)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AnimationEventDispatcher, Release)
|
||||||
|
|
||||||
|
void
|
||||||
|
AnimationEventDispatcher::Disconnect()
|
||||||
|
{
|
||||||
|
if (mIsObserving) {
|
||||||
|
MOZ_ASSERT(mPresContext && mPresContext->RefreshDriver(),
|
||||||
|
"The pres context and the refresh driver should be still "
|
||||||
|
"alive if we haven't disassociated from the refresh driver");
|
||||||
|
mPresContext->RefreshDriver()->CancelPendingAnimationEvents(this);
|
||||||
|
mIsObserving = false;
|
||||||
|
}
|
||||||
|
mPresContext = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AnimationEventDispatcher::QueueEvents(nsTArray<AnimationEventInfo>&& aEvents)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mPresContext,
|
||||||
|
"The pres context should be valid");
|
||||||
|
|
||||||
|
mPendingEvents.AppendElements(Move(aEvents));
|
||||||
|
mIsSorted = false;
|
||||||
|
if (!mIsObserving) {
|
||||||
|
mPresContext->RefreshDriver()->ScheduleAnimationEventDispatch(this);
|
||||||
|
mIsObserving = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
|
|
|
@ -0,0 +1,209 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_AnimationEventDispatcher_h
|
||||||
|
#define mozilla_AnimationEventDispatcher_h
|
||||||
|
|
||||||
|
#include <algorithm> // For <std::stable_sort>
|
||||||
|
#include "mozilla/AnimationComparator.h"
|
||||||
|
#include "mozilla/Assertions.h"
|
||||||
|
#include "mozilla/ContentEvents.h"
|
||||||
|
#include "mozilla/EventDispatcher.h"
|
||||||
|
#include "mozilla/Variant.h"
|
||||||
|
#include "nsCSSProps.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
|
||||||
|
class nsPresContext;
|
||||||
|
class nsRefreshDriver;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
struct AnimationEventInfo
|
||||||
|
{
|
||||||
|
RefPtr<dom::Element> mElement;
|
||||||
|
RefPtr<dom::Animation> mAnimation;
|
||||||
|
TimeStamp mTimeStamp;
|
||||||
|
|
||||||
|
typedef Variant<InternalTransitionEvent, InternalAnimationEvent> EventVariant;
|
||||||
|
EventVariant mEvent;
|
||||||
|
|
||||||
|
// For CSS animation events
|
||||||
|
AnimationEventInfo(nsAtom* aAnimationName,
|
||||||
|
const NonOwningAnimationTarget& aTarget,
|
||||||
|
EventMessage aMessage,
|
||||||
|
double aElapsedTime,
|
||||||
|
const TimeStamp& aTimeStamp,
|
||||||
|
dom::Animation* aAnimation)
|
||||||
|
: mElement(aTarget.mElement)
|
||||||
|
, mAnimation(aAnimation)
|
||||||
|
, mTimeStamp(aTimeStamp)
|
||||||
|
, mEvent(EventVariant(InternalAnimationEvent(true, aMessage)))
|
||||||
|
{
|
||||||
|
InternalAnimationEvent& event = mEvent.as<InternalAnimationEvent>();
|
||||||
|
|
||||||
|
aAnimationName->ToString(event.mAnimationName);
|
||||||
|
// XXX Looks like nobody initialize WidgetEvent::time
|
||||||
|
event.mElapsedTime = aElapsedTime;
|
||||||
|
event.mPseudoElement =
|
||||||
|
nsCSSPseudoElements::PseudoTypeAsString(aTarget.mPseudoType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For CSS transition events
|
||||||
|
AnimationEventInfo(nsCSSPropertyID aProperty,
|
||||||
|
const NonOwningAnimationTarget& aTarget,
|
||||||
|
EventMessage aMessage,
|
||||||
|
double aElapsedTime,
|
||||||
|
const TimeStamp& aTimeStamp,
|
||||||
|
dom::Animation* aAnimation)
|
||||||
|
: mElement(aTarget.mElement)
|
||||||
|
, mAnimation(aAnimation)
|
||||||
|
, mTimeStamp(aTimeStamp)
|
||||||
|
, mEvent(EventVariant(InternalTransitionEvent(true, aMessage)))
|
||||||
|
{
|
||||||
|
InternalTransitionEvent& event = mEvent.as<InternalTransitionEvent>();
|
||||||
|
|
||||||
|
event.mPropertyName =
|
||||||
|
NS_ConvertUTF8toUTF16(nsCSSProps::GetStringValue(aProperty));
|
||||||
|
// XXX Looks like nobody initialize WidgetEvent::time
|
||||||
|
event.mElapsedTime = aElapsedTime;
|
||||||
|
event.mPseudoElement =
|
||||||
|
nsCSSPseudoElements::PseudoTypeAsString(aTarget.mPseudoType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// InternalAnimationEvent and InternalTransitionEvent don't support
|
||||||
|
// copy-construction, so we need to ourselves in order to work with nsTArray.
|
||||||
|
//
|
||||||
|
// FIXME: Drop this copy constructor and copy assignment below once
|
||||||
|
// WidgetEvent have move constructor and move assignment (bug 1433008).
|
||||||
|
AnimationEventInfo(const AnimationEventInfo& aOther) = default;
|
||||||
|
AnimationEventInfo& operator=(const AnimationEventInfo& aOther) = default;
|
||||||
|
|
||||||
|
WidgetEvent* AsWidgetEvent()
|
||||||
|
{
|
||||||
|
if (mEvent.is<InternalTransitionEvent>()) {
|
||||||
|
return &mEvent.as<InternalTransitionEvent>();
|
||||||
|
}
|
||||||
|
if (mEvent.is<InternalAnimationEvent>()) {
|
||||||
|
return &mEvent.as<InternalAnimationEvent>();
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected event type");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AnimationEventDispatcher final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit AnimationEventDispatcher(nsPresContext* aPresContext)
|
||||||
|
: mPresContext(aPresContext)
|
||||||
|
, mIsSorted(true)
|
||||||
|
, mIsObserving(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AnimationEventDispatcher)
|
||||||
|
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(AnimationEventDispatcher)
|
||||||
|
|
||||||
|
void Disconnect();
|
||||||
|
|
||||||
|
void QueueEvents(nsTArray<AnimationEventInfo>&& aEvents);
|
||||||
|
|
||||||
|
// This will call SortEvents automatically if it has not already been
|
||||||
|
// called.
|
||||||
|
void DispatchEvents()
|
||||||
|
{
|
||||||
|
mIsObserving = false;
|
||||||
|
if (!mPresContext || mPendingEvents.IsEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SortEvents();
|
||||||
|
|
||||||
|
EventArray events;
|
||||||
|
mPendingEvents.SwapElements(events);
|
||||||
|
// mIsSorted will be set to true by SortEvents above, and we leave it
|
||||||
|
// that way since mPendingEvents is now empty
|
||||||
|
for (AnimationEventInfo& info : events) {
|
||||||
|
MOZ_ASSERT(!info.AsWidgetEvent()->mFlags.mIsBeingDispatched &&
|
||||||
|
!info.AsWidgetEvent()->mFlags.mDispatchedAtLeastOnce,
|
||||||
|
"The WidgetEvent should be fresh");
|
||||||
|
EventDispatcher::Dispatch(info.mElement,
|
||||||
|
mPresContext,
|
||||||
|
info.AsWidgetEvent());
|
||||||
|
|
||||||
|
// Bail out if our mPresContext was nullified due to destroying the pres
|
||||||
|
// context.
|
||||||
|
if (!mPresContext) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearEventQueue()
|
||||||
|
{
|
||||||
|
mPendingEvents.Clear();
|
||||||
|
mIsSorted = true;
|
||||||
|
}
|
||||||
|
bool HasQueuedEvents() const { return !mPendingEvents.IsEmpty(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
#ifndef DEBUG
|
||||||
|
~AnimationEventDispatcher() = default;
|
||||||
|
#else
|
||||||
|
~AnimationEventDispatcher()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!mIsObserving,
|
||||||
|
"AnimationEventDispatcher should have disassociated from "
|
||||||
|
"nsRefreshDriver");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class AnimationEventInfoLessThan
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool operator()(const AnimationEventInfo& a, const AnimationEventInfo& b) const
|
||||||
|
{
|
||||||
|
if (a.mTimeStamp != b.mTimeStamp) {
|
||||||
|
// Null timestamps sort first
|
||||||
|
if (a.mTimeStamp.IsNull() || b.mTimeStamp.IsNull()) {
|
||||||
|
return a.mTimeStamp.IsNull();
|
||||||
|
} else {
|
||||||
|
return a.mTimeStamp < b.mTimeStamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimationPtrComparator<RefPtr<dom::Animation>> comparator;
|
||||||
|
return comparator.LessThan(a.mAnimation, b.mAnimation);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Sort all pending CSS animation/transition events by scheduled event time
|
||||||
|
// and composite order.
|
||||||
|
// https://drafts.csswg.org/web-animations/#update-animations-and-send-events
|
||||||
|
void SortEvents()
|
||||||
|
{
|
||||||
|
if (mIsSorted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Replace with mPendingEvents.StableSort when bug 1147091 is
|
||||||
|
// fixed.
|
||||||
|
std::stable_sort(mPendingEvents.begin(), mPendingEvents.end(),
|
||||||
|
AnimationEventInfoLessThan());
|
||||||
|
mIsSorted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsPresContext* mPresContext;
|
||||||
|
typedef nsTArray<AnimationEventInfo> EventArray;
|
||||||
|
EventArray mPendingEvents;
|
||||||
|
bool mIsSorted;
|
||||||
|
bool mIsObserving;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // mozilla_AnimationEventDispatcher_h
|
|
@ -24,6 +24,7 @@ EXPORTS.mozilla.dom += [
|
||||||
|
|
||||||
EXPORTS.mozilla += [
|
EXPORTS.mozilla += [
|
||||||
'AnimationComparator.h',
|
'AnimationComparator.h',
|
||||||
|
'AnimationEventDispatcher.h',
|
||||||
'AnimationPerformanceWarning.h',
|
'AnimationPerformanceWarning.h',
|
||||||
'AnimationPropertySegment.h',
|
'AnimationPropertySegment.h',
|
||||||
'AnimationTarget.h',
|
'AnimationTarget.h',
|
||||||
|
@ -46,6 +47,7 @@ UNIFIED_SOURCES += [
|
||||||
'AnimationEffectReadOnly.cpp',
|
'AnimationEffectReadOnly.cpp',
|
||||||
'AnimationEffectTiming.cpp',
|
'AnimationEffectTiming.cpp',
|
||||||
'AnimationEffectTimingReadOnly.cpp',
|
'AnimationEffectTimingReadOnly.cpp',
|
||||||
|
'AnimationEventDispatcher.cpp',
|
||||||
'AnimationPerformanceWarning.cpp',
|
'AnimationPerformanceWarning.cpp',
|
||||||
'AnimationTimeline.cpp',
|
'AnimationTimeline.cpp',
|
||||||
'AnimationUtils.cpp',
|
'AnimationUtils.cpp',
|
||||||
|
|
|
@ -1362,8 +1362,7 @@ PresShell::Destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mPresContext) {
|
if (mPresContext) {
|
||||||
mPresContext->AnimationManager()->ClearEventQueue();
|
rd->CancelPendingAnimationEvents(mPresContext->AnimationEventDispatcher());
|
||||||
mPresContext->TransitionManager()->ClearEventQueue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Revoke any pending events. We need to do this and cancel pending reflows
|
// Revoke any pending events. We need to do this and cancel pending reflows
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#include "gfxPlatform.h"
|
#include "gfxPlatform.h"
|
||||||
#include "nsCSSRules.h"
|
#include "nsCSSRules.h"
|
||||||
#include "nsFontFaceLoader.h"
|
#include "nsFontFaceLoader.h"
|
||||||
|
#include "mozilla/AnimationEventDispatcher.h"
|
||||||
#include "mozilla/EffectCompositor.h"
|
#include "mozilla/EffectCompositor.h"
|
||||||
#include "mozilla/EventListenerManager.h"
|
#include "mozilla/EventListenerManager.h"
|
||||||
#include "prenv.h"
|
#include "prenv.h"
|
||||||
|
@ -442,8 +443,7 @@ nsPresContext::LastRelease()
|
||||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsPresContext)
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsPresContext)
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsPresContext)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsPresContext)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnimationManager);
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnimationEventDispatcher);
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransitionManager);
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument);
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument);
|
||||||
// NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mDeviceContext); // not xpcom
|
// NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mDeviceContext); // not xpcom
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEffectCompositor);
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEffectCompositor);
|
||||||
|
@ -457,8 +457,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsPresContext)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsPresContext)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsPresContext)
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnimationManager);
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnimationEventDispatcher);
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTransitionManager);
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument);
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument);
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDeviceContext); // worth bothering?
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDeviceContext); // worth bothering?
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEffectCompositor);
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEffectCompositor);
|
||||||
|
@ -888,6 +887,7 @@ nsPresContext::Init(nsDeviceContext* aDeviceContext)
|
||||||
|
|
||||||
mEventManager = new mozilla::EventStateManager();
|
mEventManager = new mozilla::EventStateManager();
|
||||||
|
|
||||||
|
mAnimationEventDispatcher = new mozilla::AnimationEventDispatcher(this);
|
||||||
mEffectCompositor = new mozilla::EffectCompositor(this);
|
mEffectCompositor = new mozilla::EffectCompositor(this);
|
||||||
mTransitionManager = new nsTransitionManager(this);
|
mTransitionManager = new nsTransitionManager(this);
|
||||||
mAnimationManager = new nsAnimationManager(this);
|
mAnimationManager = new nsAnimationManager(this);
|
||||||
|
@ -1066,6 +1066,10 @@ nsPresContext::DetachShell()
|
||||||
|
|
||||||
mShell = nullptr;
|
mShell = nullptr;
|
||||||
|
|
||||||
|
if (mAnimationEventDispatcher) {
|
||||||
|
mAnimationEventDispatcher->Disconnect();
|
||||||
|
mAnimationEventDispatcher = nullptr;
|
||||||
|
}
|
||||||
if (mEffectCompositor) {
|
if (mEffectCompositor) {
|
||||||
mEffectCompositor->Disconnect();
|
mEffectCompositor->Disconnect();
|
||||||
mEffectCompositor = nullptr;
|
mEffectCompositor = nullptr;
|
||||||
|
|
|
@ -73,6 +73,7 @@ class nsDeviceContext;
|
||||||
class gfxMissingFontRecorder;
|
class gfxMissingFontRecorder;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
class AnimationEventDispatcher;
|
||||||
class EffectCompositor;
|
class EffectCompositor;
|
||||||
class Encoding;
|
class Encoding;
|
||||||
class EventStateManager;
|
class EventStateManager;
|
||||||
|
@ -236,6 +237,11 @@ public:
|
||||||
nsCSSFrameConstructor* FrameConstructor()
|
nsCSSFrameConstructor* FrameConstructor()
|
||||||
{ return PresShell()->FrameConstructor(); }
|
{ return PresShell()->FrameConstructor(); }
|
||||||
|
|
||||||
|
mozilla::AnimationEventDispatcher* AnimationEventDispatcher()
|
||||||
|
{
|
||||||
|
return mAnimationEventDispatcher;
|
||||||
|
}
|
||||||
|
|
||||||
mozilla::EffectCompositor* EffectCompositor() { return mEffectCompositor; }
|
mozilla::EffectCompositor* EffectCompositor() { return mEffectCompositor; }
|
||||||
nsTransitionManager* TransitionManager() { return mTransitionManager; }
|
nsTransitionManager* TransitionManager() { return mTransitionManager; }
|
||||||
nsAnimationManager* AnimationManager() { return mAnimationManager; }
|
nsAnimationManager* AnimationManager() { return mAnimationManager; }
|
||||||
|
@ -1296,6 +1302,7 @@ protected:
|
||||||
// from gfx back to layout.
|
// from gfx back to layout.
|
||||||
RefPtr<mozilla::EventStateManager> mEventManager;
|
RefPtr<mozilla::EventStateManager> mEventManager;
|
||||||
RefPtr<nsRefreshDriver> mRefreshDriver;
|
RefPtr<nsRefreshDriver> mRefreshDriver;
|
||||||
|
RefPtr<mozilla::AnimationEventDispatcher> mAnimationEventDispatcher;
|
||||||
RefPtr<mozilla::EffectCompositor> mEffectCompositor;
|
RefPtr<mozilla::EffectCompositor> mEffectCompositor;
|
||||||
RefPtr<nsTransitionManager> mTransitionManager;
|
RefPtr<nsTransitionManager> mTransitionManager;
|
||||||
RefPtr<nsAnimationManager> mAnimationManager;
|
RefPtr<nsAnimationManager> mAnimationManager;
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "WinUtils.h"
|
#include "WinUtils.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "mozilla/AnimationEventDispatcher.h"
|
||||||
#include "mozilla/ArrayUtils.h"
|
#include "mozilla/ArrayUtils.h"
|
||||||
#include "mozilla/AutoRestore.h"
|
#include "mozilla/AutoRestore.h"
|
||||||
#include "mozilla/IntegerRange.h"
|
#include "mozilla/IntegerRange.h"
|
||||||
|
@ -1428,6 +1429,7 @@ nsRefreshDriver::ObserverCount() const
|
||||||
// changes can trigger transitions which fire events when they complete, and
|
// changes can trigger transitions which fire events when they complete, and
|
||||||
// layout changes can affect media queries on child documents, triggering
|
// layout changes can affect media queries on child documents, triggering
|
||||||
// style changes, etc.
|
// style changes, etc.
|
||||||
|
sum += mAnimationEventFlushObservers.Length();
|
||||||
sum += mResizeEventFlushObservers.Length();
|
sum += mResizeEventFlushObservers.Length();
|
||||||
sum += mStyleFlushObservers.Length();
|
sum += mStyleFlushObservers.Length();
|
||||||
sum += mLayoutFlushObservers.Length();
|
sum += mLayoutFlushObservers.Length();
|
||||||
|
@ -1439,14 +1441,36 @@ nsRefreshDriver::ObserverCount() const
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
bool
|
||||||
nsRefreshDriver::ImageRequestCount() const
|
nsRefreshDriver::HasObservers() const
|
||||||
{
|
{
|
||||||
uint32_t count = 0;
|
for (uint32_t i = 0; i < ArrayLength(mObservers); ++i) {
|
||||||
for (auto iter = mStartTable.ConstIter(); !iter.Done(); iter.Next()) {
|
if (!mObservers[i].IsEmpty()) {
|
||||||
count += iter.UserData()->mEntries.Count();
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return count + mRequests.Count();
|
|
||||||
|
return mViewManagerFlushIsPending ||
|
||||||
|
!mStyleFlushObservers.IsEmpty() ||
|
||||||
|
!mLayoutFlushObservers.IsEmpty() ||
|
||||||
|
!mAnimationEventFlushObservers.IsEmpty() ||
|
||||||
|
!mResizeEventFlushObservers.IsEmpty() ||
|
||||||
|
!mPendingEvents.IsEmpty() ||
|
||||||
|
!mFrameRequestCallbackDocs.IsEmpty() ||
|
||||||
|
!mThrottledFrameRequestCallbackDocs.IsEmpty() ||
|
||||||
|
!mEarlyRunners.IsEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
nsRefreshDriver::HasImageRequests() const
|
||||||
|
{
|
||||||
|
for (auto iter = mStartTable.ConstIter(); !iter.Done(); iter.Next()) {
|
||||||
|
if (!iter.UserData()->mEntries.IsEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return !mRequests.IsEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefreshDriver::ObserverArray&
|
nsRefreshDriver::ObserverArray&
|
||||||
|
@ -1578,15 +1602,6 @@ nsRefreshDriver::DispatchPendingEvents()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
CollectDocuments(nsIDocument* aDocument, void* aDocArray)
|
|
||||||
{
|
|
||||||
static_cast<AutoTArray<nsCOMPtr<nsIDocument>, 32>*>(aDocArray)->
|
|
||||||
AppendElement(aDocument);
|
|
||||||
aDocument->EnumerateSubDocuments(CollectDocuments, aDocArray);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nsRefreshDriver::UpdateIntersectionObservations()
|
nsRefreshDriver::UpdateIntersectionObservations()
|
||||||
{
|
{
|
||||||
|
@ -1616,31 +1631,19 @@ nsRefreshDriver::DispatchAnimationEvents()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoTArray<nsCOMPtr<nsIDocument>, 32> documents;
|
// Hold all AnimationEventDispatcher in mAnimationEventFlushObservers as
|
||||||
CollectDocuments(mPresContext->Document(), &documents);
|
// a RefPtr<> array since each AnimationEventDispatcher might be destroyed
|
||||||
|
// during processing the previous dispatcher.
|
||||||
|
size_t len = mAnimationEventFlushObservers.Length();
|
||||||
|
AutoTArray<RefPtr<AnimationEventDispatcher>, 16> dispatchers;
|
||||||
|
RefPtr<AnimationEventDispatcher>* elems = dispatchers.AppendElements(len);
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
elems[i] = mAnimationEventFlushObservers[i];
|
||||||
|
}
|
||||||
|
mAnimationEventFlushObservers.Clear();
|
||||||
|
|
||||||
for (uint32_t i = 0; i < documents.Length(); ++i) {
|
for (auto& dispatcher : dispatchers) {
|
||||||
nsIDocument* doc = documents[i];
|
dispatcher->DispatchEvents();
|
||||||
nsIPresShell* shell = doc->GetShell();
|
|
||||||
if (!shell) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
RefPtr<nsPresContext> context = shell->GetPresContext();
|
|
||||||
if (!context || context->RefreshDriver() != this) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
context->TransitionManager()->SortEvents();
|
|
||||||
context->AnimationManager()->SortEvents();
|
|
||||||
|
|
||||||
// Dispatch transition events first since transitions conceptually sit
|
|
||||||
// below animations in terms of compositing order.
|
|
||||||
context->TransitionManager()->DispatchEvents();
|
|
||||||
// Check that the presshell has not been destroyed
|
|
||||||
if (context->GetPresShell()) {
|
|
||||||
context->AnimationManager()->DispatchEvents();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1818,7 +1821,8 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
||||||
mWarningThreshold = 1;
|
mWarningThreshold = 1;
|
||||||
|
|
||||||
nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
|
nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
|
||||||
if (!presShell || (ObserverCount() == 0 && ImageRequestCount() == 0 && mScrollEvents.Length() == 0)) {
|
if (!presShell ||
|
||||||
|
(!HasObservers() && !HasImageRequests() && mScrollEvents.IsEmpty())) {
|
||||||
// Things are being destroyed, or we no longer have any observers.
|
// Things are being destroyed, or we no longer have any observers.
|
||||||
// We don't want to stop the timer when observers are initially
|
// We don't want to stop the timer when observers are initially
|
||||||
// removed, because sometimes observers can be added and removed
|
// removed, because sometimes observers can be added and removed
|
||||||
|
@ -2140,7 +2144,7 @@ nsRefreshDriver::Thaw()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mFreezeCount == 0) {
|
if (mFreezeCount == 0) {
|
||||||
if (ObserverCount() || ImageRequestCount()) {
|
if (HasObservers() || HasImageRequests()) {
|
||||||
// FIXME: This isn't quite right, since our EnsureTimerStarted call
|
// FIXME: This isn't quite right, since our EnsureTimerStarted call
|
||||||
// updates our mMostRecentRefresh, but the DoRefresh call won't run
|
// updates our mMostRecentRefresh, but the DoRefresh call won't run
|
||||||
// and notify our observers until we get back to the event loop.
|
// and notify our observers until we get back to the event loop.
|
||||||
|
@ -2165,7 +2169,7 @@ nsRefreshDriver::FinishedWaitingForTransaction()
|
||||||
mWaitingForTransaction = false;
|
mWaitingForTransaction = false;
|
||||||
if (mSkippedPaints &&
|
if (mSkippedPaints &&
|
||||||
!IsInRefresh() &&
|
!IsInRefresh() &&
|
||||||
(ObserverCount() || ImageRequestCount())) {
|
(HasObservers() || HasImageRequests())) {
|
||||||
AUTO_PROFILER_TRACING("Paint", "RefreshDriverTick");
|
AUTO_PROFILER_TRACING("Paint", "RefreshDriverTick");
|
||||||
DoRefresh();
|
DoRefresh();
|
||||||
}
|
}
|
||||||
|
@ -2398,6 +2402,14 @@ nsRefreshDriver::CancelPendingEvents(nsIDocument* aDocument)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsRefreshDriver::CancelPendingAnimationEvents(AnimationEventDispatcher* aDispatcher)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aDispatcher);
|
||||||
|
aDispatcher->ClearEventQueue();
|
||||||
|
mAnimationEventFlushObservers.RemoveElement(aDispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
/* static */ TimeStamp
|
/* static */ TimeStamp
|
||||||
nsRefreshDriver::GetIdleDeadlineHint(TimeStamp aDefault)
|
nsRefreshDriver::GetIdleDeadlineHint(TimeStamp aDefault)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "nsTObserverArray.h"
|
#include "nsTObserverArray.h"
|
||||||
#include "nsClassHashtable.h"
|
#include "nsClassHashtable.h"
|
||||||
#include "nsHashKeys.h"
|
#include "nsHashKeys.h"
|
||||||
|
#include "mozilla/AnimationEventDispatcher.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/layers/TransactionIdAllocator.h"
|
#include "mozilla/layers/TransactionIdAllocator.h"
|
||||||
|
@ -243,6 +244,24 @@ public:
|
||||||
*/
|
*/
|
||||||
void CancelPendingEvents(nsIDocument* aDocument);
|
void CancelPendingEvents(nsIDocument* aDocument);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queue new animation events to dispatch in next tick.
|
||||||
|
*/
|
||||||
|
void ScheduleAnimationEventDispatch(
|
||||||
|
mozilla::AnimationEventDispatcher* aDispatcher)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(!mAnimationEventFlushObservers.Contains(aDispatcher),
|
||||||
|
"Double-adding animation event flush observer");
|
||||||
|
mAnimationEventFlushObservers.AppendElement(aDispatcher);
|
||||||
|
EnsureTimerStarted();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel all pending animation events associated with |aDispatcher|.
|
||||||
|
*/
|
||||||
|
void CancelPendingAnimationEvents(
|
||||||
|
mozilla::AnimationEventDispatcher* aDispatcher);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedule a frame visibility update "soon", subject to the heuristics and
|
* Schedule a frame visibility update "soon", subject to the heuristics and
|
||||||
* throttling we apply to visibility updates.
|
* throttling we apply to visibility updates.
|
||||||
|
@ -397,8 +416,9 @@ private:
|
||||||
void EnsureTimerStarted(EnsureTimerStartedFlags aFlags = eNone);
|
void EnsureTimerStarted(EnsureTimerStartedFlags aFlags = eNone);
|
||||||
void StopTimer();
|
void StopTimer();
|
||||||
|
|
||||||
|
bool HasObservers() const;
|
||||||
uint32_t ObserverCount() const;
|
uint32_t ObserverCount() const;
|
||||||
uint32_t ImageRequestCount() const;
|
bool HasImageRequests() const;
|
||||||
ObserverArray& ArrayFor(mozilla::FlushType aFlushType);
|
ObserverArray& ArrayFor(mozilla::FlushType aFlushType);
|
||||||
// Trigger a refresh immediately, if haven't been disconnected or frozen.
|
// Trigger a refresh immediately, if haven't been disconnected or frozen.
|
||||||
void DoRefresh();
|
void DoRefresh();
|
||||||
|
@ -495,6 +515,8 @@ private:
|
||||||
nsTArray<nsIDocument*> mThrottledFrameRequestCallbackDocs;
|
nsTArray<nsIDocument*> mThrottledFrameRequestCallbackDocs;
|
||||||
nsTObserverArray<nsAPostRefreshObserver*> mPostRefreshObservers;
|
nsTObserverArray<nsAPostRefreshObserver*> mPostRefreshObservers;
|
||||||
nsTArray<PendingEvent> mPendingEvents;
|
nsTArray<PendingEvent> mPendingEvents;
|
||||||
|
AutoTArray<mozilla::AnimationEventDispatcher*, 16>
|
||||||
|
mAnimationEventFlushObservers;
|
||||||
|
|
||||||
void BeginRefreshingImages(RequestTable& aEntries,
|
void BeginRefreshingImages(RequestTable& aEntries,
|
||||||
mozilla::TimeStamp aDesired);
|
mozilla::TimeStamp aDesired);
|
||||||
|
|
|
@ -116,23 +116,6 @@ AnimationCollection<AnimationType>::GetOrCreateAnimationCollection(
|
||||||
return collection;
|
return collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class AnimationType>
|
|
||||||
/* static */ nsString
|
|
||||||
AnimationCollection<AnimationType>::PseudoTypeAsString(
|
|
||||||
CSSPseudoElementType aPseudoType)
|
|
||||||
{
|
|
||||||
switch (aPseudoType) {
|
|
||||||
case CSSPseudoElementType::before:
|
|
||||||
return NS_LITERAL_STRING("::before");
|
|
||||||
case CSSPseudoElementType::after:
|
|
||||||
return NS_LITERAL_STRING("::after");
|
|
||||||
default:
|
|
||||||
MOZ_ASSERT(aPseudoType == CSSPseudoElementType::NotPseudo,
|
|
||||||
"Unexpected pseudo type");
|
|
||||||
return EmptyString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class AnimationType>
|
template <class AnimationType>
|
||||||
void
|
void
|
||||||
AnimationCollection<AnimationType>::UpdateCheckGeneration(
|
AnimationCollection<AnimationType>::UpdateCheckGeneration(
|
||||||
|
|
|
@ -88,8 +88,6 @@ public:
|
||||||
CSSPseudoElementType aPseudoType,
|
CSSPseudoElementType aPseudoType,
|
||||||
bool* aCreatedCollection);
|
bool* aCreatedCollection);
|
||||||
|
|
||||||
static nsString PseudoTypeAsString(CSSPseudoElementType aPseudoType);
|
|
||||||
|
|
||||||
dom::Element *mElement;
|
dom::Element *mElement;
|
||||||
|
|
||||||
// the atom we use in mElement's prop table (must be a static atom,
|
// the atom we use in mElement's prop table (must be a static atom,
|
||||||
|
|
|
@ -7,33 +7,25 @@
|
||||||
#ifndef mozilla_css_AnimationCommon_h
|
#ifndef mozilla_css_AnimationCommon_h
|
||||||
#define mozilla_css_AnimationCommon_h
|
#define mozilla_css_AnimationCommon_h
|
||||||
|
|
||||||
#include <algorithm> // For <std::stable_sort>
|
|
||||||
#include "mozilla/AnimationCollection.h"
|
#include "mozilla/AnimationCollection.h"
|
||||||
#include "mozilla/AnimationComparator.h"
|
|
||||||
#include "mozilla/EventDispatcher.h"
|
|
||||||
#include "mozilla/LinkedList.h"
|
#include "mozilla/LinkedList.h"
|
||||||
#include "mozilla/MemoryReporting.h"
|
|
||||||
#include "mozilla/dom/Animation.h"
|
#include "mozilla/dom/Animation.h"
|
||||||
#include "mozilla/AnimationTarget.h"
|
|
||||||
#include "mozilla/Attributes.h" // For MOZ_NON_OWNING_REF
|
#include "mozilla/Attributes.h" // For MOZ_NON_OWNING_REF
|
||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
#include "mozilla/TimingParams.h"
|
#include "mozilla/TimingParams.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsCSSPseudoElements.h"
|
|
||||||
#include "nsCycleCollectionParticipant.h"
|
|
||||||
|
|
||||||
class nsIFrame;
|
class nsIFrame;
|
||||||
class nsPresContext;
|
class nsPresContext;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
enum class CSSPseudoElementType : uint8_t;
|
enum class CSSPseudoElementType : uint8_t;
|
||||||
template <class EventInfo> class DelayedEventDispatcher;
|
|
||||||
|
|
||||||
namespace dom {
|
namespace dom {
|
||||||
class Element;
|
class Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class AnimationType, class AnimationEventType>
|
template <class AnimationType>
|
||||||
class CommonAnimationManager {
|
class CommonAnimationManager {
|
||||||
public:
|
public:
|
||||||
explicit CommonAnimationManager(nsPresContext *aPresContext)
|
explicit CommonAnimationManager(nsPresContext *aPresContext)
|
||||||
|
@ -75,18 +67,6 @@ public:
|
||||||
collection->Destroy();
|
collection->Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add pending events.
|
|
||||||
*/
|
|
||||||
void QueueEvents(nsTArray<AnimationEventType>&& aEvents)
|
|
||||||
{
|
|
||||||
mEventDispatcher.QueueEvents(
|
|
||||||
mozilla::Forward<nsTArray<AnimationEventType>>(aEvents));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SortEvents() { mEventDispatcher.SortEvents(); }
|
|
||||||
void ClearEventQueue() { mEventDispatcher.ClearEventQueue(); }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~CommonAnimationManager()
|
virtual ~CommonAnimationManager()
|
||||||
{
|
{
|
||||||
|
@ -107,8 +87,6 @@ protected:
|
||||||
|
|
||||||
LinkedList<AnimationCollection<AnimationType>> mElementCollections;
|
LinkedList<AnimationCollection<AnimationType>> mElementCollections;
|
||||||
nsPresContext *mPresContext; // weak (non-null from ctor to Disconnect)
|
nsPresContext *mPresContext; // weak (non-null from ctor to Disconnect)
|
||||||
|
|
||||||
mozilla::DelayedEventDispatcher<AnimationEventType> mEventDispatcher;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -179,122 +157,6 @@ private:
|
||||||
NonOwningAnimationTarget mTarget;
|
NonOwningAnimationTarget mTarget;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class EventInfo>
|
|
||||||
class DelayedEventDispatcher
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DelayedEventDispatcher() : mIsSorted(true) { }
|
|
||||||
|
|
||||||
void QueueEvents(nsTArray<EventInfo>&& aEvents)
|
|
||||||
{
|
|
||||||
mPendingEvents.AppendElements(Forward<nsTArray<EventInfo>>(aEvents));
|
|
||||||
mIsSorted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is exposed as a separate method so that when we are dispatching
|
|
||||||
// *both* transition events and animation events we can sort both lists
|
|
||||||
// once using the current state of the document before beginning any
|
|
||||||
// dispatch.
|
|
||||||
void SortEvents()
|
|
||||||
{
|
|
||||||
if (mIsSorted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Replace with mPendingEvents.StableSort when bug 1147091 is
|
|
||||||
// fixed.
|
|
||||||
std::stable_sort(mPendingEvents.begin(), mPendingEvents.end(),
|
|
||||||
EventInfoLessThan());
|
|
||||||
mIsSorted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Takes a reference to the owning manager's pres context so it can
|
|
||||||
// detect if the pres context is destroyed while dispatching one of
|
|
||||||
// the events.
|
|
||||||
//
|
|
||||||
// This will call SortEvents automatically if it has not already been
|
|
||||||
// called.
|
|
||||||
void DispatchEvents(nsPresContext* const & aPresContext)
|
|
||||||
{
|
|
||||||
if (!aPresContext || mPendingEvents.IsEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SortEvents();
|
|
||||||
|
|
||||||
EventArray events;
|
|
||||||
mPendingEvents.SwapElements(events);
|
|
||||||
// mIsSorted will be set to true by SortEvents above, and we leave it
|
|
||||||
// that way since mPendingEvents is now empty
|
|
||||||
for (EventInfo& info : events) {
|
|
||||||
EventDispatcher::Dispatch(info.mElement, aPresContext, &info.mEvent);
|
|
||||||
|
|
||||||
if (!aPresContext) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearEventQueue()
|
|
||||||
{
|
|
||||||
mPendingEvents.Clear();
|
|
||||||
mIsSorted = true;
|
|
||||||
}
|
|
||||||
bool HasQueuedEvents() const { return !mPendingEvents.IsEmpty(); }
|
|
||||||
|
|
||||||
// Methods for supporting cycle-collection
|
|
||||||
void Traverse(nsCycleCollectionTraversalCallback* aCallback,
|
|
||||||
const char* aName)
|
|
||||||
{
|
|
||||||
for (EventInfo& info : mPendingEvents) {
|
|
||||||
ImplCycleCollectionTraverse(*aCallback, info.mElement, aName);
|
|
||||||
ImplCycleCollectionTraverse(*aCallback, info.mAnimation, aName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void Unlink() { ClearEventQueue(); }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
class EventInfoLessThan
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool operator()(const EventInfo& a, const EventInfo& b) const
|
|
||||||
{
|
|
||||||
if (a.mTimeStamp != b.mTimeStamp) {
|
|
||||||
// Null timestamps sort first
|
|
||||||
if (a.mTimeStamp.IsNull() || b.mTimeStamp.IsNull()) {
|
|
||||||
return a.mTimeStamp.IsNull();
|
|
||||||
} else {
|
|
||||||
return a.mTimeStamp < b.mTimeStamp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimationPtrComparator<RefPtr<dom::Animation>> comparator;
|
|
||||||
return comparator.LessThan(a.mAnimation, b.mAnimation);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef nsTArray<EventInfo> EventArray;
|
|
||||||
EventArray mPendingEvents;
|
|
||||||
bool mIsSorted;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class EventInfo>
|
|
||||||
inline void
|
|
||||||
ImplCycleCollectionUnlink(DelayedEventDispatcher<EventInfo>& aField)
|
|
||||||
{
|
|
||||||
aField.Unlink();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class EventInfo>
|
|
||||||
inline void
|
|
||||||
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
|
|
||||||
DelayedEventDispatcher<EventInfo>& aField,
|
|
||||||
const char* aName,
|
|
||||||
uint32_t aFlags = 0)
|
|
||||||
{
|
|
||||||
aField.Traverse(&aCallback, aName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the TransitionPhase or AnimationPhase to use when the animation
|
// Return the TransitionPhase or AnimationPhase to use when the animation
|
||||||
// doesn't have a target effect.
|
// doesn't have a target effect.
|
||||||
template <typename PhaseType>
|
template <typename PhaseType>
|
||||||
|
@ -303,6 +165,12 @@ PhaseType GetAnimationPhaseWithoutEffect(const dom::Animation& aAnimation)
|
||||||
MOZ_ASSERT(!aAnimation.GetEffect(),
|
MOZ_ASSERT(!aAnimation.GetEffect(),
|
||||||
"Should only be called when we do not have an effect");
|
"Should only be called when we do not have an effect");
|
||||||
|
|
||||||
|
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
|
||||||
|
// GetTickCount().
|
||||||
|
#ifdef GetCurrentTime
|
||||||
|
#undef GetCurrentTime
|
||||||
|
#endif
|
||||||
|
|
||||||
Nullable<TimeDuration> currentTime = aAnimation.GetCurrentTime();
|
Nullable<TimeDuration> currentTime = aAnimation.GetCurrentTime();
|
||||||
if (currentTime.IsNull()) {
|
if (currentTime.IsNull()) {
|
||||||
return PhaseType::Idle;
|
return PhaseType::Idle;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "nsTransitionManager.h"
|
#include "nsTransitionManager.h"
|
||||||
#include "mozilla/dom/CSSAnimationBinding.h"
|
#include "mozilla/dom/CSSAnimationBinding.h"
|
||||||
|
|
||||||
|
#include "mozilla/AnimationEventDispatcher.h"
|
||||||
#include "mozilla/AnimationTarget.h"
|
#include "mozilla/AnimationTarget.h"
|
||||||
#include "mozilla/EffectCompositor.h"
|
#include "mozilla/EffectCompositor.h"
|
||||||
#include "mozilla/EffectSet.h"
|
#include "mozilla/EffectSet.h"
|
||||||
|
@ -242,9 +243,9 @@ CSSAnimation::QueueEvents(const StickyTimeDuration& aActiveTime)
|
||||||
if (aMessage == eAnimationCancel) {
|
if (aMessage == eAnimationCancel) {
|
||||||
elapsedTime = nsRFPService::ReduceTimePrecisionAsSecs(elapsedTime);
|
elapsedTime = nsRFPService::ReduceTimePrecisionAsSecs(elapsedTime);
|
||||||
}
|
}
|
||||||
events.AppendElement(AnimationEventInfo(mOwningElement.Target(),
|
events.AppendElement(AnimationEventInfo(mAnimationName,
|
||||||
|
mOwningElement.Target(),
|
||||||
aMessage,
|
aMessage,
|
||||||
mAnimationName,
|
|
||||||
elapsedTime,
|
elapsedTime,
|
||||||
aTimeStamp,
|
aTimeStamp,
|
||||||
this));
|
this));
|
||||||
|
@ -299,7 +300,7 @@ CSSAnimation::QueueEvents(const StickyTimeDuration& aActiveTime)
|
||||||
mPreviousIteration = currentIteration;
|
mPreviousIteration = currentIteration;
|
||||||
|
|
||||||
if (!events.IsEmpty()) {
|
if (!events.IsEmpty()) {
|
||||||
presContext->AnimationManager()->QueueEvents(Move(events));
|
presContext->AnimationEventDispatcher()->QueueEvents(Move(events));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,11 +318,6 @@ CSSAnimation::UpdateTiming(SeekFlag aSeekFlag, SyncNotifyFlag aSyncNotifyFlag)
|
||||||
|
|
||||||
////////////////////////// nsAnimationManager ////////////////////////////
|
////////////////////////// nsAnimationManager ////////////////////////////
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION(nsAnimationManager, mEventDispatcher)
|
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsAnimationManager, AddRef)
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsAnimationManager, Release)
|
|
||||||
|
|
||||||
// Find the matching animation by |aName| in the old list
|
// Find the matching animation by |aName| in the old list
|
||||||
// of animations and remove the matched animation from the list.
|
// of animations and remove the matched animation from the list.
|
||||||
static already_AddRefed<CSSAnimation>
|
static already_AddRefed<CSSAnimation>
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "mozilla/Keyframe.h"
|
#include "mozilla/Keyframe.h"
|
||||||
#include "mozilla/MemoryReporting.h"
|
#include "mozilla/MemoryReporting.h"
|
||||||
#include "mozilla/TimeStamp.h"
|
#include "mozilla/TimeStamp.h"
|
||||||
|
#include "nsISupportsImpl.h"
|
||||||
|
|
||||||
class nsIGlobalObject;
|
class nsIGlobalObject;
|
||||||
class nsStyleContext;
|
class nsStyleContext;
|
||||||
|
@ -34,43 +35,6 @@ class ServoStyleContext;
|
||||||
enum class CSSPseudoElementType : uint8_t;
|
enum class CSSPseudoElementType : uint8_t;
|
||||||
struct NonOwningAnimationTarget;
|
struct NonOwningAnimationTarget;
|
||||||
|
|
||||||
struct AnimationEventInfo {
|
|
||||||
RefPtr<dom::Element> mElement;
|
|
||||||
RefPtr<dom::Animation> mAnimation;
|
|
||||||
InternalAnimationEvent mEvent;
|
|
||||||
TimeStamp mTimeStamp;
|
|
||||||
|
|
||||||
AnimationEventInfo(const NonOwningAnimationTarget& aTarget,
|
|
||||||
EventMessage aMessage,
|
|
||||||
nsAtom* aAnimationName,
|
|
||||||
double aElapsedTime,
|
|
||||||
const TimeStamp& aTimeStamp,
|
|
||||||
dom::Animation* aAnimation)
|
|
||||||
: mElement(aTarget.mElement)
|
|
||||||
, mAnimation(aAnimation)
|
|
||||||
, mEvent(true, aMessage)
|
|
||||||
, mTimeStamp(aTimeStamp)
|
|
||||||
{
|
|
||||||
// XXX Looks like nobody initialize WidgetEvent::time
|
|
||||||
aAnimationName->ToString(mEvent.mAnimationName);
|
|
||||||
mEvent.mElapsedTime = aElapsedTime;
|
|
||||||
mEvent.mPseudoElement =
|
|
||||||
AnimationCollection<dom::CSSAnimation>::PseudoTypeAsString(
|
|
||||||
aTarget.mPseudoType);
|
|
||||||
}
|
|
||||||
|
|
||||||
// InternalAnimationEvent doesn't support copy-construction, so we need
|
|
||||||
// to ourselves in order to work with nsTArray
|
|
||||||
AnimationEventInfo(const AnimationEventInfo& aOther)
|
|
||||||
: mElement(aOther.mElement)
|
|
||||||
, mAnimation(aOther.mAnimation)
|
|
||||||
, mEvent(true, aOther.mEvent.mMessage)
|
|
||||||
, mTimeStamp(aOther.mTimeStamp)
|
|
||||||
{
|
|
||||||
mEvent.AssignAnimationEventData(aOther.mEvent, false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
class CSSAnimation final : public Animation
|
class CSSAnimation final : public Animation
|
||||||
|
@ -311,18 +275,15 @@ struct AnimationTypeTraits<dom::CSSAnimation>
|
||||||
} /* namespace mozilla */
|
} /* namespace mozilla */
|
||||||
|
|
||||||
class nsAnimationManager final
|
class nsAnimationManager final
|
||||||
: public mozilla::CommonAnimationManager<mozilla::dom::CSSAnimation,
|
: public mozilla::CommonAnimationManager<mozilla::dom::CSSAnimation>
|
||||||
mozilla::AnimationEventInfo>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit nsAnimationManager(nsPresContext *aPresContext)
|
explicit nsAnimationManager(nsPresContext *aPresContext)
|
||||||
: mozilla::CommonAnimationManager<mozilla::dom::CSSAnimation,
|
: mozilla::CommonAnimationManager<mozilla::dom::CSSAnimation>(aPresContext)
|
||||||
mozilla::AnimationEventInfo>(aPresContext)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsAnimationManager)
|
NS_INLINE_DECL_REFCOUNTING(nsAnimationManager)
|
||||||
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsAnimationManager)
|
|
||||||
|
|
||||||
typedef mozilla::AnimationCollection<mozilla::dom::CSSAnimation>
|
typedef mozilla::AnimationCollection<mozilla::dom::CSSAnimation>
|
||||||
CSSAnimationCollection;
|
CSSAnimationCollection;
|
||||||
|
@ -349,19 +310,6 @@ public:
|
||||||
mozilla::CSSPseudoElementType aPseudoType,
|
mozilla::CSSPseudoElementType aPseudoType,
|
||||||
const mozilla::ServoStyleContext* aComputedValues);
|
const mozilla::ServoStyleContext* aComputedValues);
|
||||||
|
|
||||||
/**
|
|
||||||
* Dispatch any pending events. We accumulate animationend and
|
|
||||||
* animationiteration events only during refresh driver notifications
|
|
||||||
* (and dispatch them at the end of such notifications), but we
|
|
||||||
* accumulate animationstart events at other points when style
|
|
||||||
* contexts are created.
|
|
||||||
*/
|
|
||||||
void DispatchEvents()
|
|
||||||
{
|
|
||||||
RefPtr<nsAnimationManager> kungFuDeathGrip(this);
|
|
||||||
mEventDispatcher.DispatchEvents(mPresContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Utility function to walk through |aIter| to find the Keyframe with
|
// Utility function to walk through |aIter| to find the Keyframe with
|
||||||
// matching offset and timing function but stopping as soon as the offset
|
// matching offset and timing function but stopping as soon as the offset
|
||||||
// differs from |aOffset| (i.e. it assumes a sorted iterator).
|
// differs from |aOffset| (i.e. it assumes a sorted iterator).
|
||||||
|
|
|
@ -157,3 +157,19 @@ nsCSSPseudoElements::PseudoElementSupportsUserActionState(const Type aType)
|
||||||
return PseudoElementHasFlags(aType,
|
return PseudoElementHasFlags(aType,
|
||||||
CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE);
|
CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ nsString
|
||||||
|
nsCSSPseudoElements::PseudoTypeAsString(Type aPseudoType)
|
||||||
|
{
|
||||||
|
switch (aPseudoType) {
|
||||||
|
case CSSPseudoElementType::before:
|
||||||
|
return NS_LITERAL_STRING("::before");
|
||||||
|
case CSSPseudoElementType::after:
|
||||||
|
return NS_LITERAL_STRING("::after");
|
||||||
|
default:
|
||||||
|
MOZ_ASSERT(aPseudoType == CSSPseudoElementType::NotPseudo,
|
||||||
|
"Unexpected pseudo type");
|
||||||
|
return EmptyString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,6 +141,8 @@ public:
|
||||||
(aEnabledState & EnabledState::eInUASheets);
|
(aEnabledState & EnabledState::eInUASheets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static nsString PseudoTypeAsString(Type aPseudoType);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Does the given pseudo-element have all of the flags given?
|
// Does the given pseudo-element have all of the flags given?
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "nsRuleProcessorData.h"
|
#include "nsRuleProcessorData.h"
|
||||||
#include "nsRuleWalker.h"
|
#include "nsRuleWalker.h"
|
||||||
#include "nsCSSPropertyIDSet.h"
|
#include "nsCSSPropertyIDSet.h"
|
||||||
|
#include "mozilla/AnimationEventDispatcher.h"
|
||||||
#include "mozilla/EffectCompositor.h"
|
#include "mozilla/EffectCompositor.h"
|
||||||
#include "mozilla/EffectSet.h"
|
#include "mozilla/EffectSet.h"
|
||||||
#include "mozilla/EventDispatcher.h"
|
#include "mozilla/EventDispatcher.h"
|
||||||
|
@ -249,7 +250,7 @@ CSSTransition::QueueEvents(const StickyTimeDuration& aActiveTime)
|
||||||
currentPhase = TransitionPhase::Pending;
|
currentPhase = TransitionPhase::Pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoTArray<TransitionEventInfo, 3> events;
|
AutoTArray<AnimationEventInfo, 3> events;
|
||||||
|
|
||||||
auto appendTransitionEvent = [&](EventMessage aMessage,
|
auto appendTransitionEvent = [&](EventMessage aMessage,
|
||||||
const StickyTimeDuration& aElapsedTime,
|
const StickyTimeDuration& aElapsedTime,
|
||||||
|
@ -258,12 +259,12 @@ CSSTransition::QueueEvents(const StickyTimeDuration& aActiveTime)
|
||||||
if (aMessage == eTransitionCancel) {
|
if (aMessage == eTransitionCancel) {
|
||||||
elapsedTime = nsRFPService::ReduceTimePrecisionAsSecs(elapsedTime);
|
elapsedTime = nsRFPService::ReduceTimePrecisionAsSecs(elapsedTime);
|
||||||
}
|
}
|
||||||
events.AppendElement(TransitionEventInfo(mOwningElement.Target(),
|
events.AppendElement(AnimationEventInfo(TransitionProperty(),
|
||||||
aMessage,
|
mOwningElement.Target(),
|
||||||
TransitionProperty(),
|
aMessage,
|
||||||
elapsedTime,
|
elapsedTime,
|
||||||
aTimeStamp,
|
aTimeStamp,
|
||||||
this));
|
this));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle cancel events first
|
// Handle cancel events first
|
||||||
|
@ -336,7 +337,7 @@ CSSTransition::QueueEvents(const StickyTimeDuration& aActiveTime)
|
||||||
mPreviousTransitionPhase = currentPhase;
|
mPreviousTransitionPhase = currentPhase;
|
||||||
|
|
||||||
if (!events.IsEmpty()) {
|
if (!events.IsEmpty()) {
|
||||||
presContext->TransitionManager()->QueueEvents(Move(events));
|
presContext->AnimationEventDispatcher()->QueueEvents(Move(events));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,11 +423,6 @@ CSSTransition::SetEffectFromStyle(dom::AnimationEffectReadOnly* aEffect)
|
||||||
|
|
||||||
////////////////////////// nsTransitionManager ////////////////////////////
|
////////////////////////// nsTransitionManager ////////////////////////////
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION(nsTransitionManager, mEventDispatcher)
|
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTransitionManager, AddRef)
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsTransitionManager, Release)
|
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
ExtractNonDiscreteComputedValue(nsCSSPropertyID aProperty,
|
ExtractNonDiscreteComputedValue(nsCSSPropertyID aProperty,
|
||||||
GeckoStyleContext* aStyleContext,
|
GeckoStyleContext* aStyleContext,
|
||||||
|
|
|
@ -10,13 +10,11 @@
|
||||||
#define nsTransitionManager_h_
|
#define nsTransitionManager_h_
|
||||||
|
|
||||||
#include "mozilla/ComputedTiming.h"
|
#include "mozilla/ComputedTiming.h"
|
||||||
#include "mozilla/ContentEvents.h"
|
|
||||||
#include "mozilla/EffectCompositor.h" // For EffectCompositor::CascadeLevel
|
#include "mozilla/EffectCompositor.h" // For EffectCompositor::CascadeLevel
|
||||||
#include "mozilla/MemoryReporting.h"
|
|
||||||
#include "mozilla/dom/Animation.h"
|
#include "mozilla/dom/Animation.h"
|
||||||
#include "mozilla/dom/KeyframeEffectReadOnly.h"
|
#include "mozilla/dom/KeyframeEffectReadOnly.h"
|
||||||
#include "AnimationCommon.h"
|
#include "AnimationCommon.h"
|
||||||
#include "nsCSSProps.h"
|
#include "nsISupportsImpl.h"
|
||||||
|
|
||||||
class nsIGlobalObject;
|
class nsIGlobalObject;
|
||||||
class nsStyleContext;
|
class nsStyleContext;
|
||||||
|
@ -301,60 +299,19 @@ struct AnimationTypeTraits<dom::CSSTransition>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TransitionEventInfo {
|
|
||||||
RefPtr<dom::Element> mElement;
|
|
||||||
RefPtr<dom::Animation> mAnimation;
|
|
||||||
InternalTransitionEvent mEvent;
|
|
||||||
TimeStamp mTimeStamp;
|
|
||||||
|
|
||||||
TransitionEventInfo(const NonOwningAnimationTarget& aTarget,
|
|
||||||
EventMessage aMessage,
|
|
||||||
nsCSSPropertyID aProperty,
|
|
||||||
double aElapsedTime,
|
|
||||||
const TimeStamp& aTimeStamp,
|
|
||||||
dom::Animation* aAnimation)
|
|
||||||
: mElement(aTarget.mElement)
|
|
||||||
, mAnimation(aAnimation)
|
|
||||||
, mEvent(true, aMessage)
|
|
||||||
, mTimeStamp(aTimeStamp)
|
|
||||||
{
|
|
||||||
// XXX Looks like nobody initialize WidgetEvent::time
|
|
||||||
mEvent.mPropertyName =
|
|
||||||
NS_ConvertUTF8toUTF16(nsCSSProps::GetStringValue(aProperty));
|
|
||||||
mEvent.mElapsedTime = aElapsedTime;
|
|
||||||
mEvent.mPseudoElement =
|
|
||||||
AnimationCollection<dom::CSSTransition>::PseudoTypeAsString(
|
|
||||||
aTarget.mPseudoType);
|
|
||||||
}
|
|
||||||
|
|
||||||
// InternalTransitionEvent doesn't support copy-construction, so we need
|
|
||||||
// to ourselves in order to work with nsTArray
|
|
||||||
TransitionEventInfo(const TransitionEventInfo& aOther)
|
|
||||||
: mElement(aOther.mElement)
|
|
||||||
, mAnimation(aOther.mAnimation)
|
|
||||||
, mEvent(aOther.mEvent)
|
|
||||||
, mTimeStamp(aOther.mTimeStamp)
|
|
||||||
{
|
|
||||||
mEvent.AssignTransitionEventData(aOther.mEvent, false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
class nsTransitionManager final
|
class nsTransitionManager final
|
||||||
: public mozilla::CommonAnimationManager<mozilla::dom::CSSTransition,
|
: public mozilla::CommonAnimationManager<mozilla::dom::CSSTransition>
|
||||||
mozilla::TransitionEventInfo>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit nsTransitionManager(nsPresContext *aPresContext)
|
explicit nsTransitionManager(nsPresContext *aPresContext)
|
||||||
: mozilla::CommonAnimationManager<mozilla::dom::CSSTransition,
|
: mozilla::CommonAnimationManager<mozilla::dom::CSSTransition>(aPresContext)
|
||||||
mozilla::TransitionEventInfo>(aPresContext)
|
|
||||||
, mInAnimationOnlyStyleUpdate(false)
|
, mInAnimationOnlyStyleUpdate(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsTransitionManager)
|
NS_INLINE_DECL_REFCOUNTING(nsTransitionManager)
|
||||||
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsTransitionManager)
|
|
||||||
|
|
||||||
typedef mozilla::AnimationCollection<mozilla::dom::CSSTransition>
|
typedef mozilla::AnimationCollection<mozilla::dom::CSSTransition>
|
||||||
CSSTransitionCollection;
|
CSSTransitionCollection;
|
||||||
|
@ -406,12 +363,6 @@ public:
|
||||||
return mInAnimationOnlyStyleUpdate;
|
return mInAnimationOnlyStyleUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DispatchEvents()
|
|
||||||
{
|
|
||||||
RefPtr<nsTransitionManager> kungFuDeathGrip(this);
|
|
||||||
mEventDispatcher.DispatchEvents(mPresContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~nsTransitionManager() {}
|
virtual ~nsTransitionManager() {}
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,9 @@ use ipc_channel::ipc::IpcSender;
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use opaque_node::OpaqueNodeMethods;
|
use opaque_node::OpaqueNodeMethods;
|
||||||
use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC};
|
use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC};
|
||||||
use script_layout_interface::rpc::{MarginStyleResponse, NodeGeometryResponse};
|
use script_layout_interface::rpc::{NodeGeometryResponse, NodeScrollRootIdResponse};
|
||||||
use script_layout_interface::rpc::{NodeOverflowResponse, NodeScrollRootIdResponse};
|
use script_layout_interface::rpc::{OffsetParentResponse, ResolvedStyleResponse, StyleResponse};
|
||||||
use script_layout_interface::rpc::{OffsetParentResponse, ResolvedStyleResponse, TextIndexResponse};
|
use script_layout_interface::rpc::TextIndexResponse;
|
||||||
use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
||||||
use script_traits::LayoutMsg as ConstellationMsg;
|
use script_traits::LayoutMsg as ConstellationMsg;
|
||||||
use script_traits::UntrustedNodeAddress;
|
use script_traits::UntrustedNodeAddress;
|
||||||
|
@ -59,9 +59,6 @@ pub struct LayoutThreadData {
|
||||||
/// A queued response for the scroll root id for a given node.
|
/// A queued response for the scroll root id for a given node.
|
||||||
pub scroll_root_id_response: Option<ClipId>,
|
pub scroll_root_id_response: Option<ClipId>,
|
||||||
|
|
||||||
/// A pair of overflow property in x and y
|
|
||||||
pub overflow_response: NodeOverflowResponse,
|
|
||||||
|
|
||||||
/// A queued response for the scroll {top, left, width, height} of a node in pixels.
|
/// A queued response for the scroll {top, left, width, height} of a node in pixels.
|
||||||
pub scroll_area_response: Rect<i32>,
|
pub scroll_area_response: Rect<i32>,
|
||||||
|
|
||||||
|
@ -71,8 +68,8 @@ pub struct LayoutThreadData {
|
||||||
/// A queued response for the offset parent/rect of a node.
|
/// A queued response for the offset parent/rect of a node.
|
||||||
pub offset_parent_response: OffsetParentResponse,
|
pub offset_parent_response: OffsetParentResponse,
|
||||||
|
|
||||||
/// A queued response for the offset parent/rect of a node.
|
/// A queued response for the style of a node.
|
||||||
pub margin_style_response: MarginStyleResponse,
|
pub style_response: StyleResponse,
|
||||||
|
|
||||||
/// Scroll offsets of scrolling regions.
|
/// Scroll offsets of scrolling regions.
|
||||||
pub scroll_offsets: ScrollOffsetMap,
|
pub scroll_offsets: ScrollOffsetMap,
|
||||||
|
@ -128,10 +125,6 @@ impl LayoutRPC for LayoutRPCImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_overflow(&self) -> NodeOverflowResponse {
|
|
||||||
NodeOverflowResponse(self.0.lock().unwrap().overflow_response.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn node_scroll_area(&self) -> NodeGeometryResponse {
|
fn node_scroll_area(&self) -> NodeGeometryResponse {
|
||||||
NodeGeometryResponse {
|
NodeGeometryResponse {
|
||||||
client_rect: self.0.lock().unwrap().scroll_area_response
|
client_rect: self.0.lock().unwrap().scroll_area_response
|
||||||
|
@ -157,10 +150,10 @@ impl LayoutRPC for LayoutRPCImpl {
|
||||||
rw_data.offset_parent_response.clone()
|
rw_data.offset_parent_response.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn margin_style(&self) -> MarginStyleResponse {
|
fn style(&self) -> StyleResponse {
|
||||||
let &LayoutRPCImpl(ref rw_data) = self;
|
let &LayoutRPCImpl(ref rw_data) = self;
|
||||||
let rw_data = rw_data.lock().unwrap();
|
let rw_data = rw_data.lock().unwrap();
|
||||||
rw_data.margin_style_response.clone()
|
rw_data.style_response.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text_index(&self) -> TextIndexResponse {
|
fn text_index(&self) -> TextIndexResponse {
|
||||||
|
@ -863,24 +856,10 @@ pub fn process_offset_parent_query<N: LayoutNode>(requested_node: N, layout_root
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_node_overflow_request<N: LayoutNode>(requested_node: N) -> NodeOverflowResponse {
|
pub fn process_style_query<N: LayoutNode>(requested_node: N)
|
||||||
let layout_node = requested_node.to_threadsafe();
|
-> StyleResponse {
|
||||||
let style = &*layout_node.as_element().unwrap().resolved_style();
|
let element = requested_node.as_element().unwrap();
|
||||||
let style_box = style.get_box();
|
let data = element.borrow_data();
|
||||||
|
|
||||||
NodeOverflowResponse(Some(Point2D::new(style_box.overflow_x, style_box.overflow_y)))
|
StyleResponse(data.map(|d| d.styles.primary().clone()))
|
||||||
}
|
|
||||||
|
|
||||||
pub fn process_margin_style_query<N: LayoutNode>(requested_node: N)
|
|
||||||
-> MarginStyleResponse {
|
|
||||||
let layout_node = requested_node.to_threadsafe();
|
|
||||||
let style = &*layout_node.as_element().unwrap().resolved_style();
|
|
||||||
let margin = style.get_margin();
|
|
||||||
|
|
||||||
MarginStyleResponse {
|
|
||||||
top: margin.margin_top,
|
|
||||||
right: margin.margin_right,
|
|
||||||
bottom: margin.margin_bottom,
|
|
||||||
left: margin.margin_left,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,9 +75,9 @@ use layout::incremental::{LayoutDamageComputation, RelayoutMode, SpecialRestyleD
|
||||||
use layout::layout_debug;
|
use layout::layout_debug;
|
||||||
use layout::parallel;
|
use layout::parallel;
|
||||||
use layout::query::{LayoutRPCImpl, LayoutThreadData, process_content_box_request, process_content_boxes_request};
|
use layout::query::{LayoutRPCImpl, LayoutThreadData, process_content_box_request, process_content_boxes_request};
|
||||||
use layout::query::{process_margin_style_query, process_node_overflow_request, process_resolved_style_request};
|
|
||||||
use layout::query::{process_node_geometry_request, process_node_scroll_area_request};
|
use layout::query::{process_node_geometry_request, process_node_scroll_area_request};
|
||||||
use layout::query::{process_node_scroll_root_id_request, process_offset_parent_query};
|
use layout::query::{process_node_scroll_root_id_request, process_offset_parent_query, process_resolved_style_request};
|
||||||
|
use layout::query::process_style_query;
|
||||||
use layout::sequential;
|
use layout::sequential;
|
||||||
use layout::traversal::{ComputeStackingRelativePositions, PreorderFlowTraversal, RecalcStyleAndConstructFlows};
|
use layout::traversal::{ComputeStackingRelativePositions, PreorderFlowTraversal, RecalcStyleAndConstructFlows};
|
||||||
use layout::wrapper::LayoutNodeLayoutData;
|
use layout::wrapper::LayoutNodeLayoutData;
|
||||||
|
@ -94,7 +94,7 @@ use profile_traits::time::{self, TimerMetadata, profile};
|
||||||
use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType};
|
use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType};
|
||||||
use script_layout_interface::message::{Msg, NewLayoutThreadInfo, NodesFromPointQueryType, Reflow};
|
use script_layout_interface::message::{Msg, NewLayoutThreadInfo, NodesFromPointQueryType, Reflow};
|
||||||
use script_layout_interface::message::{ReflowComplete, ReflowGoal, ScriptReflow};
|
use script_layout_interface::message::{ReflowComplete, ReflowGoal, ScriptReflow};
|
||||||
use script_layout_interface::rpc::{LayoutRPC, MarginStyleResponse, NodeOverflowResponse, OffsetParentResponse};
|
use script_layout_interface::rpc::{LayoutRPC, StyleResponse, OffsetParentResponse};
|
||||||
use script_layout_interface::rpc::TextIndexResponse;
|
use script_layout_interface::rpc::TextIndexResponse;
|
||||||
use script_layout_interface::wrapper_traits::LayoutNode;
|
use script_layout_interface::wrapper_traits::LayoutNode;
|
||||||
use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
|
use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
|
||||||
|
@ -519,10 +519,9 @@ impl LayoutThread {
|
||||||
client_rect_response: Rect::zero(),
|
client_rect_response: Rect::zero(),
|
||||||
scroll_root_id_response: None,
|
scroll_root_id_response: None,
|
||||||
scroll_area_response: Rect::zero(),
|
scroll_area_response: Rect::zero(),
|
||||||
overflow_response: NodeOverflowResponse(None),
|
|
||||||
resolved_style_response: String::new(),
|
resolved_style_response: String::new(),
|
||||||
offset_parent_response: OffsetParentResponse::empty(),
|
offset_parent_response: OffsetParentResponse::empty(),
|
||||||
margin_style_response: MarginStyleResponse::empty(),
|
style_response: StyleResponse(None),
|
||||||
scroll_offsets: HashMap::new(),
|
scroll_offsets: HashMap::new(),
|
||||||
text_index_response: TextIndexResponse(None),
|
text_index_response: TextIndexResponse(None),
|
||||||
nodes_from_point_response: vec![],
|
nodes_from_point_response: vec![],
|
||||||
|
@ -1092,9 +1091,6 @@ impl LayoutThread {
|
||||||
ReflowGoal::NodeScrollGeometryQuery(_) => {
|
ReflowGoal::NodeScrollGeometryQuery(_) => {
|
||||||
rw_data.scroll_area_response = Rect::zero();
|
rw_data.scroll_area_response = Rect::zero();
|
||||||
},
|
},
|
||||||
ReflowGoal::NodeOverflowQuery(_) => {
|
|
||||||
rw_data.overflow_response = NodeOverflowResponse(None);
|
|
||||||
},
|
|
||||||
ReflowGoal::NodeScrollRootIdQuery(_) => {
|
ReflowGoal::NodeScrollRootIdQuery(_) => {
|
||||||
rw_data.scroll_root_id_response = None;
|
rw_data.scroll_root_id_response = None;
|
||||||
},
|
},
|
||||||
|
@ -1104,8 +1100,8 @@ impl LayoutThread {
|
||||||
ReflowGoal::OffsetParentQuery(_) => {
|
ReflowGoal::OffsetParentQuery(_) => {
|
||||||
rw_data.offset_parent_response = OffsetParentResponse::empty();
|
rw_data.offset_parent_response = OffsetParentResponse::empty();
|
||||||
},
|
},
|
||||||
ReflowGoal::MarginStyleQuery(_) => {
|
ReflowGoal::StyleQuery(_) => {
|
||||||
rw_data.margin_style_response = MarginStyleResponse::empty();
|
rw_data.style_response = StyleResponse(None);
|
||||||
},
|
},
|
||||||
ReflowGoal::TextIndexQuery(..) => {
|
ReflowGoal::TextIndexQuery(..) => {
|
||||||
rw_data.text_index_response = TextIndexResponse(None);
|
rw_data.text_index_response = TextIndexResponse(None);
|
||||||
|
@ -1379,10 +1375,6 @@ impl LayoutThread {
|
||||||
let node = unsafe { ServoLayoutNode::new(&node) };
|
let node = unsafe { ServoLayoutNode::new(&node) };
|
||||||
rw_data.scroll_area_response = process_node_scroll_area_request(node, root_flow);
|
rw_data.scroll_area_response = process_node_scroll_area_request(node, root_flow);
|
||||||
},
|
},
|
||||||
ReflowGoal::NodeOverflowQuery(node) => {
|
|
||||||
let node = unsafe { ServoLayoutNode::new(&node) };
|
|
||||||
rw_data.overflow_response = process_node_overflow_request(node);
|
|
||||||
},
|
|
||||||
ReflowGoal::NodeScrollRootIdQuery(node) => {
|
ReflowGoal::NodeScrollRootIdQuery(node) => {
|
||||||
let node = unsafe { ServoLayoutNode::new(&node) };
|
let node = unsafe { ServoLayoutNode::new(&node) };
|
||||||
rw_data.scroll_root_id_response = Some(process_node_scroll_root_id_request(self.id,
|
rw_data.scroll_root_id_response = Some(process_node_scroll_root_id_request(self.id,
|
||||||
|
@ -1401,9 +1393,9 @@ impl LayoutThread {
|
||||||
let node = unsafe { ServoLayoutNode::new(&node) };
|
let node = unsafe { ServoLayoutNode::new(&node) };
|
||||||
rw_data.offset_parent_response = process_offset_parent_query(node, root_flow);
|
rw_data.offset_parent_response = process_offset_parent_query(node, root_flow);
|
||||||
},
|
},
|
||||||
ReflowGoal::MarginStyleQuery(node) => {
|
ReflowGoal::StyleQuery(node) => {
|
||||||
let node = unsafe { ServoLayoutNode::new(&node) };
|
let node = unsafe { ServoLayoutNode::new(&node) };
|
||||||
rw_data.margin_style_response = process_margin_style_query(node);
|
rw_data.style_response = process_style_query(node);
|
||||||
},
|
},
|
||||||
ReflowGoal::NodesFromPointQuery(client_point, ref reflow_goal) => {
|
ReflowGoal::NodesFromPointQuery(client_point, ref reflow_goal) => {
|
||||||
let mut flags = match reflow_goal {
|
let mut flags = match reflow_goal {
|
||||||
|
|
|
@ -154,12 +154,13 @@ pub fn handle_get_layout(documents: &Documents,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn determine_auto_margins(window: &Window, node: &Node) -> AutoMargins {
|
fn determine_auto_margins(window: &Window, node: &Node) -> AutoMargins {
|
||||||
let margin = window.margin_style_query(node.to_trusted_node_address());
|
let style = window.style_query(node.to_trusted_node_address()).unwrap();
|
||||||
|
let margin = style.get_margin();
|
||||||
AutoMargins {
|
AutoMargins {
|
||||||
top: margin.top == margin_top::computed_value::T::Auto,
|
top: margin.margin_top == margin_top::computed_value::T::Auto,
|
||||||
right: margin.right == margin_right::computed_value::T::Auto,
|
right: margin.margin_right == margin_right::computed_value::T::Auto,
|
||||||
bottom: margin.bottom == margin_bottom::computed_value::T::Auto,
|
bottom: margin.margin_bottom == margin_bottom::computed_value::T::Auto,
|
||||||
left: margin.left == margin_left::computed_value::T::Auto,
|
left: margin.margin_left == margin_left::computed_value::T::Auto,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,8 @@ use style::context::QuirksMode;
|
||||||
use style::dom_apis;
|
use style::dom_apis;
|
||||||
use style::element_state::ElementState;
|
use style::element_state::ElementState;
|
||||||
use style::invalidation::element::restyle_hints::RestyleHint;
|
use style::invalidation::element::restyle_hints::RestyleHint;
|
||||||
use style::properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, parse_style_attribute};
|
use style::properties::{ComputedValues, Importance, PropertyDeclaration};
|
||||||
|
use style::properties::{PropertyDeclarationBlock, parse_style_attribute};
|
||||||
use style::properties::longhands::{self, background_image, border_spacing, font_family, font_size};
|
use style::properties::longhands::{self, background_image, border_spacing, font_family, font_size};
|
||||||
use style::properties::longhands::{overflow_x, overflow_y};
|
use style::properties::longhands::{overflow_x, overflow_y};
|
||||||
use style::rule_tree::CascadeLevel;
|
use style::rule_tree::CascadeLevel;
|
||||||
|
@ -347,28 +348,30 @@ impl Element {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// style will be `None` for elements in a `display: none` subtree. otherwise, the element has a
|
||||||
|
/// layout box iff it doesn't have `display: none`.
|
||||||
|
fn style(&self) -> Option<Arc<ComputedValues>> {
|
||||||
|
window_from_node(self).style_query(
|
||||||
|
self.upcast::<Node>().to_trusted_node_address()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// https://drafts.csswg.org/cssom-view/#css-layout-box
|
// https://drafts.csswg.org/cssom-view/#css-layout-box
|
||||||
//
|
|
||||||
// We'll have no content box if there's no fragment for the node, and we use
|
|
||||||
// bounding_content_box, for simplicity, to detect this (rather than making a more specific
|
|
||||||
// query to the layout thread).
|
|
||||||
fn has_css_layout_box(&self) -> bool {
|
fn has_css_layout_box(&self) -> bool {
|
||||||
self.upcast::<Node>().bounding_content_box().is_some()
|
self.style()
|
||||||
|
.map_or(false, |s| !s.get_box().clone_display().is_none())
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.csswg.org/cssom-view/#potentially-scrollable
|
// https://drafts.csswg.org/cssom-view/#potentially-scrollable
|
||||||
fn potentially_scrollable(&self) -> bool {
|
fn potentially_scrollable(&self) -> bool {
|
||||||
self.has_css_layout_box() &&
|
self.has_css_layout_box() && !self.has_any_visible_overflow()
|
||||||
!self.overflow_x_is_visible() &&
|
|
||||||
!self.overflow_y_is_visible()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.csswg.org/cssom-view/#scrolling-box
|
// https://drafts.csswg.org/cssom-view/#scrolling-box
|
||||||
fn has_scrolling_box(&self) -> bool {
|
fn has_scrolling_box(&self) -> bool {
|
||||||
// TODO: scrolling mechanism, such as scrollbar (We don't have scrollbar yet)
|
// TODO: scrolling mechanism, such as scrollbar (We don't have scrollbar yet)
|
||||||
// self.has_scrolling_mechanism()
|
// self.has_scrolling_mechanism()
|
||||||
self.overflow_x_is_hidden() ||
|
self.has_any_hidden_overflow()
|
||||||
self.overflow_y_is_hidden()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_overflow(&self) -> bool {
|
fn has_overflow(&self) -> bool {
|
||||||
|
@ -376,32 +379,29 @@ impl Element {
|
||||||
self.ScrollWidth() > self.ClientWidth()
|
self.ScrollWidth() > self.ClientWidth()
|
||||||
}
|
}
|
||||||
|
|
||||||
// used value of overflow-x is "visible"
|
// TODO: Once #19183 is closed (overflow-x/y types moved out of mako), then we could implement
|
||||||
fn overflow_x_is_visible(&self) -> bool {
|
// a more generic `fn has_some_overflow(&self, overflow: Overflow)` rather than have
|
||||||
let window = window_from_node(self);
|
// these two `has_any_{visible,hidden}_overflow` methods which are very structurally
|
||||||
let overflow_pair = window.overflow_query(self.upcast::<Node>().to_trusted_node_address());
|
// similar.
|
||||||
overflow_pair.x == overflow_x::computed_value::T::Visible
|
|
||||||
|
/// Computed value of overflow-x or overflow-y is "visible"
|
||||||
|
fn has_any_visible_overflow(&self) -> bool {
|
||||||
|
self.style().map_or(false, |s| {
|
||||||
|
let box_ = s.get_box();
|
||||||
|
|
||||||
|
box_.clone_overflow_x() == overflow_x::computed_value::T::Visible ||
|
||||||
|
box_.clone_overflow_y() == overflow_y::computed_value::T::Visible
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// used value of overflow-y is "visible"
|
/// Computed value of overflow-x or overflow-y is "hidden"
|
||||||
fn overflow_y_is_visible(&self) -> bool {
|
fn has_any_hidden_overflow(&self) -> bool {
|
||||||
let window = window_from_node(self);
|
self.style().map_or(false, |s| {
|
||||||
let overflow_pair = window.overflow_query(self.upcast::<Node>().to_trusted_node_address());
|
let box_ = s.get_box();
|
||||||
overflow_pair.y == overflow_y::computed_value::T::Visible
|
|
||||||
}
|
|
||||||
|
|
||||||
// used value of overflow-x is "hidden"
|
box_.clone_overflow_x() == overflow_x::computed_value::T::Hidden ||
|
||||||
fn overflow_x_is_hidden(&self) -> bool {
|
box_.clone_overflow_y() == overflow_y::computed_value::T::Hidden
|
||||||
let window = window_from_node(self);
|
})
|
||||||
let overflow_pair = window.overflow_query(self.upcast::<Node>().to_trusted_node_address());
|
|
||||||
overflow_pair.x == overflow_x::computed_value::T::Hidden
|
|
||||||
}
|
|
||||||
|
|
||||||
// used value of overflow-y is "hidden"
|
|
||||||
fn overflow_y_is_hidden(&self) -> bool {
|
|
||||||
let window = window_from_node(self);
|
|
||||||
let overflow_pair = window.overflow_query(self.upcast::<Node>().to_trusted_node_address());
|
|
||||||
overflow_pair.y == overflow_y::computed_value::T::Hidden
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,8 +72,7 @@ use script_layout_interface::{TrustedNodeAddress, PendingImageState};
|
||||||
use script_layout_interface::message::{Msg, Reflow, ReflowGoal, ScriptReflow};
|
use script_layout_interface::message::{Msg, Reflow, ReflowGoal, ScriptReflow};
|
||||||
use script_layout_interface::reporter::CSSErrorReporter;
|
use script_layout_interface::reporter::CSSErrorReporter;
|
||||||
use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC};
|
use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC};
|
||||||
use script_layout_interface::rpc::{MarginStyleResponse, NodeScrollRootIdResponse};
|
use script_layout_interface::rpc::{NodeScrollRootIdResponse, ResolvedStyleResponse, TextIndexResponse};
|
||||||
use script_layout_interface::rpc::{ResolvedStyleResponse, TextIndexResponse};
|
|
||||||
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, ScriptThreadEventCategory, Runtime};
|
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, ScriptThreadEventCategory, Runtime};
|
||||||
use script_thread::{ImageCacheMsg, MainThreadScriptChan, MainThreadScriptMsg};
|
use script_thread::{ImageCacheMsg, MainThreadScriptChan, MainThreadScriptMsg};
|
||||||
use script_thread::{ScriptThread, SendableMainThreadScriptChan};
|
use script_thread::{ScriptThread, SendableMainThreadScriptChan};
|
||||||
|
@ -82,6 +81,7 @@ use script_traits::{ScriptToConstellationChan, ScriptMsg, ScrollState, TimerEven
|
||||||
use script_traits::{TimerSchedulerMsg, UntrustedNodeAddress, WindowSizeData, WindowSizeType};
|
use script_traits::{TimerSchedulerMsg, UntrustedNodeAddress, WindowSizeData, WindowSizeType};
|
||||||
use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
|
use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
|
||||||
use selectors::attr::CaseSensitivity;
|
use selectors::attr::CaseSensitivity;
|
||||||
|
use servo_arc;
|
||||||
use servo_config::opts;
|
use servo_config::opts;
|
||||||
use servo_config::prefs::PREFS;
|
use servo_config::prefs::PREFS;
|
||||||
use servo_geometry::{f32_rect_to_au_rect, MaxRect};
|
use servo_geometry::{f32_rect_to_au_rect, MaxRect};
|
||||||
|
@ -102,8 +102,7 @@ use std::sync::mpsc::{Sender, channel};
|
||||||
use std::sync::mpsc::TryRecvError::{Disconnected, Empty};
|
use std::sync::mpsc::TryRecvError::{Disconnected, Empty};
|
||||||
use style::media_queries;
|
use style::media_queries;
|
||||||
use style::parser::ParserContext as CssParserContext;
|
use style::parser::ParserContext as CssParserContext;
|
||||||
use style::properties::PropertyId;
|
use style::properties::{ComputedValues, PropertyId};
|
||||||
use style::properties::longhands::overflow_x;
|
|
||||||
use style::selector_parser::PseudoElement;
|
use style::selector_parser::PseudoElement;
|
||||||
use style::str::HTML_SPACE_CHARACTERS;
|
use style::str::HTML_SPACE_CHARACTERS;
|
||||||
use style::stylesheets::CssRuleType;
|
use style::stylesheets::CssRuleType;
|
||||||
|
@ -1403,16 +1402,6 @@ impl Window {
|
||||||
self.layout_rpc.node_scroll_area().client_rect
|
self.layout_rpc.node_scroll_area().client_rect
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn overflow_query(&self,
|
|
||||||
node: TrustedNodeAddress) -> Point2D<overflow_x::computed_value::T> {
|
|
||||||
// NB: This is only called if the document is fully active, and the only
|
|
||||||
// reason to bail out from a query is if there's no viewport, so this
|
|
||||||
// *must* issue a reflow.
|
|
||||||
assert!(self.reflow(ReflowGoal::NodeOverflowQuery(node), ReflowReason::Query));
|
|
||||||
|
|
||||||
self.layout_rpc.node_overflow().0.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn scroll_offset_query(&self, node: &Node) -> Vector2D<f32> {
|
pub fn scroll_offset_query(&self, node: &Node) -> Vector2D<f32> {
|
||||||
if let Some(scroll_offset) = self.scroll_offsets
|
if let Some(scroll_offset) = self.scroll_offsets
|
||||||
.borrow()
|
.borrow()
|
||||||
|
@ -1477,11 +1466,11 @@ impl Window {
|
||||||
(element, response.rect)
|
(element, response.rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn margin_style_query(&self, node: TrustedNodeAddress) -> MarginStyleResponse {
|
pub fn style_query(&self, node: TrustedNodeAddress) -> Option<servo_arc::Arc<ComputedValues>> {
|
||||||
if !self.reflow(ReflowGoal::MarginStyleQuery(node), ReflowReason::Query) {
|
if !self.reflow(ReflowGoal::StyleQuery(node), ReflowReason::Query) {
|
||||||
return MarginStyleResponse::empty();
|
return None
|
||||||
}
|
}
|
||||||
self.layout_rpc.margin_style()
|
self.layout_rpc.style().0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn text_index_query(
|
pub fn text_index_query(
|
||||||
|
@ -1898,12 +1887,11 @@ fn debug_reflow_events(id: PipelineId, reflow_goal: &ReflowGoal, reason: &Reflow
|
||||||
ReflowGoal::ContentBoxesQuery(_n) => "\tContentBoxesQuery",
|
ReflowGoal::ContentBoxesQuery(_n) => "\tContentBoxesQuery",
|
||||||
ReflowGoal::NodesFromPointQuery(..) => "\tNodesFromPointQuery",
|
ReflowGoal::NodesFromPointQuery(..) => "\tNodesFromPointQuery",
|
||||||
ReflowGoal::NodeGeometryQuery(_n) => "\tNodeGeometryQuery",
|
ReflowGoal::NodeGeometryQuery(_n) => "\tNodeGeometryQuery",
|
||||||
ReflowGoal::NodeOverflowQuery(_n) => "\tNodeOverFlowQuery",
|
|
||||||
ReflowGoal::NodeScrollGeometryQuery(_n) => "\tNodeScrollGeometryQuery",
|
ReflowGoal::NodeScrollGeometryQuery(_n) => "\tNodeScrollGeometryQuery",
|
||||||
ReflowGoal::NodeScrollRootIdQuery(_n) => "\tNodeScrollRootIdQuery",
|
ReflowGoal::NodeScrollRootIdQuery(_n) => "\tNodeScrollRootIdQuery",
|
||||||
ReflowGoal::ResolvedStyleQuery(_, _, _) => "\tResolvedStyleQuery",
|
ReflowGoal::ResolvedStyleQuery(_, _, _) => "\tResolvedStyleQuery",
|
||||||
ReflowGoal::OffsetParentQuery(_n) => "\tOffsetParentQuery",
|
ReflowGoal::OffsetParentQuery(_n) => "\tOffsetParentQuery",
|
||||||
ReflowGoal::MarginStyleQuery(_n) => "\tMarginStyleQuery",
|
ReflowGoal::StyleQuery(_n) => "\tStyleQuery",
|
||||||
ReflowGoal::TextIndexQuery(..) => "\tTextIndexQuery",
|
ReflowGoal::TextIndexQuery(..) => "\tTextIndexQuery",
|
||||||
ReflowGoal::TickAnimations => "\tTickAnimations",
|
ReflowGoal::TickAnimations => "\tTickAnimations",
|
||||||
});
|
});
|
||||||
|
|
|
@ -113,13 +113,12 @@ pub enum ReflowGoal {
|
||||||
TickAnimations,
|
TickAnimations,
|
||||||
ContentBoxQuery(TrustedNodeAddress),
|
ContentBoxQuery(TrustedNodeAddress),
|
||||||
ContentBoxesQuery(TrustedNodeAddress),
|
ContentBoxesQuery(TrustedNodeAddress),
|
||||||
NodeOverflowQuery(TrustedNodeAddress),
|
|
||||||
NodeScrollRootIdQuery(TrustedNodeAddress),
|
NodeScrollRootIdQuery(TrustedNodeAddress),
|
||||||
NodeGeometryQuery(TrustedNodeAddress),
|
NodeGeometryQuery(TrustedNodeAddress),
|
||||||
NodeScrollGeometryQuery(TrustedNodeAddress),
|
NodeScrollGeometryQuery(TrustedNodeAddress),
|
||||||
ResolvedStyleQuery(TrustedNodeAddress, Option<PseudoElement>, PropertyId),
|
ResolvedStyleQuery(TrustedNodeAddress, Option<PseudoElement>, PropertyId),
|
||||||
OffsetParentQuery(TrustedNodeAddress),
|
OffsetParentQuery(TrustedNodeAddress),
|
||||||
MarginStyleQuery(TrustedNodeAddress),
|
StyleQuery(TrustedNodeAddress),
|
||||||
TextIndexQuery(TrustedNodeAddress, Point2D<f32>),
|
TextIndexQuery(TrustedNodeAddress, Point2D<f32>),
|
||||||
NodesFromPointQuery(Point2D<f32>, NodesFromPointQueryType),
|
NodesFromPointQuery(Point2D<f32>, NodesFromPointQueryType),
|
||||||
}
|
}
|
||||||
|
@ -133,9 +132,9 @@ impl ReflowGoal {
|
||||||
ReflowGoal::TickAnimations | ReflowGoal::Full => true,
|
ReflowGoal::TickAnimations | ReflowGoal::Full => true,
|
||||||
ReflowGoal::ContentBoxQuery(_) | ReflowGoal::ContentBoxesQuery(_) |
|
ReflowGoal::ContentBoxQuery(_) | ReflowGoal::ContentBoxesQuery(_) |
|
||||||
ReflowGoal::NodeGeometryQuery(_) | ReflowGoal::NodeScrollGeometryQuery(_) |
|
ReflowGoal::NodeGeometryQuery(_) | ReflowGoal::NodeScrollGeometryQuery(_) |
|
||||||
ReflowGoal::NodeOverflowQuery(_) | ReflowGoal::NodeScrollRootIdQuery(_) |
|
ReflowGoal::NodeScrollRootIdQuery(_) |
|
||||||
ReflowGoal::ResolvedStyleQuery(..) | ReflowGoal::OffsetParentQuery(_) |
|
ReflowGoal::ResolvedStyleQuery(..) | ReflowGoal::OffsetParentQuery(_) |
|
||||||
ReflowGoal::MarginStyleQuery(_) => false,
|
ReflowGoal::StyleQuery(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,10 +142,10 @@ impl ReflowGoal {
|
||||||
/// false if a layout_thread display list is sufficient.
|
/// false if a layout_thread display list is sufficient.
|
||||||
pub fn needs_display(&self) -> bool {
|
pub fn needs_display(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
ReflowGoal::MarginStyleQuery(_) | ReflowGoal::TextIndexQuery(..) |
|
ReflowGoal::StyleQuery(_) | ReflowGoal::TextIndexQuery(..) |
|
||||||
ReflowGoal::ContentBoxQuery(_) | ReflowGoal::ContentBoxesQuery(_) |
|
ReflowGoal::ContentBoxQuery(_) | ReflowGoal::ContentBoxesQuery(_) |
|
||||||
ReflowGoal::NodeGeometryQuery(_) | ReflowGoal::NodeScrollGeometryQuery(_) |
|
ReflowGoal::NodeGeometryQuery(_) | ReflowGoal::NodeScrollGeometryQuery(_) |
|
||||||
ReflowGoal::NodeOverflowQuery(_) | ReflowGoal::NodeScrollRootIdQuery(_) |
|
ReflowGoal::NodeScrollRootIdQuery(_) |
|
||||||
ReflowGoal::ResolvedStyleQuery(..) |
|
ReflowGoal::ResolvedStyleQuery(..) |
|
||||||
ReflowGoal::OffsetParentQuery(_) => false,
|
ReflowGoal::OffsetParentQuery(_) => false,
|
||||||
ReflowGoal::NodesFromPointQuery(..) | ReflowGoal::Full |
|
ReflowGoal::NodesFromPointQuery(..) | ReflowGoal::Full |
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use euclid::{Point2D, Rect};
|
use euclid::{Point2D, Rect};
|
||||||
use script_traits::UntrustedNodeAddress;
|
use script_traits::UntrustedNodeAddress;
|
||||||
use style::properties::longhands::{margin_top, margin_right, margin_bottom, margin_left, overflow_x};
|
use servo_arc::Arc;
|
||||||
|
use style::properties::ComputedValues;
|
||||||
|
use style::properties::longhands::overflow_x;
|
||||||
use webrender_api::ClipId;
|
use webrender_api::ClipId;
|
||||||
|
|
||||||
/// Synchronous messages that script can send to layout.
|
/// Synchronous messages that script can send to layout.
|
||||||
|
@ -23,8 +25,6 @@ pub trait LayoutRPC {
|
||||||
fn content_boxes(&self) -> ContentBoxesResponse;
|
fn content_boxes(&self) -> ContentBoxesResponse;
|
||||||
/// Requests the geometry of this node. Used by APIs such as `clientTop`.
|
/// Requests the geometry of this node. Used by APIs such as `clientTop`.
|
||||||
fn node_geometry(&self) -> NodeGeometryResponse;
|
fn node_geometry(&self) -> NodeGeometryResponse;
|
||||||
/// Requests the overflow-x and overflow-y of this node. Used by `scrollTop` etc.
|
|
||||||
fn node_overflow(&self) -> NodeOverflowResponse;
|
|
||||||
/// Requests the scroll geometry of this node. Used by APIs such as `scrollTop`.
|
/// Requests the scroll geometry of this node. Used by APIs such as `scrollTop`.
|
||||||
fn node_scroll_area(&self) -> NodeGeometryResponse;
|
fn node_scroll_area(&self) -> NodeGeometryResponse;
|
||||||
/// Requests the scroll root id of this node. Used by APIs such as `scrollTop`
|
/// Requests the scroll root id of this node. Used by APIs such as `scrollTop`
|
||||||
|
@ -32,8 +32,9 @@ pub trait LayoutRPC {
|
||||||
/// Query layout for the resolved value of a given CSS property
|
/// Query layout for the resolved value of a given CSS property
|
||||||
fn resolved_style(&self) -> ResolvedStyleResponse;
|
fn resolved_style(&self) -> ResolvedStyleResponse;
|
||||||
fn offset_parent(&self) -> OffsetParentResponse;
|
fn offset_parent(&self) -> OffsetParentResponse;
|
||||||
/// Query layout for the resolve values of the margin properties for an element.
|
/// Requests the styles for an element. Contains a `None` value if the element is in a `display:
|
||||||
fn margin_style(&self) -> MarginStyleResponse;
|
/// none` subtree.
|
||||||
|
fn style(&self) -> StyleResponse;
|
||||||
fn text_index(&self) -> TextIndexResponse;
|
fn text_index(&self) -> TextIndexResponse;
|
||||||
/// Requests the list of nodes from the given point.
|
/// Requests the list of nodes from the given point.
|
||||||
fn nodes_from_point_response(&self) -> Vec<UntrustedNodeAddress>;
|
fn nodes_from_point_response(&self) -> Vec<UntrustedNodeAddress>;
|
||||||
|
@ -70,23 +71,7 @@ impl OffsetParentResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct MarginStyleResponse {
|
pub struct StyleResponse(pub Option<Arc<ComputedValues>>);
|
||||||
pub top: margin_top::computed_value::T,
|
|
||||||
pub right: margin_right::computed_value::T,
|
|
||||||
pub bottom: margin_bottom::computed_value::T,
|
|
||||||
pub left: margin_left::computed_value::T,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MarginStyleResponse {
|
|
||||||
pub fn empty() -> MarginStyleResponse {
|
|
||||||
MarginStyleResponse {
|
|
||||||
top: margin_top::computed_value::T::Auto,
|
|
||||||
right: margin_right::computed_value::T::Auto,
|
|
||||||
bottom: margin_bottom::computed_value::T::Auto,
|
|
||||||
left: margin_left::computed_value::T::Auto,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TextIndexResponse(pub Option<usize>);
|
pub struct TextIndexResponse(pub Option<usize>);
|
||||||
|
|
|
@ -11,7 +11,6 @@ use invalidation::element::restyle_hints::RestyleHint;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use malloc_size_of::MallocSizeOfOps;
|
use malloc_size_of::MallocSizeOfOps;
|
||||||
use properties::ComputedValues;
|
use properties::ComputedValues;
|
||||||
use properties::longhands::display::computed_value::T as Display;
|
|
||||||
use rule_tree::StrongRuleNode;
|
use rule_tree::StrongRuleNode;
|
||||||
use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
|
use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
|
||||||
use selectors::NthIndexCache;
|
use selectors::NthIndexCache;
|
||||||
|
@ -169,7 +168,7 @@ impl ElementStyles {
|
||||||
|
|
||||||
/// Whether this element `display` value is `none`.
|
/// Whether this element `display` value is `none`.
|
||||||
pub fn is_display_none(&self) -> bool {
|
pub fn is_display_none(&self) -> bool {
|
||||||
self.primary().get_box().clone_display() == Display::None
|
self.primary().get_box().clone_display().is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
|
|
|
@ -216,6 +216,12 @@ impl Display {
|
||||||
other => other,
|
other => other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the value is `None`
|
||||||
|
#[inline]
|
||||||
|
pub fn is_none(&self) -> bool {
|
||||||
|
*self == Display::None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A specified value for the `vertical-align` property.
|
/// A specified value for the `vertical-align` property.
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
env:
|
env:
|
||||||
|
RUST_BACKTRACE: '1'
|
||||||
RUSTFLAGS: -Dwarnings
|
RUSTFLAGS: -Dwarnings
|
||||||
CARGO_INCREMENTAL: "0"
|
CARGO_INCREMENTAL: "0"
|
||||||
SCCACHE_IDLE_TIMEOUT: "600"
|
SCCACHE_IDLE_TIMEOUT: "600"
|
||||||
|
@ -96,40 +97,52 @@ mac-rel-intermittent:
|
||||||
- ./etc/ci/check_intermittents.sh --log-raw intermittents.log
|
- ./etc/ci/check_intermittents.sh --log-raw intermittents.log
|
||||||
|
|
||||||
linux-dev:
|
linux-dev:
|
||||||
- ./mach clean-nightlies --keep 3 --force
|
env:
|
||||||
- ./mach clean-cargo-cache --keep 3 --force
|
CCACHE: sccache
|
||||||
- ./mach test-tidy --no-progress --all
|
RUSTC_WRAPPER: sccache
|
||||||
- ./mach test-tidy --no-progress --self-test
|
commands:
|
||||||
- ./mach build --dev
|
- ./mach clean-nightlies --keep 3 --force
|
||||||
- ./mach test-unit
|
- ./mach clean-cargo-cache --keep 3 --force
|
||||||
- ./mach package --dev
|
- ./mach test-tidy --no-progress --all
|
||||||
- ./mach build-cef
|
- ./mach test-tidy --no-progress --self-test
|
||||||
- ./mach build --dev --no-default-features --features default-except-unstable
|
- ./mach build --dev
|
||||||
- ./mach build-geckolib
|
- ./mach test-unit
|
||||||
- ./mach test-stylo
|
- ./mach package --dev
|
||||||
- bash ./etc/ci/lockfile_changed.sh
|
- ./mach build-cef
|
||||||
- bash ./etc/ci/manifest_changed.sh
|
- ./mach build --dev --no-default-features --features default-except-unstable
|
||||||
- bash ./etc/ci/check_no_panic.sh
|
- ./mach build-geckolib
|
||||||
|
- ./mach test-stylo
|
||||||
|
- bash ./etc/ci/lockfile_changed.sh
|
||||||
|
- bash ./etc/ci/manifest_changed.sh
|
||||||
|
- bash ./etc/ci/check_no_panic.sh
|
||||||
|
|
||||||
linux-rel-wpt:
|
linux-rel-wpt:
|
||||||
- ./mach clean-nightlies --keep 3 --force
|
env:
|
||||||
- ./mach clean-cargo-cache --keep 3 --force
|
CCACHE: sccache
|
||||||
- ./mach build --release --with-debug-assertions
|
RUSTC_WRAPPER: sccache
|
||||||
- ./mach test-wpt-failure
|
commands:
|
||||||
- ./mach test-wpt --release --processes 24 --total-chunks 2 --this-chunk 1 --log-raw test-wpt.log --log-errorsummary wpt-errorsummary.log --always-succeed
|
- ./mach clean-nightlies --keep 3 --force
|
||||||
- ./mach filter-intermittents wpt-errorsummary.log --log-intermittents intermittents.log --log-filteredsummary filtered-wpt-errorsummary.log --tracker-api default --reporter-api default
|
- ./mach clean-cargo-cache --keep 3 --force
|
||||||
- ./mach test-wpt --release --binary-arg=--multiprocess --processes 24 --log-raw test-wpt-mp.log --log-errorsummary wpt-mp-errorsummary.log eventsource
|
- ./mach build --release --with-debug-assertions
|
||||||
|
- ./mach test-wpt-failure
|
||||||
|
- ./mach test-wpt --release --processes 24 --total-chunks 2 --this-chunk 1 --log-raw test-wpt.log --log-errorsummary wpt-errorsummary.log --always-succeed
|
||||||
|
- ./mach filter-intermittents wpt-errorsummary.log --log-intermittents intermittents.log --log-filteredsummary filtered-wpt-errorsummary.log --tracker-api default --reporter-api default
|
||||||
|
- ./mach test-wpt --release --binary-arg=--multiprocess --processes 24 --log-raw test-wpt-mp.log --log-errorsummary wpt-mp-errorsummary.log eventsource
|
||||||
|
|
||||||
linux-rel-css:
|
linux-rel-css:
|
||||||
- ./mach clean-nightlies --keep 3 --force
|
env:
|
||||||
- ./mach clean-cargo-cache --keep 3 --force
|
CCACHE: sccache
|
||||||
- ./mach build --release --with-debug-assertions
|
RUSTC_WRAPPER: sccache
|
||||||
- ./mach test-wpt --release --processes 24 --total-chunks 2 --this-chunk 2 --log-raw test-wpt.log --log-errorsummary wpt-errorsummary.log --always-succeed
|
commands:
|
||||||
- ./mach filter-intermittents wpt-errorsummary.log --log-intermittents intermittents.log --log-filteredsummary filtered-wpt-errorsummary.log --tracker-api default --reporter-api default
|
- ./mach clean-nightlies --keep 3 --force
|
||||||
- ./mach build-geckolib --release
|
- ./mach clean-cargo-cache --keep 3 --force
|
||||||
- ./mach test-stylo --release
|
- ./mach build --release --with-debug-assertions
|
||||||
- bash ./etc/ci/lockfile_changed.sh
|
- ./mach test-wpt --release --processes 24 --total-chunks 2 --this-chunk 2 --log-raw test-wpt.log --log-errorsummary wpt-errorsummary.log --always-succeed
|
||||||
- bash ./etc/ci/manifest_changed.sh
|
- ./mach filter-intermittents wpt-errorsummary.log --log-intermittents intermittents.log --log-filteredsummary filtered-wpt-errorsummary.log --tracker-api default --reporter-api default
|
||||||
|
- ./mach build-geckolib --release
|
||||||
|
- ./mach test-stylo --release
|
||||||
|
- bash ./etc/ci/lockfile_changed.sh
|
||||||
|
- bash ./etc/ci/manifest_changed.sh
|
||||||
|
|
||||||
linux-nightly:
|
linux-nightly:
|
||||||
- ./mach clean-nightlies --keep 3 --force
|
- ./mach clean-nightlies --keep 3 --force
|
||||||
|
|
|
@ -18,7 +18,7 @@ gcc_ext=xz
|
||||||
binutils_version=2.27
|
binutils_version=2.27
|
||||||
binutils_ext=bz2
|
binutils_ext=bz2
|
||||||
binutils_configure_flags="--target=i686-w64-mingw32"
|
binutils_configure_flags="--target=i686-w64-mingw32"
|
||||||
mingw_version=a39e1aa184206c59982d39b263553a2c58104cef
|
mingw_version=36d7b92bbcec1e72d3ce24013b01f7acc34be3b0
|
||||||
|
|
||||||
# GPG keys used to sign GCC (collected from 5.1.0, 5.4.0, 6.4.0)
|
# GPG keys used to sign GCC (collected from 5.1.0, 5.4.0, 6.4.0)
|
||||||
$GPG --import $data_dir/33C235A34C46AA3FFB293709A328C3A2C3C45C06.key
|
$GPG --import $data_dir/33C235A34C46AA3FFB293709A328C3A2C3C45C06.key
|
||||||
|
|
|
@ -334,14 +334,20 @@ class SyncedBookmarksMirror {
|
||||||
// mirror, and we're holding the Sync lock at this point.
|
// mirror, and we're holding the Sync lock at this point.
|
||||||
MirrorLog.debug("Building remote tree from mirror");
|
MirrorLog.debug("Building remote tree from mirror");
|
||||||
let remoteTree = await this.fetchRemoteTree(remoteTimeSeconds);
|
let remoteTree = await this.fetchRemoteTree(remoteTimeSeconds);
|
||||||
MirrorLog.trace("Built remote tree from mirror", remoteTree);
|
if (MirrorLog.level <= Log.Level.Trace) {
|
||||||
|
MirrorLog.trace("Built remote tree from mirror\n" +
|
||||||
|
remoteTree.toASCIITreeString());
|
||||||
|
}
|
||||||
|
|
||||||
let observersToNotify = new BookmarkObserverRecorder(this.db);
|
let observersToNotify = new BookmarkObserverRecorder(this.db);
|
||||||
|
|
||||||
let changeRecords = await this.db.executeTransaction(async () => {
|
let changeRecords = await this.db.executeTransaction(async () => {
|
||||||
MirrorLog.debug("Building local tree from Places");
|
MirrorLog.debug("Building local tree from Places");
|
||||||
let localTree = await this.fetchLocalTree(localTimeSeconds);
|
let localTree = await this.fetchLocalTree(localTimeSeconds);
|
||||||
MirrorLog.trace("Built local tree from Places", localTree);
|
if (MirrorLog.level <= Log.Level.Trace) {
|
||||||
|
MirrorLog.trace("Built local tree from Places\n" +
|
||||||
|
localTree.toASCIITreeString());
|
||||||
|
}
|
||||||
|
|
||||||
MirrorLog.debug("Fetching content info for new mirror items");
|
MirrorLog.debug("Fetching content info for new mirror items");
|
||||||
let newRemoteContents = await this.fetchNewRemoteContents();
|
let newRemoteContents = await this.fetchNewRemoteContents();
|
||||||
|
@ -358,8 +364,11 @@ class SyncedBookmarksMirror {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MirrorLog.level <= Log.Level.Trace) {
|
if (MirrorLog.level <= Log.Level.Trace) {
|
||||||
let newTreeRoot = mergedRoot.toBookmarkNode();
|
MirrorLog.trace([
|
||||||
MirrorLog.trace("Built new merged tree", newTreeRoot);
|
"Built new merged tree",
|
||||||
|
mergedRoot.toASCIITreeString(),
|
||||||
|
...merger.deletionsToStrings(),
|
||||||
|
].join("\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// The merged tree should know about all items mentioned in the local
|
// The merged tree should know about all items mentioned in the local
|
||||||
|
@ -2562,6 +2571,46 @@ class BookmarkMergeState {
|
||||||
value() {
|
value() {
|
||||||
return this.type;
|
return this.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a representation of the value ("V") and structure ("S") state
|
||||||
|
* for logging. "L" is "local", "R" is "remote", and "+" is "new". We use
|
||||||
|
* compact notation here to reduce noise in trace logs, which log the
|
||||||
|
* merge state of every node in the tree.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
toString() {
|
||||||
|
return `(${this.valueToString()}; ${this.structureToString()})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
valueToString() {
|
||||||
|
switch (this.value()) {
|
||||||
|
case BookmarkMergeState.TYPE.LOCAL:
|
||||||
|
return "V: L";
|
||||||
|
case BookmarkMergeState.TYPE.REMOTE:
|
||||||
|
return "V: R";
|
||||||
|
}
|
||||||
|
return "V: ?";
|
||||||
|
}
|
||||||
|
|
||||||
|
structureToString() {
|
||||||
|
switch (this.structure()) {
|
||||||
|
case BookmarkMergeState.TYPE.LOCAL:
|
||||||
|
return "S: L";
|
||||||
|
case BookmarkMergeState.TYPE.REMOTE:
|
||||||
|
return "S: R";
|
||||||
|
case BookmarkMergeState.TYPE.NEW:
|
||||||
|
// We intentionally don't log the new structure node here, since
|
||||||
|
// the merger already does that.
|
||||||
|
return "S: +";
|
||||||
|
}
|
||||||
|
return "S: ?";
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return this.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BookmarkMergeState.TYPE = {
|
BookmarkMergeState.TYPE = {
|
||||||
|
@ -2684,6 +2733,61 @@ class BookmarkNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a human-readable, ASCII art representation of the node and its
|
||||||
|
* descendants. This is useful for visualizing the tree structure in trace
|
||||||
|
* logs.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
toASCIITreeString(prefix = "") {
|
||||||
|
if (!this.isFolder()) {
|
||||||
|
return prefix + "- " + this.toString();
|
||||||
|
}
|
||||||
|
return prefix + "+ " + this.toString() + "\n" + this.children.map(childNode =>
|
||||||
|
childNode.toASCIITreeString(`${prefix}| `)
|
||||||
|
).join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a representation of the node for logging. This should be compact,
|
||||||
|
* because the merger logs every local and remote node when trace logging is
|
||||||
|
* enabled.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
* A string in the form of "bookmarkAAAA (B; 1.234s; !)", where
|
||||||
|
* "B" is the kind, "1.234s" is the age, and "!" indicates that the
|
||||||
|
* node needs to be merged.
|
||||||
|
*/
|
||||||
|
toString() {
|
||||||
|
let info = `${this.kindToString()}; ${this.age.toFixed(3)}s`;
|
||||||
|
if (this.needsMerge) {
|
||||||
|
info += "; !";
|
||||||
|
}
|
||||||
|
return `${this.guid} (${info})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
kindToString() {
|
||||||
|
switch (this.kind) {
|
||||||
|
case SyncedBookmarksMirror.KIND.BOOKMARK:
|
||||||
|
return "B";
|
||||||
|
case SyncedBookmarksMirror.KIND.QUERY:
|
||||||
|
return "Q";
|
||||||
|
case SyncedBookmarksMirror.KIND.FOLDER:
|
||||||
|
return "F";
|
||||||
|
case SyncedBookmarksMirror.KIND.LIVEMARK:
|
||||||
|
return "L";
|
||||||
|
case SyncedBookmarksMirror.KIND.SEPARATOR:
|
||||||
|
return "S";
|
||||||
|
}
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used by `Log.jsm`.
|
||||||
|
toJSON() {
|
||||||
|
return this.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2768,9 +2872,16 @@ class BookmarkTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON() {
|
/**
|
||||||
let deleted = Array.from(this.deletedGuids);
|
* Generates an ASCII art representation of the complete tree. Deleted GUIDs
|
||||||
return { root: this.root, deleted };
|
* are prefixed with "~".
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
toASCIITreeString() {
|
||||||
|
return this.root.toASCIITreeString() + "\n" + Array.from(this.deletedGuids,
|
||||||
|
guid => `~${guid}`
|
||||||
|
).join(", ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2876,6 +2987,38 @@ class MergedBookmarkNode {
|
||||||
{ guid: this.guid, valueState });
|
{ guid: this.guid, valueState });
|
||||||
throw new TypeError("Can't take unknown value state");
|
throw new TypeError("Can't take unknown value state");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an ASCII art representation of the merged node and its
|
||||||
|
* descendants. This is similar to the format generated by
|
||||||
|
* `BookmarkNode#toASCIITreeString`, but logs value and structure states for
|
||||||
|
* merged children.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
toASCIITreeString(prefix = "") {
|
||||||
|
if (!this.mergedChildren.length) {
|
||||||
|
return prefix + "- " + this.toString();
|
||||||
|
}
|
||||||
|
return prefix + "+ " + this.toString() + "\n" + this.mergedChildren.map(
|
||||||
|
mergedChildNode => mergedChildNode.toASCIITreeString(`${prefix}| `)
|
||||||
|
).join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a representation of the merged node for logging.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
* A string in the form of "bookmarkAAAA (V: R, S: R)", where
|
||||||
|
* "V" is the value state and "R" is the structure state.
|
||||||
|
*/
|
||||||
|
toString() {
|
||||||
|
return `${this.guid} ${this.mergeState.toString()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return this.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Caches bookmark nodes containing the decided value and structure.
|
// Caches bookmark nodes containing the decided value and structure.
|
||||||
|
@ -3668,6 +3811,25 @@ class BookmarkMerger {
|
||||||
}
|
}
|
||||||
return newLocalNode;
|
return newLocalNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of local ("L: ~bookmarkAAAA, ~bookmarkBBBB") and remote
|
||||||
|
* ("R: ~bookmarkCCCC, ~bookmarkDDDD") deletions for logging.
|
||||||
|
*
|
||||||
|
* @return {String[]}
|
||||||
|
*/
|
||||||
|
deletionsToStrings() {
|
||||||
|
let infos = [];
|
||||||
|
if (this.deleteLocally.size) {
|
||||||
|
infos.push("L: " + Array.from(this.deleteLocally,
|
||||||
|
guid => `~${guid}`).join(", "));
|
||||||
|
}
|
||||||
|
if (this.deleteRemotely.size) {
|
||||||
|
infos.push("R: " + Array.from(this.deleteRemotely,
|
||||||
|
guid => `~${guid}`).join(", "));
|
||||||
|
}
|
||||||
|
return infos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Загрузка…
Ссылка в новой задаче