mirror of
https://github.com/Feodor2/Mypal68.git
synced 2025-06-19 07:15:36 -04:00
68.13 - dom
This commit is contained in:
parent
f6176dd28b
commit
adbe3a4a0f
@ -3,19 +3,25 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "Animation.h"
|
#include "Animation.h"
|
||||||
|
|
||||||
#include "AnimationUtils.h"
|
#include "AnimationUtils.h"
|
||||||
|
#include "mozAutoDocUpdate.h"
|
||||||
#include "mozilla/dom/AnimationBinding.h"
|
#include "mozilla/dom/AnimationBinding.h"
|
||||||
#include "mozilla/dom/AnimationPlaybackEvent.h"
|
#include "mozilla/dom/AnimationPlaybackEvent.h"
|
||||||
#include "mozilla/dom/Document.h"
|
#include "mozilla/dom/Document.h"
|
||||||
#include "mozilla/dom/DocumentInlines.h"
|
#include "mozilla/dom/DocumentInlines.h"
|
||||||
#include "mozilla/dom/DocumentTimeline.h"
|
#include "mozilla/dom/DocumentTimeline.h"
|
||||||
|
#include "mozilla/dom/MutationObservers.h"
|
||||||
#include "mozilla/AnimationEventDispatcher.h"
|
#include "mozilla/AnimationEventDispatcher.h"
|
||||||
#include "mozilla/AnimationTarget.h"
|
#include "mozilla/AnimationTarget.h"
|
||||||
#include "mozilla/AutoRestore.h"
|
#include "mozilla/AutoRestore.h"
|
||||||
#include "mozilla/Maybe.h" // For Maybe
|
#include "mozilla/DeclarationBlock.h"
|
||||||
#include "mozilla/TypeTraits.h" // For std::forward<>
|
#include "mozilla/Maybe.h" // For Maybe
|
||||||
#include "nsAnimationManager.h" // For CSSAnimation
|
#include "mozilla/TypeTraits.h" // For std::forward<>
|
||||||
#include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
|
#include "nsAnimationManager.h" // For CSSAnimation
|
||||||
|
#include "nsComputedDOMStyle.h"
|
||||||
|
#include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
|
||||||
|
#include "nsDOMCSSAttrDeclaration.h" // For nsDOMCSSAttributeDeclaration
|
||||||
#include "nsThreadUtils.h" // For nsRunnableMethod and nsRevocableEventPtr
|
#include "nsThreadUtils.h" // For nsRunnableMethod and nsRevocableEventPtr
|
||||||
#include "nsTransitionManager.h" // For CSSTransition
|
#include "nsTransitionManager.h" // For CSSTransition
|
||||||
#include "PendingAnimationTracker.h" // For PendingAnimationTracker
|
#include "PendingAnimationTracker.h" // For PendingAnimationTracker
|
||||||
@ -54,8 +60,7 @@ class MOZ_RAII AutoMutationBatchForAnimation {
|
|||||||
explicit AutoMutationBatchForAnimation(
|
explicit AutoMutationBatchForAnimation(
|
||||||
const Animation& aAnimation MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
|
const Animation& aAnimation MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
|
||||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||||
Maybe<NonOwningAnimationTarget> target =
|
Maybe<NonOwningAnimationTarget> target = aAnimation.GetTargetForAnimation();
|
||||||
nsNodeUtils::GetTargetForAnimation(&aAnimation);
|
|
||||||
if (!target) {
|
if (!target) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -75,6 +80,15 @@ class MOZ_RAII AutoMutationBatchForAnimation {
|
|||||||
// Animation interface:
|
// Animation interface:
|
||||||
//
|
//
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Maybe<NonOwningAnimationTarget> Animation::GetTargetForAnimation() const {
|
||||||
|
AnimationEffect* effect = GetEffect();
|
||||||
|
if (!effect || !effect->AsKeyframeEffect()) {
|
||||||
|
return Nothing();
|
||||||
|
}
|
||||||
|
return effect->AsKeyframeEffect()->GetTarget();
|
||||||
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
already_AddRefed<Animation> Animation::Constructor(
|
already_AddRefed<Animation> Animation::Constructor(
|
||||||
const GlobalObject& aGlobal, AnimationEffect* aEffect,
|
const GlobalObject& aGlobal, AnimationEffect* aEffect,
|
||||||
@ -106,7 +120,7 @@ void Animation::SetId(const nsAString& aId) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mId = aId;
|
mId = aId;
|
||||||
nsNodeUtils::AnimationChanged(this);
|
MutationObservers::NotifyAnimationChanged(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::SetEffect(AnimationEffect* aEffect) {
|
void Animation::SetEffect(AnimationEffect* aEffect) {
|
||||||
@ -129,7 +143,7 @@ void Animation::SetEffectNoUpdate(AnimationEffect* aEffect) {
|
|||||||
// We need to notify observers now because once we set mEffect to null
|
// We need to notify observers now because once we set mEffect to null
|
||||||
// we won't be able to find the target element to notify.
|
// we won't be able to find the target element to notify.
|
||||||
if (mIsRelevant) {
|
if (mIsRelevant) {
|
||||||
nsNodeUtils::AnimationRemoved(this);
|
MutationObservers::NotifyAnimationRemoved(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Break links with the old effect and then drop it.
|
// Break links with the old effect and then drop it.
|
||||||
@ -160,12 +174,14 @@ void Animation::SetEffectNoUpdate(AnimationEffect* aEffect) {
|
|||||||
// If the target is different, the change notification will be ignored by
|
// If the target is different, the change notification will be ignored by
|
||||||
// AutoMutationBatchForAnimation.
|
// AutoMutationBatchForAnimation.
|
||||||
if (wasRelevant && mIsRelevant) {
|
if (wasRelevant && mIsRelevant) {
|
||||||
nsNodeUtils::AnimationChanged(this);
|
MutationObservers::NotifyAnimationChanged(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReschedulePendingTasks();
|
ReschedulePendingTasks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeScheduleReplacementCheck();
|
||||||
|
|
||||||
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
|
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +260,7 @@ void Animation::SetStartTime(const Nullable<TimeDuration>& aNewStartTime) {
|
|||||||
|
|
||||||
UpdateTiming(SeekFlag::DidSeek, SyncNotifyFlag::Async);
|
UpdateTiming(SeekFlag::DidSeek, SyncNotifyFlag::Async);
|
||||||
if (IsRelevant()) {
|
if (IsRelevant()) {
|
||||||
nsNodeUtils::AnimationChanged(this);
|
MutationObservers::NotifyAnimationChanged(this);
|
||||||
}
|
}
|
||||||
PostUpdate();
|
PostUpdate();
|
||||||
}
|
}
|
||||||
@ -298,7 +314,7 @@ void Animation::SetCurrentTime(const TimeDuration& aSeekTime) {
|
|||||||
|
|
||||||
UpdateTiming(SeekFlag::DidSeek, SyncNotifyFlag::Async);
|
UpdateTiming(SeekFlag::DidSeek, SyncNotifyFlag::Async);
|
||||||
if (IsRelevant()) {
|
if (IsRelevant()) {
|
||||||
nsNodeUtils::AnimationChanged(this);
|
MutationObservers::NotifyAnimationChanged(this);
|
||||||
}
|
}
|
||||||
PostUpdate();
|
PostUpdate();
|
||||||
}
|
}
|
||||||
@ -329,7 +345,7 @@ void Animation::SetPlaybackRate(double aPlaybackRate) {
|
|||||||
// - update the playback rate on animations on layers.
|
// - update the playback rate on animations on layers.
|
||||||
UpdateTiming(SeekFlag::DidSeek, SyncNotifyFlag::Async);
|
UpdateTiming(SeekFlag::DidSeek, SyncNotifyFlag::Async);
|
||||||
if (IsRelevant()) {
|
if (IsRelevant()) {
|
||||||
nsNodeUtils::AnimationChanged(this);
|
MutationObservers::NotifyAnimationChanged(this);
|
||||||
}
|
}
|
||||||
PostUpdate();
|
PostUpdate();
|
||||||
}
|
}
|
||||||
@ -374,7 +390,7 @@ void Animation::UpdatePlaybackRate(double aPlaybackRate) {
|
|||||||
// All we need to do is update observers so that, e.g. DevTools, report the
|
// All we need to do is update observers so that, e.g. DevTools, report the
|
||||||
// right information.
|
// right information.
|
||||||
if (IsRelevant()) {
|
if (IsRelevant()) {
|
||||||
nsNodeUtils::AnimationChanged(this);
|
MutationObservers::NotifyAnimationChanged(this);
|
||||||
}
|
}
|
||||||
} else if (playState == AnimationPlayState::Finished) {
|
} else if (playState == AnimationPlayState::Finished) {
|
||||||
MOZ_ASSERT(mTimeline && !mTimeline->GetCurrentTimeAsDuration().IsNull(),
|
MOZ_ASSERT(mTimeline && !mTimeline->GetCurrentTimeAsDuration().IsNull(),
|
||||||
@ -402,7 +418,7 @@ void Animation::UpdatePlaybackRate(double aPlaybackRate) {
|
|||||||
// timing.
|
// timing.
|
||||||
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
|
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
|
||||||
if (IsRelevant()) {
|
if (IsRelevant()) {
|
||||||
nsNodeUtils::AnimationChanged(this);
|
MutationObservers::NotifyAnimationChanged(this);
|
||||||
}
|
}
|
||||||
PostUpdate();
|
PostUpdate();
|
||||||
} else {
|
} else {
|
||||||
@ -476,6 +492,7 @@ void Animation::Cancel(PostRestyleMode aPostRestyle) {
|
|||||||
|
|
||||||
if (mFinished) {
|
if (mFinished) {
|
||||||
mFinished->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
|
mFinished->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
|
||||||
|
mFinished->SetSettledPromiseIsHandled();
|
||||||
}
|
}
|
||||||
ResetFinishedPromise();
|
ResetFinishedPromise();
|
||||||
|
|
||||||
@ -553,7 +570,7 @@ void Animation::Finish(ErrorResult& aRv) {
|
|||||||
}
|
}
|
||||||
UpdateTiming(SeekFlag::DidSeek, SyncNotifyFlag::Sync);
|
UpdateTiming(SeekFlag::DidSeek, SyncNotifyFlag::Sync);
|
||||||
if (didChange && IsRelevant()) {
|
if (didChange && IsRelevant()) {
|
||||||
nsNodeUtils::AnimationChanged(this);
|
MutationObservers::NotifyAnimationChanged(this);
|
||||||
}
|
}
|
||||||
PostUpdate();
|
PostUpdate();
|
||||||
}
|
}
|
||||||
@ -592,6 +609,124 @@ void Animation::Reverse(ErrorResult& aRv) {
|
|||||||
// it here.
|
// it here.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Animation::Persist() {
|
||||||
|
if (mReplaceState == AnimationReplaceState::Persisted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wasRemoved = mReplaceState == AnimationReplaceState::Removed;
|
||||||
|
|
||||||
|
mReplaceState = AnimationReplaceState::Persisted;
|
||||||
|
|
||||||
|
// If the animation is not (yet) removed, there should be no side effects of
|
||||||
|
// persisting it.
|
||||||
|
if (wasRemoved) {
|
||||||
|
UpdateEffect(PostRestyleMode::IfNeeded);
|
||||||
|
PostUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/web-animations/#dom-animation-commitstyles
|
||||||
|
void Animation::CommitStyles(ErrorResult& aRv) {
|
||||||
|
if (!mEffect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take an owning reference to the keyframe effect. This will ensure that
|
||||||
|
// this Animation and the target element remain alive after flushing style.
|
||||||
|
RefPtr<KeyframeEffect> keyframeEffect = mEffect->AsKeyframeEffect();
|
||||||
|
if (!keyframeEffect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Maybe<NonOwningAnimationTarget> target = keyframeEffect->GetTarget();
|
||||||
|
if (!target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target->mPseudoType != PseudoStyleType::NotPseudo) {
|
||||||
|
aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check it is an element with a style attribute
|
||||||
|
nsCOMPtr<nsStyledElement> styledElement = do_QueryInterface(target->mElement);
|
||||||
|
if (!styledElement) {
|
||||||
|
aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush style before checking if the target element is rendered since the
|
||||||
|
// result could depend on pending style changes.
|
||||||
|
if (Document* doc = target->mElement->GetComposedDoc()) {
|
||||||
|
doc->FlushPendingNotifications(FlushType::Style);
|
||||||
|
}
|
||||||
|
if (!target->mElement->IsRendered()) {
|
||||||
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsPresContext* presContext =
|
||||||
|
nsContentUtils::GetContextForContent(target->mElement);
|
||||||
|
if (!presContext) {
|
||||||
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the computed animation values
|
||||||
|
UniquePtr<RawServoAnimationValueMap> animationValues =
|
||||||
|
Servo_AnimationValueMap_Create().Consume();
|
||||||
|
if (!presContext->EffectCompositor()->ComposeServoAnimationRuleForEffect(
|
||||||
|
*keyframeEffect, CascadeLevel(), animationValues.get())) {
|
||||||
|
NS_WARNING("Failed to compose animation style to commit");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calling SetCSSDeclaration will trigger attribute setting code.
|
||||||
|
// Start the update now so that the old rule doesn't get used
|
||||||
|
// between when we mutate the declaration and when we set the new
|
||||||
|
// rule.
|
||||||
|
mozAutoDocUpdate autoUpdate(target->mElement->OwnerDoc(), true);
|
||||||
|
|
||||||
|
// Get the inline style to append to
|
||||||
|
RefPtr<DeclarationBlock> declarationBlock;
|
||||||
|
if (auto* existing = target->mElement->GetInlineStyleDeclaration()) {
|
||||||
|
declarationBlock = existing->EnsureMutable();
|
||||||
|
} else {
|
||||||
|
declarationBlock = new DeclarationBlock();
|
||||||
|
declarationBlock->SetDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the callback
|
||||||
|
MutationClosureData closureData;
|
||||||
|
closureData.mClosure = nsDOMCSSAttributeDeclaration::MutationClosureFunction;
|
||||||
|
closureData.mElement = target->mElement;
|
||||||
|
DeclarationBlockMutationClosure beforeChangeClosure = {
|
||||||
|
nsDOMCSSAttributeDeclaration::MutationClosureFunction,
|
||||||
|
&closureData,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set the animated styles
|
||||||
|
bool changed = false;
|
||||||
|
nsCSSPropertyIDSet properties = keyframeEffect->GetPropertySet();
|
||||||
|
for (nsCSSPropertyID property : properties) {
|
||||||
|
RefPtr<RawServoAnimationValue> computedValue =
|
||||||
|
Servo_AnimationValueMap_GetValue(animationValues.get(), property)
|
||||||
|
.Consume();
|
||||||
|
if (computedValue) {
|
||||||
|
changed |= Servo_DeclarationBlock_SetPropertyToAnimationValue(
|
||||||
|
declarationBlock->Raw(), computedValue, beforeChangeClosure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!changed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update inline style declaration
|
||||||
|
target->mElement->SetInlineStyleDeclaration(*declarationBlock, closureData);
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// JS wrappers for Animation interface:
|
// JS wrappers for Animation interface:
|
||||||
@ -648,7 +783,14 @@ void Animation::Tick() {
|
|||||||
FinishPendingAt(mTimeline->GetCurrentTimeAsDuration().Value());
|
FinishPendingAt(mTimeline->GetCurrentTimeAsDuration().Value());
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
|
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Sync);
|
||||||
|
|
||||||
|
// Check for changes to whether or not this animation is replaceable.
|
||||||
|
bool isReplaceable = IsReplaceable();
|
||||||
|
if (isReplaceable && !mWasReplaceableAtLastTick) {
|
||||||
|
ScheduleReplacementCheck();
|
||||||
|
}
|
||||||
|
mWasReplaceableAtLastTick = isReplaceable;
|
||||||
|
|
||||||
if (!mEffect) {
|
if (!mEffect) {
|
||||||
return;
|
return;
|
||||||
@ -835,16 +977,129 @@ bool Animation::ShouldBeSynchronizedWithMainThread(
|
|||||||
|
|
||||||
void Animation::UpdateRelevance() {
|
void Animation::UpdateRelevance() {
|
||||||
bool wasRelevant = mIsRelevant;
|
bool wasRelevant = mIsRelevant;
|
||||||
mIsRelevant = HasCurrentEffect() || IsInEffect();
|
mIsRelevant = mReplaceState != AnimationReplaceState::Removed &&
|
||||||
|
(HasCurrentEffect() || IsInEffect());
|
||||||
|
|
||||||
// Notify animation observers.
|
// Notify animation observers.
|
||||||
if (wasRelevant && !mIsRelevant) {
|
if (wasRelevant && !mIsRelevant) {
|
||||||
nsNodeUtils::AnimationRemoved(this);
|
MutationObservers::NotifyAnimationRemoved(this);
|
||||||
} else if (!wasRelevant && mIsRelevant) {
|
} else if (!wasRelevant && mIsRelevant) {
|
||||||
nsNodeUtils::AnimationAdded(this);
|
MutationObservers::NotifyAnimationAdded(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool IsMarkupAnimation(T* aAnimation) {
|
||||||
|
return aAnimation && aAnimation->IsTiedToMarkup();
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/web-animations/#replaceable-animation
|
||||||
|
bool Animation::IsReplaceable() const {
|
||||||
|
// We never replace CSS animations or CSS transitions since they are managed
|
||||||
|
// by CSS.
|
||||||
|
if (IsMarkupAnimation(AsCSSAnimation()) ||
|
||||||
|
IsMarkupAnimation(AsCSSTransition())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only finished animations can be replaced.
|
||||||
|
if (PlayState() != AnimationPlayState::Finished) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Already removed animations cannot be replaced.
|
||||||
|
if (ReplaceState() == AnimationReplaceState::Removed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can only replace an animation if we know that, uninterfered, it would
|
||||||
|
// never start playing again. That excludes any animations on timelines that
|
||||||
|
// aren't monotonically increasing.
|
||||||
|
//
|
||||||
|
// If we don't have any timeline at all, then we can't be in the finished
|
||||||
|
// state (since we need both a resolved start time and current time for that)
|
||||||
|
// and will have already returned false above.
|
||||||
|
//
|
||||||
|
// (However, if it ever does become possible to be finished without a timeline
|
||||||
|
// then we will want to return false here since it probably suggests an
|
||||||
|
// animation being driven directly by script, in which case we can't assume
|
||||||
|
// anything about how they will behave.)
|
||||||
|
if (!GetTimeline() || !GetTimeline()->TracksWallclockTime()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the animation doesn't have an effect then we can't determine if it is
|
||||||
|
// filling or not so just leave it alone.
|
||||||
|
if (!GetEffect()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// At the time of writing we only know about KeyframeEffects. If we introduce
|
||||||
|
// other types of effects we will need to decide if they are replaceable or
|
||||||
|
// not.
|
||||||
|
MOZ_ASSERT(GetEffect()->AsKeyframeEffect(),
|
||||||
|
"Effect should be a keyframe effect");
|
||||||
|
|
||||||
|
// We only replace animations that are filling.
|
||||||
|
if (GetEffect()->GetComputedTiming().mProgress.IsNull()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should only replace animations with a target element (since otherwise
|
||||||
|
// what other effects would we consider when determining if they are covered
|
||||||
|
// or not?).
|
||||||
|
if (!GetEffect()->AsKeyframeEffect()->GetTarget()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Animation::IsRemovable() const {
|
||||||
|
return ReplaceState() == AnimationReplaceState::Active && IsReplaceable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Animation::ScheduleReplacementCheck() {
|
||||||
|
MOZ_ASSERT(
|
||||||
|
IsReplaceable(),
|
||||||
|
"Should only schedule a replacement check for a replaceable animation");
|
||||||
|
|
||||||
|
// If IsReplaceable() is true, the following should also hold
|
||||||
|
MOZ_ASSERT(GetEffect());
|
||||||
|
MOZ_ASSERT(GetEffect()->AsKeyframeEffect());
|
||||||
|
MOZ_ASSERT(GetEffect()->AsKeyframeEffect()->GetTarget());
|
||||||
|
|
||||||
|
Maybe<NonOwningAnimationTarget> target =
|
||||||
|
GetEffect()->AsKeyframeEffect()->GetTarget();
|
||||||
|
|
||||||
|
nsPresContext* presContext =
|
||||||
|
nsContentUtils::GetContextForContent(target->mElement);
|
||||||
|
if (presContext) {
|
||||||
|
presContext->EffectCompositor()->NoteElementForReducing(*target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Animation::MaybeScheduleReplacementCheck() {
|
||||||
|
if (!IsReplaceable()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScheduleReplacementCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Animation::Remove() {
|
||||||
|
MOZ_ASSERT(IsRemovable(),
|
||||||
|
"Should not be trying to remove an effect that is not removable");
|
||||||
|
|
||||||
|
mReplaceState = AnimationReplaceState::Removed;
|
||||||
|
|
||||||
|
UpdateEffect(PostRestyleMode::IfNeeded);
|
||||||
|
PostUpdate();
|
||||||
|
|
||||||
|
QueuePlaybackEvent(NS_LITERAL_STRING("remove"),
|
||||||
|
GetTimelineCurrentTimeAsTimeStamp());
|
||||||
|
}
|
||||||
|
|
||||||
bool Animation::HasLowerCompositeOrderThan(const Animation& aOther) const {
|
bool Animation::HasLowerCompositeOrderThan(const Animation& aOther) const {
|
||||||
// 0. Object-equality case
|
// 0. Object-equality case
|
||||||
if (&aOther == this) {
|
if (&aOther == this) {
|
||||||
@ -987,11 +1242,27 @@ void Animation::ComposeStyle(RawServoAnimationValueMap& aComposeResult,
|
|||||||
|
|
||||||
void Animation::NotifyEffectTimingUpdated() {
|
void Animation::NotifyEffectTimingUpdated() {
|
||||||
MOZ_ASSERT(mEffect,
|
MOZ_ASSERT(mEffect,
|
||||||
"We should only update timing effect when we have a target "
|
"We should only update effect timing when we have a target "
|
||||||
"effect");
|
"effect");
|
||||||
UpdateTiming(Animation::SeekFlag::NoSeek, Animation::SyncNotifyFlag::Async);
|
UpdateTiming(Animation::SeekFlag::NoSeek, Animation::SyncNotifyFlag::Async);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Animation::NotifyEffectPropertiesUpdated() {
|
||||||
|
MOZ_ASSERT(mEffect,
|
||||||
|
"We should only update effect properties when we have a target "
|
||||||
|
"effect");
|
||||||
|
|
||||||
|
MaybeScheduleReplacementCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Animation::NotifyEffectTargetUpdated() {
|
||||||
|
MOZ_ASSERT(mEffect,
|
||||||
|
"We should only update the effect target when we have a target "
|
||||||
|
"effect");
|
||||||
|
|
||||||
|
MaybeScheduleReplacementCheck();
|
||||||
|
}
|
||||||
|
|
||||||
void Animation::NotifyGeometricAnimationsStartingThisFrame() {
|
void Animation::NotifyGeometricAnimationsStartingThisFrame() {
|
||||||
if (!IsNewlyStarted() || !mEffect) {
|
if (!IsNewlyStarted() || !mEffect) {
|
||||||
return;
|
return;
|
||||||
@ -1086,7 +1357,7 @@ void Animation::PlayNoUpdate(ErrorResult& aRv, LimitBehavior aLimitBehavior) {
|
|||||||
|
|
||||||
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
|
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
|
||||||
if (IsRelevant()) {
|
if (IsRelevant()) {
|
||||||
nsNodeUtils::AnimationChanged(this);
|
MutationObservers::NotifyAnimationChanged(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1134,7 +1405,7 @@ void Animation::Pause(ErrorResult& aRv) {
|
|||||||
|
|
||||||
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
|
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
|
||||||
if (IsRelevant()) {
|
if (IsRelevant()) {
|
||||||
nsNodeUtils::AnimationChanged(this);
|
MutationObservers::NotifyAnimationChanged(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PostUpdate();
|
PostUpdate();
|
||||||
@ -1177,12 +1448,12 @@ void Animation::ResumeAt(const TimeDuration& aReadyTime) {
|
|||||||
|
|
||||||
mPendingState = PendingState::NotPending;
|
mPendingState = PendingState::NotPending;
|
||||||
|
|
||||||
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
|
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Sync);
|
||||||
|
|
||||||
// If we had a pending playback rate, we will have now applied it so we need
|
// If we had a pending playback rate, we will have now applied it so we need
|
||||||
// to notify observers.
|
// to notify observers.
|
||||||
if (hadPendingPlaybackRate && IsRelevant()) {
|
if (hadPendingPlaybackRate && IsRelevant()) {
|
||||||
nsNodeUtils::AnimationChanged(this);
|
MutationObservers::NotifyAnimationChanged(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mReady) {
|
if (mReady) {
|
||||||
@ -1330,6 +1601,7 @@ void Animation::ResetPendingTasks() {
|
|||||||
|
|
||||||
if (mReady) {
|
if (mReady) {
|
||||||
mReady->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
|
mReady->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
|
||||||
|
mReady->SetSettledPromiseIsHandled();
|
||||||
mReady = nullptr;
|
mReady = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1501,7 +1773,7 @@ void Animation::QueuePlaybackEvent(const nsAString& aName,
|
|||||||
|
|
||||||
AnimationPlaybackEventInit init;
|
AnimationPlaybackEventInit init;
|
||||||
|
|
||||||
if (aName.EqualsLiteral("finish")) {
|
if (aName.EqualsLiteral("finish") || aName.EqualsLiteral("remove")) {
|
||||||
init.mCurrentTime = GetCurrentTimeAsDouble();
|
init.mCurrentTime = GetCurrentTimeAsDouble();
|
||||||
}
|
}
|
||||||
if (mTimeline) {
|
if (mTimeline) {
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "mozilla/DOMEventTargetHelper.h"
|
#include "mozilla/DOMEventTargetHelper.h"
|
||||||
#include "mozilla/EffectCompositor.h" // For EffectCompositor::CascadeLevel
|
#include "mozilla/EffectCompositor.h" // For EffectCompositor::CascadeLevel
|
||||||
#include "mozilla/LinkedList.h"
|
#include "mozilla/LinkedList.h"
|
||||||
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/PostRestyleMode.h"
|
#include "mozilla/PostRestyleMode.h"
|
||||||
#include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration
|
#include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration
|
||||||
#include "mozilla/dom/AnimationBinding.h" // for AnimationPlayState
|
#include "mozilla/dom/AnimationBinding.h" // for AnimationPlayState
|
||||||
@ -49,20 +50,19 @@ class Animation : public DOMEventTargetHelper,
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Animation(nsIGlobalObject* aGlobal)
|
explicit Animation(nsIGlobalObject* aGlobal)
|
||||||
: DOMEventTargetHelper(aGlobal),
|
: DOMEventTargetHelper(aGlobal), mAnimationIndex(sNextAnimationIndex++) {}
|
||||||
mPlaybackRate(1.0),
|
|
||||||
mAnimationIndex(sNextAnimationIndex++),
|
|
||||||
mCachedChildIndex(-1),
|
|
||||||
mPendingState(PendingState::NotPending),
|
|
||||||
mFinishedAtLastComposeStyle(false),
|
|
||||||
mIsRelevant(false),
|
|
||||||
mFinishedIsResolved(false),
|
|
||||||
mSyncWithGeometricAnimations(false) {}
|
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS_INHERITED
|
NS_DECL_ISUPPORTS_INHERITED
|
||||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Animation, DOMEventTargetHelper)
|
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Animation, DOMEventTargetHelper)
|
||||||
|
|
||||||
nsIGlobalObject* GetParentObject() const { return GetOwnerGlobal(); }
|
nsIGlobalObject* GetParentObject() const { return GetOwnerGlobal(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function to get the target (pseudo-)element associated with an
|
||||||
|
* animation.
|
||||||
|
*/
|
||||||
|
Maybe<NonOwningAnimationTarget> GetTargetForAnimation() const;
|
||||||
|
|
||||||
virtual JSObject* WrapObject(JSContext* aCx,
|
virtual JSObject* WrapObject(JSContext* aCx,
|
||||||
JS::Handle<JSObject*> aGivenProto) override;
|
JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
|
||||||
@ -118,12 +118,14 @@ class Animation : public DOMEventTargetHelper,
|
|||||||
|
|
||||||
bool Pending() const { return mPendingState != PendingState::NotPending; }
|
bool Pending() const { return mPendingState != PendingState::NotPending; }
|
||||||
virtual bool PendingFromJS() const { return Pending(); }
|
virtual bool PendingFromJS() const { return Pending(); }
|
||||||
|
AnimationReplaceState ReplaceState() const { return mReplaceState; }
|
||||||
|
|
||||||
virtual Promise* GetReady(ErrorResult& aRv);
|
virtual Promise* GetReady(ErrorResult& aRv);
|
||||||
Promise* GetFinished(ErrorResult& aRv);
|
Promise* GetFinished(ErrorResult& aRv);
|
||||||
|
|
||||||
IMPL_EVENT_HANDLER(finish);
|
IMPL_EVENT_HANDLER(finish);
|
||||||
IMPL_EVENT_HANDLER(cancel);
|
IMPL_EVENT_HANDLER(cancel);
|
||||||
|
IMPL_EVENT_HANDLER(remove);
|
||||||
|
|
||||||
void Cancel(PostRestyleMode aPostRestyle = PostRestyleMode::IfNeeded);
|
void Cancel(PostRestyleMode aPostRestyle = PostRestyleMode::IfNeeded);
|
||||||
|
|
||||||
@ -145,6 +147,9 @@ class Animation : public DOMEventTargetHelper,
|
|||||||
void UpdatePlaybackRate(double aPlaybackRate);
|
void UpdatePlaybackRate(double aPlaybackRate);
|
||||||
void Reverse(ErrorResult& aRv);
|
void Reverse(ErrorResult& aRv);
|
||||||
|
|
||||||
|
void Persist();
|
||||||
|
void CommitStyles(ErrorResult& aRv);
|
||||||
|
|
||||||
bool IsRunningOnCompositor() const;
|
bool IsRunningOnCompositor() const;
|
||||||
|
|
||||||
virtual void Tick();
|
virtual void Tick();
|
||||||
@ -327,6 +332,25 @@ class Animation : public DOMEventTargetHelper,
|
|||||||
bool IsRelevant() const { return mIsRelevant; }
|
bool IsRelevant() const { return mIsRelevant; }
|
||||||
void UpdateRelevance();
|
void UpdateRelevance();
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/web-animations-1/#replaceable-animation
|
||||||
|
bool IsReplaceable() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this Animation satisfies the requirements for being
|
||||||
|
* removed when it is replaced.
|
||||||
|
*
|
||||||
|
* Returning true does not imply this animation _should_ be removed.
|
||||||
|
* Determining that depends on the other effects in the same EffectSet to
|
||||||
|
* which this animation's effect, if any, contributes.
|
||||||
|
*/
|
||||||
|
bool IsRemovable() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make this animation's target effect no-longer part of the effect stack
|
||||||
|
* while preserving its timing information.
|
||||||
|
*/
|
||||||
|
void Remove();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this Animation has a lower composite order than aOther.
|
* Returns true if this Animation has a lower composite order than aOther.
|
||||||
*/
|
*/
|
||||||
@ -364,6 +388,8 @@ class Animation : public DOMEventTargetHelper,
|
|||||||
const nsCSSPropertyIDSet& aPropertiesToSkip);
|
const nsCSSPropertyIDSet& aPropertiesToSkip);
|
||||||
|
|
||||||
void NotifyEffectTimingUpdated();
|
void NotifyEffectTimingUpdated();
|
||||||
|
void NotifyEffectPropertiesUpdated();
|
||||||
|
void NotifyEffectTargetUpdated();
|
||||||
void NotifyGeometricAnimationsStartingThisFrame();
|
void NotifyGeometricAnimationsStartingThisFrame();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -479,6 +505,9 @@ class Animation : public DOMEventTargetHelper,
|
|||||||
return GetCurrentTimeForHoldTime(Nullable<TimeDuration>());
|
return GetCurrentTimeForHoldTime(Nullable<TimeDuration>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScheduleReplacementCheck();
|
||||||
|
void MaybeScheduleReplacementCheck();
|
||||||
|
|
||||||
// Earlier side of the elapsed time range reported in CSS Animations and CSS
|
// Earlier side of the elapsed time range reported in CSS Animations and CSS
|
||||||
// Transitions events.
|
// Transitions events.
|
||||||
//
|
//
|
||||||
@ -525,7 +554,7 @@ class Animation : public DOMEventTargetHelper,
|
|||||||
Nullable<TimeDuration> mHoldTime; // Animation timescale
|
Nullable<TimeDuration> mHoldTime; // Animation timescale
|
||||||
Nullable<TimeDuration> mPendingReadyTime; // Timeline timescale
|
Nullable<TimeDuration> mPendingReadyTime; // Timeline timescale
|
||||||
Nullable<TimeDuration> mPreviousCurrentTime; // Animation timescale
|
Nullable<TimeDuration> mPreviousCurrentTime; // Animation timescale
|
||||||
double mPlaybackRate;
|
double mPlaybackRate = 1.0;
|
||||||
Maybe<double> mPendingPlaybackRate;
|
Maybe<double> mPendingPlaybackRate;
|
||||||
|
|
||||||
// A Promise that is replaced on each call to Play()
|
// A Promise that is replaced on each call to Play()
|
||||||
@ -552,7 +581,7 @@ class Animation : public DOMEventTargetHelper,
|
|||||||
|
|
||||||
// While ordering Animation objects for event dispatch, the index of the
|
// While ordering Animation objects for event dispatch, the index of the
|
||||||
// target node in its parent may be cached in mCachedChildIndex.
|
// target node in its parent may be cached in mCachedChildIndex.
|
||||||
int32_t mCachedChildIndex;
|
int32_t mCachedChildIndex = -1;
|
||||||
|
|
||||||
// Indicates if the animation is in the pending state (and what state it is
|
// Indicates if the animation is in the pending state (and what state it is
|
||||||
// waiting to enter when it finished pending). We use this rather than
|
// waiting to enter when it finished pending). We use this rather than
|
||||||
@ -561,23 +590,28 @@ class Animation : public DOMEventTargetHelper,
|
|||||||
// from the PendingAnimationTracker while it is waiting for the next tick
|
// from the PendingAnimationTracker while it is waiting for the next tick
|
||||||
// (see TriggerOnNextTick for details).
|
// (see TriggerOnNextTick for details).
|
||||||
enum class PendingState : uint8_t { NotPending, PlayPending, PausePending };
|
enum class PendingState : uint8_t { NotPending, PlayPending, PausePending };
|
||||||
PendingState mPendingState;
|
PendingState mPendingState = PendingState::NotPending;
|
||||||
|
|
||||||
|
// Handling of this animation's target effect when filling while finished.
|
||||||
|
AnimationReplaceState mReplaceState = AnimationReplaceState::Active;
|
||||||
|
|
||||||
|
bool mFinishedAtLastComposeStyle = false;
|
||||||
|
bool mWasReplaceableAtLastTick = false;
|
||||||
|
|
||||||
bool mFinishedAtLastComposeStyle;
|
|
||||||
// Indicates that the animation should be exposed in an element's
|
// Indicates that the animation should be exposed in an element's
|
||||||
// getAnimations() list.
|
// getAnimations() list.
|
||||||
bool mIsRelevant;
|
bool mIsRelevant = false;
|
||||||
|
|
||||||
// True if mFinished is resolved or would be resolved if mFinished has
|
// True if mFinished is resolved or would be resolved if mFinished has
|
||||||
// yet to be created. This is not set when mFinished is rejected since
|
// yet to be created. This is not set when mFinished is rejected since
|
||||||
// in that case mFinished is immediately reset to represent a new current
|
// in that case mFinished is immediately reset to represent a new current
|
||||||
// finished promise.
|
// finished promise.
|
||||||
bool mFinishedIsResolved;
|
bool mFinishedIsResolved = false;
|
||||||
|
|
||||||
// True if this animation was triggered at the same time as one or more
|
// True if this animation was triggered at the same time as one or more
|
||||||
// geometric animations and hence we should run any transform animations on
|
// geometric animations and hence we should run any transform animations on
|
||||||
// the main thread.
|
// the main thread.
|
||||||
bool mSyncWithGeometricAnimations;
|
bool mSyncWithGeometricAnimations = false;
|
||||||
|
|
||||||
RefPtr<MicroTaskRunnable> mFinishNotificationTask;
|
RefPtr<MicroTaskRunnable> mFinishNotificationTask;
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "mozilla/dom/Animation.h"
|
#include "mozilla/dom/Animation.h"
|
||||||
#include "mozilla/dom/KeyframeEffect.h"
|
#include "mozilla/dom/KeyframeEffect.h"
|
||||||
|
#include "mozilla/dom/MutationObservers.h"
|
||||||
#include "mozilla/AnimationUtils.h"
|
#include "mozilla/AnimationUtils.h"
|
||||||
#include "mozilla/FloatingPoint.h"
|
#include "mozilla/FloatingPoint.h"
|
||||||
|
|
||||||
@ -77,7 +78,7 @@ void AnimationEffect::SetSpecifiedTiming(TimingParams&& aTiming) {
|
|||||||
mAnimation->NotifyEffectTimingUpdated();
|
mAnimation->NotifyEffectTimingUpdated();
|
||||||
|
|
||||||
if (mAnimation->IsRelevant()) {
|
if (mAnimation->IsRelevant()) {
|
||||||
nsNodeUtils::AnimationChanged(mAnimation);
|
MutationObservers::NotifyAnimationChanged(mAnimation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AsKeyframeEffect()) {
|
if (AsKeyframeEffect()) {
|
||||||
@ -180,9 +181,9 @@ ComputedTiming AnimationEffect::GetComputedTimingAt(
|
|||||||
// Determine the 0-based index of the current iteration.
|
// Determine the 0-based index of the current iteration.
|
||||||
// https://drafts.csswg.org/web-animations/#current-iteration
|
// https://drafts.csswg.org/web-animations/#current-iteration
|
||||||
result.mCurrentIteration =
|
result.mCurrentIteration =
|
||||||
(result.mIterations >= UINT64_MAX &&
|
(result.mIterations >= double(UINT64_MAX) &&
|
||||||
result.mPhase == ComputedTiming::AnimationPhase::After) ||
|
result.mPhase == ComputedTiming::AnimationPhase::After) ||
|
||||||
overallProgress >= UINT64_MAX
|
overallProgress >= double(UINT64_MAX)
|
||||||
? UINT64_MAX // In GetComputedTimingDictionary(),
|
? UINT64_MAX // In GetComputedTimingDictionary(),
|
||||||
// we will convert this into Infinity
|
// we will convert this into Infinity
|
||||||
: static_cast<uint64_t>(overallProgress);
|
: static_cast<uint64_t>(overallProgress);
|
||||||
|
@ -11,16 +11,15 @@ namespace mozilla {
|
|||||||
template <uint32_t N>
|
template <uint32_t N>
|
||||||
nsresult AnimationPerformanceWarning::ToLocalizedStringWithIntParams(
|
nsresult AnimationPerformanceWarning::ToLocalizedStringWithIntParams(
|
||||||
const char* aKey, nsAString& aLocalizedString) const {
|
const char* aKey, nsAString& aLocalizedString) const {
|
||||||
nsAutoString strings[N];
|
AutoTArray<nsString, N> strings;
|
||||||
const char16_t* charParams[N];
|
|
||||||
|
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(mParams->Length() == N);
|
||||||
for (size_t i = 0, n = mParams->Length(); i < n; i++) {
|
for (size_t i = 0, n = mParams->Length(); i < n; i++) {
|
||||||
strings[i].AppendInt((*mParams)[i]);
|
strings.AppendElement()->AppendInt((*mParams)[i]);
|
||||||
charParams[i] = strings[i].get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nsContentUtils::FormatLocalizedString(
|
return nsContentUtils::FormatLocalizedString(
|
||||||
nsContentUtils::eLAYOUT_PROPERTIES, aKey, charParams, aLocalizedString);
|
nsContentUtils::eLAYOUT_PROPERTIES, aKey, strings, aLocalizedString);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AnimationPerformanceWarning::ToLocalizedString(
|
bool AnimationPerformanceWarning::ToLocalizedString(
|
||||||
@ -32,13 +31,13 @@ bool AnimationPerformanceWarning::ToLocalizedString(
|
|||||||
MOZ_ASSERT(mParams && mParams->Length() == 6,
|
MOZ_ASSERT(mParams && mParams->Length() == 6,
|
||||||
"Parameter's length should be 6 for ContentTooLarge2");
|
"Parameter's length should be 6 for ContentTooLarge2");
|
||||||
|
|
||||||
return NS_SUCCEEDED(ToLocalizedStringWithIntParams<7>(
|
return NS_SUCCEEDED(ToLocalizedStringWithIntParams<6>(
|
||||||
"CompositorAnimationWarningContentTooLarge2", aLocalizedString));
|
"CompositorAnimationWarningContentTooLarge2", aLocalizedString));
|
||||||
case Type::ContentTooLargeArea:
|
case Type::ContentTooLargeArea:
|
||||||
MOZ_ASSERT(mParams && mParams->Length() == 2,
|
MOZ_ASSERT(mParams && mParams->Length() == 2,
|
||||||
"Parameter's length should be 2 for ContentTooLargeArea");
|
"Parameter's length should be 2 for ContentTooLargeArea");
|
||||||
|
|
||||||
return NS_SUCCEEDED(ToLocalizedStringWithIntParams<3>(
|
return NS_SUCCEEDED(ToLocalizedStringWithIntParams<2>(
|
||||||
"CompositorAnimationWarningContentTooLargeArea", aLocalizedString));
|
"CompositorAnimationWarningContentTooLargeArea", aLocalizedString));
|
||||||
case Type::TransformBackfaceVisibilityHidden:
|
case Type::TransformBackfaceVisibilityHidden:
|
||||||
key = "CompositorAnimationWarningTransformBackfaceVisibilityHidden";
|
key = "CompositorAnimationWarningTransformBackfaceVisibilityHidden";
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
#ifndef mozilla_AnimationTarget_h
|
#ifndef mozilla_AnimationTarget_h
|
||||||
#define mozilla_AnimationTarget_h
|
#define mozilla_AnimationTarget_h
|
||||||
|
|
||||||
#include "mozilla/Attributes.h" // For MOZ_NON_OWNING_REF
|
#include "mozilla/Attributes.h" // For MOZ_NON_OWNING_REF
|
||||||
|
#include "mozilla/HashFunctions.h" // For HashNumber, AddToHash
|
||||||
|
#include "mozilla/HashTable.h" // For DefaultHasher, PointerHasher
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/RefPtr.h"
|
#include "mozilla/RefPtr.h"
|
||||||
#include "nsCSSPseudoElements.h"
|
#include "nsCSSPseudoElements.h"
|
||||||
@ -67,6 +69,26 @@ inline void ImplCycleCollectionUnlink(Maybe<OwningAnimationTarget>& aTarget) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A DefaultHasher specialization for OwningAnimationTarget.
|
||||||
|
template <>
|
||||||
|
struct DefaultHasher<OwningAnimationTarget> {
|
||||||
|
using Key = OwningAnimationTarget;
|
||||||
|
using Lookup = OwningAnimationTarget;
|
||||||
|
using PtrHasher = PointerHasher<dom::Element*>;
|
||||||
|
|
||||||
|
static HashNumber hash(const Lookup& aLookup) {
|
||||||
|
return AddToHash(PtrHasher::hash(aLookup.mElement.get()),
|
||||||
|
static_cast<uint8_t>(aLookup.mPseudoType));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool match(const Key& aKey, const Lookup& aLookup) {
|
||||||
|
return PtrHasher::match(aKey.mElement.get(), aLookup.mElement.get()) &&
|
||||||
|
aKey.mPseudoType == aLookup.mPseudoType;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rekey(Key& aKey, Key&& aNewKey) { aKey = std::move(aNewKey); }
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
#endif // mozilla_AnimationTarget_h
|
#endif // mozilla_AnimationTarget_h
|
||||||
|
@ -43,7 +43,7 @@ JSObject* CSSPseudoElement::WrapObject(JSContext* aCx,
|
|||||||
return CSSPseudoElement_Binding::Wrap(aCx, this, aGivenProto);
|
return CSSPseudoElement_Binding::Wrap(aCx, this, aGivenProto);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSSPseudoElement::GetAnimations(const AnimationFilter& filter,
|
void CSSPseudoElement::GetAnimations(const GetAnimationsOptions& aOptions,
|
||||||
nsTArray<RefPtr<Animation>>& aRetVal) {
|
nsTArray<RefPtr<Animation>>& aRetVal) {
|
||||||
Document* doc = mOriginatingElement->GetComposedDoc();
|
Document* doc = mOriginatingElement->GetComposedDoc();
|
||||||
if (doc) {
|
if (doc) {
|
||||||
|
@ -52,7 +52,7 @@ class CSSPseudoElement final : public nsWrapperCache {
|
|||||||
return retVal.forget();
|
return retVal.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetAnimations(const AnimationFilter& filter,
|
void GetAnimations(const GetAnimationsOptions& aOptions,
|
||||||
nsTArray<RefPtr<Animation>>& aRetVal);
|
nsTArray<RefPtr<Animation>>& aRetVal);
|
||||||
already_AddRefed<Animation> Animate(
|
already_AddRefed<Animation> Animate(
|
||||||
JSContext* aContext, JS::Handle<JSObject*> aKeyframes,
|
JSContext* aContext, JS::Handle<JSObject*> aKeyframes,
|
||||||
|
@ -186,13 +186,6 @@ void DocumentTimeline::MostRecentRefreshTimeUpdated() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DocumentTimeline::WillRefresh(mozilla::TimeStamp aTime) {
|
void DocumentTimeline::WillRefresh(mozilla::TimeStamp aTime) {
|
||||||
// https://drafts.csswg.org/web-animations-1/#update-animations-and-send-events,
|
|
||||||
// step2.
|
|
||||||
// Note that this should be done before nsAutoAnimationMutationBatch which is
|
|
||||||
// inside MostRecentRefreshTimeUpdated(). If PerformMicroTaskCheckpoint was
|
|
||||||
// called before nsAutoAnimationMutationBatch is destroyed, some mutation
|
|
||||||
// records might not be delivered in this checkpoint.
|
|
||||||
nsAutoMicroTask mt;
|
|
||||||
MostRecentRefreshTimeUpdated();
|
MostRecentRefreshTimeUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "mozilla/RestyleManager.h"
|
#include "mozilla/RestyleManager.h"
|
||||||
#include "mozilla/ServoBindings.h" // Servo_GetProperties_Overriding_Animation
|
#include "mozilla/ServoBindings.h" // Servo_GetProperties_Overriding_Animation
|
||||||
#include "mozilla/ServoStyleSet.h"
|
#include "mozilla/ServoStyleSet.h"
|
||||||
|
#include "mozilla/StaticPrefs_layers.h"
|
||||||
#include "mozilla/StyleAnimationValue.h"
|
#include "mozilla/StyleAnimationValue.h"
|
||||||
#include "mozilla/TypeTraits.h" // For std::forward<>
|
#include "mozilla/TypeTraits.h" // For std::forward<>
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
@ -71,7 +72,7 @@ bool EffectCompositor::AllowCompositorAnimationsOnFrame(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!nsLayoutUtils::AreAsyncAnimationsEnabled()) {
|
if (!nsLayoutUtils::AreAsyncAnimationsEnabled()) {
|
||||||
if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
|
if (StaticPrefs::layers_offmainthreadcomposition_log_animations()) {
|
||||||
nsCString message;
|
nsCString message;
|
||||||
message.AppendLiteral(
|
message.AppendLiteral(
|
||||||
"Performance warning: Async animations are "
|
"Performance warning: Async animations are "
|
||||||
@ -392,6 +393,26 @@ class EffectCompositeOrderComparator {
|
|||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
static void ComposeSortedEffects(
|
||||||
|
const nsTArray<KeyframeEffect*>& aSortedEffects,
|
||||||
|
const EffectSet* aEffectSet, EffectCompositor::CascadeLevel aCascadeLevel,
|
||||||
|
RawServoAnimationValueMap* aAnimationValues) {
|
||||||
|
// If multiple animations affect the same property, animations with higher
|
||||||
|
// composite order (priority) override or add to animations with lower
|
||||||
|
// priority.
|
||||||
|
nsCSSPropertyIDSet propertiesToSkip;
|
||||||
|
if (aEffectSet) {
|
||||||
|
propertiesToSkip =
|
||||||
|
aCascadeLevel == EffectCompositor::CascadeLevel::Animations
|
||||||
|
? aEffectSet->PropertiesForAnimationsLevel().Inverse()
|
||||||
|
: aEffectSet->PropertiesForAnimationsLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (KeyframeEffect* effect : aSortedEffects) {
|
||||||
|
effect->GetAnimation()->ComposeStyle(*aAnimationValues, propertiesToSkip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool EffectCompositor::GetServoAnimationRule(
|
bool EffectCompositor::GetServoAnimationRule(
|
||||||
const dom::Element* aElement, PseudoStyleType aPseudoType,
|
const dom::Element* aElement, PseudoStyleType aPseudoType,
|
||||||
CascadeLevel aCascadeLevel, RawServoAnimationValueMap* aAnimationValues) {
|
CascadeLevel aCascadeLevel, RawServoAnimationValueMap* aAnimationValues) {
|
||||||
@ -415,16 +436,8 @@ bool EffectCompositor::GetServoAnimationRule(
|
|||||||
}
|
}
|
||||||
sortedEffectList.Sort(EffectCompositeOrderComparator());
|
sortedEffectList.Sort(EffectCompositeOrderComparator());
|
||||||
|
|
||||||
// If multiple animations affect the same property, animations with higher
|
ComposeSortedEffects(sortedEffectList, effectSet, aCascadeLevel,
|
||||||
// composite order (priority) override or add or animations with lower
|
aAnimationValues);
|
||||||
// priority.
|
|
||||||
const nsCSSPropertyIDSet propertiesToSkip =
|
|
||||||
aCascadeLevel == CascadeLevel::Animations
|
|
||||||
? effectSet->PropertiesForAnimationsLevel().Inverse()
|
|
||||||
: effectSet->PropertiesForAnimationsLevel();
|
|
||||||
for (KeyframeEffect* effect : sortedEffectList) {
|
|
||||||
effect->GetAnimation()->ComposeStyle(*aAnimationValues, propertiesToSkip);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(effectSet == EffectSet::GetEffectSet(aElement, aPseudoType),
|
MOZ_ASSERT(effectSet == EffectSet::GetEffectSet(aElement, aPseudoType),
|
||||||
"EffectSet should not change while composing style");
|
"EffectSet should not change while composing style");
|
||||||
@ -432,6 +445,59 @@ bool EffectCompositor::GetServoAnimationRule(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EffectCompositor::ComposeServoAnimationRuleForEffect(
|
||||||
|
KeyframeEffect& aEffect, CascadeLevel aCascadeLevel,
|
||||||
|
RawServoAnimationValueMap* aAnimationValues) {
|
||||||
|
MOZ_ASSERT(aAnimationValues);
|
||||||
|
MOZ_ASSERT(mPresContext && mPresContext->IsDynamic(),
|
||||||
|
"Should not be in print preview");
|
||||||
|
|
||||||
|
Maybe<NonOwningAnimationTarget> target = aEffect.GetTarget();
|
||||||
|
if (!target) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't try to compose animations for elements in documents without a pres
|
||||||
|
// shell (e.g. XMLHttpRequest documents).
|
||||||
|
if (!nsContentUtils::GetPresShellForContent(target->mElement)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetServoAnimationRule is called as part of the regular style resolution
|
||||||
|
// where the cascade results are updated in the pre-traversal as needed.
|
||||||
|
// This function, however, is only called when committing styles so we
|
||||||
|
// need to ensure the cascade results are up-to-date manually.
|
||||||
|
EffectCompositor::MaybeUpdateCascadeResults(target->mElement,
|
||||||
|
target->mPseudoType);
|
||||||
|
|
||||||
|
EffectSet* effectSet =
|
||||||
|
EffectSet::GetEffectSet(target->mElement, target->mPseudoType);
|
||||||
|
|
||||||
|
// Get a list of effects sorted by composite order up to and including
|
||||||
|
// |aEffect|, even if it is not in the EffectSet.
|
||||||
|
auto comparator = EffectCompositeOrderComparator();
|
||||||
|
nsTArray<KeyframeEffect*> sortedEffectList(effectSet ? effectSet->Count() + 1
|
||||||
|
: 1);
|
||||||
|
if (effectSet) {
|
||||||
|
for (KeyframeEffect* effect : *effectSet) {
|
||||||
|
if (comparator.LessThan(effect, &aEffect)) {
|
||||||
|
sortedEffectList.AppendElement(effect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sortedEffectList.Sort(comparator);
|
||||||
|
}
|
||||||
|
sortedEffectList.AppendElement(&aEffect);
|
||||||
|
|
||||||
|
ComposeSortedEffects(sortedEffectList, effectSet, aCascadeLevel,
|
||||||
|
aAnimationValues);
|
||||||
|
|
||||||
|
MOZ_ASSERT(effectSet ==
|
||||||
|
EffectSet::GetEffectSet(target->mElement, target->mPseudoType),
|
||||||
|
"EffectSet should not change while composing style");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* static */ dom::Element* EffectCompositor::GetElementToRestyle(
|
/* static */ dom::Element* EffectCompositor::GetElementToRestyle(
|
||||||
dom::Element* aElement, PseudoStyleType aPseudoType) {
|
dom::Element* aElement, PseudoStyleType aPseudoType) {
|
||||||
if (aPseudoType == PseudoStyleType::NotPseudo) {
|
if (aPseudoType == PseudoStyleType::NotPseudo) {
|
||||||
@ -860,4 +926,53 @@ bool EffectCompositor::PreTraverseInSubtree(ServoTraversalFlags aFlags,
|
|||||||
return foundElementsNeedingRestyle;
|
return foundElementsNeedingRestyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EffectCompositor::NoteElementForReducing(
|
||||||
|
const NonOwningAnimationTarget& aTarget) {
|
||||||
|
if (!StaticPrefs::dom_animations_api_autoremove_enabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Unused << mElementsToReduce.put(
|
||||||
|
OwningAnimationTarget{aTarget.mElement, aTarget.mPseudoType});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ReduceEffectSet(EffectSet& aEffectSet) {
|
||||||
|
// Get a list of effects sorted by composite order.
|
||||||
|
nsTArray<KeyframeEffect*> sortedEffectList(aEffectSet.Count());
|
||||||
|
for (KeyframeEffect* effect : aEffectSet) {
|
||||||
|
sortedEffectList.AppendElement(effect);
|
||||||
|
}
|
||||||
|
sortedEffectList.Sort(EffectCompositeOrderComparator());
|
||||||
|
|
||||||
|
nsCSSPropertyIDSet setProperties;
|
||||||
|
|
||||||
|
// Iterate in reverse
|
||||||
|
for (auto iter = sortedEffectList.rbegin(); iter != sortedEffectList.rend();
|
||||||
|
++iter) {
|
||||||
|
MOZ_ASSERT(*iter && (*iter)->GetAnimation(),
|
||||||
|
"Effect in an EffectSet should have an animation");
|
||||||
|
KeyframeEffect& effect = **iter;
|
||||||
|
Animation& animation = *effect.GetAnimation();
|
||||||
|
if (animation.IsRemovable() &&
|
||||||
|
effect.GetPropertySet().IsSubsetOf(setProperties)) {
|
||||||
|
animation.Remove();
|
||||||
|
} else if (animation.IsReplaceable()) {
|
||||||
|
setProperties |= effect.GetPropertySet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectCompositor::ReduceAnimations() {
|
||||||
|
for (auto iter = mElementsToReduce.iter(); !iter.done(); iter.next()) {
|
||||||
|
const OwningAnimationTarget& target = iter.get();
|
||||||
|
EffectSet* effectSet =
|
||||||
|
EffectSet::GetEffectSet(target.mElement, target.mPseudoType);
|
||||||
|
if (effectSet) {
|
||||||
|
ReduceEffectSet(*effectSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mElementsToReduce.clear();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -6,7 +6,9 @@
|
|||||||
#define mozilla_EffectCompositor_h
|
#define mozilla_EffectCompositor_h
|
||||||
|
|
||||||
#include "mozilla/AnimationPerformanceWarning.h"
|
#include "mozilla/AnimationPerformanceWarning.h"
|
||||||
|
#include "mozilla/AnimationTarget.h"
|
||||||
#include "mozilla/EnumeratedArray.h"
|
#include "mozilla/EnumeratedArray.h"
|
||||||
|
#include "mozilla/HashTable.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/OwningNonNull.h"
|
#include "mozilla/OwningNonNull.h"
|
||||||
#include "mozilla/PseudoElementHashEntry.h"
|
#include "mozilla/PseudoElementHashEntry.h"
|
||||||
@ -36,6 +38,7 @@ struct NonOwningAnimationTarget;
|
|||||||
namespace dom {
|
namespace dom {
|
||||||
class Animation;
|
class Animation;
|
||||||
class Element;
|
class Element;
|
||||||
|
class KeyframeEffect;
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
|
||||||
class EffectCompositor {
|
class EffectCompositor {
|
||||||
@ -114,8 +117,9 @@ class EffectCompositor {
|
|||||||
dom::Element* aElement,
|
dom::Element* aElement,
|
||||||
PseudoStyleType aPseudoType);
|
PseudoStyleType aPseudoType);
|
||||||
|
|
||||||
// Get animation rule for stylo. This is an equivalent of GetAnimationRule
|
// Get the animation rule for the appropriate level of the cascade for
|
||||||
// and will be called from servo side.
|
// a (pseudo-)element. Called from the Servo side.
|
||||||
|
//
|
||||||
// The animation rule is stored in |RawServoAnimationValueMap|.
|
// The animation rule is stored in |RawServoAnimationValueMap|.
|
||||||
// We need to be careful while doing any modification because it may cause
|
// We need to be careful while doing any modification because it may cause
|
||||||
// some thread-safe issues.
|
// some thread-safe issues.
|
||||||
@ -124,6 +128,15 @@ class EffectCompositor {
|
|||||||
CascadeLevel aCascadeLevel,
|
CascadeLevel aCascadeLevel,
|
||||||
RawServoAnimationValueMap* aAnimationValues);
|
RawServoAnimationValueMap* aAnimationValues);
|
||||||
|
|
||||||
|
// A variant on GetServoAnimationRule that composes all the effects for an
|
||||||
|
// element up to and including |aEffect|.
|
||||||
|
//
|
||||||
|
// Note that |aEffect| might not be in the EffectSet since we can use this for
|
||||||
|
// committing the computed style of a removed Animation.
|
||||||
|
bool ComposeServoAnimationRuleForEffect(
|
||||||
|
dom::KeyframeEffect& aEffect, CascadeLevel aCascadeLevel,
|
||||||
|
RawServoAnimationValueMap* aAnimationValues);
|
||||||
|
|
||||||
bool HasPendingStyleUpdates() const;
|
bool HasPendingStyleUpdates() const;
|
||||||
|
|
||||||
static bool HasAnimationsForCompositor(const nsIFrame* aFrame,
|
static bool HasAnimationsForCompositor(const nsIFrame* aFrame,
|
||||||
@ -197,6 +210,12 @@ class EffectCompositor {
|
|||||||
// at aElement.
|
// at aElement.
|
||||||
bool PreTraverseInSubtree(ServoTraversalFlags aFlags, dom::Element* aRoot);
|
bool PreTraverseInSubtree(ServoTraversalFlags aFlags, dom::Element* aRoot);
|
||||||
|
|
||||||
|
// Record a (pseudo-)element that may have animations that can be removed.
|
||||||
|
void NoteElementForReducing(const NonOwningAnimationTarget& aTarget);
|
||||||
|
|
||||||
|
bool NeedsReducing() const { return !mElementsToReduce.empty(); }
|
||||||
|
void ReduceAnimations();
|
||||||
|
|
||||||
// Returns the target element for restyling.
|
// Returns the target element for restyling.
|
||||||
//
|
//
|
||||||
// If |aPseudoType| is ::after, ::before or ::marker, returns the generated
|
// If |aPseudoType| is ::after, ::before or ::marker, returns the generated
|
||||||
@ -237,6 +256,8 @@ class EffectCompositor {
|
|||||||
mElementsToRestyle;
|
mElementsToRestyle;
|
||||||
|
|
||||||
bool mIsInPreTraverse = false;
|
bool mIsInPreTraverse = false;
|
||||||
|
|
||||||
|
HashSet<OwningAnimationTarget> mElementsToReduce;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
// For UnrestrictedDoubleOrKeyframeAnimationOptions;
|
// For UnrestrictedDoubleOrKeyframeAnimationOptions;
|
||||||
#include "mozilla/dom/CSSPseudoElement.h"
|
#include "mozilla/dom/CSSPseudoElement.h"
|
||||||
#include "mozilla/dom/KeyframeEffectBinding.h"
|
#include "mozilla/dom/KeyframeEffectBinding.h"
|
||||||
|
#include "mozilla/dom/MutationObservers.h"
|
||||||
#include "mozilla/AnimationUtils.h"
|
#include "mozilla/AnimationUtils.h"
|
||||||
#include "mozilla/AutoRestore.h"
|
#include "mozilla/AutoRestore.h"
|
||||||
#include "mozilla/ComputedStyleInlines.h"
|
#include "mozilla/ComputedStyleInlines.h"
|
||||||
@ -21,7 +22,9 @@
|
|||||||
#include "mozilla/PresShell.h"
|
#include "mozilla/PresShell.h"
|
||||||
#include "mozilla/PresShellInlines.h"
|
#include "mozilla/PresShellInlines.h"
|
||||||
#include "mozilla/ServoBindings.h"
|
#include "mozilla/ServoBindings.h"
|
||||||
#include "mozilla/StaticPrefs.h"
|
#include "mozilla/StaticPrefs_dom.h"
|
||||||
|
#include "mozilla/StaticPrefs_gfx.h"
|
||||||
|
#include "mozilla/StaticPrefs_layers.h"
|
||||||
#include "mozilla/TypeTraits.h"
|
#include "mozilla/TypeTraits.h"
|
||||||
#include "Layers.h" // For Layer
|
#include "Layers.h" // For Layer
|
||||||
#include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetComputedStyle
|
#include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetComputedStyle
|
||||||
@ -31,7 +34,6 @@
|
|||||||
#include "nsCSSPseudoElements.h" // For PseudoStyleType
|
#include "nsCSSPseudoElements.h" // For PseudoStyleType
|
||||||
#include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
|
#include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
|
||||||
#include "nsIFrame.h"
|
#include "nsIFrame.h"
|
||||||
#include "nsIScriptError.h"
|
|
||||||
#include "nsPresContextInlines.h"
|
#include "nsPresContextInlines.h"
|
||||||
#include "nsRefreshDriver.h"
|
#include "nsRefreshDriver.h"
|
||||||
|
|
||||||
@ -46,7 +48,7 @@ void AnimationProperty::SetPerformanceWarning(
|
|||||||
mPerformanceWarning = Some(aWarning);
|
mPerformanceWarning = Some(aWarning);
|
||||||
|
|
||||||
nsAutoString localizedString;
|
nsAutoString localizedString;
|
||||||
if (nsLayoutUtils::IsAnimationLoggingEnabled() &&
|
if (StaticPrefs::layers_offmainthreadcomposition_log_animations() &&
|
||||||
mPerformanceWarning->ToLocalizedString(localizedString)) {
|
mPerformanceWarning->ToLocalizedString(localizedString)) {
|
||||||
nsAutoCString logMessage = NS_ConvertUTF16toUTF8(localizedString);
|
nsAutoCString logMessage = NS_ConvertUTF16toUTF8(localizedString);
|
||||||
AnimationUtils::LogAsyncAnimationFailure(logMessage, aElement);
|
AnimationUtils::LogAsyncAnimationFailure(logMessage, aElement);
|
||||||
@ -105,7 +107,7 @@ void KeyframeEffect::SetIterationComposite(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mAnimation && mAnimation->IsRelevant()) {
|
if (mAnimation && mAnimation->IsRelevant()) {
|
||||||
nsNodeUtils::AnimationChanged(mAnimation);
|
MutationObservers::NotifyAnimationChanged(mAnimation);
|
||||||
}
|
}
|
||||||
|
|
||||||
mEffectOptions.mIterationComposite = aIterationComposite;
|
mEffectOptions.mIterationComposite = aIterationComposite;
|
||||||
@ -124,7 +126,7 @@ void KeyframeEffect::SetComposite(const CompositeOperation& aComposite) {
|
|||||||
mEffectOptions.mComposite = aComposite;
|
mEffectOptions.mComposite = aComposite;
|
||||||
|
|
||||||
if (mAnimation && mAnimation->IsRelevant()) {
|
if (mAnimation && mAnimation->IsRelevant()) {
|
||||||
nsNodeUtils::AnimationChanged(mAnimation);
|
MutationObservers::NotifyAnimationChanged(mAnimation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mTarget) {
|
if (mTarget) {
|
||||||
@ -145,7 +147,7 @@ void KeyframeEffect::NotifySpecifiedTimingUpdated() {
|
|||||||
mAnimation->NotifyEffectTimingUpdated();
|
mAnimation->NotifyEffectTimingUpdated();
|
||||||
|
|
||||||
if (mAnimation->IsRelevant()) {
|
if (mAnimation->IsRelevant()) {
|
||||||
nsNodeUtils::AnimationChanged(mAnimation);
|
MutationObservers::NotifyAnimationChanged(mAnimation);
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestRestyle(EffectCompositor::RestyleType::Layer);
|
RequestRestyle(EffectCompositor::RestyleType::Layer);
|
||||||
@ -238,7 +240,7 @@ void KeyframeEffect::SetKeyframes(nsTArray<Keyframe>&& aKeyframes,
|
|||||||
KeyframeUtils::DistributeKeyframes(mKeyframes);
|
KeyframeUtils::DistributeKeyframes(mKeyframes);
|
||||||
|
|
||||||
if (mAnimation && mAnimation->IsRelevant()) {
|
if (mAnimation && mAnimation->IsRelevant()) {
|
||||||
nsNodeUtils::AnimationChanged(mAnimation);
|
MutationObservers::NotifyAnimationChanged(mAnimation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to call UpdateProperties() unless the target element doesn't have
|
// We need to call UpdateProperties() unless the target element doesn't have
|
||||||
@ -315,7 +317,7 @@ nsCSSPropertyIDSet KeyframeEffect::GetPropertiesForCompositor(
|
|||||||
|
|
||||||
nsCSSPropertyIDSet properties;
|
nsCSSPropertyIDSet properties;
|
||||||
|
|
||||||
if (!IsInEffect() && !IsCurrent()) {
|
if (!mAnimation || !mAnimation->IsRelevant()) {
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,14 +342,14 @@ nsCSSPropertyIDSet KeyframeEffect::GetPropertiesForCompositor(
|
|||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KeyframeEffect::HasAnimationOfPropertySet(
|
nsCSSPropertyIDSet KeyframeEffect::GetPropertySet() const {
|
||||||
const nsCSSPropertyIDSet& aPropertySet) const {
|
nsCSSPropertyIDSet result;
|
||||||
|
|
||||||
for (const AnimationProperty& property : mProperties) {
|
for (const AnimationProperty& property : mProperties) {
|
||||||
if (aPropertySet.HasProperty(property.mProperty)) {
|
result.AddProperty(property.mProperty);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@ -416,6 +418,10 @@ void KeyframeEffect::UpdateProperties(const ComputedStyle* aStyle) {
|
|||||||
|
|
||||||
MarkCascadeNeedsUpdate();
|
MarkCascadeNeedsUpdate();
|
||||||
|
|
||||||
|
if (mAnimation) {
|
||||||
|
mAnimation->NotifyEffectPropertiesUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
RequestRestyle(EffectCompositor::RestyleType::Layer);
|
RequestRestyle(EffectCompositor::RestyleType::Layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -573,13 +579,10 @@ void KeyframeEffect::ComposeStyle(RawServoAnimationValueMap& aComposeResult,
|
|||||||
if (HasPropertiesThatMightAffectOverflow()) {
|
if (HasPropertiesThatMightAffectOverflow()) {
|
||||||
nsPresContext* presContext =
|
nsPresContext* presContext =
|
||||||
nsContentUtils::GetContextForContent(mTarget->mElement);
|
nsContentUtils::GetContextForContent(mTarget->mElement);
|
||||||
if (presContext) {
|
EffectSet* effectSet =
|
||||||
|
EffectSet::GetEffectSet(mTarget->mElement, mTarget->mPseudoType);
|
||||||
|
if (presContext && effectSet) {
|
||||||
TimeStamp now = presContext->RefreshDriver()->MostRecentRefresh();
|
TimeStamp now = presContext->RefreshDriver()->MostRecentRefresh();
|
||||||
EffectSet* effectSet =
|
|
||||||
EffectSet::GetEffectSet(mTarget->mElement, mTarget->mPseudoType);
|
|
||||||
MOZ_ASSERT(effectSet,
|
|
||||||
"ComposeStyle should only be called on an effect "
|
|
||||||
"that is part of an effect set");
|
|
||||||
effectSet->UpdateLastOverflowAnimationSyncTime(now);
|
effectSet->UpdateLastOverflowAnimationSyncTime(now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -790,7 +793,9 @@ void KeyframeEffect::UpdateTargetRegistration() {
|
|||||||
// something calls Animation::UpdateRelevance. Whenever our timing changes,
|
// something calls Animation::UpdateRelevance. Whenever our timing changes,
|
||||||
// we should be notifying our Animation before calling this, so
|
// we should be notifying our Animation before calling this, so
|
||||||
// Animation::IsRelevant() should be up-to-date by the time we get here.
|
// Animation::IsRelevant() should be up-to-date by the time we get here.
|
||||||
MOZ_ASSERT(isRelevant == IsCurrent() || IsInEffect(),
|
MOZ_ASSERT(isRelevant ==
|
||||||
|
((IsCurrent() || IsInEffect()) && mAnimation &&
|
||||||
|
mAnimation->ReplaceState() != AnimationReplaceState::Removed),
|
||||||
"Out of date Animation::IsRelevant value");
|
"Out of date Animation::IsRelevant value");
|
||||||
|
|
||||||
if (isRelevant && !mInEffectSet) {
|
if (isRelevant && !mInEffectSet) {
|
||||||
@ -976,7 +981,7 @@ void KeyframeEffect::SetTarget(
|
|||||||
|
|
||||||
nsAutoAnimationMutationBatch mb(mTarget->mElement->OwnerDoc());
|
nsAutoAnimationMutationBatch mb(mTarget->mElement->OwnerDoc());
|
||||||
if (mAnimation) {
|
if (mAnimation) {
|
||||||
nsNodeUtils::AnimationRemoved(mAnimation);
|
MutationObservers::NotifyAnimationRemoved(mAnimation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -993,10 +998,14 @@ void KeyframeEffect::SetTarget(
|
|||||||
|
|
||||||
nsAutoAnimationMutationBatch mb(mTarget->mElement->OwnerDoc());
|
nsAutoAnimationMutationBatch mb(mTarget->mElement->OwnerDoc());
|
||||||
if (mAnimation) {
|
if (mAnimation) {
|
||||||
nsNodeUtils::AnimationAdded(mAnimation);
|
MutationObservers::NotifyAnimationAdded(mAnimation);
|
||||||
mAnimation->ReschedulePendingTasks();
|
mAnimation->ReschedulePendingTasks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mAnimation) {
|
||||||
|
mAnimation->NotifyEffectTargetUpdated();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CreatePropertyValue(
|
static void CreatePropertyValue(
|
||||||
@ -1726,6 +1735,11 @@ bool KeyframeEffect::ContainsAnimatedScale(const nsIFrame* aFrame) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!mAnimation ||
|
||||||
|
mAnimation->ReplaceState() == AnimationReplaceState::Removed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (const AnimationProperty& prop : mProperties) {
|
for (const AnimationProperty& prop : mProperties) {
|
||||||
if (prop.mProperty != eCSSProperty_transform &&
|
if (prop.mProperty != eCSSProperty_transform &&
|
||||||
prop.mProperty != eCSSProperty_scale &&
|
prop.mProperty != eCSSProperty_scale &&
|
||||||
|
@ -72,7 +72,7 @@ struct AnimationProperty {
|
|||||||
|
|
||||||
Maybe<AnimationPerformanceWarning> mPerformanceWarning;
|
Maybe<AnimationPerformanceWarning> mPerformanceWarning;
|
||||||
|
|
||||||
InfallibleTArray<AnimationPropertySegment> mSegments;
|
nsTArray<AnimationPropertySegment> mSegments;
|
||||||
|
|
||||||
// The copy constructor/assignment doesn't copy mIsRunningOnCompositor and
|
// The copy constructor/assignment doesn't copy mIsRunningOnCompositor and
|
||||||
// mPerformanceWarning.
|
// mPerformanceWarning.
|
||||||
@ -99,7 +99,7 @@ struct AnimationProperty {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SetPerformanceWarning(const AnimationPerformanceWarning& aWarning,
|
void SetPerformanceWarning(const AnimationPerformanceWarning& aWarning,
|
||||||
const Element* aElement);
|
const dom::Element* aElement);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ElementPropertyTransition;
|
struct ElementPropertyTransition;
|
||||||
@ -181,9 +181,15 @@ class KeyframeEffect : public AnimationEffect {
|
|||||||
void SetKeyframes(nsTArray<Keyframe>&& aKeyframes,
|
void SetKeyframes(nsTArray<Keyframe>&& aKeyframes,
|
||||||
const ComputedStyle* aStyle);
|
const ComputedStyle* aStyle);
|
||||||
|
|
||||||
|
// Returns the set of properties affected by this effect regardless of
|
||||||
|
// whether any of these properties is overridden by an !important rule.
|
||||||
|
nsCSSPropertyIDSet GetPropertySet() const;
|
||||||
|
|
||||||
// Returns true if the effect includes a property in |aPropertySet| regardless
|
// Returns true if the effect includes a property in |aPropertySet| regardless
|
||||||
// of whether any property in the set is overridden by !important rule.
|
// of whether any property in the set is overridden by an !important rule.
|
||||||
bool HasAnimationOfPropertySet(const nsCSSPropertyIDSet& aPropertySet) const;
|
bool HasAnimationOfPropertySet(const nsCSSPropertyIDSet& aPropertySet) const {
|
||||||
|
return GetPropertySet().Intersects(aPropertySet);
|
||||||
|
}
|
||||||
|
|
||||||
// GetEffectiveAnimationOfProperty returns AnimationProperty corresponding
|
// GetEffectiveAnimationOfProperty returns AnimationProperty corresponding
|
||||||
// to a given CSS property if the effect includes the property and the
|
// to a given CSS property if the effect includes the property and the
|
||||||
@ -237,9 +243,7 @@ class KeyframeEffect : public AnimationEffect {
|
|||||||
nsCSSPropertyIDSet GetPropertiesForCompositor(EffectSet& aEffects,
|
nsCSSPropertyIDSet GetPropertiesForCompositor(EffectSet& aEffects,
|
||||||
const nsIFrame* aFrame) const;
|
const nsIFrame* aFrame) const;
|
||||||
|
|
||||||
const InfallibleTArray<AnimationProperty>& Properties() const {
|
const nsTArray<AnimationProperty>& Properties() const { return mProperties; }
|
||||||
return mProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update |mProperties| by recalculating from |mKeyframes| using
|
// Update |mProperties| by recalculating from |mKeyframes| using
|
||||||
// |aComputedStyle| to resolve specified values.
|
// |aComputedStyle| to resolve specified values.
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#include "mozilla/ServoBindingTypes.h"
|
#include "mozilla/ServoBindingTypes.h"
|
||||||
#include "mozilla/ServoCSSParser.h"
|
#include "mozilla/ServoCSSParser.h"
|
||||||
#include "mozilla/StyleAnimationValue.h"
|
#include "mozilla/StyleAnimationValue.h"
|
||||||
#include "mozilla/StaticPrefs.h"
|
#include "mozilla/StaticPrefs_dom.h"
|
||||||
#include "mozilla/TimingParams.h"
|
#include "mozilla/TimingParams.h"
|
||||||
#include "mozilla/dom/BaseKeyframeTypesBinding.h" // For FastBaseKeyframe etc.
|
#include "mozilla/dom/BaseKeyframeTypesBinding.h" // For FastBaseKeyframe etc.
|
||||||
#include "mozilla/dom/Document.h" // For Document::AreWebAnimationsImplicitKeyframesEnabled
|
#include "mozilla/dom/Document.h" // For Document::AreWebAnimationsImplicitKeyframesEnabled
|
||||||
@ -365,8 +365,8 @@ static void GetKeyframeListFromKeyframeSequence(JSContext* aCx,
|
|||||||
// Check that the keyframes are loosely sorted and with values all
|
// Check that the keyframes are loosely sorted and with values all
|
||||||
// between 0% and 100%.
|
// between 0% and 100%.
|
||||||
if (!HasValidOffsets(aResult)) {
|
if (!HasValidOffsets(aResult)) {
|
||||||
aRv.ThrowTypeError<dom::MSG_INVALID_KEYFRAME_OFFSETS>();
|
|
||||||
aResult.Clear();
|
aResult.Clear();
|
||||||
|
aRv.ThrowTypeError<dom::MSG_INVALID_KEYFRAME_OFFSETS>();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -500,7 +500,7 @@ static bool GetPropertyValuesPairs(JSContext* aCx,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (size_t i = 0, n = ids.length(); i < n; i++) {
|
for (size_t i = 0, n = ids.length(); i < n; i++) {
|
||||||
nsAutoJSString propName;
|
nsAutoJSCString propName;
|
||||||
if (!propName.init(aCx, ids[i])) {
|
if (!propName.init(aCx, ids[i])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -591,14 +591,13 @@ static bool AppendValueAsString(JSContext* aCx, nsTArray<nsString>& aValues,
|
|||||||
static void ReportInvalidPropertyValueToConsole(
|
static void ReportInvalidPropertyValueToConsole(
|
||||||
nsCSSPropertyID aProperty, const nsAString& aInvalidPropertyValue,
|
nsCSSPropertyID aProperty, const nsAString& aInvalidPropertyValue,
|
||||||
dom::Document* aDoc) {
|
dom::Document* aDoc) {
|
||||||
const nsString& invalidValue = PromiseFlatString(aInvalidPropertyValue);
|
AutoTArray<nsString, 2> params;
|
||||||
const NS_ConvertASCIItoUTF16 propertyName(
|
params.AppendElement(aInvalidPropertyValue);
|
||||||
nsCSSProps::GetStringValue(aProperty));
|
CopyASCIItoUTF16(nsCSSProps::GetStringValue(aProperty),
|
||||||
const char16_t* params[] = {invalidValue.get(), propertyName.get()};
|
*params.AppendElement());
|
||||||
nsContentUtils::ReportToConsole(
|
nsContentUtils::ReportToConsole(
|
||||||
nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Animation"), aDoc,
|
nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Animation"), aDoc,
|
||||||
nsContentUtils::eDOM_PROPERTIES, "InvalidKeyframePropertyValue", params,
|
nsContentUtils::eDOM_PROPERTIES, "InvalidKeyframePropertyValue", params);
|
||||||
ArrayLength(params));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1057,8 +1056,8 @@ static void GetKeyframeListFromPropertyIndexedKeyframe(
|
|||||||
// offsets are thrown before exceptions arising from invalid easings, we check
|
// offsets are thrown before exceptions arising from invalid easings, we check
|
||||||
// the offsets here.
|
// the offsets here.
|
||||||
if (!HasValidOffsets(aResult)) {
|
if (!HasValidOffsets(aResult)) {
|
||||||
aRv.ThrowTypeError<dom::MSG_INVALID_KEYFRAME_OFFSETS>();
|
|
||||||
aResult.Clear();
|
aResult.Clear();
|
||||||
|
aRv.ThrowTypeError<dom::MSG_INVALID_KEYFRAME_OFFSETS>();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
prefs =
|
prefs =
|
||||||
|
dom.animations-api.autoremove.enabled=true
|
||||||
dom.animations-api.compositing.enabled=true
|
dom.animations-api.compositing.enabled=true
|
||||||
gfx.omta.background-color=true
|
gfx.omta.background-color=true
|
||||||
layout.css.individual-transform.enabled=true
|
layout.css.individual-transform.enabled=true
|
||||||
|
@ -40,6 +40,7 @@ var gObserver = new MutationObserver(newRecords => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function setupAsynchronousObserver(t, options) {
|
function setupAsynchronousObserver(t, options) {
|
||||||
|
|
||||||
gRecords = [];
|
gRecords = [];
|
||||||
t.add_cleanup(() => {
|
t.add_cleanup(() => {
|
||||||
gObserver.disconnect();
|
gObserver.disconnect();
|
||||||
@ -578,5 +579,86 @@ promise_test(t => {
|
|||||||
});
|
});
|
||||||
}, "tree_ordering: subtree");
|
}, "tree_ordering: subtree");
|
||||||
|
|
||||||
runTest();
|
// Test that animations removed by auto-removal trigger an event
|
||||||
|
promise_test(async t => {
|
||||||
|
setupAsynchronousObserver(t, { observe: div, subtree: false });
|
||||||
|
|
||||||
|
// Start two animations such that one will be auto-removed
|
||||||
|
const animA = div.animate(
|
||||||
|
{ opacity: 1 },
|
||||||
|
{ duration: 100 * MS_PER_SEC, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
const animB = div.animate(
|
||||||
|
{ opacity: 1 },
|
||||||
|
{ duration: 100 * MS_PER_SEC, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Wait for the MutationRecords corresponding to each addition.
|
||||||
|
await waitForNextFrame();
|
||||||
|
|
||||||
|
assert_records(
|
||||||
|
[
|
||||||
|
{ added: [animA], changed: [], removed: [] },
|
||||||
|
{ added: [animB], changed: [], removed: [] },
|
||||||
|
],
|
||||||
|
'records after animation start'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Finish the animations -- this should cause animA to be replaced, and
|
||||||
|
// automatically removed.
|
||||||
|
animA.finish();
|
||||||
|
animB.finish();
|
||||||
|
|
||||||
|
// Wait for the MutationRecords corresponding to the timing changes and the
|
||||||
|
// subsequent removal to be delivered.
|
||||||
|
await waitForNextFrame();
|
||||||
|
|
||||||
|
assert_records(
|
||||||
|
[
|
||||||
|
{ added: [], changed: [animA], removed: [] },
|
||||||
|
{ added: [], changed: [animB], removed: [] },
|
||||||
|
{ added: [], changed: [], removed: [animA] },
|
||||||
|
],
|
||||||
|
'records after finishing'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Restore animA.
|
||||||
|
animA.persist();
|
||||||
|
|
||||||
|
// Wait for the MutationRecord corresponding to the re-addition of animA.
|
||||||
|
await waitForNextFrame();
|
||||||
|
|
||||||
|
assert_records(
|
||||||
|
[{ added: [animA], changed: [], removed: [] }],
|
||||||
|
'records after persisting'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Tidy up
|
||||||
|
animA.cancel();
|
||||||
|
animB.cancel();
|
||||||
|
|
||||||
|
await waitForNextFrame();
|
||||||
|
|
||||||
|
assert_records(
|
||||||
|
[
|
||||||
|
{ added: [], changed: [], removed: [animA] },
|
||||||
|
{ added: [], changed: [], removed: [animB] },
|
||||||
|
],
|
||||||
|
'records after tidying up end'
|
||||||
|
);
|
||||||
|
}, 'Animations automatically removed are reported');
|
||||||
|
|
||||||
|
setup({explicit_done: true});
|
||||||
|
SpecialPowers.pushPrefEnv(
|
||||||
|
{
|
||||||
|
set: [
|
||||||
|
["dom.animations-api.autoremove.enabled", true],
|
||||||
|
["dom.animations-api.implicit-keyframes.enabled", true],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
runTest();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
@ -43,7 +43,7 @@ function setupSynchronousObserver(t, target, subtree) {
|
|||||||
t.add_cleanup(() => {
|
t.add_cleanup(() => {
|
||||||
observer.disconnect();
|
observer.disconnect();
|
||||||
});
|
});
|
||||||
observer.observe(target, { animations: true, subtree: subtree });
|
observer.observe(target, { animations: true, subtree });
|
||||||
return observer;
|
return observer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ function assert_properties_equal(actual, expected) {
|
|||||||
|
|
||||||
// Shorthand for constructing a value object
|
// Shorthand for constructing a value object
|
||||||
function value(offset, value, composite, easing) {
|
function value(offset, value, composite, easing) {
|
||||||
return { offset: offset, value: value, easing: easing, composite: composite };
|
return { offset, value, easing, composite };
|
||||||
}
|
}
|
||||||
|
|
||||||
var gTests = [
|
var gTests = [
|
||||||
|
@ -14,6 +14,7 @@ support-files =
|
|||||||
chrome/file_animate_xrays.html
|
chrome/file_animate_xrays.html
|
||||||
mozilla/xhr_doc.html
|
mozilla/xhr_doc.html
|
||||||
mozilla/file_deferred_start.html
|
mozilla/file_deferred_start.html
|
||||||
|
mozilla/file_disable_animations_api_autoremove.html
|
||||||
mozilla/file_disable_animations_api_compositing.html
|
mozilla/file_disable_animations_api_compositing.html
|
||||||
mozilla/file_disable_animations_api_get_animations.html
|
mozilla/file_disable_animations_api_get_animations.html
|
||||||
mozilla/file_disable_animations_api_implicit_keyframes.html
|
mozilla/file_disable_animations_api_implicit_keyframes.html
|
||||||
@ -32,6 +33,7 @@ skip-if = (verify && !debug && (os == 'mac'))
|
|||||||
[mozilla/test_cubic_bezier_limits.html]
|
[mozilla/test_cubic_bezier_limits.html]
|
||||||
[mozilla/test_deferred_start.html]
|
[mozilla/test_deferred_start.html]
|
||||||
skip-if = (toolkit == 'android' && debug) || (os == 'win' && bits == 64) # Bug 1363957
|
skip-if = (toolkit == 'android' && debug) || (os == 'win' && bits == 64) # Bug 1363957
|
||||||
|
[mozilla/test_disable_animations_api_autoremove.html]
|
||||||
[mozilla/test_disable_animations_api_compositing.html]
|
[mozilla/test_disable_animations_api_compositing.html]
|
||||||
[mozilla/test_disable_animations_api_get_animations.html]
|
[mozilla/test_disable_animations_api_get_animations.html]
|
||||||
[mozilla/test_disable_animations_api_implicit_keyframes.html]
|
[mozilla/test_disable_animations_api_implicit_keyframes.html]
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<script src="../testcommon.js"></script>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const div = addDiv(t);
|
||||||
|
|
||||||
|
const animA = div.animate({ opacity: 1 }, { duration: 1, fill: 'forwards' });
|
||||||
|
const animB = div.animate({ opacity: 1 }, { duration: 1, fill: 'forwards' });
|
||||||
|
|
||||||
|
// This should be assert_not_own_property but our local copy of testharness.js
|
||||||
|
// is old.
|
||||||
|
assert_equals(
|
||||||
|
animA.replaceState,
|
||||||
|
undefined,
|
||||||
|
'Should not have a replaceState member'
|
||||||
|
);
|
||||||
|
|
||||||
|
animA.addEventListener(
|
||||||
|
'remove',
|
||||||
|
t.step_func(() => {
|
||||||
|
assert_unreached('Should not fire a remove event');
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Allow a chance for the remove event to be fired
|
||||||
|
|
||||||
|
await animA.finished;
|
||||||
|
await waitForNextFrame();
|
||||||
|
}, 'Remove events should not be fired if the pref is not set');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const div = addDiv(t);
|
||||||
|
div.style.opacity = '0.1';
|
||||||
|
|
||||||
|
const animA = div.animate(
|
||||||
|
{ opacity: 0.2 },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
const animB = div.animate(
|
||||||
|
{ opacity: 0.3, composite: 'add' },
|
||||||
|
{ duration: 1, fill: 'forwards' }
|
||||||
|
);
|
||||||
|
|
||||||
|
await animA.finished;
|
||||||
|
|
||||||
|
assert_approx_equals(
|
||||||
|
parseFloat(getComputedStyle(div).opacity),
|
||||||
|
0.5,
|
||||||
|
0.0001,
|
||||||
|
'Covered animation should still contribute to effect stack when adding'
|
||||||
|
);
|
||||||
|
|
||||||
|
animB.cancel();
|
||||||
|
|
||||||
|
assert_approx_equals(
|
||||||
|
parseFloat(getComputedStyle(div).opacity),
|
||||||
|
0.2,
|
||||||
|
0.0001,
|
||||||
|
'Covered animation should still contribute to animated style when replacing'
|
||||||
|
);
|
||||||
|
}, 'Covered animations should still affect style if the pref is not set');
|
||||||
|
|
||||||
|
done();
|
||||||
|
</script>
|
||||||
|
</body>
|
@ -0,0 +1,15 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<div id="log"></div>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
setup({ explicit_done: true });
|
||||||
|
SpecialPowers.pushPrefEnv(
|
||||||
|
{ set: [['dom.animations-api.autoremove.enabled', false]] },
|
||||||
|
function() {
|
||||||
|
window.open('file_disable_animations_api_autoremove.html');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
@ -13,20 +13,20 @@ function waitForSetPref(pref, value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These tests rely on the fact that the -webkit-text-fill-color property
|
* These tests rely on the fact that the -webkit-line-clamp property is
|
||||||
* is disabled by the layout.css.prefixes.webkit pref. If we ever remove that
|
* disabled by the layout.css.webkit-line-clamp.enabled pref. If we ever remove
|
||||||
* pref we will need to substitute some other pref:property combination.
|
* that pref we will need to substitute some other pref:property combination.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
promise_test(function(t) {
|
promise_test(function(t) {
|
||||||
return waitForSetPref('layout.css.prefixes.webkit', true).then(() => {
|
return waitForSetPref('layout.css.webkit-line-clamp.enabled', true).then(() => {
|
||||||
var anim = addDiv(t).animate({ webkitTextFillColor: [ 'green', 'blue' ]});
|
var anim = addDiv(t).animate({ webkitLineClamp: [ '2', '4' ]});
|
||||||
assert_equals(anim.effect.getKeyframes().length, 2,
|
assert_equals(anim.effect.getKeyframes().length, 2,
|
||||||
'A property-indexed keyframe specifying only enabled'
|
'A property-indexed keyframe specifying only enabled'
|
||||||
+ ' properties produces keyframes');
|
+ ' properties produces keyframes');
|
||||||
return waitForSetPref('layout.css.prefixes.webkit', false);
|
return waitForSetPref('layout.css.webkit-line-clamp.enabled', false);
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
var anim = addDiv(t).animate({ webkitTextFillColor: [ 'green', 'blue' ]});
|
var anim = addDiv(t).animate({ webkitLineClamp: [ '2', '4' ]});
|
||||||
assert_equals(anim.effect.getKeyframes().length, 0,
|
assert_equals(anim.effect.getKeyframes().length, 0,
|
||||||
'A property-indexed keyframe specifying only disabled'
|
'A property-indexed keyframe specifying only disabled'
|
||||||
+ ' properties produces no keyframes');
|
+ ' properties produces no keyframes');
|
||||||
@ -35,8 +35,8 @@ promise_test(function(t) {
|
|||||||
|
|
||||||
promise_test(function(t) {
|
promise_test(function(t) {
|
||||||
var createAnim = () => {
|
var createAnim = () => {
|
||||||
var anim = addDiv(t).animate([ { webkitTextFillColor: 'green' },
|
var anim = addDiv(t).animate([ { webkitLineClamp: '2' },
|
||||||
{ webkitTextFillColor: 'blue' } ]);
|
{ webkitLineClamp: '4' } ]);
|
||||||
assert_equals(anim.effect.getKeyframes().length, 2,
|
assert_equals(anim.effect.getKeyframes().length, 2,
|
||||||
'Animation specified using a keyframe sequence should'
|
'Animation specified using a keyframe sequence should'
|
||||||
+ ' return the same number of keyframes regardless of'
|
+ ' return the same number of keyframes regardless of'
|
||||||
@ -55,17 +55,17 @@ promise_test(function(t) {
|
|||||||
`${descr} should NOT have the '${property}' property`);
|
`${descr} should NOT have the '${property}' property`);
|
||||||
};
|
};
|
||||||
|
|
||||||
return waitForSetPref('layout.css.prefixes.webkit', true).then(() => {
|
return waitForSetPref('layout.css.webkit-line-clamp.enabled', true).then(() => {
|
||||||
var anim = createAnim();
|
var anim = createAnim();
|
||||||
assert_has_property(anim, 0, 'Initial keyframe', 'webkitTextFillColor');
|
assert_has_property(anim, 0, 'Initial keyframe', 'webkitLineClamp');
|
||||||
assert_has_property(anim, 1, 'Final keyframe', 'webkitTextFillColor');
|
assert_has_property(anim, 1, 'Final keyframe', 'webkitLineClamp');
|
||||||
return waitForSetPref('layout.css.prefixes.webkit', false);
|
return waitForSetPref('layout.css.webkit-line-clamp.enabled', false);
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
var anim = createAnim();
|
var anim = createAnim();
|
||||||
assert_does_not_have_property(anim, 0, 'Initial keyframe',
|
assert_does_not_have_property(anim, 0, 'Initial keyframe',
|
||||||
'webkitTextFillColor');
|
'webkitLineClamp');
|
||||||
assert_does_not_have_property(anim, 1, 'Final keyframe',
|
assert_does_not_have_property(anim, 1, 'Final keyframe',
|
||||||
'webkitTextFillColor');
|
'webkitLineClamp');
|
||||||
});
|
});
|
||||||
}, 'Specifying a disabled property using a keyframe sequence');
|
}, 'Specifying a disabled property using a keyframe sequence');
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ setup({explicit_done: true});
|
|||||||
SpecialPowers.pushPrefEnv(
|
SpecialPowers.pushPrefEnv(
|
||||||
{ "set": [
|
{ "set": [
|
||||||
["layout.css.osx-font-smoothing.enabled", true],
|
["layout.css.osx-font-smoothing.enabled", true],
|
||||||
["layout.css.prefixes.webkit", true]
|
|
||||||
] },
|
] },
|
||||||
function() {
|
function() {
|
||||||
window.open("file_discrete_animations.html");
|
window.open("file_discrete_animations.html");
|
||||||
|
@ -60,7 +60,7 @@ const testcases = [
|
|||||||
property: "-moz-user-modify"
|
property: "-moz-user-modify"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
property: "-moz-user-select"
|
property: "user-select"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
property: "-moz-window-dragging"
|
property: "-moz-window-dragging"
|
||||||
|
@ -29,7 +29,7 @@ test(function(t) {
|
|||||||
sandbox.importFunction(document, "document");
|
sandbox.importFunction(document, "document");
|
||||||
sandbox.importFunction(assert_true, "assert_true");
|
sandbox.importFunction(assert_true, "assert_true");
|
||||||
sandbox.importFunction(assert_unreached, "assert_unreached");
|
sandbox.importFunction(assert_unreached, "assert_unreached");
|
||||||
SpecialPowers.Cu.evalInSandbox(`(${contentScript.toSource()})()`, sandbox);
|
SpecialPowers.Cu.evalInSandbox(`(${contentScript.toString()})()`, sandbox);
|
||||||
}, 'Setting easing should not throw any exceptions in sandbox');
|
}, 'Setting easing should not throw any exceptions in sandbox');
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -136,7 +136,7 @@ function assert_properties_equal(actual, expected) {
|
|||||||
* e.g. { offset: 0.1, value: '1px', composite: 'replace', easing: 'ease'}
|
* e.g. { offset: 0.1, value: '1px', composite: 'replace', easing: 'ease'}
|
||||||
*/
|
*/
|
||||||
function valueFormat(offset, value, composite, easing) {
|
function valueFormat(offset, value, composite, easing) {
|
||||||
return { offset: offset, value: value, easing: easing, composite: composite };
|
return { offset, value, easing, composite };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,9 +7,7 @@
|
|||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "mozilla/dom/Document.h"
|
#include "mozilla/dom/Document.h"
|
||||||
#include "nsIDOMWindow.h"
|
|
||||||
#include "nsPIDOMWindow.h"
|
#include "nsPIDOMWindow.h"
|
||||||
#include "nsIURI.h"
|
|
||||||
|
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
|
|
||||||
@ -64,7 +62,7 @@ AudioChannelAgent::InitWithWeakCallback(
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsresult AudioChannelAgent::FindCorrectWindow(nsPIDOMWindowInner* aWindow) {
|
nsresult AudioChannelAgent::FindCorrectWindow(nsPIDOMWindowInner* aWindow) {
|
||||||
mWindow = aWindow->GetScriptableTop();
|
mWindow = aWindow->GetInProcessScriptableTop();
|
||||||
if (NS_WARN_IF(!mWindow)) {
|
if (NS_WARN_IF(!mWindow)) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -76,7 +74,7 @@ nsresult AudioChannelAgent::FindCorrectWindow(nsPIDOMWindowInner* aWindow) {
|
|||||||
// iframe (what is controlled by the system app).
|
// iframe (what is controlled by the system app).
|
||||||
// For doing this we go recursively back into the chain of windows until we
|
// For doing this we go recursively back into the chain of windows until we
|
||||||
// find apps that are not the system one.
|
// find apps that are not the system one.
|
||||||
nsCOMPtr<nsPIDOMWindowOuter> outerParent = mWindow->GetParent();
|
nsCOMPtr<nsPIDOMWindowOuter> outerParent = mWindow->GetInProcessParent();
|
||||||
if (!outerParent || outerParent == mWindow) {
|
if (!outerParent || outerParent == mWindow) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -126,13 +124,25 @@ nsresult AudioChannelAgent::InitInternal(
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
void AudioChannelAgent::PullInitialUpdate() {
|
||||||
AudioChannelAgent::NotifyStartedPlaying(AudioPlaybackConfig* aConfig,
|
RefPtr<AudioChannelService> service = AudioChannelService::Get();
|
||||||
uint8_t aAudible) {
|
MOZ_ASSERT(service);
|
||||||
if (NS_WARN_IF(!aConfig)) {
|
MOZ_ASSERT(mIsRegToService);
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
AudioPlaybackConfig config = service->GetMediaConfig(mWindow);
|
||||||
|
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
|
||||||
|
("AudioChannelAgent, PullInitialUpdate, this=%p, "
|
||||||
|
"mute=%s, volume=%f, suspend=%s, audioCapturing=%s\n",
|
||||||
|
this, config.mMuted ? "true" : "false", config.mVolume,
|
||||||
|
SuspendTypeToStr(config.mSuspend),
|
||||||
|
config.mCapturedAudio ? "true" : "false"));
|
||||||
|
WindowVolumeChanged(config.mVolume, config.mMuted);
|
||||||
|
WindowSuspendChanged(config.mSuspend);
|
||||||
|
WindowAudioCaptureChanged(InnerWindowID(), config.mCapturedAudio);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
AudioChannelAgent::NotifyStartedPlaying(uint8_t aAudible) {
|
||||||
RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
|
RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
|
||||||
if (service == nullptr || mIsRegToService) {
|
if (service == nullptr || mIsRegToService) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
@ -144,18 +154,12 @@ AudioChannelAgent::NotifyStartedPlaying(AudioPlaybackConfig* aConfig,
|
|||||||
service->RegisterAudioChannelAgent(
|
service->RegisterAudioChannelAgent(
|
||||||
this, static_cast<AudioChannelService::AudibleState>(aAudible));
|
this, static_cast<AudioChannelService::AudibleState>(aAudible));
|
||||||
|
|
||||||
AudioPlaybackConfig config = service->GetMediaConfig(mWindow);
|
|
||||||
|
|
||||||
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
|
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
|
||||||
("AudioChannelAgent, NotifyStartedPlaying, this = %p, "
|
("AudioChannelAgent, NotifyStartedPlaying, this = %p, audible = %s\n",
|
||||||
"audible = %s, mute = %s, volume = %f, suspend = %s\n",
|
|
||||||
this,
|
this,
|
||||||
AudibleStateToStr(
|
AudibleStateToStr(
|
||||||
static_cast<AudioChannelService::AudibleState>(aAudible)),
|
static_cast<AudioChannelService::AudibleState>(aAudible))));
|
||||||
config.mMuted ? "true" : "false", config.mVolume,
|
|
||||||
SuspendTypeToStr(config.mSuspend)));
|
|
||||||
|
|
||||||
aConfig->SetConfig(config.mVolume, config.mMuted, config.mSuspend);
|
|
||||||
mIsRegToService = true;
|
mIsRegToService = true;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -210,19 +214,17 @@ AudioChannelAgent::GetCallback() {
|
|||||||
return callback.forget();
|
return callback.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioChannelAgent::WindowVolumeChanged() {
|
void AudioChannelAgent::WindowVolumeChanged(float aVolume, bool aMuted) {
|
||||||
nsCOMPtr<nsIAudioChannelAgentCallback> callback = GetCallback();
|
nsCOMPtr<nsIAudioChannelAgentCallback> callback = GetCallback();
|
||||||
if (!callback) {
|
if (!callback) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioPlaybackConfig config = GetMediaConfig();
|
|
||||||
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
|
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
|
||||||
("AudioChannelAgent, WindowVolumeChanged, this = %p, mute = %s, "
|
("AudioChannelAgent, WindowVolumeChanged, this = %p, mute = %s, "
|
||||||
"volume = %f\n",
|
"volume = %f\n",
|
||||||
this, config.mMuted ? "true" : "false", config.mVolume));
|
this, aMuted ? "true" : "false", aVolume));
|
||||||
|
callback->WindowVolumeChanged(aVolume, aMuted);
|
||||||
callback->WindowVolumeChanged(config.mVolume, config.mMuted);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioChannelAgent::WindowSuspendChanged(nsSuspendedTypes aSuspend) {
|
void AudioChannelAgent::WindowSuspendChanged(nsSuspendedTypes aSuspend) {
|
||||||
@ -243,7 +245,7 @@ void AudioChannelAgent::WindowSuspendChanged(nsSuspendedTypes aSuspend) {
|
|||||||
callback->WindowSuspendChanged(aSuspend);
|
callback->WindowSuspendChanged(aSuspend);
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioPlaybackConfig AudioChannelAgent::GetMediaConfig() {
|
AudioPlaybackConfig AudioChannelAgent::GetMediaConfig() const {
|
||||||
RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
|
RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
|
||||||
AudioPlaybackConfig config(1.0, false, nsISuspendedTypes::NONE_SUSPENDED);
|
AudioPlaybackConfig config(1.0, false, nsISuspendedTypes::NONE_SUSPENDED);
|
||||||
if (service) {
|
if (service) {
|
||||||
@ -282,6 +284,10 @@ void AudioChannelAgent::WindowAudioCaptureChanged(uint64_t aInnerWindowID,
|
|||||||
callback->WindowAudioCaptureChanged(aCapture);
|
callback->WindowAudioCaptureChanged(aCapture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AudioChannelAgent::IsWindowAudioCapturingEnabled() const {
|
||||||
|
return GetMediaConfig().mCapturedAudio;
|
||||||
|
}
|
||||||
|
|
||||||
bool AudioChannelAgent::IsPlayingStarted() const { return mIsRegToService; }
|
bool AudioChannelAgent::IsPlayingStarted() const { return mIsRegToService; }
|
||||||
|
|
||||||
bool AudioChannelAgent::ShouldBlockMedia() const {
|
bool AudioChannelAgent::ShouldBlockMedia() const {
|
||||||
|
@ -28,22 +28,30 @@ class AudioChannelAgent : public nsIAudioChannelAgent {
|
|||||||
|
|
||||||
AudioChannelAgent();
|
AudioChannelAgent();
|
||||||
|
|
||||||
void WindowVolumeChanged();
|
// nsIAudioChannelAgentCallback MUST call this function after calling
|
||||||
void WindowSuspendChanged(nsSuspendedTypes aSuspend);
|
// NotifyStartedPlaying() to require the initial update for
|
||||||
void WindowAudioCaptureChanged(uint64_t aInnerWindowID, bool aCapture);
|
// volume/suspend/audio-capturing which might set before starting the agent.
|
||||||
|
// Ex. starting the agent in a tab which has been muted before, so the agent
|
||||||
nsPIDOMWindowOuter* Window() const { return mWindow; }
|
// should apply mute state to its callback.
|
||||||
|
void PullInitialUpdate();
|
||||||
|
|
||||||
uint64_t WindowID() const;
|
uint64_t WindowID() const;
|
||||||
uint64_t InnerWindowID() const;
|
|
||||||
|
|
||||||
|
bool IsWindowAudioCapturingEnabled() const;
|
||||||
bool IsPlayingStarted() const;
|
bool IsPlayingStarted() const;
|
||||||
bool ShouldBlockMedia() const;
|
bool ShouldBlockMedia() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual ~AudioChannelAgent();
|
virtual ~AudioChannelAgent();
|
||||||
|
|
||||||
AudioPlaybackConfig GetMediaConfig();
|
friend class AudioChannelService;
|
||||||
|
void WindowVolumeChanged(float aVolume, bool aMuted);
|
||||||
|
void WindowSuspendChanged(nsSuspendedTypes aSuspend);
|
||||||
|
void WindowAudioCaptureChanged(uint64_t aInnerWindowID, bool aCapture);
|
||||||
|
|
||||||
|
nsPIDOMWindowOuter* Window() const { return mWindow; }
|
||||||
|
uint64_t InnerWindowID() const;
|
||||||
|
AudioPlaybackConfig GetMediaConfig() const;
|
||||||
bool IsDisposableSuspend(nsSuspendedTypes aSuspend) const;
|
bool IsDisposableSuspend(nsSuspendedTypes aSuspend) const;
|
||||||
|
|
||||||
// Returns mCallback if that's non-null, or otherwise tries to get an
|
// Returns mCallback if that's non-null, or otherwise tries to get an
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
|
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsIScriptSecurityManager.h"
|
|
||||||
#include "nsISupportsPrimitives.h"
|
#include "nsISupportsPrimitives.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
#include "nsHashPropertyBag.h"
|
#include "nsHashPropertyBag.h"
|
||||||
@ -319,7 +318,9 @@ AudioPlaybackConfig AudioChannelService::GetMediaConfig(
|
|||||||
AudioPlaybackConfig config(1.0, false, nsISuspendedTypes::NONE_SUSPENDED);
|
AudioPlaybackConfig config(1.0, false, nsISuspendedTypes::NONE_SUSPENDED);
|
||||||
|
|
||||||
if (!aWindow) {
|
if (!aWindow) {
|
||||||
config.SetConfig(0.0, true, nsISuspendedTypes::SUSPENDED_BLOCK);
|
config.mVolume = 0.0;
|
||||||
|
config.mMuted = true;
|
||||||
|
config.mSuspend = nsISuspendedTypes::SUSPENDED_BLOCK;
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,6 +337,7 @@ AudioPlaybackConfig AudioChannelService::GetMediaConfig(
|
|||||||
config.mSuspend = winData->mOwningAudioFocus
|
config.mSuspend = winData->mOwningAudioFocus
|
||||||
? config.mSuspend
|
? config.mSuspend
|
||||||
: nsISuspendedTypes::SUSPENDED_STOP_DISPOSABLE;
|
: nsISuspendedTypes::SUSPENDED_STOP_DISPOSABLE;
|
||||||
|
config.mCapturedAudio = winData->mIsAudioCaptured;
|
||||||
}
|
}
|
||||||
|
|
||||||
config.mVolume *= window->GetAudioVolume();
|
config.mVolume *= window->GetAudioVolume();
|
||||||
@ -344,7 +346,8 @@ AudioPlaybackConfig AudioChannelService::GetMediaConfig(
|
|||||||
config.mSuspend = window->GetMediaSuspend();
|
config.mSuspend = window->GetMediaSuspend();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsPIDOMWindowOuter> win = window->GetScriptableParentOrNull();
|
nsCOMPtr<nsPIDOMWindowOuter> win =
|
||||||
|
window->GetInProcessScriptableParentOrNull();
|
||||||
if (!win) {
|
if (!win) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -404,7 +407,8 @@ AudioChannelService::Observe(nsISupports* aSubject, const char* aTopic,
|
|||||||
nsTObserverArray<AudioChannelAgent*>::ForwardIterator iter(
|
nsTObserverArray<AudioChannelAgent*>::ForwardIterator iter(
|
||||||
winData->mAgents);
|
winData->mAgents);
|
||||||
while (iter.HasMore()) {
|
while (iter.HasMore()) {
|
||||||
iter.GetNext()->WindowVolumeChanged();
|
iter.GetNext()->WindowVolumeChanged(winData->mConfig.mVolume,
|
||||||
|
winData->mConfig.mMuted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -417,7 +421,7 @@ void AudioChannelService::RefreshAgents(
|
|||||||
const std::function<void(AudioChannelAgent*)>& aFunc) {
|
const std::function<void(AudioChannelAgent*)>& aFunc) {
|
||||||
MOZ_ASSERT(aWindow);
|
MOZ_ASSERT(aWindow);
|
||||||
|
|
||||||
nsCOMPtr<nsPIDOMWindowOuter> topWindow = aWindow->GetScriptableTop();
|
nsCOMPtr<nsPIDOMWindowOuter> topWindow = aWindow->GetInProcessScriptableTop();
|
||||||
if (!topWindow) {
|
if (!topWindow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -433,9 +437,11 @@ void AudioChannelService::RefreshAgents(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioChannelService::RefreshAgentsVolume(nsPIDOMWindowOuter* aWindow) {
|
void AudioChannelService::RefreshAgentsVolume(nsPIDOMWindowOuter* aWindow,
|
||||||
RefreshAgents(aWindow,
|
float aVolume, bool aMuted) {
|
||||||
[](AudioChannelAgent* agent) { agent->WindowVolumeChanged(); });
|
RefreshAgents(aWindow, [aVolume, aMuted](AudioChannelAgent* agent) {
|
||||||
|
agent->WindowVolumeChanged(aVolume, aMuted);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioChannelService::RefreshAgentsSuspend(nsPIDOMWindowOuter* aWindow,
|
void AudioChannelService::RefreshAgentsSuspend(nsPIDOMWindowOuter* aWindow,
|
||||||
@ -456,7 +462,7 @@ void AudioChannelService::SetWindowAudioCaptured(nsPIDOMWindowOuter* aWindow,
|
|||||||
"aCapture = %d\n",
|
"aCapture = %d\n",
|
||||||
aWindow, aCapture));
|
aWindow, aCapture));
|
||||||
|
|
||||||
nsCOMPtr<nsPIDOMWindowOuter> topWindow = aWindow->GetScriptableTop();
|
nsCOMPtr<nsPIDOMWindowOuter> topWindow = aWindow->GetInProcessScriptableTop();
|
||||||
if (!topWindow) {
|
if (!topWindow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -513,7 +519,7 @@ AudioChannelService::AudioChannelWindow* AudioChannelService::GetWindowData(
|
|||||||
bool AudioChannelService::IsWindowActive(nsPIDOMWindowOuter* aWindow) {
|
bool AudioChannelService::IsWindowActive(nsPIDOMWindowOuter* aWindow) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
auto* window = nsPIDOMWindowOuter::From(aWindow)->GetScriptableTop();
|
auto* window = nsPIDOMWindowOuter::From(aWindow)->GetInProcessScriptableTop();
|
||||||
if (!window) {
|
if (!window) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -544,7 +550,7 @@ void AudioChannelService::NotifyMediaResumedFromBlock(
|
|||||||
nsPIDOMWindowOuter* aWindow) {
|
nsPIDOMWindowOuter* aWindow) {
|
||||||
MOZ_ASSERT(aWindow);
|
MOZ_ASSERT(aWindow);
|
||||||
|
|
||||||
nsCOMPtr<nsPIDOMWindowOuter> topWindow = aWindow->GetScriptableTop();
|
nsCOMPtr<nsPIDOMWindowOuter> topWindow = aWindow->GetInProcessScriptableTop();
|
||||||
if (!topWindow) {
|
if (!topWindow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -713,7 +719,6 @@ void AudioChannelService::AudioChannelWindow::AppendAgent(
|
|||||||
|
|
||||||
RequestAudioFocus(aAgent);
|
RequestAudioFocus(aAgent);
|
||||||
AppendAgentAndIncreaseAgentsNum(aAgent);
|
AppendAgentAndIncreaseAgentsNum(aAgent);
|
||||||
AudioCapturedChanged(aAgent, AudioCaptureState::eCapturing);
|
|
||||||
if (aAudible == AudibleState::eAudible) {
|
if (aAudible == AudibleState::eAudible) {
|
||||||
AudioAudibleChanged(aAgent, AudibleState::eAudible,
|
AudioAudibleChanged(aAgent, AudibleState::eAudible,
|
||||||
AudibleChangedReasons::eDataAudibleChanged);
|
AudibleChangedReasons::eDataAudibleChanged);
|
||||||
@ -728,7 +733,6 @@ void AudioChannelService::AudioChannelWindow::RemoveAgent(
|
|||||||
MOZ_ASSERT(aAgent);
|
MOZ_ASSERT(aAgent);
|
||||||
|
|
||||||
RemoveAgentAndReduceAgentsNum(aAgent);
|
RemoveAgentAndReduceAgentsNum(aAgent);
|
||||||
AudioCapturedChanged(aAgent, AudioCaptureState::eNotCapturing);
|
|
||||||
AudioAudibleChanged(aAgent, AudibleState::eNotAudible,
|
AudioAudibleChanged(aAgent, AudibleState::eNotAudible,
|
||||||
AudibleChangedReasons::ePauseStateChanged);
|
AudibleChangedReasons::ePauseStateChanged);
|
||||||
}
|
}
|
||||||
@ -784,15 +788,6 @@ void AudioChannelService::AudioChannelWindow::RemoveAgentAndReduceAgentsNum(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioChannelService::AudioChannelWindow::AudioCapturedChanged(
|
|
||||||
AudioChannelAgent* aAgent, AudioCaptureState aCapture) {
|
|
||||||
MOZ_ASSERT(aAgent);
|
|
||||||
|
|
||||||
if (mIsAudioCaptured) {
|
|
||||||
aAgent->WindowAudioCaptureChanged(aAgent->InnerWindowID(), aCapture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioChannelService::AudioChannelWindow::AudioAudibleChanged(
|
void AudioChannelService::AudioChannelWindow::AudioAudibleChanged(
|
||||||
AudioChannelAgent* aAgent, AudibleState aAudible,
|
AudioChannelAgent* aAgent, AudibleState aAudible,
|
||||||
AudibleChangedReasons aReason) {
|
AudibleChangedReasons aReason) {
|
||||||
|
@ -36,15 +36,10 @@ class AudioPlaybackConfig {
|
|||||||
mSuspend(aSuspended),
|
mSuspend(aSuspended),
|
||||||
mNumberOfAgents(0) {}
|
mNumberOfAgents(0) {}
|
||||||
|
|
||||||
void SetConfig(float aVolume, bool aMuted, uint32_t aSuspended) {
|
|
||||||
mVolume = aVolume;
|
|
||||||
mMuted = aMuted;
|
|
||||||
mSuspend = aSuspended;
|
|
||||||
}
|
|
||||||
|
|
||||||
float mVolume;
|
float mVolume;
|
||||||
bool mMuted;
|
bool mMuted;
|
||||||
uint32_t mSuspend;
|
uint32_t mSuspend;
|
||||||
|
bool mCapturedAudio = false;
|
||||||
uint32_t mNumberOfAgents;
|
uint32_t mNumberOfAgents;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -118,7 +113,8 @@ class AudioChannelService final : public nsIObserver {
|
|||||||
|
|
||||||
bool IsWindowActive(nsPIDOMWindowOuter* aWindow);
|
bool IsWindowActive(nsPIDOMWindowOuter* aWindow);
|
||||||
|
|
||||||
void RefreshAgentsVolume(nsPIDOMWindowOuter* aWindow);
|
void RefreshAgentsVolume(nsPIDOMWindowOuter* aWindow, float aVolume,
|
||||||
|
bool aMuted);
|
||||||
void RefreshAgentsSuspend(nsPIDOMWindowOuter* aWindow,
|
void RefreshAgentsSuspend(nsPIDOMWindowOuter* aWindow,
|
||||||
nsSuspendedTypes aSuspend);
|
nsSuspendedTypes aSuspend);
|
||||||
|
|
||||||
@ -182,9 +178,6 @@ class AudioChannelService final : public nsIObserver {
|
|||||||
bool mShouldSendActiveMediaBlockStopEvent;
|
bool mShouldSendActiveMediaBlockStopEvent;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void AudioCapturedChanged(AudioChannelAgent* aAgent,
|
|
||||||
AudioCaptureState aCapture);
|
|
||||||
|
|
||||||
void AppendAudibleAgentIfNotContained(AudioChannelAgent* aAgent,
|
void AppendAudibleAgentIfNotContained(AudioChannelAgent* aAgent,
|
||||||
AudibleChangedReasons aReason);
|
AudibleChangedReasons aReason);
|
||||||
void RemoveAudibleAgentIfContained(AudioChannelAgent* aAgent,
|
void RemoveAudibleAgentIfContained(AudioChannelAgent* aAgent,
|
||||||
|
@ -55,16 +55,6 @@ interface nsISuspendedTypes : nsISupports
|
|||||||
const uint32_t SUSPENDED_STOP_DISPOSABLE = 4;
|
const uint32_t SUSPENDED_STOP_DISPOSABLE = 4;
|
||||||
};
|
};
|
||||||
|
|
||||||
%{C++
|
|
||||||
namespace mozilla {
|
|
||||||
namespace dom {
|
|
||||||
// It's defined in dom/audiochannel/AudioChannelService.h.
|
|
||||||
class AudioPlaybackConfig;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
%}
|
|
||||||
[ptr] native AudioPlaybackConfig(mozilla::dom::AudioPlaybackConfig);
|
|
||||||
|
|
||||||
[uuid(15c05894-408e-4798-b527-a8c32d9c5f8c)]
|
[uuid(15c05894-408e-4798-b527-a8c32d9c5f8c)]
|
||||||
interface nsIAudioChannelAgentCallback : nsISupports
|
interface nsIAudioChannelAgentCallback : nsISupports
|
||||||
{
|
{
|
||||||
@ -131,11 +121,8 @@ interface nsIAudioChannelAgent : nsISupports
|
|||||||
* Notify the agent that we want to start playing.
|
* Notify the agent that we want to start playing.
|
||||||
* Note: Gecko component SHOULD call this function first then start to
|
* Note: Gecko component SHOULD call this function first then start to
|
||||||
* play audio stream only when return value is true.
|
* play audio stream only when return value is true.
|
||||||
*
|
|
||||||
* @param config
|
|
||||||
* It contains the playback related states (volume/mute/suspend)
|
|
||||||
*/
|
*/
|
||||||
void notifyStartedPlaying(in AudioPlaybackConfig config, in uint8_t audible);
|
void notifyStartedPlaying(in uint8_t audible);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify the agent we no longer want to play.
|
* Notify the agent we no longer want to play.
|
||||||
|
148
dom/base/AbstractRange.cpp
Normal file
148
dom/base/AbstractRange.cpp
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
/* 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/dom/AbstractRange.h"
|
||||||
|
#include "mozilla/dom/AbstractRangeBinding.h"
|
||||||
|
|
||||||
|
#include "mozilla/RangeUtils.h"
|
||||||
|
#include "mozilla/dom/StaticRange.h"
|
||||||
|
#include "nsContentUtils.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
#include "nsGkAtoms.h"
|
||||||
|
#include "nsINode.h"
|
||||||
|
#include "nsRange.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
template nsresult AbstractRange::SetStartAndEndInternal(
|
||||||
|
const RangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary,
|
||||||
|
nsRange* aRange);
|
||||||
|
template nsresult AbstractRange::SetStartAndEndInternal(
|
||||||
|
const RangeBoundary& aStartBoundary, const RawRangeBoundary& aEndBoundary,
|
||||||
|
nsRange* aRange);
|
||||||
|
template nsresult AbstractRange::SetStartAndEndInternal(
|
||||||
|
const RawRangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary,
|
||||||
|
nsRange* aRange);
|
||||||
|
template nsresult AbstractRange::SetStartAndEndInternal(
|
||||||
|
const RawRangeBoundary& aStartBoundary,
|
||||||
|
const RawRangeBoundary& aEndBoundary, nsRange* aRange);
|
||||||
|
template nsresult AbstractRange::SetStartAndEndInternal(
|
||||||
|
const RangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary,
|
||||||
|
StaticRange* aRange);
|
||||||
|
template nsresult AbstractRange::SetStartAndEndInternal(
|
||||||
|
const RangeBoundary& aStartBoundary, const RawRangeBoundary& aEndBoundary,
|
||||||
|
StaticRange* aRange);
|
||||||
|
template nsresult AbstractRange::SetStartAndEndInternal(
|
||||||
|
const RawRangeBoundary& aStartBoundary, const RangeBoundary& aEndBoundary,
|
||||||
|
StaticRange* aRange);
|
||||||
|
template nsresult AbstractRange::SetStartAndEndInternal(
|
||||||
|
const RawRangeBoundary& aStartBoundary,
|
||||||
|
const RawRangeBoundary& aEndBoundary, StaticRange* aRange);
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(AbstractRange)
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(AbstractRange)
|
||||||
|
|
||||||
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AbstractRange)
|
||||||
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||||
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(AbstractRange)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AbstractRange)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner);
|
||||||
|
// mStart and mEnd may depend on or be depended on some other members in
|
||||||
|
// concrete classes so that they should be unlinked in sub classes.
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AbstractRange)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStart)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEnd)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(AbstractRange)
|
||||||
|
|
||||||
|
AbstractRange::AbstractRange(nsINode* aNode)
|
||||||
|
: mIsPositioned(false), mIsGenerated(false), mCalledByJS(false) {
|
||||||
|
MOZ_ASSERT(aNode, "range isn't in a document!");
|
||||||
|
mOwner = aNode->OwnerDoc();
|
||||||
|
}
|
||||||
|
|
||||||
|
nsINode* AbstractRange::GetCommonAncestor() const {
|
||||||
|
return mIsPositioned ? nsContentUtils::GetCommonAncestor(mStart.Container(),
|
||||||
|
mEnd.Container())
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
template <typename SPT, typename SRT, typename EPT, typename ERT,
|
||||||
|
typename RangeType>
|
||||||
|
nsresult AbstractRange::SetStartAndEndInternal(
|
||||||
|
const RangeBoundaryBase<SPT, SRT>& aStartBoundary,
|
||||||
|
const RangeBoundaryBase<EPT, ERT>& aEndBoundary, RangeType* aRange) {
|
||||||
|
if (NS_WARN_IF(!aStartBoundary.IsSet()) ||
|
||||||
|
NS_WARN_IF(!aEndBoundary.IsSet())) {
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsINode* newStartRoot =
|
||||||
|
RangeUtils::ComputeRootNode(aStartBoundary.Container());
|
||||||
|
if (!newStartRoot) {
|
||||||
|
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
|
||||||
|
}
|
||||||
|
if (!aStartBoundary.IsSetAndValid()) {
|
||||||
|
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aStartBoundary.Container() == aEndBoundary.Container()) {
|
||||||
|
if (!aEndBoundary.IsSetAndValid()) {
|
||||||
|
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||||
|
}
|
||||||
|
// XXX: Offsets - handle this more efficiently.
|
||||||
|
// If the end offset is less than the start offset, this should be
|
||||||
|
// collapsed at the end offset.
|
||||||
|
if (aStartBoundary.Offset() > aEndBoundary.Offset()) {
|
||||||
|
aRange->DoSetRange(aEndBoundary, aEndBoundary, newStartRoot);
|
||||||
|
} else {
|
||||||
|
aRange->DoSetRange(aStartBoundary, aEndBoundary, newStartRoot);
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsINode* newEndRoot = RangeUtils::ComputeRootNode(aEndBoundary.Container());
|
||||||
|
if (!newEndRoot) {
|
||||||
|
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
|
||||||
|
}
|
||||||
|
if (!aEndBoundary.IsSetAndValid()) {
|
||||||
|
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If they have different root, this should be collapsed at the end point.
|
||||||
|
if (newStartRoot != newEndRoot) {
|
||||||
|
aRange->DoSetRange(aEndBoundary, aEndBoundary, newEndRoot);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the end point is before the start point, this should be collapsed at
|
||||||
|
// the end point.
|
||||||
|
if (nsContentUtils::ComparePoints(aStartBoundary, aEndBoundary) == 1) {
|
||||||
|
aRange->DoSetRange(aEndBoundary, aEndBoundary, newEndRoot);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, set the range as specified.
|
||||||
|
aRange->DoSetRange(aStartBoundary, aEndBoundary, newStartRoot);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSObject* AbstractRange::WrapObject(JSContext* aCx,
|
||||||
|
JS::Handle<JSObject*> aGivenProto) {
|
||||||
|
MOZ_CRASH("Must be overridden");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dom
|
||||||
|
} // namespace mozilla
|
89
dom/base/AbstractRange.h
Normal file
89
dom/base/AbstractRange.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_dom_AbstractRange_h
|
||||||
|
#define mozilla_dom_AbstractRange_h
|
||||||
|
|
||||||
|
#include "mozilla/RangeBoundary.h"
|
||||||
|
#include "mozilla/dom/Document.h"
|
||||||
|
#include "nsIContent.h"
|
||||||
|
#include "nsINode.h"
|
||||||
|
#include "nsWrapperCache.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
class AbstractRange : public nsISupports, public nsWrapperCache {
|
||||||
|
protected:
|
||||||
|
explicit AbstractRange(nsINode* aNode);
|
||||||
|
virtual ~AbstractRange() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AbstractRange() = delete;
|
||||||
|
explicit AbstractRange(const AbstractRange& aOther) = delete;
|
||||||
|
|
||||||
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AbstractRange)
|
||||||
|
|
||||||
|
const RangeBoundary& StartRef() const { return mStart; }
|
||||||
|
const RangeBoundary& EndRef() const { return mEnd; }
|
||||||
|
|
||||||
|
nsIContent* GetChildAtStartOffset() const {
|
||||||
|
return mStart.GetChildAtOffset();
|
||||||
|
}
|
||||||
|
nsIContent* GetChildAtEndOffset() const { return mEnd.GetChildAtOffset(); }
|
||||||
|
bool IsPositioned() const { return mIsPositioned; }
|
||||||
|
nsINode* GetCommonAncestor() const;
|
||||||
|
|
||||||
|
// WebIDL
|
||||||
|
|
||||||
|
// If Range is created from JS, it's initialized with Document.createRange()
|
||||||
|
// and it collaps the range to start of the Document. Therefore, the
|
||||||
|
// following WebIDL methods are called only when `mIsPositioned` is true.
|
||||||
|
// So, it does not make sense to take `ErrorResult` as their parameter
|
||||||
|
// since its destruction cost may appear in profile. If you create range
|
||||||
|
// object from C++ and needs to check whether it's positioned, should call
|
||||||
|
// `IsPositioned()` directly.
|
||||||
|
|
||||||
|
nsINode* GetStartContainer() const { return mStart.Container(); }
|
||||||
|
nsINode* GetEndContainer() const { return mEnd.Container(); }
|
||||||
|
uint32_t StartOffset() const {
|
||||||
|
// FYI: Returns 0 if it's not positioned.
|
||||||
|
return static_cast<uint32_t>(mStart.Offset());
|
||||||
|
}
|
||||||
|
uint32_t EndOffset() const {
|
||||||
|
// FYI: Returns 0 if it's not positioned.
|
||||||
|
return static_cast<uint32_t>(mEnd.Offset());
|
||||||
|
}
|
||||||
|
bool Collapsed() const {
|
||||||
|
return !mIsPositioned || (mStart.Container() == mEnd.Container() &&
|
||||||
|
mStart.Offset() == mEnd.Offset());
|
||||||
|
}
|
||||||
|
|
||||||
|
nsINode* GetParentObject() const { return mOwner; }
|
||||||
|
virtual JSObject* WrapObject(JSContext* aCx,
|
||||||
|
JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template <typename SPT, typename SRT, typename EPT, typename ERT,
|
||||||
|
typename RangeType>
|
||||||
|
static nsresult SetStartAndEndInternal(
|
||||||
|
const RangeBoundaryBase<SPT, SRT>& aStartBoundary,
|
||||||
|
const RangeBoundaryBase<EPT, ERT>& aEndBoundary, RangeType* aRange);
|
||||||
|
|
||||||
|
RefPtr<Document> mOwner;
|
||||||
|
RangeBoundary mStart;
|
||||||
|
RangeBoundary mEnd;
|
||||||
|
bool mIsPositioned;
|
||||||
|
|
||||||
|
// Used by nsRange, but this should have this for minimizing the size.
|
||||||
|
bool mIsGenerated;
|
||||||
|
// Used by nsRange, but this should have this for minimizing the size.
|
||||||
|
bool mCalledByJS;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace dom
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // #ifndef mozilla_dom_AbstractRange_h
|
@ -176,7 +176,7 @@ bool AnonymousContent::WrapObject(JSContext* aCx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AnonymousContent::GetComputedStylePropertyValue(
|
void AnonymousContent::GetComputedStylePropertyValue(
|
||||||
const nsAString& aElementId, const nsAString& aPropertyName,
|
const nsAString& aElementId, const nsACString& aPropertyName,
|
||||||
DOMString& aResult, ErrorResult& aRv) {
|
DOMString& aResult, ErrorResult& aRv) {
|
||||||
Element* element = GetElementById(aElementId);
|
Element* element = GetElementById(aElementId);
|
||||||
if (!element) {
|
if (!element) {
|
||||||
@ -205,5 +205,17 @@ void AnonymousContent::GetTargetIdForEvent(Event& aEvent, DOMString& aResult) {
|
|||||||
aResult.SetNull();
|
aResult.SetNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnonymousContent::SetStyle(const nsACString& aProperty,
|
||||||
|
const nsACString& aValue, ErrorResult& aRv) {
|
||||||
|
if (!mContentNode->IsHTMLElement()) {
|
||||||
|
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsGenericHTMLElement* element = nsGenericHTMLElement::FromNode(mContentNode);
|
||||||
|
nsCOMPtr<nsICSSDeclaration> declaration = element->Style();
|
||||||
|
declaration->SetProperty(aProperty, aValue, EmptyString());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -64,11 +64,14 @@ class AnonymousContent final {
|
|||||||
ErrorResult& aError);
|
ErrorResult& aError);
|
||||||
|
|
||||||
void GetComputedStylePropertyValue(const nsAString& aElementId,
|
void GetComputedStylePropertyValue(const nsAString& aElementId,
|
||||||
const nsAString& aPropertyName,
|
const nsACString& aPropertyName,
|
||||||
DOMString& aResult, ErrorResult& aRv);
|
DOMString& aResult, ErrorResult& aRv);
|
||||||
|
|
||||||
void GetTargetIdForEvent(Event& aEvent, DOMString& aResult);
|
void GetTargetIdForEvent(Event& aEvent, DOMString& aResult);
|
||||||
|
|
||||||
|
void SetStyle(const nsACString& aProperty, const nsACString& aValue,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~AnonymousContent();
|
~AnonymousContent();
|
||||||
RefPtr<Element> mContentNode;
|
RefPtr<Element> mContentNode;
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include "nsGkAtoms.h"
|
#include "nsGkAtoms.h"
|
||||||
#include "nsCOMArray.h"
|
#include "nsCOMArray.h"
|
||||||
#include "nsNameSpaceManager.h"
|
#include "nsNameSpaceManager.h"
|
||||||
#include "nsNodeUtils.h"
|
|
||||||
#include "nsTextNode.h"
|
#include "nsTextNode.h"
|
||||||
#include "mozAutoDocUpdate.h"
|
#include "mozAutoDocUpdate.h"
|
||||||
#include "nsWrapperCacheInlines.h"
|
#include "nsWrapperCacheInlines.h"
|
||||||
@ -92,8 +91,7 @@ NS_INTERFACE_TABLE_HEAD(Attr)
|
|||||||
NS_INTERFACE_MAP_END
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(Attr)
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(Attr)
|
||||||
NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(Attr, LastRelease())
|
||||||
Attr, nsNodeUtils::LastRelease(this))
|
|
||||||
|
|
||||||
void Attr::SetMap(nsDOMAttributeMap* aMap) {
|
void Attr::SetMap(nsDOMAttributeMap* aMap) {
|
||||||
if (mAttrMap && !aMap && sInitialized) {
|
if (mAttrMap && !aMap && sInitialized) {
|
||||||
@ -180,7 +178,7 @@ nsresult Attr::Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const {
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsIURI> Attr::GetBaseURI(bool aTryUseXHRDocBaseURI) const {
|
nsIURI* Attr::GetBaseURI(bool aTryUseXHRDocBaseURI) const {
|
||||||
Element* parent = GetElement();
|
Element* parent = GetElement();
|
||||||
|
|
||||||
return parent ? parent->GetBaseURI(aTryUseXHRDocBaseURI) : nullptr;
|
return parent ? parent->GetBaseURI(aTryUseXHRDocBaseURI) : nullptr;
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#define mozilla_dom_Attr_h
|
#define mozilla_dom_Attr_h
|
||||||
|
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
|
#include "nsDOMAttributeMap.h"
|
||||||
#include "nsINode.h"
|
#include "nsINode.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
@ -64,8 +65,7 @@ class Attr final : public nsINode {
|
|||||||
// nsINode interface
|
// nsINode interface
|
||||||
virtual bool IsNodeOfType(uint32_t aFlags) const override;
|
virtual bool IsNodeOfType(uint32_t aFlags) const override;
|
||||||
virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
|
virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
|
||||||
virtual already_AddRefed<nsIURI> GetBaseURI(
|
nsIURI* GetBaseURI(bool aTryUseXHRDocBaseURI = false) const override;
|
||||||
bool aTryUseXHRDocBaseURI = false) const override;
|
|
||||||
|
|
||||||
static void Initialize();
|
static void Initialize();
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
#include "mozilla/dom/BarPropBinding.h"
|
#include "mozilla/dom/BarPropBinding.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsGlobalWindow.h"
|
#include "nsGlobalWindow.h"
|
||||||
#include "nsIDocShell.h"
|
|
||||||
#include "nsIScrollable.h"
|
#include "nsIScrollable.h"
|
||||||
#include "nsIWebBrowserChrome.h"
|
#include "nsIWebBrowserChrome.h"
|
||||||
|
|
||||||
|
161
dom/base/BindContext.h
Normal file
161
dom/base/BindContext.h
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
/* State that is passed down to BindToTree. */
|
||||||
|
|
||||||
|
#ifndef mozilla_dom_BindContext_h__
|
||||||
|
#define mozilla_dom_BindContext_h__
|
||||||
|
|
||||||
|
#include "nsXBLBinding.h"
|
||||||
|
#include "mozilla/Attributes.h"
|
||||||
|
#include "mozilla/AutoRestore.h"
|
||||||
|
#include "mozilla/dom/Document.h"
|
||||||
|
#include "mozilla/dom/Element.h"
|
||||||
|
#include "mozilla/dom/ShadowRoot.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
struct MOZ_STACK_CLASS BindContext final {
|
||||||
|
struct NestingLevel;
|
||||||
|
friend struct NestingLevel;
|
||||||
|
|
||||||
|
// The document that owns the tree we're getting bound to.
|
||||||
|
//
|
||||||
|
// This is mostly an optimization to avoid silly pointer-chases to get the
|
||||||
|
// OwnerDoc().
|
||||||
|
Document& OwnerDoc() const { return mDoc; }
|
||||||
|
|
||||||
|
// Whether we're getting connected.
|
||||||
|
//
|
||||||
|
// https://dom.spec.whatwg.org/#connected
|
||||||
|
bool InComposedDoc() const { return mInComposedDoc; }
|
||||||
|
|
||||||
|
// Whether we're getting bound to the document tree.
|
||||||
|
//
|
||||||
|
// https://dom.spec.whatwg.org/#in-a-document-tree
|
||||||
|
bool InUncomposedDoc() const { return mInUncomposedDoc; }
|
||||||
|
|
||||||
|
Document* GetComposedDoc() const { return mInComposedDoc ? &mDoc : nullptr; }
|
||||||
|
|
||||||
|
Document* GetUncomposedDoc() const {
|
||||||
|
return mInUncomposedDoc ? &mDoc : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whether our subtree root is changing as a result of this operation.
|
||||||
|
bool SubtreeRootChanges() const { return mSubtreeRootChanges; }
|
||||||
|
|
||||||
|
// Returns the binding parent of the subtree to be inserted.
|
||||||
|
//
|
||||||
|
// This can be null.
|
||||||
|
Element* GetBindingParent() const { return mBindingParent; }
|
||||||
|
|
||||||
|
// This constructor should be used for regular appends to content.
|
||||||
|
explicit BindContext(nsINode& aParent)
|
||||||
|
: mDoc(*aParent.OwnerDoc()),
|
||||||
|
mBindingParent(aParent.IsContent()
|
||||||
|
? aParent.AsContent()->GetBindingParent()
|
||||||
|
: nullptr),
|
||||||
|
mInComposedDoc(aParent.IsInComposedDoc()),
|
||||||
|
mInUncomposedDoc(aParent.IsInUncomposedDoc()),
|
||||||
|
mSubtreeRootChanges(true),
|
||||||
|
mCollectingDisplayedNodeDataDuringLoad(
|
||||||
|
ShouldCollectDisplayedNodeDataDuringLoad(mInComposedDoc, mDoc,
|
||||||
|
aParent)) {}
|
||||||
|
|
||||||
|
// When re-binding a shadow host into a tree, we re-bind all the shadow tree
|
||||||
|
// from the root. In that case, the shadow tree contents remain within the
|
||||||
|
// same subtree root. So children should avoid doing silly things like adding
|
||||||
|
// themselves to the ShadowRoot's id table twice or what not.
|
||||||
|
//
|
||||||
|
// This constructor is only meant to be used in that situation.
|
||||||
|
explicit BindContext(ShadowRoot& aShadowRoot)
|
||||||
|
: mDoc(*aShadowRoot.OwnerDoc()),
|
||||||
|
mBindingParent(aShadowRoot.Host()),
|
||||||
|
mInComposedDoc(aShadowRoot.IsInComposedDoc()),
|
||||||
|
mInUncomposedDoc(false),
|
||||||
|
mSubtreeRootChanges(false),
|
||||||
|
mCollectingDisplayedNodeDataDuringLoad(
|
||||||
|
ShouldCollectDisplayedNodeDataDuringLoad(mInComposedDoc, mDoc,
|
||||||
|
aShadowRoot)) {}
|
||||||
|
|
||||||
|
// This constructor is meant to be used when inserting native-anonymous
|
||||||
|
// children into a subtree.
|
||||||
|
enum ForNativeAnonymous { ForNativeAnonymous };
|
||||||
|
BindContext(Element& aParentElement, enum ForNativeAnonymous)
|
||||||
|
: mDoc(*aParentElement.OwnerDoc()),
|
||||||
|
mBindingParent(&aParentElement),
|
||||||
|
mInComposedDoc(aParentElement.IsInComposedDoc()),
|
||||||
|
mInUncomposedDoc(aParentElement.IsInUncomposedDoc()),
|
||||||
|
mSubtreeRootChanges(true),
|
||||||
|
mCollectingDisplayedNodeDataDuringLoad(
|
||||||
|
ShouldCollectDisplayedNodeDataDuringLoad(mInComposedDoc, mDoc,
|
||||||
|
aParentElement)) {
|
||||||
|
MOZ_ASSERT(mInComposedDoc, "Binding NAC in a disconnected subtree?");
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is meant to be used to bind XBL anonymous content.
|
||||||
|
BindContext(nsXBLBinding& aBinding, Element& aParentElement)
|
||||||
|
: mDoc(*aParentElement.OwnerDoc()),
|
||||||
|
mBindingParent(aBinding.GetBoundElement()),
|
||||||
|
mInComposedDoc(aParentElement.IsInComposedDoc()),
|
||||||
|
mInUncomposedDoc(aParentElement.IsInUncomposedDoc()),
|
||||||
|
mSubtreeRootChanges(true),
|
||||||
|
mCollectingDisplayedNodeDataDuringLoad(
|
||||||
|
ShouldCollectDisplayedNodeDataDuringLoad(mInComposedDoc, mDoc,
|
||||||
|
aParentElement)) {}
|
||||||
|
|
||||||
|
bool CollectingDisplayedNodeDataDuringLoad() const {
|
||||||
|
return mCollectingDisplayedNodeDataDuringLoad;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool IsLikelyUndisplayed(const nsINode& aParent) {
|
||||||
|
return aParent.IsAnyOfHTMLElements(nsGkAtoms::style, nsGkAtoms::script);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ShouldCollectDisplayedNodeDataDuringLoad(bool aConnected,
|
||||||
|
Document& aDoc,
|
||||||
|
nsINode& aParent) {
|
||||||
|
return aDoc.GetReadyStateEnum() == Document::READYSTATE_LOADING &&
|
||||||
|
aConnected && !IsLikelyUndisplayed(aParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
Document& mDoc;
|
||||||
|
|
||||||
|
Element* const mBindingParent;
|
||||||
|
|
||||||
|
const bool mInComposedDoc;
|
||||||
|
const bool mInUncomposedDoc;
|
||||||
|
|
||||||
|
// Whether the bind operation will change the subtree root of the content
|
||||||
|
// we're binding.
|
||||||
|
const bool mSubtreeRootChanges;
|
||||||
|
|
||||||
|
// Whether it's likely that we're in an undisplayed part of the DOM.
|
||||||
|
//
|
||||||
|
// NOTE(emilio): We don't inherit this in BindContext's for Shadow DOM or XBL
|
||||||
|
// or such. This means that if you have a shadow tree inside an undisplayed
|
||||||
|
// element it will be incorrectly counted. But given our current definition
|
||||||
|
// of undisplayed element this is not likely to matter in practice.
|
||||||
|
bool mCollectingDisplayedNodeDataDuringLoad;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MOZ_STACK_CLASS BindContext::NestingLevel {
|
||||||
|
explicit NestingLevel(BindContext& aContext, const Element& aParent)
|
||||||
|
: mRestoreCollecting(aContext.mCollectingDisplayedNodeDataDuringLoad) {
|
||||||
|
if (aContext.mCollectingDisplayedNodeDataDuringLoad) {
|
||||||
|
aContext.mCollectingDisplayedNodeDataDuringLoad =
|
||||||
|
BindContext::IsLikelyUndisplayed(aParent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AutoRestore<bool> mRestoreCollecting;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace dom
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
@ -2,14 +2,16 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "Fetch.h"
|
#include "BodyConsumer.h"
|
||||||
#include "FetchConsumer.h"
|
|
||||||
|
|
||||||
#include "mozilla/dom/BlobBinding.h"
|
#include "mozilla/dom/BlobBinding.h"
|
||||||
#include "mozilla/dom/BlobURLProtocolHandler.h"
|
#include "mozilla/dom/BlobURLProtocolHandler.h"
|
||||||
|
#include "mozilla/dom/BodyUtil.h"
|
||||||
#include "mozilla/dom/File.h"
|
#include "mozilla/dom/File.h"
|
||||||
#include "mozilla/dom/FileBinding.h"
|
#include "mozilla/dom/FileBinding.h"
|
||||||
#include "mozilla/dom/FileCreatorHelper.h"
|
#include "mozilla/dom/FileCreatorHelper.h"
|
||||||
|
#include "mozilla/dom/MutableBlobStreamListener.h"
|
||||||
|
#include "mozilla/dom/Promise.h"
|
||||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||||
#include "mozilla/dom/WorkerCommon.h"
|
#include "mozilla/dom/WorkerCommon.h"
|
||||||
#include "mozilla/dom/WorkerPrivate.h"
|
#include "mozilla/dom/WorkerPrivate.h"
|
||||||
@ -17,8 +19,9 @@
|
|||||||
#include "mozilla/dom/WorkerRunnable.h"
|
#include "mozilla/dom/WorkerRunnable.h"
|
||||||
#include "mozilla/dom/WorkerScope.h"
|
#include "mozilla/dom/WorkerScope.h"
|
||||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||||
#include "nsIInputStreamPump.h"
|
|
||||||
#include "nsIThreadRetargetableRequest.h"
|
#include "nsIThreadRetargetableRequest.h"
|
||||||
|
#include "nsIStreamLoader.h"
|
||||||
|
#include "nsNetUtil.h"
|
||||||
#include "nsProxyRelease.h"
|
#include "nsProxyRelease.h"
|
||||||
|
|
||||||
// Undefine the macro of CreateFile to avoid FileCreatorHelper#CreateFile being
|
// Undefine the macro of CreateFile to avoid FileCreatorHelper#CreateFile being
|
||||||
@ -32,42 +35,40 @@ namespace dom {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
template <class Derived>
|
|
||||||
class BeginConsumeBodyRunnable final : public Runnable {
|
class BeginConsumeBodyRunnable final : public Runnable {
|
||||||
public:
|
public:
|
||||||
BeginConsumeBodyRunnable(FetchBodyConsumer<Derived>* aConsumer,
|
BeginConsumeBodyRunnable(BodyConsumer* aConsumer,
|
||||||
ThreadSafeWorkerRef* aWorkerRef)
|
ThreadSafeWorkerRef* aWorkerRef)
|
||||||
: Runnable("BeginConsumeBodyRunnable"),
|
: Runnable("BeginConsumeBodyRunnable"),
|
||||||
mFetchBodyConsumer(aConsumer),
|
mBodyConsumer(aConsumer),
|
||||||
mWorkerRef(aWorkerRef) {}
|
mWorkerRef(aWorkerRef) {}
|
||||||
|
|
||||||
NS_IMETHOD
|
NS_IMETHOD
|
||||||
Run() override {
|
Run() override {
|
||||||
mFetchBodyConsumer->BeginConsumeBodyMainThread(mWorkerRef);
|
mBodyConsumer->BeginConsumeBodyMainThread(mWorkerRef);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer;
|
RefPtr<BodyConsumer> mBodyConsumer;
|
||||||
RefPtr<ThreadSafeWorkerRef> mWorkerRef;
|
RefPtr<ThreadSafeWorkerRef> mWorkerRef;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called on successfully reading the complete stream.
|
* Called on successfully reading the complete stream.
|
||||||
*/
|
*/
|
||||||
template <class Derived>
|
|
||||||
class ContinueConsumeBodyRunnable final : public MainThreadWorkerRunnable {
|
class ContinueConsumeBodyRunnable final : public MainThreadWorkerRunnable {
|
||||||
RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer;
|
RefPtr<BodyConsumer> mBodyConsumer;
|
||||||
nsresult mStatus;
|
nsresult mStatus;
|
||||||
uint32_t mLength;
|
uint32_t mLength;
|
||||||
uint8_t* mResult;
|
uint8_t* mResult;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ContinueConsumeBodyRunnable(FetchBodyConsumer<Derived>* aFetchBodyConsumer,
|
ContinueConsumeBodyRunnable(BodyConsumer* aBodyConsumer,
|
||||||
WorkerPrivate* aWorkerPrivate, nsresult aStatus,
|
WorkerPrivate* aWorkerPrivate, nsresult aStatus,
|
||||||
uint32_t aLength, uint8_t* aResult)
|
uint32_t aLength, uint8_t* aResult)
|
||||||
: MainThreadWorkerRunnable(aWorkerPrivate),
|
: MainThreadWorkerRunnable(aWorkerPrivate),
|
||||||
mFetchBodyConsumer(aFetchBodyConsumer),
|
mBodyConsumer(aBodyConsumer),
|
||||||
mStatus(aStatus),
|
mStatus(aStatus),
|
||||||
mLength(aLength),
|
mLength(aLength),
|
||||||
mResult(aResult) {
|
mResult(aResult) {
|
||||||
@ -75,30 +76,28 @@ class ContinueConsumeBodyRunnable final : public MainThreadWorkerRunnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
|
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
|
||||||
mFetchBodyConsumer->ContinueConsumeBody(mStatus, mLength, mResult);
|
mBodyConsumer->ContinueConsumeBody(mStatus, mLength, mResult);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ControlRunnable used to complete the releasing of resources on the worker
|
// ControlRunnable used to complete the releasing of resources on the worker
|
||||||
// thread when already shutting down.
|
// thread when already shutting down.
|
||||||
template <class Derived>
|
|
||||||
class AbortConsumeBodyControlRunnable final
|
class AbortConsumeBodyControlRunnable final
|
||||||
: public MainThreadWorkerControlRunnable {
|
: public MainThreadWorkerControlRunnable {
|
||||||
RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer;
|
RefPtr<BodyConsumer> mBodyConsumer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AbortConsumeBodyControlRunnable(
|
AbortConsumeBodyControlRunnable(BodyConsumer* aBodyConsumer,
|
||||||
FetchBodyConsumer<Derived>* aFetchBodyConsumer,
|
WorkerPrivate* aWorkerPrivate)
|
||||||
WorkerPrivate* aWorkerPrivate)
|
|
||||||
: MainThreadWorkerControlRunnable(aWorkerPrivate),
|
: MainThreadWorkerControlRunnable(aWorkerPrivate),
|
||||||
mFetchBodyConsumer(aFetchBodyConsumer) {
|
mBodyConsumer(aBodyConsumer) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
|
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
|
||||||
mFetchBodyConsumer->ContinueConsumeBody(NS_BINDING_ABORTED, 0, nullptr,
|
mBodyConsumer->ContinueConsumeBody(NS_BINDING_ABORTED, 0, nullptr,
|
||||||
true /* shutting down */);
|
true /* shutting down */);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -107,10 +106,9 @@ class AbortConsumeBodyControlRunnable final
|
|||||||
* In case of failure to create a stream pump or dispatch stream completion to
|
* In case of failure to create a stream pump or dispatch stream completion to
|
||||||
* worker, ensure we cleanup properly. Thread agnostic.
|
* worker, ensure we cleanup properly. Thread agnostic.
|
||||||
*/
|
*/
|
||||||
template <class Derived>
|
|
||||||
class MOZ_STACK_CLASS AutoFailConsumeBody final {
|
class MOZ_STACK_CLASS AutoFailConsumeBody final {
|
||||||
public:
|
public:
|
||||||
AutoFailConsumeBody(FetchBodyConsumer<Derived>* aBodyConsumer,
|
AutoFailConsumeBody(BodyConsumer* aBodyConsumer,
|
||||||
ThreadSafeWorkerRef* aWorkerRef)
|
ThreadSafeWorkerRef* aWorkerRef)
|
||||||
: mBodyConsumer(aBodyConsumer), mWorkerRef(aWorkerRef) {}
|
: mBodyConsumer(aBodyConsumer), mWorkerRef(aWorkerRef) {}
|
||||||
|
|
||||||
@ -123,9 +121,9 @@ class MOZ_STACK_CLASS AutoFailConsumeBody final {
|
|||||||
|
|
||||||
// Web Worker
|
// Web Worker
|
||||||
if (mWorkerRef) {
|
if (mWorkerRef) {
|
||||||
RefPtr<AbortConsumeBodyControlRunnable<Derived>> r =
|
RefPtr<AbortConsumeBodyControlRunnable> r =
|
||||||
new AbortConsumeBodyControlRunnable<Derived>(mBodyConsumer,
|
new AbortConsumeBodyControlRunnable(mBodyConsumer,
|
||||||
mWorkerRef->Private());
|
mWorkerRef->Private());
|
||||||
if (!r->Dispatch()) {
|
if (!r->Dispatch()) {
|
||||||
MOZ_CRASH("We are going to leak");
|
MOZ_CRASH("We are going to leak");
|
||||||
}
|
}
|
||||||
@ -139,67 +137,62 @@ class MOZ_STACK_CLASS AutoFailConsumeBody final {
|
|||||||
void DontFail() { mBodyConsumer = nullptr; }
|
void DontFail() { mBodyConsumer = nullptr; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RefPtr<FetchBodyConsumer<Derived>> mBodyConsumer;
|
RefPtr<BodyConsumer> mBodyConsumer;
|
||||||
RefPtr<ThreadSafeWorkerRef> mWorkerRef;
|
RefPtr<ThreadSafeWorkerRef> mWorkerRef;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called on successfully reading the complete stream for Blob.
|
* Called on successfully reading the complete stream for Blob.
|
||||||
*/
|
*/
|
||||||
template <class Derived>
|
|
||||||
class ContinueConsumeBlobBodyRunnable final : public MainThreadWorkerRunnable {
|
class ContinueConsumeBlobBodyRunnable final : public MainThreadWorkerRunnable {
|
||||||
RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer;
|
RefPtr<BodyConsumer> mBodyConsumer;
|
||||||
RefPtr<BlobImpl> mBlobImpl;
|
RefPtr<BlobImpl> mBlobImpl;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ContinueConsumeBlobBodyRunnable(
|
ContinueConsumeBlobBodyRunnable(BodyConsumer* aBodyConsumer,
|
||||||
FetchBodyConsumer<Derived>* aFetchBodyConsumer,
|
WorkerPrivate* aWorkerPrivate,
|
||||||
WorkerPrivate* aWorkerPrivate, BlobImpl* aBlobImpl)
|
BlobImpl* aBlobImpl)
|
||||||
: MainThreadWorkerRunnable(aWorkerPrivate),
|
: MainThreadWorkerRunnable(aWorkerPrivate),
|
||||||
mFetchBodyConsumer(aFetchBodyConsumer),
|
mBodyConsumer(aBodyConsumer),
|
||||||
mBlobImpl(aBlobImpl) {
|
mBlobImpl(aBlobImpl) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
MOZ_ASSERT(mBlobImpl);
|
MOZ_ASSERT(mBlobImpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
|
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
|
||||||
mFetchBodyConsumer->ContinueConsumeBlobBody(mBlobImpl);
|
mBodyConsumer->ContinueConsumeBlobBody(mBlobImpl);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ControlRunnable used to complete the releasing of resources on the worker
|
// ControlRunnable used to complete the releasing of resources on the worker
|
||||||
// thread when already shutting down.
|
// thread when already shutting down.
|
||||||
template <class Derived>
|
|
||||||
class AbortConsumeBlobBodyControlRunnable final
|
class AbortConsumeBlobBodyControlRunnable final
|
||||||
: public MainThreadWorkerControlRunnable {
|
: public MainThreadWorkerControlRunnable {
|
||||||
RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer;
|
RefPtr<BodyConsumer> mBodyConsumer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AbortConsumeBlobBodyControlRunnable(
|
AbortConsumeBlobBodyControlRunnable(BodyConsumer* aBodyConsumer,
|
||||||
FetchBodyConsumer<Derived>* aFetchBodyConsumer,
|
WorkerPrivate* aWorkerPrivate)
|
||||||
WorkerPrivate* aWorkerPrivate)
|
|
||||||
: MainThreadWorkerControlRunnable(aWorkerPrivate),
|
: MainThreadWorkerControlRunnable(aWorkerPrivate),
|
||||||
mFetchBodyConsumer(aFetchBodyConsumer) {
|
mBodyConsumer(aBodyConsumer) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
|
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
|
||||||
mFetchBodyConsumer->ContinueConsumeBlobBody(nullptr,
|
mBodyConsumer->ContinueConsumeBlobBody(nullptr, true /* shutting down */);
|
||||||
true /* shutting down */);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Derived>
|
|
||||||
class ConsumeBodyDoneObserver final : public nsIStreamLoaderObserver,
|
class ConsumeBodyDoneObserver final : public nsIStreamLoaderObserver,
|
||||||
public MutableBlobStorageCallback {
|
public MutableBlobStorageCallback {
|
||||||
public:
|
public:
|
||||||
NS_DECL_THREADSAFE_ISUPPORTS
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
|
|
||||||
ConsumeBodyDoneObserver(FetchBodyConsumer<Derived>* aFetchBodyConsumer,
|
ConsumeBodyDoneObserver(BodyConsumer* aBodyConsumer,
|
||||||
ThreadSafeWorkerRef* aWorkerRef)
|
ThreadSafeWorkerRef* aWorkerRef)
|
||||||
: mFetchBodyConsumer(aFetchBodyConsumer), mWorkerRef(aWorkerRef) {}
|
: mBodyConsumer(aBodyConsumer), mWorkerRef(aWorkerRef) {}
|
||||||
|
|
||||||
NS_IMETHOD
|
NS_IMETHOD
|
||||||
OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aCtxt,
|
OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aCtxt,
|
||||||
@ -209,26 +202,25 @@ class ConsumeBodyDoneObserver final : public nsIStreamLoaderObserver,
|
|||||||
|
|
||||||
// The loading is completed. Let's nullify the pump before continuing the
|
// The loading is completed. Let's nullify the pump before continuing the
|
||||||
// consuming of the body.
|
// consuming of the body.
|
||||||
mFetchBodyConsumer->NullifyConsumeBodyPump();
|
mBodyConsumer->NullifyConsumeBodyPump();
|
||||||
|
|
||||||
uint8_t* nonconstResult = const_cast<uint8_t*>(aResult);
|
uint8_t* nonconstResult = const_cast<uint8_t*>(aResult);
|
||||||
|
|
||||||
// Main-thread.
|
// Main-thread.
|
||||||
if (!mWorkerRef) {
|
if (!mWorkerRef) {
|
||||||
mFetchBodyConsumer->ContinueConsumeBody(aStatus, aResultLength,
|
mBodyConsumer->ContinueConsumeBody(aStatus, aResultLength,
|
||||||
nonconstResult);
|
nonconstResult);
|
||||||
// FetchBody is responsible for data.
|
// The caller is responsible for data.
|
||||||
return NS_SUCCESS_ADOPTED_DATA;
|
return NS_SUCCESS_ADOPTED_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Web Worker.
|
// Web Worker.
|
||||||
{
|
{
|
||||||
RefPtr<ContinueConsumeBodyRunnable<Derived>> r =
|
RefPtr<ContinueConsumeBodyRunnable> r = new ContinueConsumeBodyRunnable(
|
||||||
new ContinueConsumeBodyRunnable<Derived>(
|
mBodyConsumer, mWorkerRef->Private(), aStatus, aResultLength,
|
||||||
mFetchBodyConsumer, mWorkerRef->Private(), aStatus, aResultLength,
|
nonconstResult);
|
||||||
nonconstResult);
|
|
||||||
if (r->Dispatch()) {
|
if (r->Dispatch()) {
|
||||||
// FetchBody is responsible for data.
|
// The caller is responsible for data.
|
||||||
return NS_SUCCESS_ADOPTED_DATA;
|
return NS_SUCCESS_ADOPTED_DATA;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,9 +228,9 @@ class ConsumeBodyDoneObserver final : public nsIStreamLoaderObserver,
|
|||||||
// The worker is shutting down. Let's use a control runnable to complete the
|
// The worker is shutting down. Let's use a control runnable to complete the
|
||||||
// shutting down procedure.
|
// shutting down procedure.
|
||||||
|
|
||||||
RefPtr<AbortConsumeBodyControlRunnable<Derived>> r =
|
RefPtr<AbortConsumeBodyControlRunnable> r =
|
||||||
new AbortConsumeBodyControlRunnable<Derived>(mFetchBodyConsumer,
|
new AbortConsumeBodyControlRunnable(mBodyConsumer,
|
||||||
mWorkerRef->Private());
|
mWorkerRef->Private());
|
||||||
if (NS_WARN_IF(!r->Dispatch())) {
|
if (NS_WARN_IF(!r->Dispatch())) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
@ -257,36 +249,29 @@ class ConsumeBodyDoneObserver final : public nsIStreamLoaderObserver,
|
|||||||
|
|
||||||
// The loading is completed. Let's nullify the pump before continuing the
|
// The loading is completed. Let's nullify the pump before continuing the
|
||||||
// consuming of the body.
|
// consuming of the body.
|
||||||
mFetchBodyConsumer->NullifyConsumeBodyPump();
|
mBodyConsumer->NullifyConsumeBodyPump();
|
||||||
|
|
||||||
mFetchBodyConsumer->OnBlobResult(aBlob, mWorkerRef);
|
mBodyConsumer->OnBlobResult(aBlob, mWorkerRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~ConsumeBodyDoneObserver() = default;
|
~ConsumeBodyDoneObserver() = default;
|
||||||
|
|
||||||
RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer;
|
RefPtr<BodyConsumer> mBodyConsumer;
|
||||||
RefPtr<ThreadSafeWorkerRef> mWorkerRef;
|
RefPtr<ThreadSafeWorkerRef> mWorkerRef;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Derived>
|
NS_IMPL_ISUPPORTS(ConsumeBodyDoneObserver, nsIStreamLoaderObserver)
|
||||||
NS_IMPL_ADDREF(ConsumeBodyDoneObserver<Derived>)
|
|
||||||
template <class Derived>
|
|
||||||
NS_IMPL_RELEASE(ConsumeBodyDoneObserver<Derived>)
|
|
||||||
template <class Derived>
|
|
||||||
NS_INTERFACE_MAP_BEGIN(ConsumeBodyDoneObserver<Derived>)
|
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIStreamLoaderObserver)
|
|
||||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStreamLoaderObserver)
|
|
||||||
NS_INTERFACE_MAP_END
|
|
||||||
|
|
||||||
} // anonymous
|
} // namespace
|
||||||
|
|
||||||
template <class Derived>
|
/* static */ already_AddRefed<Promise> BodyConsumer::Create(
|
||||||
/* static */ already_AddRefed<Promise> FetchBodyConsumer<Derived>::Create(
|
|
||||||
nsIGlobalObject* aGlobal, nsIEventTarget* aMainThreadEventTarget,
|
nsIGlobalObject* aGlobal, nsIEventTarget* aMainThreadEventTarget,
|
||||||
FetchBody<Derived>* aBody, nsIInputStream* aBodyStream,
|
nsIInputStream* aBodyStream, AbortSignalImpl* aSignalImpl,
|
||||||
AbortSignalImpl* aSignalImpl, FetchConsumeType aType, ErrorResult& aRv) {
|
ConsumeType aType, const nsACString& aBodyBlobURISpec,
|
||||||
MOZ_ASSERT(aBody);
|
const nsAString& aBodyLocalPath, const nsACString& aBodyMimeType,
|
||||||
|
MutableBlobStorage::MutableBlobStorageType aBlobStorageType,
|
||||||
|
ErrorResult& aRv) {
|
||||||
MOZ_ASSERT(aBodyStream);
|
MOZ_ASSERT(aBodyStream);
|
||||||
MOZ_ASSERT(aMainThreadEventTarget);
|
MOZ_ASSERT(aMainThreadEventTarget);
|
||||||
|
|
||||||
@ -295,8 +280,9 @@ template <class Derived>
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<FetchBodyConsumer<Derived>> consumer = new FetchBodyConsumer<Derived>(
|
RefPtr<BodyConsumer> consumer = new BodyConsumer(
|
||||||
aMainThreadEventTarget, aGlobal, aBody, aBodyStream, promise, aType);
|
aMainThreadEventTarget, aGlobal, aBodyStream, promise, aType,
|
||||||
|
aBodyBlobURISpec, aBodyLocalPath, aBodyMimeType, aBlobStorageType);
|
||||||
|
|
||||||
RefPtr<ThreadSafeWorkerRef> workerRef;
|
RefPtr<ThreadSafeWorkerRef> workerRef;
|
||||||
|
|
||||||
@ -305,7 +291,7 @@ template <class Derived>
|
|||||||
MOZ_ASSERT(workerPrivate);
|
MOZ_ASSERT(workerPrivate);
|
||||||
|
|
||||||
RefPtr<StrongWorkerRef> strongWorkerRef = StrongWorkerRef::Create(
|
RefPtr<StrongWorkerRef> strongWorkerRef = StrongWorkerRef::Create(
|
||||||
workerPrivate, "FetchBodyConsumer",
|
workerPrivate, "BodyConsumer",
|
||||||
[consumer]() { consumer->ShutDownMainThreadConsuming(); });
|
[consumer]() { consumer->ShutDownMainThreadConsuming(); });
|
||||||
if (NS_WARN_IF(!strongWorkerRef)) {
|
if (NS_WARN_IF(!strongWorkerRef)) {
|
||||||
aRv.Throw(NS_ERROR_FAILURE);
|
aRv.Throw(NS_ERROR_FAILURE);
|
||||||
@ -331,8 +317,7 @@ template <class Derived>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIRunnable> r =
|
nsCOMPtr<nsIRunnable> r = new BeginConsumeBodyRunnable(consumer, workerRef);
|
||||||
new BeginConsumeBodyRunnable<Derived>(consumer, workerRef);
|
|
||||||
aRv = aMainThreadEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
|
aRv = aMainThreadEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
|
||||||
if (NS_WARN_IF(aRv.Failed())) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -345,8 +330,7 @@ template <class Derived>
|
|||||||
return promise.forget();
|
return promise.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Derived>
|
void BodyConsumer::ReleaseObject() {
|
||||||
void FetchBodyConsumer<Derived>::ReleaseObject() {
|
|
||||||
AssertIsOnTargetThread();
|
AssertIsOnTargetThread();
|
||||||
|
|
||||||
if (NS_IsMainThread()) {
|
if (NS_IsMainThread()) {
|
||||||
@ -359,78 +343,51 @@ void FetchBodyConsumer<Derived>::ReleaseObject() {
|
|||||||
|
|
||||||
mGlobal = nullptr;
|
mGlobal = nullptr;
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
mBody = nullptr;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Unfollow();
|
Unfollow();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Derived>
|
BodyConsumer::BodyConsumer(
|
||||||
FetchBodyConsumer<Derived>::FetchBodyConsumer(
|
|
||||||
nsIEventTarget* aMainThreadEventTarget, nsIGlobalObject* aGlobalObject,
|
nsIEventTarget* aMainThreadEventTarget, nsIGlobalObject* aGlobalObject,
|
||||||
FetchBody<Derived>* aBody, nsIInputStream* aBodyStream, Promise* aPromise,
|
nsIInputStream* aBodyStream, Promise* aPromise, ConsumeType aType,
|
||||||
FetchConsumeType aType)
|
const nsACString& aBodyBlobURISpec, const nsAString& aBodyLocalPath,
|
||||||
|
const nsACString& aBodyMimeType,
|
||||||
|
MutableBlobStorage::MutableBlobStorageType aBlobStorageType)
|
||||||
: mTargetThread(NS_GetCurrentThread()),
|
: mTargetThread(NS_GetCurrentThread()),
|
||||||
mMainThreadEventTarget(aMainThreadEventTarget)
|
mMainThreadEventTarget(aMainThreadEventTarget),
|
||||||
#ifdef DEBUG
|
|
||||||
,
|
|
||||||
mBody(aBody)
|
|
||||||
#endif
|
|
||||||
,
|
|
||||||
mBodyStream(aBodyStream),
|
mBodyStream(aBodyStream),
|
||||||
mBlobStorageType(MutableBlobStorage::eOnlyInMemory),
|
mBlobStorageType(aBlobStorageType),
|
||||||
mBodyBlobURISpec(aBody ? aBody->BodyBlobURISpec() : VoidCString()),
|
mBodyMimeType(aBodyMimeType),
|
||||||
mBodyLocalPath(aBody ? aBody->BodyLocalPath() : VoidString()),
|
mBodyBlobURISpec(aBodyBlobURISpec),
|
||||||
|
mBodyLocalPath(aBodyLocalPath),
|
||||||
mGlobal(aGlobalObject),
|
mGlobal(aGlobalObject),
|
||||||
mConsumeType(aType),
|
mConsumeType(aType),
|
||||||
mConsumePromise(aPromise),
|
mConsumePromise(aPromise),
|
||||||
mBodyConsumed(false),
|
mBodyConsumed(false),
|
||||||
mShuttingDown(false) {
|
mShuttingDown(false) {
|
||||||
MOZ_ASSERT(aMainThreadEventTarget);
|
MOZ_ASSERT(aMainThreadEventTarget);
|
||||||
MOZ_ASSERT(aBody);
|
|
||||||
MOZ_ASSERT(aBodyStream);
|
MOZ_ASSERT(aBodyStream);
|
||||||
MOZ_ASSERT(aPromise);
|
MOZ_ASSERT(aPromise);
|
||||||
|
|
||||||
const mozilla::UniquePtr<mozilla::ipc::PrincipalInfo>& principalInfo =
|
|
||||||
aBody->DerivedClass()->GetPrincipalInfo();
|
|
||||||
// We support temporary file for blobs only if the principal is known and
|
|
||||||
// it's system or content not in private Browsing.
|
|
||||||
if (principalInfo &&
|
|
||||||
(principalInfo->type() ==
|
|
||||||
mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo ||
|
|
||||||
(principalInfo->type() ==
|
|
||||||
mozilla::ipc::PrincipalInfo::TContentPrincipalInfo &&
|
|
||||||
principalInfo->get_ContentPrincipalInfo().attrs().mPrivateBrowsingId ==
|
|
||||||
0))) {
|
|
||||||
mBlobStorageType = MutableBlobStorage::eCouldBeInTemporaryFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
mBodyMimeType = aBody->MimeType();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Derived>
|
BodyConsumer::~BodyConsumer() = default;
|
||||||
FetchBodyConsumer<Derived>::~FetchBodyConsumer() {}
|
|
||||||
|
|
||||||
template <class Derived>
|
void BodyConsumer::AssertIsOnTargetThread() const {
|
||||||
void FetchBodyConsumer<Derived>::AssertIsOnTargetThread() const {
|
|
||||||
MOZ_ASSERT(NS_GetCurrentThread() == mTargetThread);
|
MOZ_ASSERT(NS_GetCurrentThread() == mTargetThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
template <class Derived>
|
|
||||||
class FileCreationHandler final : public PromiseNativeHandler {
|
class FileCreationHandler final : public PromiseNativeHandler {
|
||||||
public:
|
public:
|
||||||
NS_DECL_THREADSAFE_ISUPPORTS
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
|
|
||||||
static void Create(Promise* aPromise, FetchBodyConsumer<Derived>* aConsumer,
|
static void Create(Promise* aPromise, BodyConsumer* aConsumer,
|
||||||
ThreadSafeWorkerRef* aWorkerRef) {
|
ThreadSafeWorkerRef* aWorkerRef) {
|
||||||
AssertIsOnMainThread();
|
AssertIsOnMainThread();
|
||||||
MOZ_ASSERT(aPromise);
|
MOZ_ASSERT(aPromise);
|
||||||
|
|
||||||
RefPtr<FileCreationHandler> handler =
|
RefPtr<FileCreationHandler> handler =
|
||||||
new FileCreationHandler<Derived>(aConsumer, aWorkerRef);
|
new FileCreationHandler(aConsumer, aWorkerRef);
|
||||||
aPromise->AppendNativeHandler(handler);
|
aPromise->AppendNativeHandler(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,8 +415,7 @@ class FileCreationHandler final : public PromiseNativeHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FileCreationHandler<Derived>(FetchBodyConsumer<Derived>* aConsumer,
|
FileCreationHandler(BodyConsumer* aConsumer, ThreadSafeWorkerRef* aWorkerRef)
|
||||||
ThreadSafeWorkerRef* aWorkerRef)
|
|
||||||
: mConsumer(aConsumer), mWorkerRef(aWorkerRef) {
|
: mConsumer(aConsumer), mWorkerRef(aWorkerRef) {
|
||||||
AssertIsOnMainThread();
|
AssertIsOnMainThread();
|
||||||
MOZ_ASSERT(aConsumer);
|
MOZ_ASSERT(aConsumer);
|
||||||
@ -467,23 +423,15 @@ class FileCreationHandler final : public PromiseNativeHandler {
|
|||||||
|
|
||||||
~FileCreationHandler() = default;
|
~FileCreationHandler() = default;
|
||||||
|
|
||||||
RefPtr<FetchBodyConsumer<Derived>> mConsumer;
|
RefPtr<BodyConsumer> mConsumer;
|
||||||
RefPtr<ThreadSafeWorkerRef> mWorkerRef;
|
RefPtr<ThreadSafeWorkerRef> mWorkerRef;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Derived>
|
NS_IMPL_ISUPPORTS0(FileCreationHandler)
|
||||||
NS_IMPL_ADDREF(FileCreationHandler<Derived>)
|
|
||||||
template <class Derived>
|
|
||||||
NS_IMPL_RELEASE(FileCreationHandler<Derived>)
|
|
||||||
template <class Derived>
|
|
||||||
NS_INTERFACE_MAP_BEGIN(FileCreationHandler<Derived>)
|
|
||||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
||||||
NS_INTERFACE_MAP_END
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
template <class Derived>
|
nsresult BodyConsumer::GetBodyLocalFile(nsIFile** aFile) const {
|
||||||
nsresult FetchBodyConsumer<Derived>::GetBodyLocalFile(nsIFile** aFile) const {
|
|
||||||
AssertIsOnMainThread();
|
AssertIsOnMainThread();
|
||||||
|
|
||||||
if (!mBodyLocalPath.Length()) {
|
if (!mBodyLocalPath.Length()) {
|
||||||
@ -522,12 +470,10 @@ nsresult FetchBodyConsumer<Derived>::GetBodyLocalFile(nsIFile** aFile) const {
|
|||||||
* and clean up on any failures, so there is no need for callers to do so,
|
* and clean up on any failures, so there is no need for callers to do so,
|
||||||
* reflected in a lack of error return code.
|
* reflected in a lack of error return code.
|
||||||
*/
|
*/
|
||||||
template <class Derived>
|
void BodyConsumer::BeginConsumeBodyMainThread(ThreadSafeWorkerRef* aWorkerRef) {
|
||||||
void FetchBodyConsumer<Derived>::BeginConsumeBodyMainThread(
|
|
||||||
ThreadSafeWorkerRef* aWorkerRef) {
|
|
||||||
AssertIsOnMainThread();
|
AssertIsOnMainThread();
|
||||||
|
|
||||||
AutoFailConsumeBody<Derived> autoReject(this, aWorkerRef);
|
AutoFailConsumeBody autoReject(this, aWorkerRef);
|
||||||
|
|
||||||
if (mShuttingDown) {
|
if (mShuttingDown) {
|
||||||
// We haven't started yet, but we have been terminated. AutoFailConsumeBody
|
// We haven't started yet, but we have been terminated. AutoFailConsumeBody
|
||||||
@ -567,7 +513,7 @@ void FetchBodyConsumer<Derived>::BeginConsumeBodyMainThread(
|
|||||||
}
|
}
|
||||||
|
|
||||||
autoReject.DontFail();
|
autoReject.DontFail();
|
||||||
FileCreationHandler<Derived>::Create(promise, this, aWorkerRef);
|
FileCreationHandler::Create(promise, this, aWorkerRef);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -580,8 +526,8 @@ void FetchBodyConsumer<Derived>::BeginConsumeBodyMainThread(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<ConsumeBodyDoneObserver<Derived>> p =
|
RefPtr<ConsumeBodyDoneObserver> p =
|
||||||
new ConsumeBodyDoneObserver<Derived>(this, aWorkerRef);
|
new ConsumeBodyDoneObserver(this, aWorkerRef);
|
||||||
|
|
||||||
nsCOMPtr<nsIStreamListener> listener;
|
nsCOMPtr<nsIStreamListener> listener;
|
||||||
if (mConsumeType == CONSUME_BLOB) {
|
if (mConsumeType == CONSUME_BLOB) {
|
||||||
@ -603,7 +549,7 @@ void FetchBodyConsumer<Derived>::BeginConsumeBodyMainThread(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now that everything succeeded, we can assign the pump to a pointer that
|
// Now that everything succeeded, we can assign the pump to a pointer that
|
||||||
// stays alive for the lifetime of the FetchConsumer.
|
// stays alive for the lifetime of the BodyConsumer.
|
||||||
mConsumeBodyPump = pump;
|
mConsumeBodyPump = pump;
|
||||||
|
|
||||||
// It is ok for retargeting to fail and reads to happen on the main thread.
|
// It is ok for retargeting to fail and reads to happen on the main thread.
|
||||||
@ -627,16 +573,13 @@ void FetchBodyConsumer<Derived>::BeginConsumeBodyMainThread(
|
|||||||
* been wrapped by FileCreationHandler). The blob is sent to the target thread
|
* been wrapped by FileCreationHandler). The blob is sent to the target thread
|
||||||
* and ContinueConsumeBody is called.
|
* and ContinueConsumeBody is called.
|
||||||
*/
|
*/
|
||||||
template <class Derived>
|
void BodyConsumer::OnBlobResult(Blob* aBlob, ThreadSafeWorkerRef* aWorkerRef) {
|
||||||
void FetchBodyConsumer<Derived>::OnBlobResult(Blob* aBlob,
|
|
||||||
ThreadSafeWorkerRef* aWorkerRef) {
|
|
||||||
AssertIsOnMainThread();
|
AssertIsOnMainThread();
|
||||||
|
|
||||||
DispatchContinueConsumeBlobBody(aBlob ? aBlob->Impl() : nullptr, aWorkerRef);
|
DispatchContinueConsumeBlobBody(aBlob ? aBlob->Impl() : nullptr, aWorkerRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Derived>
|
void BodyConsumer::DispatchContinueConsumeBlobBody(
|
||||||
void FetchBodyConsumer<Derived>::DispatchContinueConsumeBlobBody(
|
|
||||||
BlobImpl* aBlobImpl, ThreadSafeWorkerRef* aWorkerRef) {
|
BlobImpl* aBlobImpl, ThreadSafeWorkerRef* aWorkerRef) {
|
||||||
AssertIsOnMainThread();
|
AssertIsOnMainThread();
|
||||||
|
|
||||||
@ -652,17 +595,16 @@ void FetchBodyConsumer<Derived>::DispatchContinueConsumeBlobBody(
|
|||||||
|
|
||||||
// Web Worker.
|
// Web Worker.
|
||||||
if (aBlobImpl) {
|
if (aBlobImpl) {
|
||||||
RefPtr<ContinueConsumeBlobBodyRunnable<Derived>> r =
|
RefPtr<ContinueConsumeBlobBodyRunnable> r =
|
||||||
new ContinueConsumeBlobBodyRunnable<Derived>(
|
new ContinueConsumeBlobBodyRunnable(this, aWorkerRef->Private(),
|
||||||
this, aWorkerRef->Private(), aBlobImpl);
|
aBlobImpl);
|
||||||
|
|
||||||
if (r->Dispatch()) {
|
if (r->Dispatch()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
RefPtr<ContinueConsumeBodyRunnable<Derived>> r =
|
RefPtr<ContinueConsumeBodyRunnable> r = new ContinueConsumeBodyRunnable(
|
||||||
new ContinueConsumeBodyRunnable<Derived>(
|
this, aWorkerRef->Private(), NS_ERROR_DOM_ABORT_ERR, 0, nullptr);
|
||||||
this, aWorkerRef->Private(), NS_ERROR_DOM_ABORT_ERR, 0, nullptr);
|
|
||||||
|
|
||||||
if (r->Dispatch()) {
|
if (r->Dispatch()) {
|
||||||
return;
|
return;
|
||||||
@ -672,9 +614,8 @@ void FetchBodyConsumer<Derived>::DispatchContinueConsumeBlobBody(
|
|||||||
// The worker is shutting down. Let's use a control runnable to complete the
|
// The worker is shutting down. Let's use a control runnable to complete the
|
||||||
// shutting down procedure.
|
// shutting down procedure.
|
||||||
|
|
||||||
RefPtr<AbortConsumeBlobBodyControlRunnable<Derived>> r =
|
RefPtr<AbortConsumeBlobBodyControlRunnable> r =
|
||||||
new AbortConsumeBlobBodyControlRunnable<Derived>(this,
|
new AbortConsumeBlobBodyControlRunnable(this, aWorkerRef->Private());
|
||||||
aWorkerRef->Private());
|
|
||||||
|
|
||||||
Unused << NS_WARN_IF(!r->Dispatch());
|
Unused << NS_WARN_IF(!r->Dispatch());
|
||||||
}
|
}
|
||||||
@ -685,11 +626,8 @@ void FetchBodyConsumer<Derived>::DispatchContinueConsumeBlobBody(
|
|||||||
* rejected based on whether the fetch succeeded, and the body can be
|
* rejected based on whether the fetch succeeded, and the body can be
|
||||||
* converted into the expected type of JS object.
|
* converted into the expected type of JS object.
|
||||||
*/
|
*/
|
||||||
template <class Derived>
|
void BodyConsumer::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength,
|
||||||
void FetchBodyConsumer<Derived>::ContinueConsumeBody(nsresult aStatus,
|
uint8_t* aResult, bool aShuttingDown) {
|
||||||
uint32_t aResultLength,
|
|
||||||
uint8_t* aResult,
|
|
||||||
bool aShuttingDown) {
|
|
||||||
AssertIsOnTargetThread();
|
AssertIsOnTargetThread();
|
||||||
|
|
||||||
// This makes sure that we free the data correctly.
|
// This makes sure that we free the data correctly.
|
||||||
@ -700,14 +638,10 @@ void FetchBodyConsumer<Derived>::ContinueConsumeBody(nsresult aStatus,
|
|||||||
}
|
}
|
||||||
mBodyConsumed = true;
|
mBodyConsumed = true;
|
||||||
|
|
||||||
// Just a precaution to ensure ContinueConsumeBody is not called out of
|
|
||||||
// sync with a body read.
|
|
||||||
MOZ_ASSERT(mBody->CheckBodyUsed());
|
|
||||||
|
|
||||||
MOZ_ASSERT(mConsumePromise);
|
MOZ_ASSERT(mConsumePromise);
|
||||||
RefPtr<Promise> localPromise = mConsumePromise.forget();
|
RefPtr<Promise> localPromise = mConsumePromise.forget();
|
||||||
|
|
||||||
RefPtr<FetchBodyConsumer<Derived>> self = this;
|
RefPtr<BodyConsumer> self = this;
|
||||||
auto autoReleaseObject =
|
auto autoReleaseObject =
|
||||||
mozilla::MakeScopeExit([self] { self->ReleaseObject(); });
|
mozilla::MakeScopeExit([self] { self->ReleaseObject(); });
|
||||||
|
|
||||||
@ -721,9 +655,7 @@ void FetchBodyConsumer<Derived>::ContinueConsumeBody(nsresult aStatus,
|
|||||||
// https://fetch.spec.whatwg.org/#concept-read-all-bytes-from-readablestream
|
// https://fetch.spec.whatwg.org/#concept-read-all-bytes-from-readablestream
|
||||||
// Decoding errors should reject with a TypeError
|
// Decoding errors should reject with a TypeError
|
||||||
if (aStatus == NS_ERROR_INVALID_CONTENT_ENCODING) {
|
if (aStatus == NS_ERROR_INVALID_CONTENT_ENCODING) {
|
||||||
IgnoredErrorResult rv;
|
localPromise->MaybeRejectWithTypeError<MSG_DOM_DECODING_FAILED>();
|
||||||
rv.ThrowTypeError<MSG_DOM_DECODING_FAILED>();
|
|
||||||
localPromise->MaybeReject(rv);
|
|
||||||
} else {
|
} else {
|
||||||
localPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
|
localPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
|
||||||
}
|
}
|
||||||
@ -806,9 +738,8 @@ void FetchBodyConsumer<Derived>::ContinueConsumeBody(nsresult aStatus,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Derived>
|
void BodyConsumer::ContinueConsumeBlobBody(BlobImpl* aBlobImpl,
|
||||||
void FetchBodyConsumer<Derived>::ContinueConsumeBlobBody(BlobImpl* aBlobImpl,
|
bool aShuttingDown) {
|
||||||
bool aShuttingDown) {
|
|
||||||
AssertIsOnTargetThread();
|
AssertIsOnTargetThread();
|
||||||
MOZ_ASSERT(mConsumeType == CONSUME_BLOB);
|
MOZ_ASSERT(mConsumeType == CONSUME_BLOB);
|
||||||
|
|
||||||
@ -817,10 +748,6 @@ void FetchBodyConsumer<Derived>::ContinueConsumeBlobBody(BlobImpl* aBlobImpl,
|
|||||||
}
|
}
|
||||||
mBodyConsumed = true;
|
mBodyConsumed = true;
|
||||||
|
|
||||||
// Just a precaution to ensure ContinueConsumeBody is not called out of
|
|
||||||
// sync with a body read.
|
|
||||||
MOZ_ASSERT(mBody->CheckBodyUsed());
|
|
||||||
|
|
||||||
MOZ_ASSERT(mConsumePromise);
|
MOZ_ASSERT(mConsumePromise);
|
||||||
RefPtr<Promise> localPromise = mConsumePromise.forget();
|
RefPtr<Promise> localPromise = mConsumePromise.forget();
|
||||||
|
|
||||||
@ -834,13 +761,12 @@ void FetchBodyConsumer<Derived>::ContinueConsumeBlobBody(BlobImpl* aBlobImpl,
|
|||||||
ReleaseObject();
|
ReleaseObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Derived>
|
void BodyConsumer::ShutDownMainThreadConsuming() {
|
||||||
void FetchBodyConsumer<Derived>::ShutDownMainThreadConsuming() {
|
|
||||||
if (!NS_IsMainThread()) {
|
if (!NS_IsMainThread()) {
|
||||||
RefPtr<FetchBodyConsumer<Derived>> self = this;
|
RefPtr<BodyConsumer> self = this;
|
||||||
|
|
||||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
|
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
|
||||||
"FetchBodyConsumer::ShutDownMainThreadConsuming",
|
"BodyConsumer::ShutDownMainThreadConsuming",
|
||||||
[self]() { self->ShutDownMainThreadConsuming(); });
|
[self]() { self->ShutDownMainThreadConsuming(); });
|
||||||
|
|
||||||
mMainThreadEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
|
mMainThreadEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
|
||||||
@ -857,10 +783,8 @@ void FetchBodyConsumer<Derived>::ShutDownMainThreadConsuming() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Derived>
|
NS_IMETHODIMP BodyConsumer::Observe(nsISupports* aSubject, const char* aTopic,
|
||||||
NS_IMETHODIMP FetchBodyConsumer<Derived>::Observe(nsISupports* aSubject,
|
const char16_t* aData) {
|
||||||
const char* aTopic,
|
|
||||||
const char16_t* aData) {
|
|
||||||
AssertIsOnMainThread();
|
AssertIsOnMainThread();
|
||||||
|
|
||||||
MOZ_ASSERT((strcmp(aTopic, DOM_WINDOW_FROZEN_TOPIC) == 0) ||
|
MOZ_ASSERT((strcmp(aTopic, DOM_WINDOW_FROZEN_TOPIC) == 0) ||
|
||||||
@ -874,22 +798,13 @@ NS_IMETHODIMP FetchBodyConsumer<Derived>::Observe(nsISupports* aSubject,
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Derived>
|
void BodyConsumer::Abort() {
|
||||||
void FetchBodyConsumer<Derived>::Abort() {
|
|
||||||
AssertIsOnTargetThread();
|
AssertIsOnTargetThread();
|
||||||
ShutDownMainThreadConsuming();
|
ShutDownMainThreadConsuming();
|
||||||
ContinueConsumeBody(NS_ERROR_DOM_ABORT_ERR, 0, nullptr);
|
ContinueConsumeBody(NS_ERROR_DOM_ABORT_ERR, 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Derived>
|
NS_IMPL_ISUPPORTS(BodyConsumer, nsIObserver, nsISupportsWeakReference)
|
||||||
NS_IMPL_ADDREF(FetchBodyConsumer<Derived>)
|
|
||||||
|
|
||||||
template <class Derived>
|
|
||||||
NS_IMPL_RELEASE(FetchBodyConsumer<Derived>)
|
|
||||||
|
|
||||||
template <class Derived>
|
|
||||||
NS_IMPL_QUERY_INTERFACE(FetchBodyConsumer<Derived>, nsIObserver,
|
|
||||||
nsISupportsWeakReference)
|
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
136
dom/base/BodyConsumer.h
Normal file
136
dom/base/BodyConsumer.h
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_dom_BodyConsumer_h
|
||||||
|
#define mozilla_dom_BodyConsumer_h
|
||||||
|
|
||||||
|
#include "mozilla/dom/AbortSignal.h"
|
||||||
|
#include "mozilla/dom/MutableBlobStorage.h"
|
||||||
|
#include "nsIInputStreamPump.h"
|
||||||
|
#include "nsIObserver.h"
|
||||||
|
#include "nsWeakReference.h"
|
||||||
|
|
||||||
|
class nsIThread;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
class Promise;
|
||||||
|
class ThreadSafeWorkerRef;
|
||||||
|
|
||||||
|
// In order to keep alive the object all the time, we use a ThreadSafeWorkerRef,
|
||||||
|
// if created on workers.
|
||||||
|
class BodyConsumer final : public nsIObserver,
|
||||||
|
public nsSupportsWeakReference,
|
||||||
|
public AbortFollower {
|
||||||
|
public:
|
||||||
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
|
NS_DECL_NSIOBSERVER
|
||||||
|
|
||||||
|
enum ConsumeType {
|
||||||
|
CONSUME_ARRAYBUFFER,
|
||||||
|
CONSUME_BLOB,
|
||||||
|
CONSUME_FORMDATA,
|
||||||
|
CONSUME_JSON,
|
||||||
|
CONSUME_TEXT,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a promise which will be resolved when the body is completely
|
||||||
|
* consumed and converted to the wanted type (See ConsumeType).
|
||||||
|
*
|
||||||
|
* @param aGlobal the global to construct the Promise.
|
||||||
|
* @param aMainThreadEventTarget the main-thread event target. The reading
|
||||||
|
* needs to start on the main-thread because of nsIInputStreamPump.
|
||||||
|
* @param aBodyStream the stream to read.
|
||||||
|
* @param aSignalImpl an AbortSignal object. Optional.
|
||||||
|
* @param aType the consume type.
|
||||||
|
* @param aBodyBlobURISpec this is used only if the consume type is
|
||||||
|
* CONSUME_BLOB. Optional.
|
||||||
|
* @param aBodyLocalPath local path in case the blob is created from a local
|
||||||
|
* file. Used only by CONSUME_BLOB. Optional.
|
||||||
|
* @param aBodyMimeType the mime-type for blob. Used only by CONSUME_BLOB.
|
||||||
|
* Optional.
|
||||||
|
* @param aBlobStorageType Blobs can be saved in temporary file. This is the
|
||||||
|
* type of blob storage to use. Used only by CONSUME_BLOB.
|
||||||
|
* @param aRv An ErrorResult.
|
||||||
|
*/
|
||||||
|
static already_AddRefed<Promise> Create(
|
||||||
|
nsIGlobalObject* aGlobal, nsIEventTarget* aMainThreadEventTarget,
|
||||||
|
nsIInputStream* aBodyStream, AbortSignalImpl* aSignalImpl,
|
||||||
|
ConsumeType aType, const nsACString& aBodyBlobURISpec,
|
||||||
|
const nsAString& aBodyLocalPath, const nsACString& aBodyMimeType,
|
||||||
|
MutableBlobStorage::MutableBlobStorageType aBlobStorageType,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
void ReleaseObject();
|
||||||
|
|
||||||
|
void BeginConsumeBodyMainThread(ThreadSafeWorkerRef* aWorkerRef);
|
||||||
|
|
||||||
|
void OnBlobResult(Blob* aBlob, ThreadSafeWorkerRef* aWorkerRef = nullptr);
|
||||||
|
|
||||||
|
void ContinueConsumeBody(nsresult aStatus, uint32_t aLength, uint8_t* aResult,
|
||||||
|
bool aShuttingDown = false);
|
||||||
|
|
||||||
|
void ContinueConsumeBlobBody(BlobImpl* aBlobImpl, bool aShuttingDown = false);
|
||||||
|
|
||||||
|
void DispatchContinueConsumeBlobBody(BlobImpl* aBlobImpl,
|
||||||
|
ThreadSafeWorkerRef* aWorkerRef);
|
||||||
|
|
||||||
|
void ShutDownMainThreadConsuming();
|
||||||
|
|
||||||
|
void NullifyConsumeBodyPump() {
|
||||||
|
mShuttingDown = true;
|
||||||
|
mConsumeBodyPump = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// AbortFollower
|
||||||
|
void Abort() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BodyConsumer(nsIEventTarget* aMainThreadEventTarget,
|
||||||
|
nsIGlobalObject* aGlobalObject, nsIInputStream* aBodyStream,
|
||||||
|
Promise* aPromise, ConsumeType aType,
|
||||||
|
const nsACString& aBodyBlobURISpec,
|
||||||
|
const nsAString& aBodyLocalPath, const nsACString& aBodyMimeType,
|
||||||
|
MutableBlobStorage::MutableBlobStorageType aBlobStorageType);
|
||||||
|
|
||||||
|
~BodyConsumer();
|
||||||
|
|
||||||
|
nsresult GetBodyLocalFile(nsIFile** aFile) const;
|
||||||
|
|
||||||
|
void AssertIsOnTargetThread() const;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIThread> mTargetThread;
|
||||||
|
nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
|
||||||
|
|
||||||
|
// This is nullified when the consuming of the body starts.
|
||||||
|
nsCOMPtr<nsIInputStream> mBodyStream;
|
||||||
|
|
||||||
|
MutableBlobStorage::MutableBlobStorageType mBlobStorageType;
|
||||||
|
nsCString mBodyMimeType;
|
||||||
|
|
||||||
|
nsCString mBodyBlobURISpec;
|
||||||
|
nsString mBodyLocalPath;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||||
|
|
||||||
|
// Touched on the main-thread only.
|
||||||
|
nsCOMPtr<nsIInputStreamPump> mConsumeBodyPump;
|
||||||
|
|
||||||
|
// Only ever set once, always on target thread.
|
||||||
|
ConsumeType mConsumeType;
|
||||||
|
RefPtr<Promise> mConsumePromise;
|
||||||
|
|
||||||
|
// touched only on the target thread.
|
||||||
|
bool mBodyConsumed;
|
||||||
|
|
||||||
|
// touched only on the main-thread.
|
||||||
|
bool mShuttingDown;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace dom
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // mozilla_dom_BodyConsumer_h
|
@ -2,12 +2,13 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "FetchStream.h"
|
#include "BodyStream.h"
|
||||||
#include "mozilla/CycleCollectedJSContext.h"
|
#include "mozilla/CycleCollectedJSContext.h"
|
||||||
#include "mozilla/dom/DOMException.h"
|
#include "mozilla/dom/DOMException.h"
|
||||||
#include "mozilla/dom/ScriptSettings.h"
|
#include "mozilla/dom/ScriptSettings.h"
|
||||||
#include "mozilla/dom/WorkerCommon.h"
|
#include "mozilla/dom/WorkerCommon.h"
|
||||||
#include "mozilla/dom/WorkerPrivate.h"
|
#include "mozilla/dom/WorkerPrivate.h"
|
||||||
|
#include "mozilla/dom/WorkerRunnable.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "nsProxyRelease.h"
|
#include "nsProxyRelease.h"
|
||||||
#include "nsStreamUtils.h"
|
#include "nsStreamUtils.h"
|
||||||
@ -17,9 +18,47 @@ static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID);
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
class FetchStream::WorkerShutdown final : public WorkerControlRunnable {
|
// BodyStreamHolder
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(BodyStreamHolder)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BodyStreamHolder)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BodyStreamHolder)
|
||||||
|
if (tmp->mBodyStream) {
|
||||||
|
tmp->mBodyStream->ReleaseObjects();
|
||||||
|
MOZ_ASSERT(!tmp->mBodyStream);
|
||||||
|
}
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(BodyStreamHolder)
|
||||||
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(BodyStreamHolder)
|
||||||
|
|
||||||
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BodyStreamHolder)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||||
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
|
BodyStreamHolder::BodyStreamHolder() : mBodyStream(nullptr) {}
|
||||||
|
|
||||||
|
void BodyStreamHolder::StoreBodyStream(BodyStream* aBodyStream) {
|
||||||
|
MOZ_ASSERT(aBodyStream);
|
||||||
|
MOZ_ASSERT(!mBodyStream);
|
||||||
|
mBodyStream = aBodyStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BodyStreamHolder::ForgetBodyStream() {
|
||||||
|
MOZ_ASSERT_IF(mStreamCreated, mBodyStream);
|
||||||
|
mBodyStream = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyStream
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class BodyStream::WorkerShutdown final : public WorkerControlRunnable {
|
||||||
public:
|
public:
|
||||||
WorkerShutdown(WorkerPrivate* aWorkerPrivate, RefPtr<FetchStream> aStream)
|
WorkerShutdown(WorkerPrivate* aWorkerPrivate, RefPtr<BodyStream> aStream)
|
||||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||||
mStream(aStream) {}
|
mStream(aStream) {}
|
||||||
|
|
||||||
@ -37,23 +76,24 @@ class FetchStream::WorkerShutdown final : public WorkerControlRunnable {
|
|||||||
bool aDispatchResult) override {}
|
bool aDispatchResult) override {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RefPtr<FetchStream> mStream;
|
RefPtr<BodyStream> mStream;
|
||||||
};
|
};
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(FetchStream, nsIInputStreamCallback, nsIObserver,
|
NS_IMPL_ISUPPORTS(BodyStream, nsIInputStreamCallback, nsIObserver,
|
||||||
nsISupportsWeakReference)
|
nsISupportsWeakReference)
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
void FetchStream::Create(JSContext* aCx, FetchStreamHolder* aStreamHolder,
|
void BodyStream::Create(JSContext* aCx, BodyStreamHolder* aStreamHolder,
|
||||||
nsIGlobalObject* aGlobal, nsIInputStream* aInputStream,
|
nsIGlobalObject* aGlobal, nsIInputStream* aInputStream,
|
||||||
JS::MutableHandle<JSObject*> aStream,
|
ErrorResult& aRv) {
|
||||||
ErrorResult& aRv) {
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aCx);
|
MOZ_DIAGNOSTIC_ASSERT(aCx);
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aStreamHolder);
|
MOZ_DIAGNOSTIC_ASSERT(aStreamHolder);
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aInputStream);
|
MOZ_DIAGNOSTIC_ASSERT(aInputStream);
|
||||||
|
|
||||||
RefPtr<FetchStream> stream =
|
RefPtr<BodyStream> stream =
|
||||||
new FetchStream(aGlobal, aStreamHolder, aInputStream);
|
new BodyStream(aGlobal, aStreamHolder, aInputStream);
|
||||||
|
|
||||||
|
auto cleanup = MakeScopeExit([stream] { stream->Close(); });
|
||||||
|
|
||||||
if (NS_IsMainThread()) {
|
if (NS_IsMainThread()) {
|
||||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||||
@ -86,23 +126,30 @@ void FetchStream::Create(JSContext* aCx, FetchStreamHolder* aStreamHolder,
|
|||||||
}
|
}
|
||||||
|
|
||||||
aRv.MightThrowJSException();
|
aRv.MightThrowJSException();
|
||||||
JS::Rooted<JSObject*> body(
|
JS::Rooted<JSObject*> body(aCx, JS::NewReadableExternalSourceStreamObject(
|
||||||
aCx, JS::NewReadableExternalSourceStreamObject(aCx, stream));
|
aCx, stream, aStreamHolder));
|
||||||
if (!body) {
|
if (!body) {
|
||||||
aRv.StealExceptionFromJSContext(aCx);
|
aRv.StealExceptionFromJSContext(aCx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This will be released in FetchStream::FinalizeCallback(). We are
|
// This will be released in BodyStream::FinalizeCallback(). We are
|
||||||
// guaranteed the jsapi will call FinalizeCallback when ReadableStream
|
// guaranteed the jsapi will call FinalizeCallback when ReadableStream
|
||||||
// js object is finalized.
|
// js object is finalized.
|
||||||
NS_ADDREF(stream.get());
|
NS_ADDREF(stream.get());
|
||||||
|
|
||||||
aStream.set(body);
|
cleanup.release();
|
||||||
|
|
||||||
|
aStreamHolder->StoreBodyStream(stream);
|
||||||
|
aStreamHolder->SetReadableStreamBody(body);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
aStreamHolder->mStreamCreated = true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void FetchStream::requestData(JSContext* aCx, JS::HandleObject aStream,
|
void BodyStream::requestData(JSContext* aCx, JS::HandleObject aStream,
|
||||||
size_t aDesiredSize) {
|
size_t aDesiredSize) {
|
||||||
#if MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
#if MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||||
bool disturbed;
|
bool disturbed;
|
||||||
if (!JS::ReadableStreamIsDisturbed(aCx, aStream, &disturbed)) {
|
if (!JS::ReadableStreamIsDisturbed(aCx, aStream, &disturbed)) {
|
||||||
@ -168,10 +215,10 @@ void FetchStream::requestData(JSContext* aCx, JS::HandleObject aStream,
|
|||||||
// All good.
|
// All good.
|
||||||
}
|
}
|
||||||
|
|
||||||
void FetchStream::writeIntoReadRequestBuffer(JSContext* aCx,
|
void BodyStream::writeIntoReadRequestBuffer(JSContext* aCx,
|
||||||
JS::HandleObject aStream,
|
JS::HandleObject aStream,
|
||||||
void* aBuffer, size_t aLength,
|
void* aBuffer, size_t aLength,
|
||||||
size_t* aByteWritten) {
|
size_t* aByteWritten) {
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aBuffer);
|
MOZ_DIAGNOSTIC_ASSERT(aBuffer);
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aByteWritten);
|
MOZ_DIAGNOSTIC_ASSERT(aByteWritten);
|
||||||
|
|
||||||
@ -207,8 +254,8 @@ void FetchStream::writeIntoReadRequestBuffer(JSContext* aCx,
|
|||||||
// All good.
|
// All good.
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::Value FetchStream::cancel(JSContext* aCx, JS::HandleObject aStream,
|
JS::Value BodyStream::cancel(JSContext* aCx, JS::HandleObject aStream,
|
||||||
JS::HandleValue aReason) {
|
JS::HandleValue aReason) {
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
|
|
||||||
if (mState == eInitializing) {
|
if (mState == eInitializing) {
|
||||||
@ -231,10 +278,10 @@ JS::Value FetchStream::cancel(JSContext* aCx, JS::HandleObject aStream,
|
|||||||
return JS::UndefinedValue();
|
return JS::UndefinedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FetchStream::onClosed(JSContext* aCx, JS::HandleObject aStream) {}
|
void BodyStream::onClosed(JSContext* aCx, JS::HandleObject aStream) {}
|
||||||
|
|
||||||
void FetchStream::onErrored(JSContext* aCx, JS::HandleObject aStream,
|
void BodyStream::onErrored(JSContext* aCx, JS::HandleObject aStream,
|
||||||
JS::HandleValue aReason) {
|
JS::HandleValue aReason) {
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
|
|
||||||
if (mState == eInitializing) {
|
if (mState == eInitializing) {
|
||||||
@ -249,19 +296,19 @@ void FetchStream::onErrored(JSContext* aCx, JS::HandleObject aStream,
|
|||||||
ReleaseObjects();
|
ReleaseObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FetchStream::finalize() {
|
void BodyStream::finalize() {
|
||||||
// This can be called in any thread.
|
// This can be called in any thread.
|
||||||
|
|
||||||
// This takes ownership of the ref created in FetchStream::Create().
|
// This takes ownership of the ref created in BodyStream::Create().
|
||||||
RefPtr<FetchStream> stream = dont_AddRef(this);
|
RefPtr<BodyStream> stream = dont_AddRef(this);
|
||||||
|
|
||||||
stream->ReleaseObjects();
|
stream->ReleaseObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
FetchStream::FetchStream(nsIGlobalObject* aGlobal,
|
BodyStream::BodyStream(nsIGlobalObject* aGlobal,
|
||||||
FetchStreamHolder* aStreamHolder,
|
BodyStreamHolder* aStreamHolder,
|
||||||
nsIInputStream* aInputStream)
|
nsIInputStream* aInputStream)
|
||||||
: mMutex("FetchStream::mMutex"),
|
: mMutex("BodyStream::mMutex"),
|
||||||
mState(eInitializing),
|
mState(eInitializing),
|
||||||
mGlobal(aGlobal),
|
mGlobal(aGlobal),
|
||||||
mStreamHolder(aStreamHolder),
|
mStreamHolder(aStreamHolder),
|
||||||
@ -271,11 +318,11 @@ FetchStream::FetchStream(nsIGlobalObject* aGlobal,
|
|||||||
MOZ_DIAGNOSTIC_ASSERT(aStreamHolder);
|
MOZ_DIAGNOSTIC_ASSERT(aStreamHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
FetchStream::~FetchStream() {}
|
BodyStream::~BodyStream() {}
|
||||||
|
|
||||||
void FetchStream::ErrorPropagation(JSContext* aCx,
|
void BodyStream::ErrorPropagation(JSContext* aCx,
|
||||||
const MutexAutoLock& aProofOfLock,
|
const MutexAutoLock& aProofOfLock,
|
||||||
JS::HandleObject aStream, nsresult aError) {
|
JS::HandleObject aStream, nsresult aError) {
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
|
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
@ -302,7 +349,7 @@ void FetchStream::ErrorPropagation(JSContext* aCx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
FetchStream::OnInputStreamReady(nsIAsyncInputStream* aStream) {
|
BodyStream::OnInputStreamReady(nsIAsyncInputStream* aStream) {
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aStream);
|
MOZ_DIAGNOSTIC_ASSERT(aStream);
|
||||||
|
|
||||||
@ -320,8 +367,13 @@ FetchStream::OnInputStreamReady(nsIAsyncInputStream* aStream) {
|
|||||||
MOZ_DIAGNOSTIC_ASSERT(mInputStream);
|
MOZ_DIAGNOSTIC_ASSERT(mInputStream);
|
||||||
MOZ_DIAGNOSTIC_ASSERT(mState == eReading || mState == eChecking);
|
MOZ_DIAGNOSTIC_ASSERT(mState == eReading || mState == eChecking);
|
||||||
|
|
||||||
|
JSObject* streamObj = mStreamHolder->GetReadableStreamBody();
|
||||||
|
if (!streamObj) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
JSContext* cx = aes.cx();
|
JSContext* cx = aes.cx();
|
||||||
JS::Rooted<JSObject*> stream(cx, mStreamHolder->ReadableStreamBody());
|
JS::Rooted<JSObject*> stream(cx, streamObj);
|
||||||
|
|
||||||
uint64_t size = 0;
|
uint64_t size = 0;
|
||||||
nsresult rv = mInputStream->Available(&size);
|
nsresult rv = mInputStream->Available(&size);
|
||||||
@ -347,20 +399,21 @@ FetchStream::OnInputStreamReady(nsIAsyncInputStream* aStream) {
|
|||||||
|
|
||||||
lock.reset();
|
lock.reset();
|
||||||
|
|
||||||
JS::ReadableStreamUpdateDataAvailableFromSource(cx, stream, size);
|
DebugOnly<bool> ok =
|
||||||
|
JS::ReadableStreamUpdateDataAvailableFromSource(cx, stream, size);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
nsresult FetchStream::RetrieveInputStream(
|
nsresult BodyStream::RetrieveInputStream(
|
||||||
JS::ReadableStreamUnderlyingSource* aUnderlyingReadableStreamSource,
|
JS::ReadableStreamUnderlyingSource* aUnderlyingReadableStreamSource,
|
||||||
nsIInputStream** aInputStream) {
|
nsIInputStream** aInputStream) {
|
||||||
MOZ_ASSERT(aUnderlyingReadableStreamSource);
|
MOZ_ASSERT(aUnderlyingReadableStreamSource);
|
||||||
MOZ_ASSERT(aInputStream);
|
MOZ_ASSERT(aInputStream);
|
||||||
|
|
||||||
RefPtr<FetchStream> stream =
|
RefPtr<BodyStream> stream =
|
||||||
static_cast<FetchStream*>(aUnderlyingReadableStreamSource);
|
static_cast<BodyStream*>(aUnderlyingReadableStreamSource);
|
||||||
stream->AssertIsOnOwningThread();
|
stream->AssertIsOnOwningThread();
|
||||||
|
|
||||||
// if mOriginalInputStream is null, the reading already started. We don't want
|
// if mOriginalInputStream is null, the reading already started. We don't want
|
||||||
@ -374,7 +427,7 @@ nsresult FetchStream::RetrieveInputStream(
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FetchStream::Close() {
|
void BodyStream::Close() {
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
|
|
||||||
MutexAutoLock lock(mMutex);
|
MutexAutoLock lock(mMutex);
|
||||||
@ -389,14 +442,19 @@ void FetchStream::Close() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSContext* cx = jsapi.cx();
|
JSObject* streamObj = mStreamHolder->GetReadableStreamBody();
|
||||||
JS::Rooted<JSObject*> stream(cx, mStreamHolder->ReadableStreamBody());
|
if (streamObj) {
|
||||||
CloseAndReleaseObjects(cx, lock, stream);
|
JSContext* cx = jsapi.cx();
|
||||||
|
JS::Rooted<JSObject*> stream(cx, streamObj);
|
||||||
|
CloseAndReleaseObjects(cx, lock, stream);
|
||||||
|
} else {
|
||||||
|
ReleaseObjects(lock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FetchStream::CloseAndReleaseObjects(JSContext* aCx,
|
void BodyStream::CloseAndReleaseObjects(JSContext* aCx,
|
||||||
const MutexAutoLock& aProofOfLock,
|
const MutexAutoLock& aProofOfLock,
|
||||||
JS::HandleObject aStream) {
|
JS::HandleObject aStream) {
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
MOZ_DIAGNOSTIC_ASSERT(mState != eClosed);
|
MOZ_DIAGNOSTIC_ASSERT(mState != eClosed);
|
||||||
|
|
||||||
@ -412,12 +470,12 @@ void FetchStream::CloseAndReleaseObjects(JSContext* aCx,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FetchStream::ReleaseObjects() {
|
void BodyStream::ReleaseObjects() {
|
||||||
MutexAutoLock lock(mMutex);
|
MutexAutoLock lock(mMutex);
|
||||||
ReleaseObjects(lock);
|
ReleaseObjects(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FetchStream::ReleaseObjects(const MutexAutoLock& aProofOfLock) {
|
void BodyStream::ReleaseObjects(const MutexAutoLock& aProofOfLock) {
|
||||||
// This method can be called on 2 possible threads: the owning one and a JS
|
// This method can be called on 2 possible threads: the owning one and a JS
|
||||||
// thread used to release resources. If we are on the JS thread, we need to
|
// thread used to release resources. If we are on the JS thread, we need to
|
||||||
// dispatch a runnable to go back to the owning thread in order to release
|
// dispatch a runnable to go back to the owning thread in order to release
|
||||||
@ -428,8 +486,6 @@ void FetchStream::ReleaseObjects(const MutexAutoLock& aProofOfLock) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mState = eClosed;
|
|
||||||
|
|
||||||
if (!NS_IsMainThread() && !IsCurrentThreadRunningWorker()) {
|
if (!NS_IsMainThread() && !IsCurrentThreadRunningWorker()) {
|
||||||
// Let's dispatch a WorkerControlRunnable if the owning thread is a worker.
|
// Let's dispatch a WorkerControlRunnable if the owning thread is a worker.
|
||||||
if (mWorkerRef) {
|
if (mWorkerRef) {
|
||||||
@ -440,15 +496,17 @@ void FetchStream::ReleaseObjects(const MutexAutoLock& aProofOfLock) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A normal runnable of the owning thread is the main-thread.
|
// A normal runnable of the owning thread is the main-thread.
|
||||||
RefPtr<FetchStream> self = this;
|
RefPtr<BodyStream> self = this;
|
||||||
RefPtr<Runnable> r = NS_NewRunnableFunction(
|
RefPtr<Runnable> r = NS_NewRunnableFunction(
|
||||||
"FetchStream::ReleaseObjects", [self]() { self->ReleaseObjects(); });
|
"BodyStream::ReleaseObjects", [self]() { self->ReleaseObjects(); });
|
||||||
mOwningEventTarget->Dispatch(r.forget());
|
mOwningEventTarget->Dispatch(r.forget());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
|
|
||||||
|
mState = eClosed;
|
||||||
|
|
||||||
if (NS_IsMainThread()) {
|
if (NS_IsMainThread()) {
|
||||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||||
if (obs) {
|
if (obs) {
|
||||||
@ -456,16 +514,23 @@ void FetchStream::ReleaseObjects(const MutexAutoLock& aProofOfLock) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSObject* streamObj = mStreamHolder->GetReadableStreamBody();
|
||||||
|
if (streamObj) {
|
||||||
|
// Let's inform the JSEngine that we are going to be released.
|
||||||
|
JS::ReadableStreamReleaseCCObject(streamObj);
|
||||||
|
}
|
||||||
|
|
||||||
mWorkerRef = nullptr;
|
mWorkerRef = nullptr;
|
||||||
mGlobal = nullptr;
|
mGlobal = nullptr;
|
||||||
|
|
||||||
|
mStreamHolder->ForgetBodyStream();
|
||||||
mStreamHolder->NullifyStream();
|
mStreamHolder->NullifyStream();
|
||||||
mStreamHolder = nullptr;
|
mStreamHolder = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
void FetchStream::AssertIsOnOwningThread() {
|
void BodyStream::AssertIsOnOwningThread() {
|
||||||
NS_ASSERT_OWNINGTHREAD(FetchStream);
|
NS_ASSERT_OWNINGTHREAD(BodyStream);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -473,8 +538,8 @@ void FetchStream::AssertIsOnOwningThread() {
|
|||||||
// -----------
|
// -----------
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
FetchStream::Observe(nsISupports* aSubject, const char* aTopic,
|
BodyStream::Observe(nsISupports* aSubject, const char* aTopic,
|
||||||
const char16_t* aData) {
|
const char16_t* aData) {
|
||||||
AssertIsOnMainThread();
|
AssertIsOnMainThread();
|
||||||
AssertIsOnOwningThread();
|
AssertIsOnOwningThread();
|
||||||
|
|
@ -2,10 +2,9 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#ifndef mozilla_dom_FetchStream_h
|
#ifndef mozilla_dom_BodyStream_h
|
||||||
#define mozilla_dom_FetchStream_h
|
#define mozilla_dom_BodyStream_h
|
||||||
|
|
||||||
#include "Fetch.h"
|
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "js/Stream.h"
|
#include "js/Stream.h"
|
||||||
#include "nsIAsyncInputStream.h"
|
#include "nsIAsyncInputStream.h"
|
||||||
@ -20,21 +19,58 @@ class nsIInputStream;
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
class FetchStreamHolder;
|
class BodyStream;
|
||||||
class WeakWorkerRef;
|
class WeakWorkerRef;
|
||||||
|
|
||||||
class FetchStream final : public nsIInputStreamCallback,
|
class BodyStreamHolder : public nsISupports {
|
||||||
public nsIObserver,
|
friend class BodyStream;
|
||||||
public nsSupportsWeakReference,
|
|
||||||
private JS::ReadableStreamUnderlyingSource {
|
public:
|
||||||
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
|
NS_DECL_CYCLE_COLLECTION_CLASS(BodyStreamHolder)
|
||||||
|
|
||||||
|
BodyStreamHolder();
|
||||||
|
|
||||||
|
virtual void NullifyStream() = 0;
|
||||||
|
|
||||||
|
virtual void MarkAsRead() = 0;
|
||||||
|
|
||||||
|
virtual void SetReadableStreamBody(JSObject* aBody) = 0;
|
||||||
|
|
||||||
|
virtual JSObject* GetReadableStreamBody() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ~BodyStreamHolder() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void StoreBodyStream(BodyStream* aBodyStream);
|
||||||
|
void ForgetBodyStream();
|
||||||
|
|
||||||
|
// Raw pointer because BodyStream keeps BodyStreamHolder alive and it
|
||||||
|
// nullifies this stream before being released.
|
||||||
|
BodyStream* mBodyStream;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
bool mStreamCreated = false;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
class BodyStream final : public nsIInputStreamCallback,
|
||||||
|
public nsIObserver,
|
||||||
|
public nsSupportsWeakReference,
|
||||||
|
private JS::ReadableStreamUnderlyingSource {
|
||||||
|
friend class BodyStreamHolder;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NS_DECL_THREADSAFE_ISUPPORTS
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
NS_DECL_NSIINPUTSTREAMCALLBACK
|
NS_DECL_NSIINPUTSTREAMCALLBACK
|
||||||
NS_DECL_NSIOBSERVER
|
NS_DECL_NSIOBSERVER
|
||||||
|
|
||||||
static void Create(JSContext* aCx, FetchStreamHolder* aStreamHolder,
|
// This method creates a JS ReadableStream object and it assigns it to the
|
||||||
|
// aStreamHolder calling SetReadableStreamBody().
|
||||||
|
static void Create(JSContext* aCx, BodyStreamHolder* aStreamHolder,
|
||||||
nsIGlobalObject* aGlobal, nsIInputStream* aInputStream,
|
nsIGlobalObject* aGlobal, nsIInputStream* aInputStream,
|
||||||
JS::MutableHandle<JSObject*> aStream, ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
|
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
@ -43,9 +79,9 @@ class FetchStream final : public nsIInputStreamCallback,
|
|||||||
nsIInputStream** aInputStream);
|
nsIInputStream** aInputStream);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FetchStream(nsIGlobalObject* aGlobal, FetchStreamHolder* aStreamHolder,
|
BodyStream(nsIGlobalObject* aGlobal, BodyStreamHolder* aStreamHolder,
|
||||||
nsIInputStream* aInputStream);
|
nsIInputStream* aInputStream);
|
||||||
~FetchStream();
|
~BodyStream();
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
void AssertIsOnOwningThread();
|
void AssertIsOnOwningThread();
|
||||||
@ -107,7 +143,7 @@ class FetchStream final : public nsIInputStreamCallback,
|
|||||||
eClosed,
|
eClosed,
|
||||||
};
|
};
|
||||||
|
|
||||||
// We need a mutex because JS engine can release FetchStream on a non-owning
|
// We need a mutex because JS engine can release BodyStream on a non-owning
|
||||||
// thread. We must be sure that the releasing of resources doesn't trigger
|
// thread. We must be sure that the releasing of resources doesn't trigger
|
||||||
// race conditions.
|
// race conditions.
|
||||||
Mutex mMutex;
|
Mutex mMutex;
|
||||||
@ -116,7 +152,7 @@ class FetchStream final : public nsIInputStreamCallback,
|
|||||||
State mState;
|
State mState;
|
||||||
|
|
||||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||||
RefPtr<FetchStreamHolder> mStreamHolder;
|
RefPtr<BodyStreamHolder> mStreamHolder;
|
||||||
nsCOMPtr<nsIEventTarget> mOwningEventTarget;
|
nsCOMPtr<nsIEventTarget> mOwningEventTarget;
|
||||||
|
|
||||||
// This is the original inputStream received during the CTOR. It will be
|
// This is the original inputStream received during the CTOR. It will be
|
||||||
@ -131,4 +167,4 @@ class FetchStream final : public nsIInputStreamCallback,
|
|||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
#endif // mozilla_dom_FetchStream_h
|
#endif // mozilla_dom_BodyStream_h
|
@ -13,18 +13,18 @@
|
|||||||
|
|
||||||
#include "mozilla/AsyncEventDispatcher.h"
|
#include "mozilla/AsyncEventDispatcher.h"
|
||||||
#include "mozilla/MemoryReporting.h"
|
#include "mozilla/MemoryReporting.h"
|
||||||
|
#include "mozilla/dom/BindContext.h"
|
||||||
#include "mozilla/dom/Element.h"
|
#include "mozilla/dom/Element.h"
|
||||||
#include "mozilla/dom/HTMLSlotElement.h"
|
#include "mozilla/dom/HTMLSlotElement.h"
|
||||||
|
#include "mozilla/dom/MutationObservers.h"
|
||||||
#include "mozilla/dom/ShadowRoot.h"
|
#include "mozilla/dom/ShadowRoot.h"
|
||||||
#include "mozilla/dom/Document.h"
|
#include "mozilla/dom/Document.h"
|
||||||
#include "nsReadableUtils.h"
|
#include "nsReadableUtils.h"
|
||||||
#include "mozilla/InternalMutationEvent.h"
|
#include "mozilla/InternalMutationEvent.h"
|
||||||
#include "nsIURI.h"
|
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsDOMString.h"
|
#include "nsDOMString.h"
|
||||||
#include "nsChangeHint.h"
|
#include "nsChangeHint.h"
|
||||||
#include "nsCOMArray.h"
|
#include "nsCOMArray.h"
|
||||||
#include "nsNodeUtils.h"
|
|
||||||
#include "mozilla/dom/DirectionalityUtils.h"
|
#include "mozilla/dom/DirectionalityUtils.h"
|
||||||
#include "nsBindingManager.h"
|
#include "nsBindingManager.h"
|
||||||
#include "nsCCUncollectableMarker.h"
|
#include "nsCCUncollectableMarker.h"
|
||||||
@ -93,12 +93,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CharacterData)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CharacterData)
|
||||||
nsIContent::Unlink(tmp);
|
nsIContent::Unlink(tmp);
|
||||||
|
|
||||||
// Clear flag here because unlinking slots will clear the
|
if (nsContentSlots* slots = tmp->GetExistingContentSlots()) {
|
||||||
// containing shadow root pointer.
|
|
||||||
tmp->UnsetFlags(NODE_IS_IN_SHADOW_TREE);
|
|
||||||
|
|
||||||
nsContentSlots* slots = tmp->GetExistingContentSlots();
|
|
||||||
if (slots) {
|
|
||||||
slots->Unlink();
|
slots->Unlink();
|
||||||
}
|
}
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
@ -243,13 +238,14 @@ nsresult CharacterData::SetTextInternal(
|
|||||||
if (aNotify) {
|
if (aNotify) {
|
||||||
CharacterDataChangeInfo info = {aOffset == textLength, aOffset, endOffset,
|
CharacterDataChangeInfo info = {aOffset == textLength, aOffset, endOffset,
|
||||||
aLength, aDetails};
|
aLength, aDetails};
|
||||||
nsNodeUtils::CharacterDataWillChange(this, info);
|
MutationObservers::NotifyCharacterDataWillChange(this, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
Directionality oldDir = eDir_NotSet;
|
Directionality oldDir = eDir_NotSet;
|
||||||
bool dirAffectsAncestor =
|
bool dirAffectsAncestor =
|
||||||
(NodeType() == TEXT_NODE &&
|
(NodeType() == TEXT_NODE &&
|
||||||
TextNodeWillChangeDirection(this, &oldDir, aOffset));
|
TextNodeWillChangeDirection(static_cast<nsTextNode*>(this), &oldDir,
|
||||||
|
aOffset));
|
||||||
|
|
||||||
if (aOffset == 0 && endOffset == textLength) {
|
if (aOffset == 0 && endOffset == textLength) {
|
||||||
// Replacing whole text or old text was empty. Don't bother to check for
|
// Replacing whole text or old text was empty. Don't bother to check for
|
||||||
@ -321,7 +317,7 @@ nsresult CharacterData::SetTextInternal(
|
|||||||
if (aNotify) {
|
if (aNotify) {
|
||||||
CharacterDataChangeInfo info = {aOffset == textLength, aOffset, endOffset,
|
CharacterDataChangeInfo info = {aOffset == textLength, aOffset, endOffset,
|
||||||
aLength, aDetails};
|
aLength, aDetails};
|
||||||
nsNodeUtils::CharacterDataChanged(this, info);
|
MutationObservers::NotifyCharacterDataChanged(this, info);
|
||||||
|
|
||||||
if (haveMutationListeners) {
|
if (haveMutationListeners) {
|
||||||
InternalMutationEvent mutation(true, eLegacyCharacterDataModified);
|
InternalMutationEvent mutation(true, eLegacyCharacterDataModified);
|
||||||
@ -388,121 +384,133 @@ void CharacterData::ToCString(nsAString& aBuf, int32_t aOffset,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nsresult CharacterData::BindToTree(Document* aDocument, nsIContent* aParent,
|
nsresult CharacterData::BindToTree(BindContext& aContext, nsINode& aParent) {
|
||||||
nsIContent* aBindingParent) {
|
MOZ_ASSERT(aParent.IsContent() || aParent.IsDocument(),
|
||||||
MOZ_ASSERT(aParent || aDocument, "Must have document if no parent!");
|
"Must have content or document parent!");
|
||||||
MOZ_ASSERT(NODE_FROM(aParent, aDocument)->OwnerDoc() == OwnerDoc(),
|
MOZ_ASSERT(aParent.OwnerDoc() == OwnerDoc(),
|
||||||
"Must have the same owner document");
|
"Must have the same owner document");
|
||||||
MOZ_ASSERT(!aParent || aDocument == aParent->GetUncomposedDoc(),
|
MOZ_ASSERT(OwnerDoc() == &aContext.OwnerDoc(), "These should match too");
|
||||||
"aDocument must be current doc of aParent");
|
MOZ_ASSERT(!IsInUncomposedDoc(), "Already have a document. Unbind first!");
|
||||||
MOZ_ASSERT(!GetUncomposedDoc() && !IsInUncomposedDoc(),
|
|
||||||
"Already have a document. Unbind first!");
|
|
||||||
MOZ_ASSERT(!IsInComposedDoc(), "Already have a document. Unbind first!");
|
MOZ_ASSERT(!IsInComposedDoc(), "Already have a document. Unbind first!");
|
||||||
// Note that as we recurse into the kids, they'll have a non-null parent. So
|
// Note that as we recurse into the kids, they'll have a non-null parent. So
|
||||||
// only assert if our parent is _changing_ while we have a parent.
|
// only assert if our parent is _changing_ while we have a parent.
|
||||||
MOZ_ASSERT(!GetParent() || aParent == GetParent(),
|
MOZ_ASSERT(!GetParentNode() || &aParent == GetParentNode(),
|
||||||
"Already have a parent. Unbind first!");
|
"Already have a parent. Unbind first!");
|
||||||
MOZ_ASSERT(!GetBindingParent() || aBindingParent == GetBindingParent() ||
|
MOZ_ASSERT(
|
||||||
(!aBindingParent && aParent &&
|
!GetBindingParent() ||
|
||||||
aParent->GetBindingParent() == GetBindingParent()),
|
aContext.GetBindingParent() == GetBindingParent() ||
|
||||||
"Already have a binding parent. Unbind first!");
|
(!aContext.GetBindingParent() && aParent.IsContent() &&
|
||||||
MOZ_ASSERT(aBindingParent != this,
|
aParent.AsContent()->GetBindingParent() == GetBindingParent()),
|
||||||
"Content must not be its own binding parent");
|
"Already have a binding parent. Unbind first!");
|
||||||
MOZ_ASSERT(!IsRootOfNativeAnonymousSubtree() || aBindingParent == aParent,
|
MOZ_ASSERT(!IsRootOfNativeAnonymousSubtree() ||
|
||||||
|
aContext.GetBindingParent() == &aParent,
|
||||||
"Native anonymous content must have its parent as its "
|
"Native anonymous content must have its parent as its "
|
||||||
"own binding parent");
|
"own binding parent");
|
||||||
|
MOZ_ASSERT(aContext.GetBindingParent() || !aParent.IsContent() ||
|
||||||
if (!aBindingParent && aParent) {
|
aContext.GetBindingParent() ==
|
||||||
aBindingParent = aParent->GetBindingParent();
|
aParent.AsContent()->GetBindingParent(),
|
||||||
}
|
"We should be passed the right binding parent");
|
||||||
|
|
||||||
// First set the binding parent
|
// First set the binding parent
|
||||||
if (aBindingParent) {
|
if (Element* bindingParent = aContext.GetBindingParent()) {
|
||||||
NS_ASSERTION(IsRootOfNativeAnonymousSubtree() ||
|
ExtendedContentSlots()->mBindingParent = bindingParent;
|
||||||
!HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE) ||
|
|
||||||
(aParent && aParent->IsInNativeAnonymousSubtree()),
|
|
||||||
"Trying to re-bind content from native anonymous subtree to "
|
|
||||||
"non-native anonymous parent!");
|
|
||||||
ExtendedContentSlots()->mBindingParent =
|
|
||||||
aBindingParent; // Weak, so no addref happens.
|
|
||||||
if (aParent->IsInNativeAnonymousSubtree()) {
|
|
||||||
SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
|
|
||||||
}
|
|
||||||
if (aParent->HasFlag(NODE_HAS_BEEN_IN_UA_WIDGET)) {
|
|
||||||
SetFlags(NODE_HAS_BEEN_IN_UA_WIDGET);
|
|
||||||
}
|
|
||||||
if (HasFlag(NODE_IS_ANONYMOUS_ROOT)) {
|
|
||||||
aParent->SetMayHaveAnonymousChildren();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aParent && aParent->IsInShadowTree()) {
|
const bool hadParent = !!GetParentNode();
|
||||||
ClearSubtreeRootPointer();
|
|
||||||
SetFlags(NODE_IS_IN_SHADOW_TREE);
|
|
||||||
SetIsConnected(aParent->IsInComposedDoc());
|
|
||||||
MOZ_ASSERT(aParent->GetContainingShadow());
|
|
||||||
ExtendedContentSlots()->mContainingShadow = aParent->GetContainingShadow();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hadParent = !!GetParentNode();
|
NS_ASSERTION(!aContext.GetBindingParent() ||
|
||||||
|
IsRootOfNativeAnonymousSubtree() ||
|
||||||
|
!HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE) ||
|
||||||
|
aParent.IsInNativeAnonymousSubtree(),
|
||||||
|
"Trying to re-bind content from native anonymous subtree to "
|
||||||
|
"non-native anonymous parent!");
|
||||||
|
if (aParent.IsInNativeAnonymousSubtree()) {
|
||||||
|
SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
|
||||||
|
}
|
||||||
|
if (aParent.HasFlag(NODE_HAS_BEEN_IN_UA_WIDGET)) {
|
||||||
|
SetFlags(NODE_HAS_BEEN_IN_UA_WIDGET);
|
||||||
|
}
|
||||||
|
if (HasFlag(NODE_IS_ANONYMOUS_ROOT)) {
|
||||||
|
aParent.SetMayHaveAnonymousChildren();
|
||||||
|
}
|
||||||
|
|
||||||
// Set parent
|
// Set parent
|
||||||
if (aParent) {
|
mParent = &aParent;
|
||||||
if (!GetParent()) {
|
if (!hadParent && aParent.IsContent()) {
|
||||||
NS_ADDREF(aParent);
|
SetParentIsContent(true);
|
||||||
}
|
NS_ADDREF(mParent);
|
||||||
mParent = aParent;
|
|
||||||
} else {
|
|
||||||
mParent = aDocument;
|
|
||||||
}
|
}
|
||||||
SetParentIsContent(aParent);
|
MOZ_ASSERT(!!GetParent() == aParent.IsContent());
|
||||||
|
|
||||||
// XXXbz sXBL/XBL2 issue!
|
if (aParent.IsInUncomposedDoc() || aParent.IsInShadowTree()) {
|
||||||
|
|
||||||
// Set document
|
|
||||||
if (aDocument) {
|
|
||||||
// We no longer need to track the subtree pointer (and in fact we'll assert
|
// We no longer need to track the subtree pointer (and in fact we'll assert
|
||||||
// if we do this any later).
|
// if we do this any later).
|
||||||
ClearSubtreeRootPointer();
|
ClearSubtreeRootPointer();
|
||||||
|
SetIsConnected(aParent.IsInComposedDoc());
|
||||||
|
|
||||||
// XXX See the comment in Element::BindToTree
|
if (aParent.IsInUncomposedDoc()) {
|
||||||
SetIsInDocument();
|
SetIsInDocument();
|
||||||
SetIsConnected(true);
|
} else {
|
||||||
if (mText.IsBidi()) {
|
SetFlags(NODE_IS_IN_SHADOW_TREE);
|
||||||
aDocument->SetBidiEnabled();
|
MOZ_ASSERT(aParent.IsContent() &&
|
||||||
|
aParent.AsContent()->GetContainingShadow());
|
||||||
|
ExtendedContentSlots()->mContainingShadow =
|
||||||
|
aParent.AsContent()->GetContainingShadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsInComposedDoc()) {
|
||||||
|
if (mText.IsBidi()) {
|
||||||
|
aContext.OwnerDoc().SetBidiEnabled();
|
||||||
|
}
|
||||||
|
if (aContext.CollectingDisplayedNodeDataDuringLoad()) {
|
||||||
|
aContext.OwnerDoc().AddToVisibleContentHeuristic(mText.GetLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Clear the lazy frame construction bits.
|
// Clear the lazy frame construction bits.
|
||||||
UnsetFlags(NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES);
|
UnsetFlags(NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES);
|
||||||
} else if (!IsInShadowTree()) {
|
} else {
|
||||||
// If we're not in the doc and not in a shadow tree,
|
// If we're not in the doc and not in a shadow tree,
|
||||||
// update our subtree pointer.
|
// update our subtree pointer.
|
||||||
SetSubtreeRootPointer(aParent->SubtreeRoot());
|
SetSubtreeRootPointer(aParent.SubtreeRoot());
|
||||||
}
|
}
|
||||||
|
|
||||||
nsNodeUtils::ParentChainChanged(this);
|
MutationObservers::NotifyParentChainChanged(this);
|
||||||
if (!hadParent && IsRootOfNativeAnonymousSubtree()) {
|
if (!hadParent && IsRootOfNativeAnonymousSubtree()) {
|
||||||
nsNodeUtils::NativeAnonymousChildListChange(this, false);
|
MutationObservers::NotifyNativeAnonymousChildListChange(this, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateEditableState(false);
|
UpdateEditableState(false);
|
||||||
|
|
||||||
MOZ_ASSERT(aDocument == GetUncomposedDoc(), "Bound to wrong document");
|
// Ensure we only do these once, in the case we move the shadow host around.
|
||||||
MOZ_ASSERT(aParent == GetParent(), "Bound to wrong parent");
|
if (aContext.SubtreeRootChanges()) {
|
||||||
MOZ_ASSERT(aBindingParent == GetBindingParent(),
|
HandleShadowDOMRelatedInsertionSteps(hadParent);
|
||||||
"Bound to wrong binding parent");
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(OwnerDoc() == aParent.OwnerDoc(), "Bound to wrong document");
|
||||||
|
MOZ_ASSERT(IsInComposedDoc() == aContext.InComposedDoc());
|
||||||
|
MOZ_ASSERT(IsInUncomposedDoc() == aContext.InUncomposedDoc());
|
||||||
|
MOZ_ASSERT(&aParent == GetParentNode(), "Bound to wrong parent node");
|
||||||
|
MOZ_ASSERT(aContext.GetBindingParent() == GetBindingParent(),
|
||||||
|
"Bound to wrong binding parent");
|
||||||
|
MOZ_ASSERT(aParent.IsInUncomposedDoc() == IsInUncomposedDoc());
|
||||||
|
MOZ_ASSERT(aParent.IsInComposedDoc() == IsInComposedDoc());
|
||||||
|
MOZ_ASSERT(aParent.IsInShadowTree() == IsInShadowTree());
|
||||||
|
MOZ_ASSERT(aParent.SubtreeRoot() == SubtreeRoot());
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterData::UnbindFromTree(bool aDeep, bool aNullParent) {
|
void CharacterData::UnbindFromTree(bool aNullParent) {
|
||||||
// Unset frame flags; if we need them again later, they'll get set again.
|
// Unset frame flags; if we need them again later, they'll get set again.
|
||||||
UnsetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE | NS_REFRAME_IF_WHITESPACE);
|
UnsetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE | NS_REFRAME_IF_WHITESPACE);
|
||||||
|
|
||||||
|
HandleShadowDOMRelatedRemovalSteps(aNullParent);
|
||||||
|
|
||||||
Document* document = GetComposedDoc();
|
Document* document = GetComposedDoc();
|
||||||
|
|
||||||
if (aNullParent) {
|
if (aNullParent) {
|
||||||
if (this->IsRootOfNativeAnonymousSubtree()) {
|
if (IsRootOfNativeAnonymousSubtree()) {
|
||||||
nsNodeUtils::NativeAnonymousChildListChange(this, true);
|
MutationObservers::NotifyNativeAnonymousChildListChange(this, true);
|
||||||
}
|
}
|
||||||
if (GetParent()) {
|
if (GetParent()) {
|
||||||
NS_RELEASE(mParent);
|
NS_RELEASE(mParent);
|
||||||
@ -540,7 +548,7 @@ void CharacterData::UnbindFromTree(bool aDeep, bool aNullParent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsNodeUtils::ParentChainChanged(this);
|
MutationObservers::NotifyParentChainChanged(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
@ -60,10 +60,14 @@ enum {
|
|||||||
// This bit is set if the node may be modified frequently. This is typically
|
// This bit is set if the node may be modified frequently. This is typically
|
||||||
// specified if the instance is in <input> or <textarea>.
|
// specified if the instance is in <input> or <textarea>.
|
||||||
NS_MAYBE_MODIFIED_FREQUENTLY = CHARACTER_DATA_FLAG_BIT(6),
|
NS_MAYBE_MODIFIED_FREQUENTLY = CHARACTER_DATA_FLAG_BIT(6),
|
||||||
|
|
||||||
|
// This bit is set if the node may be masked because of being in a password
|
||||||
|
// field.
|
||||||
|
NS_MAYBE_MASKED = CHARACTER_DATA_FLAG_BIT(7),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Make sure we have enough space for those bits
|
// Make sure we have enough space for those bits
|
||||||
ASSERT_NODE_FLAGS_SPACE(NODE_TYPE_SPECIFIC_BITS_OFFSET + 7);
|
ASSERT_NODE_FLAGS_SPACE(NODE_TYPE_SPECIFIC_BITS_OFFSET + 8);
|
||||||
|
|
||||||
#undef CHARACTER_DATA_FLAG_BIT
|
#undef CHARACTER_DATA_FLAG_BIT
|
||||||
|
|
||||||
@ -85,6 +89,7 @@ class CharacterData : public nsIContent {
|
|||||||
void MarkAsMaybeModifiedFrequently() {
|
void MarkAsMaybeModifiedFrequently() {
|
||||||
SetFlags(NS_MAYBE_MODIFIED_FREQUENTLY);
|
SetFlags(NS_MAYBE_MODIFIED_FREQUENTLY);
|
||||||
}
|
}
|
||||||
|
void MarkAsMaybeMasked() { SetFlags(NS_MAYBE_MASKED); }
|
||||||
|
|
||||||
NS_IMPL_FROMNODE_HELPER(CharacterData, IsCharacterData())
|
NS_IMPL_FROMNODE_HELPER(CharacterData, IsCharacterData())
|
||||||
|
|
||||||
@ -105,20 +110,19 @@ class CharacterData : public nsIContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Implementation for nsIContent
|
// Implementation for nsIContent
|
||||||
nsresult BindToTree(Document* aDocument, nsIContent* aParent,
|
nsresult BindToTree(BindContext&, nsINode& aParent) override;
|
||||||
nsIContent* aBindingParent) override;
|
|
||||||
|
|
||||||
void UnbindFromTree(bool aDeep = true, bool aNullParent = true) override;
|
void UnbindFromTree(bool aNullParent = true) override;
|
||||||
|
|
||||||
already_AddRefed<nsINodeList> GetChildren(uint32_t aFilter) final {
|
already_AddRefed<nsINodeList> GetChildren(uint32_t aFilter) final {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nsTextFragment* GetText() override { return &mText; }
|
const nsTextFragment* GetText() override { return &mText; }
|
||||||
|
uint32_t TextLength() const final { return TextDataLength(); }
|
||||||
|
|
||||||
const nsTextFragment& TextFragment() const { return mText; }
|
const nsTextFragment& TextFragment() const { return mText; }
|
||||||
|
uint32_t TextDataLength() const { return mText.GetLength(); }
|
||||||
uint32_t TextLength() const final { return TextDataLength(); }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the text to the given value. If aNotify is true then
|
* Set the text to the given value. If aNotify is true then
|
||||||
@ -195,8 +199,6 @@ class CharacterData : public nsIContent {
|
|||||||
void ReplaceData(uint32_t aOffset, uint32_t aCount, const nsAString& aData,
|
void ReplaceData(uint32_t aOffset, uint32_t aCount, const nsAString& aData,
|
||||||
ErrorResult& rv);
|
ErrorResult& rv);
|
||||||
|
|
||||||
uint32_t TextDataLength() const { return mText.GetLength(); }
|
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -9,7 +9,7 @@ using namespace mozilla;
|
|||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
|
|
||||||
already_AddRefed<ChromeNodeList> ChromeNodeList::Constructor(
|
already_AddRefed<ChromeNodeList> ChromeNodeList::Constructor(
|
||||||
const GlobalObject& aGlobal, ErrorResult& aRv) {
|
const GlobalObject& aGlobal) {
|
||||||
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aGlobal.GetAsSupports());
|
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aGlobal.GetAsSupports());
|
||||||
Document* root = win ? win->GetExtantDoc() : nullptr;
|
Document* root = win ? win->GetExtantDoc() : nullptr;
|
||||||
RefPtr<ChromeNodeList> list = new ChromeNodeList(root);
|
RefPtr<ChromeNodeList> list = new ChromeNodeList(root);
|
||||||
|
@ -16,7 +16,7 @@ class ChromeNodeList final : public nsSimpleContentList {
|
|||||||
explicit ChromeNodeList(nsINode* aOwner) : nsSimpleContentList(aOwner) {}
|
explicit ChromeNodeList(nsINode* aOwner) : nsSimpleContentList(aOwner) {}
|
||||||
|
|
||||||
static already_AddRefed<ChromeNodeList> Constructor(
|
static already_AddRefed<ChromeNodeList> Constructor(
|
||||||
const GlobalObject& aGlobal, ErrorResult& aRv);
|
const GlobalObject& aGlobal);
|
||||||
|
|
||||||
virtual JSObject* WrapObject(JSContext* aCx,
|
virtual JSObject* WrapObject(JSContext* aCx,
|
||||||
JS::Handle<JSObject*> aGivenProto) override;
|
JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
@ -206,17 +206,12 @@ ContentAreaDropListener.prototype =
|
|||||||
if (sourceNode &&
|
if (sourceNode &&
|
||||||
(sourceNode.localName !== "browser" ||
|
(sourceNode.localName !== "browser" ||
|
||||||
sourceNode.namespaceURI !== "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul")) {
|
sourceNode.namespaceURI !== "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul")) {
|
||||||
// Use sourceNode's principal only if the sourceNode is not browser.
|
// Use sourceNode's csp only if the sourceNode is not browser.
|
||||||
//
|
//
|
||||||
// If sourceNode is browser, the actual triggering principal may be
|
// If sourceNode is browser, the actual triggering csp may be differ than sourceNode's csp,
|
||||||
// differ than sourceNode's principal, since sourceNode's principal is
|
// since sourceNode's csp is top level document's one and the drag may be triggered from a
|
||||||
// top level document's one and the drag may be triggered from a frame
|
// frame with different csp.
|
||||||
// with different principal.
|
return sourceNode.csp;
|
||||||
if (sourceNode.nodePrincipal) {
|
|
||||||
// Currently we query the CSP from the nodePrincipal. After Bug 965637 we can
|
|
||||||
// query the CSP directly from the sourceNode.
|
|
||||||
return sourceNode.nodePrincipal.csp;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
@ -4,19 +4,23 @@
|
|||||||
|
|
||||||
#include "ContentBlockingLog.h"
|
#include "ContentBlockingLog.h"
|
||||||
|
|
||||||
|
#include "nsStringStream.h"
|
||||||
#include "mozilla/dom/ContentChild.h"
|
#include "mozilla/dom/ContentChild.h"
|
||||||
#include "mozilla/RandomNum.h"
|
#include "mozilla/RandomNum.h"
|
||||||
|
#include "mozilla/StaticPrefs_privacy.h"
|
||||||
|
#include "mozilla/StaticPrefs_telemetry.h"
|
||||||
#include "mozilla/Telemetry.h"
|
#include "mozilla/Telemetry.h"
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
#include "mozilla/XorShift128PlusRNG.h"
|
#include "mozilla/XorShift128PlusRNG.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
static LazyLogModule gContentBlockingLog("ContentBlockingLog");
|
static LazyLogModule gContentBlockingLog("ContentBlockingLog");
|
||||||
#define LOG(fmt, ...) \
|
#define LOG(fmt, ...) \
|
||||||
MOZ_LOG(gContentBlockingLog, mozilla::LogLevel::Debug, (fmt, ##__VA_ARGS__))
|
MOZ_LOG(gContentBlockingLog, LogLevel::Debug, (fmt, ##__VA_ARGS__))
|
||||||
|
|
||||||
typedef mozilla::Telemetry::OriginMetricID OriginMetricID;
|
typedef Telemetry::OriginMetricID OriginMetricID;
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
// randomly choose 1% users included in the content blocking measurement
|
// randomly choose 1% users included in the content blocking measurement
|
||||||
@ -64,7 +68,7 @@ static bool IsReportingPerUserEnabled() {
|
|||||||
|
|
||||||
static bool IsReportingPerDocumentEnabled() {
|
static bool IsReportingPerDocumentEnabled() {
|
||||||
constexpr double boundary =
|
constexpr double boundary =
|
||||||
kRatioReportDocument * std::numeric_limits<uint64_t>::max();
|
kRatioReportDocument * double(std::numeric_limits<uint64_t>::max());
|
||||||
Maybe<uint64_t> randomNum = RandomUint64();
|
Maybe<uint64_t> randomNum = RandomUint64();
|
||||||
return randomNum.isSome() && randomNum.value() <= boundary;
|
return randomNum.isSome() && randomNum.value() <= boundary;
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,10 @@
|
|||||||
#include "mozilla/AntiTrackingCommon.h"
|
#include "mozilla/AntiTrackingCommon.h"
|
||||||
#include "mozilla/JSONWriter.h"
|
#include "mozilla/JSONWriter.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/StaticPrefs.h"
|
#include "mozilla/StaticPrefs_browser.h"
|
||||||
#include "mozilla/Tuple.h"
|
#include "mozilla/Tuple.h"
|
||||||
#include "mozilla/UniquePtr.h"
|
#include "mozilla/UniquePtr.h"
|
||||||
|
#include "nsIWebProgressListener.h"
|
||||||
#include "nsReadableUtils.h"
|
#include "nsReadableUtils.h"
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
#include "nsWindowSizes.h"
|
#include "nsWindowSizes.h"
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "mozilla/DebugOnly.h"
|
#include "mozilla/DebugOnly.h"
|
||||||
#include "mozilla/RangeBoundary.h"
|
#include "mozilla/RangeBoundary.h"
|
||||||
|
#include "mozilla/RangeUtils.h"
|
||||||
|
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsElementTable.h"
|
#include "nsElementTable.h"
|
||||||
@ -115,8 +116,8 @@ nsresult ContentIteratorBase::Init(nsINode* aStartContainer,
|
|||||||
uint32_t aEndOffset) {
|
uint32_t aEndOffset) {
|
||||||
mIsDone = false;
|
mIsDone = false;
|
||||||
|
|
||||||
if (NS_WARN_IF(!nsRange::IsValidPoints(aStartContainer, aStartOffset,
|
if (NS_WARN_IF(!RangeUtils::IsValidPoints(aStartContainer, aStartOffset,
|
||||||
aEndContainer, aEndOffset))) {
|
aEndContainer, aEndOffset))) {
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,8 +129,7 @@ nsresult ContentIteratorBase::Init(const RawRangeBoundary& aStart,
|
|||||||
const RawRangeBoundary& aEnd) {
|
const RawRangeBoundary& aEnd) {
|
||||||
mIsDone = false;
|
mIsDone = false;
|
||||||
|
|
||||||
if (NS_WARN_IF(!nsRange::IsValidPoints(aStart.Container(), aStart.Offset(),
|
if (NS_WARN_IF(!RangeUtils::IsValidPoints(aStart, aEnd))) {
|
||||||
aEnd.Container(), aEnd.Offset()))) {
|
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +260,7 @@ nsresult ContentIteratorBase::InitInternal(const RawRangeBoundary& aStart,
|
|||||||
NS_WARNING_ASSERTION(mLast, "PrevNode returned null");
|
NS_WARNING_ASSERTION(mLast, "PrevNode returned null");
|
||||||
if (mLast && mLast != mFirst &&
|
if (mLast && mLast != mFirst &&
|
||||||
NS_WARN_IF(!NodeIsInTraversalRange(
|
NS_WARN_IF(!NodeIsInTraversalRange(
|
||||||
mLast, mPre, RawRangeBoundary(mFirst, 0), aEnd))) {
|
mLast, mPre, RawRangeBoundary(mFirst, 0u), aEnd))) {
|
||||||
mLast = nullptr;
|
mLast = nullptr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -556,31 +556,30 @@ nsresult ContentIteratorBase::PositionAt(nsINode* aCurNode) {
|
|||||||
|
|
||||||
// Check to see if the node falls within the traversal range.
|
// Check to see if the node falls within the traversal range.
|
||||||
|
|
||||||
RawRangeBoundary first(mFirst, 0);
|
RawRangeBoundary first(mFirst, 0u);
|
||||||
RawRangeBoundary last(mLast, 0);
|
RawRangeBoundary last(mLast, 0u);
|
||||||
|
|
||||||
if (mFirst && mLast) {
|
if (mFirst && mLast) {
|
||||||
if (mPre) {
|
if (mPre) {
|
||||||
// In pre we want to record the point immediately before mFirst, which is
|
// In pre we want to record the point immediately before mFirst, which is
|
||||||
// the point immediately after mFirst's previous sibling.
|
// the point immediately after mFirst's previous sibling.
|
||||||
first.SetAfterRef(mFirst->GetParentNode(), mFirst->GetPreviousSibling());
|
first = {mFirst->GetParentNode(), mFirst->GetPreviousSibling()};
|
||||||
|
|
||||||
// If mLast has no children, then we want to make sure to include it.
|
// If mLast has no children, then we want to make sure to include it.
|
||||||
if (!mLast->HasChildren()) {
|
if (!mLast->HasChildren()) {
|
||||||
last.SetAfterRef(mLast->GetParentNode(), mLast->AsContent());
|
last = {mLast->GetParentNode(), mLast->AsContent()};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If the first node has any children, we want to be immediately after the
|
// If the first node has any children, we want to be immediately after the
|
||||||
// last. Otherwise we want to be immediately before mFirst.
|
// last. Otherwise we want to be immediately before mFirst.
|
||||||
if (mFirst->HasChildren()) {
|
if (mFirst->HasChildren()) {
|
||||||
first.SetAfterRef(mFirst, mFirst->GetLastChild());
|
first = {mFirst, mFirst->GetLastChild()};
|
||||||
} else {
|
} else {
|
||||||
first.SetAfterRef(mFirst->GetParentNode(),
|
first = {mFirst->GetParentNode(), mFirst->GetPreviousSibling()};
|
||||||
mFirst->GetPreviousSibling());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the last point immediately after the final node.
|
// Set the last point immediately after the final node.
|
||||||
last.SetAfterRef(mLast->GetParentNode(), mLast->AsContent());
|
last = {mLast->GetParentNode(), mLast->AsContent()};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -641,19 +640,18 @@ nsresult ContentSubtreeIterator::Init(nsINode* aStartContainer,
|
|||||||
RawRangeBoundary(aEndContainer, aEndOffset));
|
RawRangeBoundary(aEndContainer, aEndOffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult ContentSubtreeIterator::Init(const RawRangeBoundary& aStart,
|
nsresult ContentSubtreeIterator::Init(const RawRangeBoundary& aStartBoundary,
|
||||||
const RawRangeBoundary& aEnd) {
|
const RawRangeBoundary& aEndBoundary) {
|
||||||
mIsDone = false;
|
mIsDone = false;
|
||||||
|
|
||||||
RefPtr<nsRange> range;
|
RefPtr<nsRange> range =
|
||||||
nsresult rv = nsRange::CreateRange(aStart, aEnd, getter_AddRefs(range));
|
nsRange::Create(aStartBoundary, aEndBoundary, IgnoreErrors());
|
||||||
if (NS_WARN_IF(NS_FAILED(rv)) || NS_WARN_IF(!range) ||
|
if (NS_WARN_IF(!range) || NS_WARN_IF(!range->IsPositioned())) {
|
||||||
NS_WARN_IF(!range->IsPositioned())) {
|
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NS_WARN_IF(range->StartRef() != aStart) ||
|
if (NS_WARN_IF(range->StartRef() != aStartBoundary) ||
|
||||||
NS_WARN_IF(range->EndRef() != aEnd)) {
|
NS_WARN_IF(range->EndRef() != aEndBoundary)) {
|
||||||
return NS_ERROR_UNEXPECTED;
|
return NS_ERROR_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -734,8 +732,8 @@ nsresult ContentSubtreeIterator::InitWithRange() {
|
|||||||
// we have a range that does not fully contain any node.
|
// we have a range that does not fully contain any node.
|
||||||
|
|
||||||
bool nodeBefore, nodeAfter;
|
bool nodeBefore, nodeAfter;
|
||||||
MOZ_ALWAYS_SUCCEEDS(nsRange::CompareNodeToRange(firstCandidate, mRange,
|
MOZ_ALWAYS_SUCCEEDS(RangeUtils::CompareNodeToRange(firstCandidate, mRange,
|
||||||
&nodeBefore, &nodeAfter));
|
&nodeBefore, &nodeAfter));
|
||||||
|
|
||||||
if (nodeBefore || nodeAfter) {
|
if (nodeBefore || nodeAfter) {
|
||||||
MakeEmpty();
|
MakeEmpty();
|
||||||
@ -779,8 +777,8 @@ nsresult ContentSubtreeIterator::InitWithRange() {
|
|||||||
// confirm that this last possible contained node is indeed contained. Else
|
// confirm that this last possible contained node is indeed contained. Else
|
||||||
// we have a range that does not fully contain any node.
|
// we have a range that does not fully contain any node.
|
||||||
|
|
||||||
MOZ_ALWAYS_SUCCEEDS(nsRange::CompareNodeToRange(lastCandidate, mRange,
|
MOZ_ALWAYS_SUCCEEDS(RangeUtils::CompareNodeToRange(lastCandidate, mRange,
|
||||||
&nodeBefore, &nodeAfter));
|
&nodeBefore, &nodeAfter));
|
||||||
|
|
||||||
if (nodeBefore || nodeAfter) {
|
if (nodeBefore || nodeAfter) {
|
||||||
MakeEmpty();
|
MakeEmpty();
|
||||||
@ -899,7 +897,7 @@ nsIContent* ContentSubtreeIterator::GetTopAncestorInRange(nsINode* aNode) {
|
|||||||
// sanity check: aNode is itself in the range
|
// sanity check: aNode is itself in the range
|
||||||
bool nodeBefore, nodeAfter;
|
bool nodeBefore, nodeAfter;
|
||||||
nsresult res =
|
nsresult res =
|
||||||
nsRange::CompareNodeToRange(aNode, mRange, &nodeBefore, &nodeAfter);
|
RangeUtils::CompareNodeToRange(aNode, mRange, &nodeBefore, &nodeAfter);
|
||||||
NS_ASSERTION(NS_SUCCEEDED(res) && !nodeBefore && !nodeAfter,
|
NS_ASSERTION(NS_SUCCEEDED(res) && !nodeBefore && !nodeAfter,
|
||||||
"aNode isn't in mRange, or something else weird happened");
|
"aNode isn't in mRange, or something else weird happened");
|
||||||
if (NS_FAILED(res) || nodeBefore || nodeAfter) {
|
if (NS_FAILED(res) || nodeBefore || nodeAfter) {
|
||||||
@ -917,8 +915,8 @@ nsIContent* ContentSubtreeIterator::GetTopAncestorInRange(nsINode* aNode) {
|
|||||||
if (!parent || !parent->GetParentNode()) {
|
if (!parent || !parent->GetParentNode()) {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
MOZ_ALWAYS_SUCCEEDS(
|
MOZ_ALWAYS_SUCCEEDS(RangeUtils::CompareNodeToRange(
|
||||||
nsRange::CompareNodeToRange(parent, mRange, &nodeBefore, &nodeAfter));
|
parent, mRange, &nodeBefore, &nodeAfter));
|
||||||
|
|
||||||
if (nodeBefore || nodeAfter) {
|
if (nodeBefore || nodeAfter) {
|
||||||
return content;
|
return content;
|
||||||
|
@ -176,8 +176,8 @@ class ContentSubtreeIterator final : public ContentIteratorBase {
|
|||||||
virtual nsresult Init(nsRange* aRange) override;
|
virtual nsresult Init(nsRange* aRange) override;
|
||||||
virtual nsresult Init(nsINode* aStartContainer, uint32_t aStartOffset,
|
virtual nsresult Init(nsINode* aStartContainer, uint32_t aStartOffset,
|
||||||
nsINode* aEndContainer, uint32_t aEndOffset) override;
|
nsINode* aEndContainer, uint32_t aEndOffset) override;
|
||||||
virtual nsresult Init(const RawRangeBoundary& aStart,
|
virtual nsresult Init(const RawRangeBoundary& aStartBoundary,
|
||||||
const RawRangeBoundary& aEnd) override;
|
const RawRangeBoundary& aEndBoundary) override;
|
||||||
|
|
||||||
virtual void Next() override;
|
virtual void Next() override;
|
||||||
virtual void Prev() override;
|
virtual void Prev() override;
|
||||||
|
@ -11,8 +11,6 @@
|
|||||||
#include "nsFrameMessageManager.h"
|
#include "nsFrameMessageManager.h"
|
||||||
#include "nsIScriptContext.h"
|
#include "nsIScriptContext.h"
|
||||||
#include "nsIScriptContext.h"
|
#include "nsIScriptContext.h"
|
||||||
#include "nsIClassInfo.h"
|
|
||||||
#include "nsIRunnable.h"
|
|
||||||
#include "nsServiceManagerUtils.h"
|
#include "nsServiceManagerUtils.h"
|
||||||
#include "nsWeakReference.h"
|
#include "nsWeakReference.h"
|
||||||
#include "nsWrapperCache.h"
|
#include "nsWrapperCache.h"
|
||||||
|
@ -42,13 +42,6 @@ void Crypto::GetRandomValues(JSContext* aCx, const ArrayBufferView& aArray,
|
|||||||
ErrorResult& aRv) {
|
ErrorResult& aRv) {
|
||||||
JS::Rooted<JSObject*> view(aCx, aArray.Obj());
|
JS::Rooted<JSObject*> view(aCx, aArray.Obj());
|
||||||
|
|
||||||
if (JS_IsTypedArrayObject(view) && JS_GetTypedArraySharedness(view)) {
|
|
||||||
// Throw if the object is mapping shared memory (must opt in).
|
|
||||||
aRv.ThrowTypeError<MSG_TYPEDARRAY_IS_SHARED>(
|
|
||||||
NS_LITERAL_STRING("Argument of Crypto.getRandomValues"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Throw if the wrong type of ArrayBufferView is passed in
|
// Throw if the wrong type of ArrayBufferView is passed in
|
||||||
// (Part of the Web Crypto API spec)
|
// (Part of the Web Crypto API spec)
|
||||||
switch (JS_GetArrayBufferViewType(view)) {
|
switch (JS_GetArrayBufferViewType(view)) {
|
||||||
|
@ -172,6 +172,12 @@ void CustomElementData::SetCustomElementDefinition(
|
|||||||
mCustomElementDefinition = aDefinition;
|
mCustomElementDefinition = aDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CustomElementData::AttachedInternals() {
|
||||||
|
MOZ_ASSERT(!mIsAttachedInternals);
|
||||||
|
|
||||||
|
mIsAttachedInternals = true;
|
||||||
|
}
|
||||||
|
|
||||||
CustomElementDefinition* CustomElementData::GetCustomElementDefinition() {
|
CustomElementDefinition* CustomElementData::GetCustomElementDefinition() {
|
||||||
MOZ_ASSERT(mCustomElementDefinition ? mState == State::eCustom
|
MOZ_ASSERT(mCustomElementDefinition ? mState == State::eCustom
|
||||||
: mState != State::eCustom);
|
: mState != State::eCustom);
|
||||||
@ -634,7 +640,62 @@ int32_t CustomElementRegistry::InferNamespace(
|
|||||||
return kNameSpaceID_XHTML;
|
return kNameSpaceID_XHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/scripting.html#element-definition
|
bool CustomElementRegistry::JSObjectToAtomArray(
|
||||||
|
JSContext* aCx, JS::Handle<JSObject*> aConstructor, const char16_t* aName,
|
||||||
|
nsTArray<RefPtr<nsAtom>>& aArray, ErrorResult& aRv) {
|
||||||
|
JS::RootedValue iterable(aCx, JS::UndefinedValue());
|
||||||
|
if (!JS_GetUCProperty(aCx, aConstructor, aName,
|
||||||
|
std::char_traits<char16_t>::length(aName), &iterable)) {
|
||||||
|
aRv.NoteJSContextException(aCx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!iterable.isUndefined()) {
|
||||||
|
if (!iterable.isObject()) {
|
||||||
|
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(nsDependentString(aName));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::ForOfIterator iter(aCx);
|
||||||
|
if (!iter.init(iterable, JS::ForOfIterator::AllowNonIterable)) {
|
||||||
|
aRv.NoteJSContextException(aCx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!iter.valueIsIterable()) {
|
||||||
|
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(nsDependentString(aName));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::Rooted<JS::Value> attribute(aCx);
|
||||||
|
while (true) {
|
||||||
|
bool done;
|
||||||
|
if (!iter.next(&attribute, &done)) {
|
||||||
|
aRv.NoteJSContextException(aCx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (done) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsAutoString attrStr;
|
||||||
|
if (!ConvertJSValueToString(aCx, attribute, eStringify, eStringify,
|
||||||
|
attrStr)) {
|
||||||
|
aRv.NoteJSContextException(aCx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aArray.AppendElement(NS_Atomize(attrStr))) {
|
||||||
|
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/commit-snapshots/b48bb2238269d90ea4f455a52cdf29505aff3df0/#dom-customelementregistry-define
|
||||||
void CustomElementRegistry::Define(
|
void CustomElementRegistry::Define(
|
||||||
JSContext* aCx, const nsAString& aName,
|
JSContext* aCx, const nsAString& aName,
|
||||||
CustomElementConstructor& aFunctionConstructor,
|
CustomElementConstructor& aFunctionConstructor,
|
||||||
@ -675,7 +736,10 @@ void CustomElementRegistry::Define(
|
|||||||
Document* doc = mWindow->GetExtantDoc();
|
Document* doc = mWindow->GetExtantDoc();
|
||||||
RefPtr<nsAtom> nameAtom(NS_Atomize(aName));
|
RefPtr<nsAtom> nameAtom(NS_Atomize(aName));
|
||||||
if (!nsContentUtils::IsCustomElementName(nameAtom, nameSpaceID)) {
|
if (!nsContentUtils::IsCustomElementName(nameAtom, nameSpaceID)) {
|
||||||
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
aRv.ThrowDOMException(
|
||||||
|
NS_ERROR_DOM_SYNTAX_ERR,
|
||||||
|
nsPrintfCString("'%s' is not a valid custom element name",
|
||||||
|
NS_ConvertUTF16toUTF8(aName).get()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -684,7 +748,10 @@ void CustomElementRegistry::Define(
|
|||||||
* throw a "NotSupportedError" DOMException and abort these steps.
|
* throw a "NotSupportedError" DOMException and abort these steps.
|
||||||
*/
|
*/
|
||||||
if (mCustomDefinitions.GetWeak(nameAtom)) {
|
if (mCustomDefinitions.GetWeak(nameAtom)) {
|
||||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
aRv.ThrowDOMException(
|
||||||
|
NS_ERROR_DOM_NOT_SUPPORTED_ERR,
|
||||||
|
nsPrintfCString("'%s' has already been defined as a custom element",
|
||||||
|
NS_ConvertUTF16toUTF8(aName).get()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -697,7 +764,12 @@ void CustomElementRegistry::Define(
|
|||||||
if (ptr) {
|
if (ptr) {
|
||||||
MOZ_ASSERT(mCustomDefinitions.GetWeak(ptr->value()),
|
MOZ_ASSERT(mCustomDefinitions.GetWeak(ptr->value()),
|
||||||
"Definition must be found in mCustomDefinitions");
|
"Definition must be found in mCustomDefinitions");
|
||||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
nsAutoCString name;
|
||||||
|
ptr->value()->ToUTF8String(name);
|
||||||
|
aRv.ThrowDOMException(
|
||||||
|
NS_ERROR_DOM_NOT_SUPPORTED_ERR,
|
||||||
|
nsPrintfCString("'%s' and '%s' have the same constructor",
|
||||||
|
NS_ConvertUTF16toUTF8(aName).get(), name.get()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -729,7 +801,10 @@ void CustomElementRegistry::Define(
|
|||||||
if (aOptions.mExtends.WasPassed()) {
|
if (aOptions.mExtends.WasPassed()) {
|
||||||
RefPtr<nsAtom> extendsAtom(NS_Atomize(aOptions.mExtends.Value()));
|
RefPtr<nsAtom> extendsAtom(NS_Atomize(aOptions.mExtends.Value()));
|
||||||
if (nsContentUtils::IsCustomElementName(extendsAtom, kNameSpaceID_XHTML)) {
|
if (nsContentUtils::IsCustomElementName(extendsAtom, kNameSpaceID_XHTML)) {
|
||||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
aRv.ThrowDOMException(
|
||||||
|
NS_ERROR_DOM_NOT_SUPPORTED_ERR,
|
||||||
|
nsPrintfCString("'%s' cannot extend a custom element",
|
||||||
|
NS_ConvertUTF16toUTF8(aName).get()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -758,12 +833,17 @@ void CustomElementRegistry::Define(
|
|||||||
* set, then throw a "NotSupportedError" DOMException and abort these steps.
|
* set, then throw a "NotSupportedError" DOMException and abort these steps.
|
||||||
*/
|
*/
|
||||||
if (mIsCustomDefinitionRunning) {
|
if (mIsCustomDefinitionRunning) {
|
||||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
aRv.ThrowDOMException(
|
||||||
|
NS_ERROR_DOM_NOT_SUPPORTED_ERR,
|
||||||
|
"Cannot define a custom element while defining another custom element");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto callbacksHolder = MakeUnique<LifecycleCallbacks>();
|
auto callbacksHolder = MakeUnique<LifecycleCallbacks>();
|
||||||
nsTArray<RefPtr<nsAtom>> observedAttributes;
|
nsTArray<RefPtr<nsAtom>> observedAttributes;
|
||||||
|
AutoTArray<RefPtr<nsAtom>, 2> disabledFeatures;
|
||||||
|
bool disableInternals = false;
|
||||||
|
bool disableShadow = false;
|
||||||
{ // Set mIsCustomDefinitionRunning.
|
{ // Set mIsCustomDefinitionRunning.
|
||||||
/**
|
/**
|
||||||
* 9. Set this CustomElementRegistry's element definition is running flag.
|
* 9. Set this CustomElementRegistry's element definition is running flag.
|
||||||
@ -771,7 +851,7 @@ void CustomElementRegistry::Define(
|
|||||||
AutoSetRunningFlag as(this);
|
AutoSetRunningFlag as(this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 10.1. Let prototype be Get(constructor, "prototype"). Rethrow any
|
* 14.1. Let prototype be Get(constructor, "prototype"). Rethrow any
|
||||||
* exceptions.
|
* exceptions.
|
||||||
*/
|
*/
|
||||||
// The .prototype on the constructor passed could be an "expando" of a
|
// The .prototype on the constructor passed could be an "expando" of a
|
||||||
@ -784,7 +864,7 @@ void CustomElementRegistry::Define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 10.2. If Type(prototype) is not Object, then throw a TypeError exception.
|
* 14.2. If Type(prototype) is not Object, then throw a TypeError exception.
|
||||||
*/
|
*/
|
||||||
if (!prototype.isObject()) {
|
if (!prototype.isObject()) {
|
||||||
aRv.ThrowTypeError<MSG_NOT_OBJECT>(
|
aRv.ThrowTypeError<MSG_NOT_OBJECT>(
|
||||||
@ -793,12 +873,12 @@ void CustomElementRegistry::Define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 10.3. Let lifecycleCallbacks be a map with the four keys
|
* 14.3. Let lifecycleCallbacks be a map with the four keys
|
||||||
* "connectedCallback", "disconnectedCallback", "adoptedCallback", and
|
* "connectedCallback", "disconnectedCallback", "adoptedCallback", and
|
||||||
* "attributeChangedCallback", each of which belongs to an entry whose
|
* "attributeChangedCallback", each of which belongs to an entry whose
|
||||||
* value is null. The 'getCustomInterface' callback is also included
|
* value is null. The 'getCustomInterface' callback is also included
|
||||||
* for chrome usage.
|
* for chrome usage.
|
||||||
* 10.4. For each of the four keys callbackName in lifecycleCallbacks:
|
* 14.4. For each of the four keys callbackName in lifecycleCallbacks:
|
||||||
* 1. Let callbackValue be Get(prototype, callbackName). Rethrow any
|
* 1. Let callbackValue be Get(prototype, callbackName). Rethrow any
|
||||||
* exceptions.
|
* exceptions.
|
||||||
* 2. If callbackValue is not undefined, then set the value of the
|
* 2. If callbackValue is not undefined, then set the value of the
|
||||||
@ -812,8 +892,7 @@ void CustomElementRegistry::Define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 10.5. Let observedAttributes be an empty sequence<DOMString>.
|
* 14.5. If the value of the entry in lifecycleCallbacks with key
|
||||||
* 10.6. If the value of the entry in lifecycleCallbacks with key
|
|
||||||
* "attributeChangedCallback" is not null, then:
|
* "attributeChangedCallback" is not null, then:
|
||||||
* 1. Let observedAttributesIterable be Get(constructor,
|
* 1. Let observedAttributesIterable be Get(constructor,
|
||||||
* "observedAttributes"). Rethrow any exceptions.
|
* "observedAttributes"). Rethrow any exceptions.
|
||||||
@ -823,63 +902,41 @@ void CustomElementRegistry::Define(
|
|||||||
* any exceptions from the conversion.
|
* any exceptions from the conversion.
|
||||||
*/
|
*/
|
||||||
if (callbacksHolder->mAttributeChangedCallback.WasPassed()) {
|
if (callbacksHolder->mAttributeChangedCallback.WasPassed()) {
|
||||||
JS::Rooted<JS::Value> observedAttributesIterable(aCx);
|
if (!JSObjectToAtomArray(aCx, constructor, u"observedAttributes",
|
||||||
|
observedAttributes, aRv)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!JS_GetProperty(aCx, constructor, "observedAttributes",
|
/**
|
||||||
&observedAttributesIterable)) {
|
* 14.6. Let disabledFeatures be an empty sequence<DOMString>.
|
||||||
aRv.NoteJSContextException(aCx);
|
* 14.7. Let disabledFeaturesIterable be Get(constructor,
|
||||||
|
* "disabledFeatures"). Rethrow any exceptions.
|
||||||
|
* 14.8. If disabledFeaturesIterable is not undefined, then set
|
||||||
|
* disabledFeatures to the result of converting
|
||||||
|
* disabledFeaturesIterable to a sequence<DOMString>.
|
||||||
|
* Rethrow any exceptions from the conversion.
|
||||||
|
*/
|
||||||
|
if (StaticPrefs::dom_webcomponents_elementInternals_enabled()) {
|
||||||
|
if (!JSObjectToAtomArray(aCx, constructor, u"disabledFeatures",
|
||||||
|
disabledFeatures, aRv)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!observedAttributesIterable.isUndefined()) {
|
// 14.9. Set disableInternals to true if disabledFeaturesSequence contains
|
||||||
if (!observedAttributesIterable.isObject()) {
|
// "internals".
|
||||||
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(
|
disableInternals = disabledFeatures.Contains(
|
||||||
NS_LITERAL_STRING("observedAttributes"));
|
static_cast<nsStaticAtom*>(nsGkAtoms::internals));
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::ForOfIterator iter(aCx);
|
// 14.10. Set disableShadow to true if disabledFeaturesSequence contains
|
||||||
if (!iter.init(observedAttributesIterable,
|
// "shadow".
|
||||||
JS::ForOfIterator::AllowNonIterable)) {
|
disableShadow = disabledFeatures.Contains(
|
||||||
aRv.NoteJSContextException(aCx);
|
static_cast<nsStaticAtom*>(nsGkAtoms::shadow));
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!iter.valueIsIterable()) {
|
|
||||||
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(
|
|
||||||
NS_LITERAL_STRING("observedAttributes"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::Rooted<JS::Value> attribute(aCx);
|
|
||||||
while (true) {
|
|
||||||
bool done;
|
|
||||||
if (!iter.next(&attribute, &done)) {
|
|
||||||
aRv.NoteJSContextException(aCx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (done) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoString attrStr;
|
|
||||||
if (!ConvertJSValueToString(aCx, attribute, eStringify, eStringify,
|
|
||||||
attrStr)) {
|
|
||||||
aRv.NoteJSContextException(aCx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!observedAttributes.AppendElement(NS_Atomize(attrStr))) {
|
|
||||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} // Unset mIsCustomDefinitionRunning
|
} // Unset mIsCustomDefinitionRunning
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 11. Let definition be a new custom element definition with name name,
|
* 15. Let definition be a new custom element definition with name name,
|
||||||
* local name localName, constructor constructor, prototype prototype,
|
* local name localName, constructor constructor, prototype prototype,
|
||||||
* observed attributes observedAttributes, and lifecycle callbacks
|
* observed attributes observedAttributes, and lifecycle callbacks
|
||||||
* lifecycleCallbacks.
|
* lifecycleCallbacks.
|
||||||
@ -888,7 +945,7 @@ void CustomElementRegistry::Define(
|
|||||||
RefPtr<nsAtom> localNameAtom(NS_Atomize(localName));
|
RefPtr<nsAtom> localNameAtom(NS_Atomize(localName));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 12. Add definition to this CustomElementRegistry.
|
* 16. Add definition to this CustomElementRegistry.
|
||||||
*/
|
*/
|
||||||
if (!mConstructors.put(constructorUnwrapped, nameAtom)) {
|
if (!mConstructors.put(constructorUnwrapped, nameAtom)) {
|
||||||
aRv.Throw(NS_ERROR_FAILURE);
|
aRv.Throw(NS_ERROR_FAILURE);
|
||||||
@ -897,7 +954,8 @@ void CustomElementRegistry::Define(
|
|||||||
|
|
||||||
RefPtr<CustomElementDefinition> definition = new CustomElementDefinition(
|
RefPtr<CustomElementDefinition> definition = new CustomElementDefinition(
|
||||||
nameAtom, localNameAtom, nameSpaceID, &aFunctionConstructor,
|
nameAtom, localNameAtom, nameSpaceID, &aFunctionConstructor,
|
||||||
std::move(observedAttributes), std::move(callbacksHolder));
|
std::move(observedAttributes), std::move(callbacksHolder),
|
||||||
|
disableInternals, disableShadow);
|
||||||
|
|
||||||
CustomElementDefinition* def = definition.get();
|
CustomElementDefinition* def = definition.get();
|
||||||
mCustomDefinitions.Put(nameAtom, definition.forget());
|
mCustomDefinitions.Put(nameAtom, definition.forget());
|
||||||
@ -906,12 +964,12 @@ void CustomElementRegistry::Define(
|
|||||||
"Number of entries should be the same");
|
"Number of entries should be the same");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 13. 14. 15. Upgrade candidates
|
* 17. 18. 19. Upgrade candidates
|
||||||
*/
|
*/
|
||||||
UpgradeCandidates(nameAtom, def, aRv);
|
UpgradeCandidates(nameAtom, def, aRv);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 16. If this CustomElementRegistry's when-defined promise map contains an
|
* 20. If this CustomElementRegistry's when-defined promise map contains an
|
||||||
* entry with key name:
|
* entry with key name:
|
||||||
* 1. Let promise be the value of that entry.
|
* 1. Let promise be the value of that entry.
|
||||||
* 2. Resolve promise with undefined.
|
* 2. Resolve promise with undefined.
|
||||||
@ -1034,8 +1092,19 @@ already_AddRefed<Promise> CustomElementRegistry::WhenDefined(
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
MOZ_CAN_RUN_SCRIPT
|
MOZ_CAN_RUN_SCRIPT
|
||||||
static void DoUpgrade(Element* aElement, CustomElementConstructor* aConstructor,
|
static void DoUpgrade(Element* aElement, CustomElementDefinition* aDefinition,
|
||||||
|
CustomElementConstructor* aConstructor,
|
||||||
ErrorResult& aRv) {
|
ErrorResult& aRv) {
|
||||||
|
if (aDefinition->mDisableShadow && aElement->GetShadowRoot()) {
|
||||||
|
aRv.ThrowDOMException(
|
||||||
|
NS_ERROR_DOM_NOT_SUPPORTED_ERR,
|
||||||
|
nsPrintfCString(
|
||||||
|
"Custom element upgrade to '%s' is disabled due to shadow root "
|
||||||
|
"already exists",
|
||||||
|
NS_ConvertUTF16toUTF8(aDefinition->mType->GetUTF16String()).get()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
JS::Rooted<JS::Value> constructResult(RootingCx());
|
JS::Rooted<JS::Value> constructResult(RootingCx());
|
||||||
// Rethrow the exception since it might actually throw the exception from the
|
// Rethrow the exception since it might actually throw the exception from the
|
||||||
// upgrade steps back out to the caller of document.createElement.
|
// upgrade steps back out to the caller of document.createElement.
|
||||||
@ -1106,7 +1175,8 @@ void CustomElementRegistry::Upgrade(Element* aElement,
|
|||||||
AutoConstructionStackEntry acs(aDefinition->mConstructionStack, aElement);
|
AutoConstructionStackEntry acs(aDefinition->mConstructionStack, aElement);
|
||||||
|
|
||||||
// Step 6 and step 7.
|
// Step 6 and step 7.
|
||||||
DoUpgrade(aElement, MOZ_KnownLive(aDefinition->mConstructor), aRv);
|
DoUpgrade(aElement, aDefinition, MOZ_KnownLive(aDefinition->mConstructor),
|
||||||
|
aRv);
|
||||||
if (aRv.Failed()) {
|
if (aRv.Failed()) {
|
||||||
data->mState = CustomElementData::State::eFailed;
|
data->mState = CustomElementData::State::eFailed;
|
||||||
// Empty element's custom element reaction queue.
|
// Empty element's custom element reaction queue.
|
||||||
@ -1387,13 +1457,16 @@ CustomElementDefinition::CustomElementDefinition(
|
|||||||
nsAtom* aType, nsAtom* aLocalName, int32_t aNamespaceID,
|
nsAtom* aType, nsAtom* aLocalName, int32_t aNamespaceID,
|
||||||
CustomElementConstructor* aConstructor,
|
CustomElementConstructor* aConstructor,
|
||||||
nsTArray<RefPtr<nsAtom>>&& aObservedAttributes,
|
nsTArray<RefPtr<nsAtom>>&& aObservedAttributes,
|
||||||
UniquePtr<LifecycleCallbacks>&& aCallbacks)
|
UniquePtr<LifecycleCallbacks>&& aCallbacks, bool aDisableInternals,
|
||||||
|
bool aDisableShadow)
|
||||||
: mType(aType),
|
: mType(aType),
|
||||||
mLocalName(aLocalName),
|
mLocalName(aLocalName),
|
||||||
mNamespaceID(aNamespaceID),
|
mNamespaceID(aNamespaceID),
|
||||||
mConstructor(aConstructor),
|
mConstructor(aConstructor),
|
||||||
mObservedAttributes(std::move(aObservedAttributes)),
|
mObservedAttributes(std::move(aObservedAttributes)),
|
||||||
mCallbacks(std::move(aCallbacks)) {}
|
mCallbacks(std::move(aCallbacks)),
|
||||||
|
mDisableInternals(aDisableInternals),
|
||||||
|
mDisableShadow(aDisableShadow) {}
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -103,6 +103,8 @@ struct CustomElementData {
|
|||||||
void SetCustomElementDefinition(CustomElementDefinition* aDefinition);
|
void SetCustomElementDefinition(CustomElementDefinition* aDefinition);
|
||||||
CustomElementDefinition* GetCustomElementDefinition();
|
CustomElementDefinition* GetCustomElementDefinition();
|
||||||
nsAtom* GetCustomElementType() const { return mType; }
|
nsAtom* GetCustomElementType() const { return mType; }
|
||||||
|
void AttachedInternals();
|
||||||
|
bool HasAttachedInternals() const { return mIsAttachedInternals; }
|
||||||
|
|
||||||
void Traverse(nsCycleCollectionTraversalCallback& aCb) const;
|
void Traverse(nsCycleCollectionTraversalCallback& aCb) const;
|
||||||
void Unlink();
|
void Unlink();
|
||||||
@ -121,6 +123,7 @@ struct CustomElementData {
|
|||||||
// this would be x-button.
|
// this would be x-button.
|
||||||
RefPtr<nsAtom> mType;
|
RefPtr<nsAtom> mType;
|
||||||
RefPtr<CustomElementDefinition> mCustomElementDefinition;
|
RefPtr<CustomElementDefinition> mCustomElementDefinition;
|
||||||
|
bool mIsAttachedInternals = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ALREADY_CONSTRUCTED_MARKER nullptr
|
#define ALREADY_CONSTRUCTED_MARKER nullptr
|
||||||
@ -135,7 +138,8 @@ struct CustomElementDefinition {
|
|||||||
int32_t aNamespaceID,
|
int32_t aNamespaceID,
|
||||||
CustomElementConstructor* aConstructor,
|
CustomElementConstructor* aConstructor,
|
||||||
nsTArray<RefPtr<nsAtom>>&& aObservedAttributes,
|
nsTArray<RefPtr<nsAtom>>&& aObservedAttributes,
|
||||||
UniquePtr<LifecycleCallbacks>&& aCallbacks);
|
UniquePtr<LifecycleCallbacks>&& aCallbacks,
|
||||||
|
bool aDisableInternals, bool aDisableShadow);
|
||||||
|
|
||||||
// The type (name) for this custom element, for <button is="x-foo"> or <x-foo>
|
// The type (name) for this custom element, for <button is="x-foo"> or <x-foo>
|
||||||
// this would be x-foo.
|
// this would be x-foo.
|
||||||
@ -156,6 +160,12 @@ struct CustomElementDefinition {
|
|||||||
// The lifecycle callbacks to call for this custom element.
|
// The lifecycle callbacks to call for this custom element.
|
||||||
UniquePtr<LifecycleCallbacks> mCallbacks;
|
UniquePtr<LifecycleCallbacks> mCallbacks;
|
||||||
|
|
||||||
|
// Determine whether to allow to attachInternals() for this custom element.
|
||||||
|
bool mDisableInternals = false;
|
||||||
|
|
||||||
|
// Determine whether to allow to attachShadow() for this custom element.
|
||||||
|
bool mDisableShadow = false;
|
||||||
|
|
||||||
// A construction stack. Use nullptr to represent an "already constructed
|
// A construction stack. Use nullptr to represent an "already constructed
|
||||||
// marker".
|
// marker".
|
||||||
nsTArray<RefPtr<Element>> mConstructionStack;
|
nsTArray<RefPtr<Element>> mConstructionStack;
|
||||||
@ -466,6 +476,10 @@ class CustomElementRegistry final : public nsISupports, public nsWrapperCache {
|
|||||||
private:
|
private:
|
||||||
~CustomElementRegistry();
|
~CustomElementRegistry();
|
||||||
|
|
||||||
|
bool JSObjectToAtomArray(JSContext* aCx, JS::Handle<JSObject*> aConstructor,
|
||||||
|
const char16_t* aName,
|
||||||
|
nsTArray<RefPtr<nsAtom>>& aArray, ErrorResult& aRv);
|
||||||
|
|
||||||
static UniquePtr<CustomElementCallback> CreateCustomElementCallback(
|
static UniquePtr<CustomElementCallback> CreateCustomElementCallback(
|
||||||
Document::ElementCallbackType aType, Element* aCustomElement,
|
Document::ElementCallbackType aType, Element* aCustomElement,
|
||||||
LifecycleCallbackArgs* aArgs,
|
LifecycleCallbackArgs* aArgs,
|
||||||
|
@ -1,71 +0,0 @@
|
|||||||
/* 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/dom/DOMError.h"
|
|
||||||
#include "mozilla/dom/DOMErrorBinding.h"
|
|
||||||
#include "mozilla/dom/DOMException.h"
|
|
||||||
#include "mozilla/UseCounter.h"
|
|
||||||
#include "mozilla/dom/Document.h"
|
|
||||||
#include "nsPIDOMWindow.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace dom {
|
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMError, mWindow)
|
|
||||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMError)
|
|
||||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMError)
|
|
||||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMError)
|
|
||||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
||||||
NS_INTERFACE_MAP_ENTRY(DOMError)
|
|
||||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
||||||
NS_INTERFACE_MAP_END
|
|
||||||
|
|
||||||
DOMError::DOMError(nsPIDOMWindowInner* aWindow) : mWindow(aWindow) {}
|
|
||||||
|
|
||||||
DOMError::DOMError(nsPIDOMWindowInner* aWindow, nsresult aValue)
|
|
||||||
: mWindow(aWindow) {
|
|
||||||
nsCString name, message;
|
|
||||||
NS_GetNameAndMessageForDOMNSResult(aValue, name, message);
|
|
||||||
|
|
||||||
CopyUTF8toUTF16(name, mName);
|
|
||||||
CopyUTF8toUTF16(message, mMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
DOMError::DOMError(nsPIDOMWindowInner* aWindow, const nsAString& aName)
|
|
||||||
: mWindow(aWindow), mName(aName) {}
|
|
||||||
|
|
||||||
DOMError::DOMError(nsPIDOMWindowInner* aWindow, const nsAString& aName,
|
|
||||||
const nsAString& aMessage)
|
|
||||||
: mWindow(aWindow), mName(aName), mMessage(aMessage) {}
|
|
||||||
|
|
||||||
DOMError::~DOMError() {}
|
|
||||||
|
|
||||||
JSObject* DOMError::WrapObject(JSContext* aCx,
|
|
||||||
JS::Handle<JSObject*> aGivenProto) {
|
|
||||||
return DOMError_Binding::Wrap(aCx, this, aGivenProto);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */
|
|
||||||
already_AddRefed<DOMError> DOMError::Constructor(const GlobalObject& aGlobal,
|
|
||||||
const nsAString& aName,
|
|
||||||
const nsAString& aMessage,
|
|
||||||
ErrorResult& aRv) {
|
|
||||||
nsCOMPtr<nsPIDOMWindowInner> window =
|
|
||||||
do_QueryInterface(aGlobal.GetAsSupports());
|
|
||||||
|
|
||||||
if (window) {
|
|
||||||
nsCOMPtr<Document> doc = window->GetExtantDoc();
|
|
||||||
if (doc) {
|
|
||||||
doc->SetDocumentAndPageUseCounter(eUseCounter_custom_DOMErrorConstructor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Window is null for chrome code.
|
|
||||||
|
|
||||||
RefPtr<DOMError> ret = new DOMError(window, aName, aMessage);
|
|
||||||
return ret.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace dom
|
|
||||||
} // namespace mozilla
|
|
@ -1,76 +0,0 @@
|
|||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#ifndef mozilla_dom_domerror_h__
|
|
||||||
#define mozilla_dom_domerror_h__
|
|
||||||
|
|
||||||
#include "mozilla/Attributes.h"
|
|
||||||
#include "nsWrapperCache.h"
|
|
||||||
#include "nsCOMPtr.h"
|
|
||||||
#include "nsString.h"
|
|
||||||
|
|
||||||
#define DOMERROR_IID \
|
|
||||||
{ \
|
|
||||||
0x220cb63f, 0xa37d, 0x4ba4, { \
|
|
||||||
0x8e, 0x31, 0xfc, 0xde, 0xec, 0x48, 0xe1, 0x66 \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
class nsPIDOMWindowInner;
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
|
|
||||||
class ErrorResult;
|
|
||||||
|
|
||||||
namespace dom {
|
|
||||||
|
|
||||||
class GlobalObject;
|
|
||||||
|
|
||||||
class DOMError : public nsISupports, public nsWrapperCache {
|
|
||||||
nsCOMPtr<nsPIDOMWindowInner> mWindow;
|
|
||||||
nsString mName;
|
|
||||||
nsString mMessage;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual ~DOMError();
|
|
||||||
|
|
||||||
public:
|
|
||||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
|
||||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMError)
|
|
||||||
|
|
||||||
NS_DECLARE_STATIC_IID_ACCESSOR(DOMERROR_IID)
|
|
||||||
|
|
||||||
// aWindow can be null if this DOMError is not associated with a particular
|
|
||||||
// window.
|
|
||||||
|
|
||||||
explicit DOMError(nsPIDOMWindowInner* aWindow);
|
|
||||||
|
|
||||||
DOMError(nsPIDOMWindowInner* aWindow, nsresult aValue);
|
|
||||||
|
|
||||||
DOMError(nsPIDOMWindowInner* aWindow, const nsAString& aName);
|
|
||||||
|
|
||||||
DOMError(nsPIDOMWindowInner* aWindow, const nsAString& aName,
|
|
||||||
const nsAString& aMessage);
|
|
||||||
|
|
||||||
nsPIDOMWindowInner* GetParentObject() const { return mWindow; }
|
|
||||||
|
|
||||||
virtual JSObject* WrapObject(JSContext* aCx,
|
|
||||||
JS::Handle<JSObject*> aGivenProto) override;
|
|
||||||
|
|
||||||
static already_AddRefed<DOMError> Constructor(const GlobalObject& global,
|
|
||||||
const nsAString& name,
|
|
||||||
const nsAString& message,
|
|
||||||
ErrorResult& aRv);
|
|
||||||
|
|
||||||
void GetName(nsString& aRetval) const { aRetval = mName; }
|
|
||||||
|
|
||||||
void GetMessage(nsString& aRetval) const { aRetval = mMessage; }
|
|
||||||
};
|
|
||||||
|
|
||||||
NS_DEFINE_STATIC_IID_ACCESSOR(DOMError, DOMERROR_IID)
|
|
||||||
|
|
||||||
} // namespace dom
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#endif // mozilla_dom_domerror_h__
|
|
@ -356,7 +356,7 @@ void DOMException::GetName(nsString& retval) { CopyUTF8toUTF16(mName, retval); }
|
|||||||
|
|
||||||
already_AddRefed<DOMException> DOMException::Constructor(
|
already_AddRefed<DOMException> DOMException::Constructor(
|
||||||
GlobalObject& /* unused */, const nsAString& aMessage,
|
GlobalObject& /* unused */, const nsAString& aMessage,
|
||||||
const Optional<nsAString>& aName, ErrorResult& aError) {
|
const Optional<nsAString>& aName) {
|
||||||
nsresult exceptionResult = NS_OK;
|
nsresult exceptionResult = NS_OK;
|
||||||
uint16_t exceptionCode = 0;
|
uint16_t exceptionCode = 0;
|
||||||
nsCString name(NS_LITERAL_CSTRING("Error"));
|
nsCString name(NS_LITERAL_CSTRING("Error"));
|
||||||
|
@ -145,7 +145,7 @@ class DOMException : public Exception {
|
|||||||
|
|
||||||
static already_AddRefed<DOMException> Constructor(
|
static already_AddRefed<DOMException> Constructor(
|
||||||
GlobalObject& /* unused */, const nsAString& aMessage,
|
GlobalObject& /* unused */, const nsAString& aMessage,
|
||||||
const Optional<nsAString>& aName, ErrorResult& aError);
|
const Optional<nsAString>& aName);
|
||||||
|
|
||||||
uint16_t Code() const { return mCode; }
|
uint16_t Code() const { return mCode; }
|
||||||
|
|
||||||
|
@ -59,16 +59,14 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMIntersectionObserver)
|
|||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
already_AddRefed<DOMIntersectionObserver> DOMIntersectionObserver::Constructor(
|
already_AddRefed<DOMIntersectionObserver> DOMIntersectionObserver::Constructor(
|
||||||
const mozilla::dom::GlobalObject& aGlobal,
|
const GlobalObject& aGlobal, dom::IntersectionCallback& aCb,
|
||||||
mozilla::dom::IntersectionCallback& aCb, mozilla::ErrorResult& aRv) {
|
ErrorResult& aRv) {
|
||||||
return Constructor(aGlobal, aCb, IntersectionObserverInit(), aRv);
|
return Constructor(aGlobal, aCb, IntersectionObserverInit(), aRv);
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<DOMIntersectionObserver> DOMIntersectionObserver::Constructor(
|
already_AddRefed<DOMIntersectionObserver> DOMIntersectionObserver::Constructor(
|
||||||
const mozilla::dom::GlobalObject& aGlobal,
|
const GlobalObject& aGlobal, dom::IntersectionCallback& aCb,
|
||||||
mozilla::dom::IntersectionCallback& aCb,
|
const IntersectionObserverInit& aOptions, ErrorResult& aRv) {
|
||||||
const mozilla::dom::IntersectionObserverInit& aOptions,
|
|
||||||
mozilla::ErrorResult& aRv) {
|
|
||||||
nsCOMPtr<nsPIDOMWindowInner> window =
|
nsCOMPtr<nsPIDOMWindowInner> window =
|
||||||
do_QueryInterface(aGlobal.GetAsSupports());
|
do_QueryInterface(aGlobal.GetAsSupports());
|
||||||
if (!window) {
|
if (!window) {
|
||||||
@ -81,15 +79,12 @@ already_AddRefed<DOMIntersectionObserver> DOMIntersectionObserver::Constructor(
|
|||||||
observer->mRoot = aOptions.mRoot;
|
observer->mRoot = aOptions.mRoot;
|
||||||
|
|
||||||
if (!observer->SetRootMargin(aOptions.mRootMargin)) {
|
if (!observer->SetRootMargin(aOptions.mRootMargin)) {
|
||||||
aRv.ThrowDOMException(
|
aRv.ThrowSyntaxError("rootMargin must be specified in pixels or percent.");
|
||||||
NS_ERROR_DOM_SYNTAX_ERR,
|
|
||||||
NS_LITERAL_CSTRING(
|
|
||||||
"rootMargin must be specified in pixels or percent."));
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aOptions.mThreshold.IsDoubleSequence()) {
|
if (aOptions.mThreshold.IsDoubleSequence()) {
|
||||||
const mozilla::dom::Sequence<double>& thresholds =
|
const Sequence<double>& thresholds =
|
||||||
aOptions.mThreshold.GetAsDoubleSequence();
|
aOptions.mThreshold.GetAsDoubleSequence();
|
||||||
observer->mThresholds.SetCapacity(thresholds.Length());
|
observer->mThresholds.SetCapacity(thresholds.Length());
|
||||||
for (const auto& thresh : thresholds) {
|
for (const auto& thresh : thresholds) {
|
||||||
@ -116,7 +111,7 @@ bool DOMIntersectionObserver::SetRootMargin(const nsAString& aString) {
|
|||||||
return Servo_IntersectionObserverRootMargin_Parse(&aString, &mRootMargin);
|
return Servo_IntersectionObserverRootMargin_Parse(&aString, &mRootMargin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DOMIntersectionObserver::GetRootMargin(mozilla::dom::DOMString& aRetVal) {
|
void DOMIntersectionObserver::GetRootMargin(DOMString& aRetVal) {
|
||||||
nsString& retVal = aRetVal;
|
nsString& retVal = aRetVal;
|
||||||
Servo_IntersectionObserverRootMargin_ToString(&mRootMargin, &retVal);
|
Servo_IntersectionObserverRootMargin_ToString(&mRootMargin, &retVal);
|
||||||
}
|
}
|
||||||
@ -451,8 +446,7 @@ void DOMIntersectionObserver::Notify() {
|
|||||||
if (!mQueuedEntries.Length()) {
|
if (!mQueuedEntries.Length()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mozilla::dom::Sequence<mozilla::OwningNonNull<DOMIntersectionObserverEntry>>
|
Sequence<OwningNonNull<DOMIntersectionObserverEntry>> entries;
|
||||||
entries;
|
|
||||||
if (entries.SetCapacity(mQueuedEntries.Length(), mozilla::fallible)) {
|
if (entries.SetCapacity(mQueuedEntries.Length(), mozilla::fallible)) {
|
||||||
for (size_t i = 0; i < mQueuedEntries.Length(); ++i) {
|
for (size_t i = 0; i < mQueuedEntries.Length(); ++i) {
|
||||||
RefPtr<DOMIntersectionObserverEntry> next = mQueuedEntries[i];
|
RefPtr<DOMIntersectionObserverEntry> next = mQueuedEntries[i];
|
||||||
|
@ -7,12 +7,9 @@
|
|||||||
|
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/dom/IntersectionObserverBinding.h"
|
#include "mozilla/dom/IntersectionObserverBinding.h"
|
||||||
#include "nsStyleCoord.h"
|
#include "mozilla/ServoStyleConsts.h"
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
|
|
||||||
using mozilla::dom::DOMRect;
|
|
||||||
using mozilla::dom::Element;
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
@ -42,13 +39,12 @@ class DOMIntersectionObserverEntry final : public nsISupports,
|
|||||||
|
|
||||||
nsISupports* GetParentObject() const { return mOwner; }
|
nsISupports* GetParentObject() const { return mOwner; }
|
||||||
|
|
||||||
virtual JSObject* WrapObject(JSContext* aCx,
|
JSObject* WrapObject(JSContext* aCx,
|
||||||
JS::Handle<JSObject*> aGivenProto) override {
|
JS::Handle<JSObject*> aGivenProto) override {
|
||||||
return mozilla::dom::IntersectionObserverEntry_Binding::Wrap(aCx, this,
|
return IntersectionObserverEntry_Binding::Wrap(aCx, this, aGivenProto);
|
||||||
aGivenProto);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DOMHighResTimeStamp Time() { return mTime; }
|
DOMHighResTimeStamp Time() const { return mTime; }
|
||||||
|
|
||||||
DOMRect* GetRootBounds() { return mRootBounds; }
|
DOMRect* GetRootBounds() { return mRootBounds; }
|
||||||
|
|
||||||
@ -56,9 +52,9 @@ class DOMIntersectionObserverEntry final : public nsISupports,
|
|||||||
|
|
||||||
DOMRect* IntersectionRect() { return mIntersectionRect; }
|
DOMRect* IntersectionRect() { return mIntersectionRect; }
|
||||||
|
|
||||||
bool IsIntersecting() { return mIsIntersecting; }
|
bool IsIntersecting() const { return mIsIntersecting; }
|
||||||
|
|
||||||
double IntersectionRatio() { return mIntersectionRatio; }
|
double IntersectionRatio() const { return mIntersectionRatio; }
|
||||||
|
|
||||||
Element* Target() { return mTarget; }
|
Element* Target() { return mTarget; }
|
||||||
|
|
||||||
@ -86,7 +82,7 @@ class DOMIntersectionObserver final : public nsISupports,
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
DOMIntersectionObserver(already_AddRefed<nsPIDOMWindowInner>&& aOwner,
|
DOMIntersectionObserver(already_AddRefed<nsPIDOMWindowInner>&& aOwner,
|
||||||
mozilla::dom::IntersectionCallback& aCb)
|
dom::IntersectionCallback& aCb)
|
||||||
: mOwner(aOwner),
|
: mOwner(aOwner),
|
||||||
mDocument(mOwner->GetExtantDoc()),
|
mDocument(mOwner->GetExtantDoc()),
|
||||||
mCallback(&aCb),
|
mCallback(&aCb),
|
||||||
@ -96,25 +92,21 @@ class DOMIntersectionObserver final : public nsISupports,
|
|||||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_INTERSECTION_OBSERVER_IID)
|
NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_INTERSECTION_OBSERVER_IID)
|
||||||
|
|
||||||
static already_AddRefed<DOMIntersectionObserver> Constructor(
|
static already_AddRefed<DOMIntersectionObserver> Constructor(
|
||||||
const mozilla::dom::GlobalObject& aGlobal,
|
const GlobalObject&, dom::IntersectionCallback&, ErrorResult&);
|
||||||
mozilla::dom::IntersectionCallback& aCb, mozilla::ErrorResult& aRv);
|
|
||||||
static already_AddRefed<DOMIntersectionObserver> Constructor(
|
static already_AddRefed<DOMIntersectionObserver> Constructor(
|
||||||
const mozilla::dom::GlobalObject& aGlobal,
|
const GlobalObject&, dom::IntersectionCallback&,
|
||||||
mozilla::dom::IntersectionCallback& aCb,
|
const IntersectionObserverInit&, ErrorResult&);
|
||||||
const mozilla::dom::IntersectionObserverInit& aOptions,
|
|
||||||
mozilla::ErrorResult& aRv);
|
|
||||||
|
|
||||||
virtual JSObject* WrapObject(JSContext* aCx,
|
JSObject* WrapObject(JSContext* aCx,
|
||||||
JS::Handle<JSObject*> aGivenProto) override {
|
JS::Handle<JSObject*> aGivenProto) override {
|
||||||
return mozilla::dom::IntersectionObserver_Binding::Wrap(aCx, this,
|
return IntersectionObserver_Binding::Wrap(aCx, this, aGivenProto);
|
||||||
aGivenProto);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsISupports* GetParentObject() const { return mOwner; }
|
nsISupports* GetParentObject() const { return mOwner; }
|
||||||
|
|
||||||
Element* GetRoot() const { return mRoot; }
|
Element* GetRoot() const { return mRoot; }
|
||||||
|
|
||||||
void GetRootMargin(mozilla::dom::DOMString& aRetVal);
|
void GetRootMargin(DOMString& aRetVal);
|
||||||
void GetThresholds(nsTArray<double>& aRetVal);
|
void GetThresholds(nsTArray<double>& aRetVal);
|
||||||
void Observe(Element& aTarget);
|
void Observe(Element& aTarget);
|
||||||
void Unobserve(Element& aTarget);
|
void Unobserve(Element& aTarget);
|
||||||
@ -124,9 +116,7 @@ class DOMIntersectionObserver final : public nsISupports,
|
|||||||
|
|
||||||
void TakeRecords(nsTArray<RefPtr<DOMIntersectionObserverEntry>>& aRetVal);
|
void TakeRecords(nsTArray<RefPtr<DOMIntersectionObserverEntry>>& aRetVal);
|
||||||
|
|
||||||
mozilla::dom::IntersectionCallback* IntersectionCallback() {
|
dom::IntersectionCallback* IntersectionCallback() { return mCallback; }
|
||||||
return mCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SetRootMargin(const nsAString& aString);
|
bool SetRootMargin(const nsAString& aString);
|
||||||
|
|
||||||
@ -144,7 +134,7 @@ class DOMIntersectionObserver final : public nsISupports,
|
|||||||
|
|
||||||
nsCOMPtr<nsPIDOMWindowInner> mOwner;
|
nsCOMPtr<nsPIDOMWindowInner> mOwner;
|
||||||
RefPtr<Document> mDocument;
|
RefPtr<Document> mDocument;
|
||||||
RefPtr<mozilla::dom::IntersectionCallback> mCallback;
|
RefPtr<dom::IntersectionCallback> mCallback;
|
||||||
RefPtr<Element> mRoot;
|
RefPtr<Element> mRoot;
|
||||||
StyleRect<LengthPercentage> mRootMargin;
|
StyleRect<LengthPercentage> mRootMargin;
|
||||||
nsTArray<double> mThresholds;
|
nsTArray<double> mThresholds;
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "js/Conversions.h" // JS::NumberToString
|
||||||
|
#include "js/Equality.h" // JS::SameValueZero
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
@ -36,29 +39,235 @@ JSObject* DOMMatrixReadOnly::WrapObject(JSContext* aCx,
|
|||||||
return DOMMatrixReadOnly_Binding::Wrap(aCx, this, aGivenProto);
|
return DOMMatrixReadOnly_Binding::Wrap(aCx, this, aGivenProto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://drafts.fxtf.org/geometry/#matrix-validate-and-fixup-2d
|
||||||
|
static bool ValidateAndFixupMatrix2DInit(DOMMatrix2DInit& aMatrixInit,
|
||||||
|
ErrorResult& aRv) {
|
||||||
|
#define ValidateAliases(field, alias, fieldName, aliasName) \
|
||||||
|
if ((field).WasPassed() && (alias).WasPassed() && \
|
||||||
|
!JS::SameValueZero((field).Value(), (alias).Value())) { \
|
||||||
|
aRv.ThrowTypeError<MSG_MATRIX_INIT_CONFLICTING_VALUE>((fieldName), \
|
||||||
|
(aliasName)); \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
#define SetFromAliasOrDefault(field, alias, defaultValue) \
|
||||||
|
if (!(field).WasPassed()) { \
|
||||||
|
if ((alias).WasPassed()) { \
|
||||||
|
(field).Construct((alias).Value()); \
|
||||||
|
} else { \
|
||||||
|
(field).Construct(defaultValue); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
#define ValidateAndSet(field, alias, fieldName, aliasName, defaultValue) \
|
||||||
|
ValidateAliases((field), (alias), NS_LITERAL_STRING(fieldName), \
|
||||||
|
NS_LITERAL_STRING(aliasName)); \
|
||||||
|
SetFromAliasOrDefault((field), (alias), (defaultValue));
|
||||||
|
|
||||||
|
ValidateAndSet(aMatrixInit.mM11, aMatrixInit.mA, "m11", "a", 1);
|
||||||
|
ValidateAndSet(aMatrixInit.mM12, aMatrixInit.mB, "m12", "b", 0);
|
||||||
|
ValidateAndSet(aMatrixInit.mM21, aMatrixInit.mC, "m21", "c", 0);
|
||||||
|
ValidateAndSet(aMatrixInit.mM22, aMatrixInit.mD, "m22", "d", 1);
|
||||||
|
ValidateAndSet(aMatrixInit.mM41, aMatrixInit.mE, "m41", "e", 0);
|
||||||
|
ValidateAndSet(aMatrixInit.mM42, aMatrixInit.mF, "m42", "f", 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#undef ValidateAliases
|
||||||
|
#undef SetFromAliasOrDefault
|
||||||
|
#undef ValidateAndSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://drafts.fxtf.org/geometry/#matrix-validate-and-fixup
|
||||||
|
static bool ValidateAndFixupMatrixInit(DOMMatrixInit& aMatrixInit,
|
||||||
|
ErrorResult& aRv) {
|
||||||
|
#define Check3DField(field, fieldName, defaultValue) \
|
||||||
|
if ((field) != (defaultValue)) { \
|
||||||
|
if (!aMatrixInit.mIs2D.WasPassed()) { \
|
||||||
|
aMatrixInit.mIs2D.Construct(false); \
|
||||||
|
return true; \
|
||||||
|
} \
|
||||||
|
if (aMatrixInit.mIs2D.Value()) { \
|
||||||
|
aRv.ThrowTypeError<MSG_MATRIX_INIT_EXCEEDS_2D>( \
|
||||||
|
NS_LITERAL_STRING(fieldName)); \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ValidateAndFixupMatrix2DInit(aMatrixInit, aRv)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Check3DField(aMatrixInit.mM13, "m13", 0);
|
||||||
|
Check3DField(aMatrixInit.mM14, "m14", 0);
|
||||||
|
Check3DField(aMatrixInit.mM23, "m23", 0);
|
||||||
|
Check3DField(aMatrixInit.mM24, "m24", 0);
|
||||||
|
Check3DField(aMatrixInit.mM31, "m31", 0);
|
||||||
|
Check3DField(aMatrixInit.mM32, "m32", 0);
|
||||||
|
Check3DField(aMatrixInit.mM34, "m34", 0);
|
||||||
|
Check3DField(aMatrixInit.mM43, "m43", 0);
|
||||||
|
Check3DField(aMatrixInit.mM33, "m33", 1);
|
||||||
|
Check3DField(aMatrixInit.mM44, "m44", 1);
|
||||||
|
|
||||||
|
if (!aMatrixInit.mIs2D.WasPassed()) {
|
||||||
|
aMatrixInit.mIs2D.Construct(true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#undef Check3DField
|
||||||
|
}
|
||||||
|
|
||||||
|
void DOMMatrixReadOnly::SetDataFromMatrix2DInit(
|
||||||
|
const DOMMatrix2DInit& aMatrixInit) {
|
||||||
|
MOZ_ASSERT(Is2D());
|
||||||
|
mMatrix2D->_11 = aMatrixInit.mM11.Value();
|
||||||
|
mMatrix2D->_12 = aMatrixInit.mM12.Value();
|
||||||
|
mMatrix2D->_21 = aMatrixInit.mM21.Value();
|
||||||
|
mMatrix2D->_22 = aMatrixInit.mM22.Value();
|
||||||
|
mMatrix2D->_31 = aMatrixInit.mM41.Value();
|
||||||
|
mMatrix2D->_32 = aMatrixInit.mM42.Value();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DOMMatrixReadOnly::SetDataFromMatrixInit(
|
||||||
|
const DOMMatrixInit& aMatrixInit) {
|
||||||
|
const bool is2D = aMatrixInit.mIs2D.Value();
|
||||||
|
MOZ_ASSERT(is2D == Is2D());
|
||||||
|
if (is2D) {
|
||||||
|
SetDataFromMatrix2DInit(aMatrixInit);
|
||||||
|
} else {
|
||||||
|
mMatrix3D->_11 = aMatrixInit.mM11.Value();
|
||||||
|
mMatrix3D->_12 = aMatrixInit.mM12.Value();
|
||||||
|
mMatrix3D->_13 = aMatrixInit.mM13;
|
||||||
|
mMatrix3D->_14 = aMatrixInit.mM14;
|
||||||
|
mMatrix3D->_21 = aMatrixInit.mM21.Value();
|
||||||
|
mMatrix3D->_22 = aMatrixInit.mM22.Value();
|
||||||
|
mMatrix3D->_23 = aMatrixInit.mM23;
|
||||||
|
mMatrix3D->_24 = aMatrixInit.mM24;
|
||||||
|
mMatrix3D->_31 = aMatrixInit.mM31;
|
||||||
|
mMatrix3D->_32 = aMatrixInit.mM32;
|
||||||
|
mMatrix3D->_33 = aMatrixInit.mM33;
|
||||||
|
mMatrix3D->_34 = aMatrixInit.mM34;
|
||||||
|
mMatrix3D->_41 = aMatrixInit.mM41.Value();
|
||||||
|
mMatrix3D->_42 = aMatrixInit.mM42.Value();
|
||||||
|
mMatrix3D->_43 = aMatrixInit.mM43;
|
||||||
|
mMatrix3D->_44 = aMatrixInit.mM44;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<DOMMatrixReadOnly> DOMMatrixReadOnly::FromMatrix(
|
||||||
|
nsISupports* aParent, const DOMMatrix2DInit& aMatrixInit,
|
||||||
|
ErrorResult& aRv) {
|
||||||
|
DOMMatrix2DInit matrixInit(aMatrixInit);
|
||||||
|
if (!ValidateAndFixupMatrix2DInit(matrixInit, aRv)) {
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
RefPtr<DOMMatrixReadOnly> matrix =
|
||||||
|
new DOMMatrixReadOnly(aParent, /* is2D */ true);
|
||||||
|
matrix->SetDataFromMatrix2DInit(matrixInit);
|
||||||
|
return matrix.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<DOMMatrixReadOnly> DOMMatrixReadOnly::FromMatrix(
|
||||||
|
nsISupports* aParent, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv) {
|
||||||
|
DOMMatrixInit matrixInit(aMatrixInit);
|
||||||
|
if (!ValidateAndFixupMatrixInit(matrixInit, aRv)) {
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
RefPtr<DOMMatrixReadOnly> rval =
|
||||||
|
new DOMMatrixReadOnly(aParent, matrixInit.mIs2D.Value());
|
||||||
|
rval->SetDataFromMatrixInit(matrixInit);
|
||||||
|
return rval.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<DOMMatrixReadOnly> DOMMatrixReadOnly::FromMatrix(
|
||||||
|
const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit,
|
||||||
|
ErrorResult& aRv) {
|
||||||
|
RefPtr<DOMMatrixReadOnly> matrix =
|
||||||
|
FromMatrix(aGlobal.GetAsSupports(), aMatrixInit, aRv);
|
||||||
|
return matrix.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<DOMMatrixReadOnly> DOMMatrixReadOnly::FromFloat32Array(
|
||||||
|
const GlobalObject& aGlobal, const Float32Array& aArray32,
|
||||||
|
ErrorResult& aRv) {
|
||||||
|
aArray32.ComputeLengthAndData();
|
||||||
|
|
||||||
|
const int length = aArray32.Length();
|
||||||
|
const bool is2D = length == 6;
|
||||||
|
RefPtr<DOMMatrixReadOnly> obj =
|
||||||
|
new DOMMatrixReadOnly(aGlobal.GetAsSupports(), is2D);
|
||||||
|
SetDataInMatrix(obj, aArray32.Data(), length, aRv);
|
||||||
|
|
||||||
|
return obj.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<DOMMatrixReadOnly> DOMMatrixReadOnly::FromFloat64Array(
|
||||||
|
const GlobalObject& aGlobal, const Float64Array& aArray64,
|
||||||
|
ErrorResult& aRv) {
|
||||||
|
aArray64.ComputeLengthAndData();
|
||||||
|
|
||||||
|
const int length = aArray64.Length();
|
||||||
|
const bool is2D = length == 6;
|
||||||
|
RefPtr<DOMMatrixReadOnly> obj =
|
||||||
|
new DOMMatrixReadOnly(aGlobal.GetAsSupports(), is2D);
|
||||||
|
SetDataInMatrix(obj, aArray64.Data(), length, aRv);
|
||||||
|
|
||||||
|
return obj.forget();
|
||||||
|
}
|
||||||
|
|
||||||
already_AddRefed<DOMMatrixReadOnly> DOMMatrixReadOnly::Constructor(
|
already_AddRefed<DOMMatrixReadOnly> DOMMatrixReadOnly::Constructor(
|
||||||
const GlobalObject& aGlobal,
|
const GlobalObject& aGlobal,
|
||||||
const Optional<StringOrUnrestrictedDoubleSequence>& aArg,
|
const Optional<UTF8StringOrUnrestrictedDoubleSequenceOrDOMMatrixReadOnly>&
|
||||||
|
aArg,
|
||||||
ErrorResult& aRv) {
|
ErrorResult& aRv) {
|
||||||
RefPtr<DOMMatrixReadOnly> rval =
|
|
||||||
new DOMMatrixReadOnly(aGlobal.GetAsSupports());
|
|
||||||
if (!aArg.WasPassed()) {
|
if (!aArg.WasPassed()) {
|
||||||
|
RefPtr<DOMMatrixReadOnly> rval =
|
||||||
|
new DOMMatrixReadOnly(aGlobal.GetAsSupports());
|
||||||
return rval.forget();
|
return rval.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& arg = aArg.Value();
|
const auto& arg = aArg.Value();
|
||||||
if (arg.IsString()) {
|
if (arg.IsUTF8String()) {
|
||||||
nsCOMPtr<nsPIDOMWindowInner> win =
|
nsCOMPtr<nsPIDOMWindowInner> win =
|
||||||
do_QueryInterface(aGlobal.GetAsSupports());
|
do_QueryInterface(aGlobal.GetAsSupports());
|
||||||
if (!win) {
|
if (!win) {
|
||||||
aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
|
aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
rval->SetMatrixValue(arg.GetAsString(), aRv);
|
RefPtr<DOMMatrixReadOnly> rval =
|
||||||
} else {
|
new DOMMatrixReadOnly(aGlobal.GetAsSupports());
|
||||||
const auto& sequence = arg.GetAsUnrestrictedDoubleSequence();
|
rval->SetMatrixValue(arg.GetAsUTF8String(), aRv);
|
||||||
SetDataInMatrix(rval, sequence.Elements(), sequence.Length(), aRv);
|
return rval.forget();
|
||||||
}
|
}
|
||||||
|
if (arg.IsDOMMatrixReadOnly()) {
|
||||||
|
RefPtr<DOMMatrixReadOnly> obj = new DOMMatrixReadOnly(
|
||||||
|
aGlobal.GetAsSupports(), arg.GetAsDOMMatrixReadOnly());
|
||||||
|
return obj.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& sequence = arg.GetAsUnrestrictedDoubleSequence();
|
||||||
|
const int length = sequence.Length();
|
||||||
|
const bool is2D = length == 6;
|
||||||
|
RefPtr<DOMMatrixReadOnly> rval =
|
||||||
|
new DOMMatrixReadOnly(aGlobal.GetAsSupports(), is2D);
|
||||||
|
SetDataInMatrix(rval, sequence.Elements(), length, aRv);
|
||||||
|
return rval.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<DOMMatrixReadOnly> DOMMatrixReadOnly::ReadStructuredClone(
|
||||||
|
JSContext* aCx, nsIGlobalObject* aGlobal,
|
||||||
|
JSStructuredCloneReader* aReader) {
|
||||||
|
uint8_t is2D;
|
||||||
|
|
||||||
|
if (!JS_ReadBytes(aReader, &is2D, 1)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<DOMMatrixReadOnly> rval = new DOMMatrixReadOnly(aGlobal, is2D);
|
||||||
|
|
||||||
|
if (!ReadStructuredCloneElements(aReader, rval)) {
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
return rval.forget();
|
return rval.forget();
|
||||||
}
|
}
|
||||||
@ -71,11 +280,11 @@ already_AddRefed<DOMMatrix> DOMMatrixReadOnly::Translate(double aTx, double aTy,
|
|||||||
return retval.forget();
|
return retval.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<DOMMatrix> DOMMatrixReadOnly::Scale(double aScale,
|
already_AddRefed<DOMMatrix> DOMMatrixReadOnly::Scale(
|
||||||
double aOriginX,
|
double aScaleX, const Optional<double>& aScaleY, double aScaleZ,
|
||||||
double aOriginY) const {
|
double aOriginX, double aOriginY, double aOriginZ) const {
|
||||||
RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||||
retval->ScaleSelf(aScale, aOriginX, aOriginY);
|
retval->ScaleSelf(aScaleX, aScaleY, aScaleZ, aOriginX, aOriginY, aOriginZ);
|
||||||
|
|
||||||
return retval.forget();
|
return retval.forget();
|
||||||
}
|
}
|
||||||
@ -91,20 +300,18 @@ already_AddRefed<DOMMatrix> DOMMatrixReadOnly::Scale3d(double aScale,
|
|||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<DOMMatrix> DOMMatrixReadOnly::ScaleNonUniform(
|
already_AddRefed<DOMMatrix> DOMMatrixReadOnly::ScaleNonUniform(
|
||||||
double aScaleX, double aScaleY, double aScaleZ, double aOriginX,
|
double aScaleX, double aScaleY) const {
|
||||||
double aOriginY, double aOriginZ) const {
|
|
||||||
RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||||
retval->ScaleNonUniformSelf(aScaleX, aScaleY, aScaleZ, aOriginX, aOriginY,
|
retval->ScaleSelf(aScaleX, Optional<double>(aScaleY), 1, 0, 0, 0);
|
||||||
aOriginZ);
|
|
||||||
|
|
||||||
return retval.forget();
|
return retval.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<DOMMatrix> DOMMatrixReadOnly::Rotate(double aAngle,
|
already_AddRefed<DOMMatrix> DOMMatrixReadOnly::Rotate(
|
||||||
double aOriginX,
|
double aRotX, const Optional<double>& aRotY,
|
||||||
double aOriginY) const {
|
const Optional<double>& aRotZ) const {
|
||||||
RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||||
retval->RotateSelf(aAngle, aOriginX, aOriginY);
|
retval->RotateSelf(aRotX, aRotY, aRotZ);
|
||||||
|
|
||||||
return retval.forget();
|
return retval.forget();
|
||||||
}
|
}
|
||||||
@ -140,9 +347,9 @@ already_AddRefed<DOMMatrix> DOMMatrixReadOnly::SkewY(double aSy) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<DOMMatrix> DOMMatrixReadOnly::Multiply(
|
already_AddRefed<DOMMatrix> DOMMatrixReadOnly::Multiply(
|
||||||
const DOMMatrix& other) const {
|
const DOMMatrixInit& other, ErrorResult& aRv) const {
|
||||||
RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||||
retval->MultiplySelf(other);
|
retval->MultiplySelf(other, aRv);
|
||||||
|
|
||||||
return retval.forget();
|
return retval.forget();
|
||||||
}
|
}
|
||||||
@ -150,13 +357,13 @@ already_AddRefed<DOMMatrix> DOMMatrixReadOnly::Multiply(
|
|||||||
already_AddRefed<DOMMatrix> DOMMatrixReadOnly::FlipX() const {
|
already_AddRefed<DOMMatrix> DOMMatrixReadOnly::FlipX() const {
|
||||||
RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||||
if (mMatrix3D) {
|
if (mMatrix3D) {
|
||||||
gfx::Matrix4x4 m;
|
gfx::Matrix4x4Double m;
|
||||||
m._11 = -1;
|
m._11 = -1;
|
||||||
retval->mMatrix3D = new gfx::Matrix4x4(m * *mMatrix3D);
|
retval->mMatrix3D = new gfx::Matrix4x4Double(m * *mMatrix3D);
|
||||||
} else {
|
} else {
|
||||||
gfx::Matrix m;
|
gfx::MatrixDouble m;
|
||||||
m._11 = -1;
|
m._11 = -1;
|
||||||
retval->mMatrix2D = new gfx::Matrix(mMatrix2D ? m * *mMatrix2D : m);
|
retval->mMatrix2D = new gfx::MatrixDouble(mMatrix2D ? m * *mMatrix2D : m);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval.forget();
|
return retval.forget();
|
||||||
@ -165,13 +372,13 @@ already_AddRefed<DOMMatrix> DOMMatrixReadOnly::FlipX() const {
|
|||||||
already_AddRefed<DOMMatrix> DOMMatrixReadOnly::FlipY() const {
|
already_AddRefed<DOMMatrix> DOMMatrixReadOnly::FlipY() const {
|
||||||
RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||||
if (mMatrix3D) {
|
if (mMatrix3D) {
|
||||||
gfx::Matrix4x4 m;
|
gfx::Matrix4x4Double m;
|
||||||
m._22 = -1;
|
m._22 = -1;
|
||||||
retval->mMatrix3D = new gfx::Matrix4x4(m * *mMatrix3D);
|
retval->mMatrix3D = new gfx::Matrix4x4Double(m * *mMatrix3D);
|
||||||
} else {
|
} else {
|
||||||
gfx::Matrix m;
|
gfx::MatrixDouble m;
|
||||||
m._22 = -1;
|
m._22 = -1;
|
||||||
retval->mMatrix2D = new gfx::Matrix(mMatrix2D ? m * *mMatrix2D : m);
|
retval->mMatrix2D = new gfx::MatrixDouble(mMatrix2D ? m * *mMatrix2D : m);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval.forget();
|
return retval.forget();
|
||||||
@ -212,9 +419,9 @@ already_AddRefed<DOMPoint> DOMMatrixReadOnly::TransformPoint(
|
|||||||
retval->SetZ(transformedPoint.z);
|
retval->SetZ(transformedPoint.z);
|
||||||
retval->SetW(transformedPoint.w);
|
retval->SetW(transformedPoint.w);
|
||||||
} else if (point.mZ != 0 || point.mW != 1.0) {
|
} else if (point.mZ != 0 || point.mW != 1.0) {
|
||||||
gfx::Matrix4x4 tempMatrix(gfx::Matrix4x4::From2D(*mMatrix2D));
|
gfx::Matrix4x4Double tempMatrix(gfx::Matrix4x4Double::From2D(*mMatrix2D));
|
||||||
|
|
||||||
gfx::Point4D transformedPoint;
|
gfx::PointDouble4D transformedPoint;
|
||||||
transformedPoint.x = point.mX;
|
transformedPoint.x = point.mX;
|
||||||
transformedPoint.y = point.mY;
|
transformedPoint.y = point.mY;
|
||||||
transformedPoint.z = point.mZ;
|
transformedPoint.z = point.mZ;
|
||||||
@ -227,7 +434,7 @@ already_AddRefed<DOMPoint> DOMMatrixReadOnly::TransformPoint(
|
|||||||
retval->SetZ(transformedPoint.z);
|
retval->SetZ(transformedPoint.z);
|
||||||
retval->SetW(transformedPoint.w);
|
retval->SetW(transformedPoint.w);
|
||||||
} else {
|
} else {
|
||||||
gfx::Point transformedPoint;
|
gfx::PointDouble transformedPoint;
|
||||||
transformedPoint.x = point.mX;
|
transformedPoint.x = point.mX;
|
||||||
transformedPoint.y = point.mY;
|
transformedPoint.y = point.mY;
|
||||||
|
|
||||||
@ -289,90 +496,205 @@ void DOMMatrixReadOnly::ToFloat64Array(JSContext* aCx,
|
|||||||
aResult.set(&value.toObject());
|
aResult.set(&value.toObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenient way to append things as floats, not doubles. We use this because
|
void DOMMatrixReadOnly::Stringify(nsAString& aResult, ErrorResult& aRv) {
|
||||||
// we only want to output about 6 digits of precision for our matrix()
|
char cbuf[JS::MaximumNumberToStringLength];
|
||||||
// functions, to preserve the behavior we used to have when we used
|
|
||||||
// AppendPrintf.
|
|
||||||
static void AppendFloat(nsAString& aStr, float f) { aStr.AppendFloat(f); }
|
|
||||||
|
|
||||||
void DOMMatrixReadOnly::Stringify(nsAString& aResult) {
|
|
||||||
nsAutoString matrixStr;
|
nsAutoString matrixStr;
|
||||||
|
auto AppendDouble = [&aRv, &cbuf, &matrixStr](double d,
|
||||||
|
bool isLastItem = false) {
|
||||||
|
if (!mozilla::IsFinite(d)) {
|
||||||
|
aRv.ThrowDOMException(
|
||||||
|
NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||||
|
"Matrix with a non-finite element cannot be stringified.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
JS::NumberToString(d, cbuf);
|
||||||
|
matrixStr.AppendASCII(cbuf);
|
||||||
|
if (!isLastItem) {
|
||||||
|
matrixStr.AppendLiteral(", ");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
if (mMatrix3D) {
|
if (mMatrix3D) {
|
||||||
// We can't use AppendPrintf here, because it does locale-specific
|
// We can't use AppendPrintf here, because it does locale-specific
|
||||||
// formatting of floating-point values.
|
// formatting of floating-point values.
|
||||||
matrixStr.AssignLiteral("matrix3d(");
|
matrixStr.AssignLiteral("matrix3d(");
|
||||||
AppendFloat(matrixStr, M11());
|
if (!AppendDouble(M11()) || !AppendDouble(M12()) || !AppendDouble(M13()) ||
|
||||||
matrixStr.AppendLiteral(", ");
|
!AppendDouble(M14()) || !AppendDouble(M21()) || !AppendDouble(M22()) ||
|
||||||
AppendFloat(matrixStr, M12());
|
!AppendDouble(M23()) || !AppendDouble(M24()) || !AppendDouble(M31()) ||
|
||||||
matrixStr.AppendLiteral(", ");
|
!AppendDouble(M32()) || !AppendDouble(M33()) || !AppendDouble(M34()) ||
|
||||||
AppendFloat(matrixStr, M13());
|
!AppendDouble(M41()) || !AppendDouble(M42()) || !AppendDouble(M43()) ||
|
||||||
matrixStr.AppendLiteral(", ");
|
!AppendDouble(M44(), true)) {
|
||||||
AppendFloat(matrixStr, M14());
|
return;
|
||||||
matrixStr.AppendLiteral(", ");
|
}
|
||||||
AppendFloat(matrixStr, M21());
|
|
||||||
matrixStr.AppendLiteral(", ");
|
|
||||||
AppendFloat(matrixStr, M22());
|
|
||||||
matrixStr.AppendLiteral(", ");
|
|
||||||
AppendFloat(matrixStr, M23());
|
|
||||||
matrixStr.AppendLiteral(", ");
|
|
||||||
AppendFloat(matrixStr, M24());
|
|
||||||
matrixStr.AppendLiteral(", ");
|
|
||||||
AppendFloat(matrixStr, M31());
|
|
||||||
matrixStr.AppendLiteral(", ");
|
|
||||||
AppendFloat(matrixStr, M32());
|
|
||||||
matrixStr.AppendLiteral(", ");
|
|
||||||
AppendFloat(matrixStr, M33());
|
|
||||||
matrixStr.AppendLiteral(", ");
|
|
||||||
AppendFloat(matrixStr, M34());
|
|
||||||
matrixStr.AppendLiteral(", ");
|
|
||||||
AppendFloat(matrixStr, M41());
|
|
||||||
matrixStr.AppendLiteral(", ");
|
|
||||||
AppendFloat(matrixStr, M42());
|
|
||||||
matrixStr.AppendLiteral(", ");
|
|
||||||
AppendFloat(matrixStr, M43());
|
|
||||||
matrixStr.AppendLiteral(", ");
|
|
||||||
AppendFloat(matrixStr, M44());
|
|
||||||
matrixStr.AppendLiteral(")");
|
matrixStr.AppendLiteral(")");
|
||||||
} else {
|
} else {
|
||||||
// We can't use AppendPrintf here, because it does locale-specific
|
// We can't use AppendPrintf here, because it does locale-specific
|
||||||
// formatting of floating-point values.
|
// formatting of floating-point values.
|
||||||
matrixStr.AssignLiteral("matrix(");
|
matrixStr.AssignLiteral("matrix(");
|
||||||
AppendFloat(matrixStr, A());
|
if (!AppendDouble(A()) || !AppendDouble(B()) || !AppendDouble(C()) ||
|
||||||
matrixStr.AppendLiteral(", ");
|
!AppendDouble(D()) || !AppendDouble(E()) || !AppendDouble(F(), true)) {
|
||||||
AppendFloat(matrixStr, B());
|
return;
|
||||||
matrixStr.AppendLiteral(", ");
|
}
|
||||||
AppendFloat(matrixStr, C());
|
|
||||||
matrixStr.AppendLiteral(", ");
|
|
||||||
AppendFloat(matrixStr, D());
|
|
||||||
matrixStr.AppendLiteral(", ");
|
|
||||||
AppendFloat(matrixStr, E());
|
|
||||||
matrixStr.AppendLiteral(", ");
|
|
||||||
AppendFloat(matrixStr, F());
|
|
||||||
matrixStr.AppendLiteral(")");
|
matrixStr.AppendLiteral(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
aResult = matrixStr;
|
aResult = matrixStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<DOMMatrix> DOMMatrix::Constructor(const GlobalObject& aGlobal,
|
// https://drafts.fxtf.org/geometry/#structured-serialization
|
||||||
ErrorResult& aRv) {
|
bool DOMMatrixReadOnly::WriteStructuredClone(
|
||||||
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports());
|
JSContext* aCx, JSStructuredCloneWriter* aWriter) const {
|
||||||
|
#define WriteDouble(d) \
|
||||||
|
JS_WriteUint32Pair(aWriter, (BitwiseCast<uint64_t>(d) >> 32) & 0xffffffff, \
|
||||||
|
BitwiseCast<uint64_t>(d) & 0xffffffff)
|
||||||
|
|
||||||
|
const uint8_t is2D = Is2D();
|
||||||
|
|
||||||
|
if (!JS_WriteBytes(aWriter, &is2D, 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is2D == 1) {
|
||||||
|
return WriteDouble(mMatrix2D->_11) && WriteDouble(mMatrix2D->_12) &&
|
||||||
|
WriteDouble(mMatrix2D->_21) && WriteDouble(mMatrix2D->_22) &&
|
||||||
|
WriteDouble(mMatrix2D->_31) && WriteDouble(mMatrix2D->_32);
|
||||||
|
}
|
||||||
|
|
||||||
|
return WriteDouble(mMatrix3D->_11) && WriteDouble(mMatrix3D->_12) &&
|
||||||
|
WriteDouble(mMatrix3D->_13) && WriteDouble(mMatrix3D->_14) &&
|
||||||
|
WriteDouble(mMatrix3D->_21) && WriteDouble(mMatrix3D->_22) &&
|
||||||
|
WriteDouble(mMatrix3D->_23) && WriteDouble(mMatrix3D->_24) &&
|
||||||
|
WriteDouble(mMatrix3D->_31) && WriteDouble(mMatrix3D->_32) &&
|
||||||
|
WriteDouble(mMatrix3D->_33) && WriteDouble(mMatrix3D->_34) &&
|
||||||
|
WriteDouble(mMatrix3D->_41) && WriteDouble(mMatrix3D->_42) &&
|
||||||
|
WriteDouble(mMatrix3D->_43) && WriteDouble(mMatrix3D->_44);
|
||||||
|
|
||||||
|
#undef WriteDouble
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DOMMatrixReadOnly::ReadStructuredCloneElements(
|
||||||
|
JSStructuredCloneReader* aReader, DOMMatrixReadOnly* matrix) {
|
||||||
|
uint32_t high;
|
||||||
|
uint32_t low;
|
||||||
|
|
||||||
|
#define ReadDouble(d) \
|
||||||
|
if (!JS_ReadUint32Pair(aReader, &high, &low)) { \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
(*(d) = BitwiseCast<double>(static_cast<uint64_t>(high) << 32 | low))
|
||||||
|
|
||||||
|
if (matrix->Is2D() == 1) {
|
||||||
|
ReadDouble(&(matrix->mMatrix2D->_11));
|
||||||
|
ReadDouble(&(matrix->mMatrix2D->_12));
|
||||||
|
ReadDouble(&(matrix->mMatrix2D->_21));
|
||||||
|
ReadDouble(&(matrix->mMatrix2D->_22));
|
||||||
|
ReadDouble(&(matrix->mMatrix2D->_31));
|
||||||
|
ReadDouble(&(matrix->mMatrix2D->_32));
|
||||||
|
} else {
|
||||||
|
ReadDouble(&(matrix->mMatrix3D->_11));
|
||||||
|
ReadDouble(&(matrix->mMatrix3D->_12));
|
||||||
|
ReadDouble(&(matrix->mMatrix3D->_13));
|
||||||
|
ReadDouble(&(matrix->mMatrix3D->_14));
|
||||||
|
ReadDouble(&(matrix->mMatrix3D->_21));
|
||||||
|
ReadDouble(&(matrix->mMatrix3D->_22));
|
||||||
|
ReadDouble(&(matrix->mMatrix3D->_23));
|
||||||
|
ReadDouble(&(matrix->mMatrix3D->_24));
|
||||||
|
ReadDouble(&(matrix->mMatrix3D->_31));
|
||||||
|
ReadDouble(&(matrix->mMatrix3D->_32));
|
||||||
|
ReadDouble(&(matrix->mMatrix3D->_33));
|
||||||
|
ReadDouble(&(matrix->mMatrix3D->_34));
|
||||||
|
ReadDouble(&(matrix->mMatrix3D->_41));
|
||||||
|
ReadDouble(&(matrix->mMatrix3D->_42));
|
||||||
|
ReadDouble(&(matrix->mMatrix3D->_43));
|
||||||
|
ReadDouble(&(matrix->mMatrix3D->_44));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#undef ReadDouble
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<DOMMatrix> DOMMatrix::FromMatrix(
|
||||||
|
nsISupports* aParent, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv) {
|
||||||
|
DOMMatrixInit matrixInit(aMatrixInit);
|
||||||
|
if (!ValidateAndFixupMatrixInit(matrixInit, aRv)) {
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
RefPtr<DOMMatrix> matrix = new DOMMatrix(aParent, matrixInit.mIs2D.Value());
|
||||||
|
matrix->SetDataFromMatrixInit(matrixInit);
|
||||||
|
return matrix.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<DOMMatrix> DOMMatrix::FromMatrix(
|
||||||
|
const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit,
|
||||||
|
ErrorResult& aRv) {
|
||||||
|
RefPtr<DOMMatrix> matrix =
|
||||||
|
FromMatrix(aGlobal.GetAsSupports(), aMatrixInit, aRv);
|
||||||
|
return matrix.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<DOMMatrix> DOMMatrix::FromFloat32Array(
|
||||||
|
const GlobalObject& aGlobal, const Float32Array& aArray32,
|
||||||
|
ErrorResult& aRv) {
|
||||||
|
aArray32.ComputeLengthAndData();
|
||||||
|
|
||||||
|
const int length = aArray32.Length();
|
||||||
|
const bool is2D = length == 6;
|
||||||
|
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports(), is2D);
|
||||||
|
SetDataInMatrix(obj, aArray32.Data(), length, aRv);
|
||||||
|
|
||||||
|
return obj.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<DOMMatrix> DOMMatrix::FromFloat64Array(
|
||||||
|
const GlobalObject& aGlobal, const Float64Array& aArray64,
|
||||||
|
ErrorResult& aRv) {
|
||||||
|
aArray64.ComputeLengthAndData();
|
||||||
|
|
||||||
|
const int length = aArray64.Length();
|
||||||
|
const bool is2D = length == 6;
|
||||||
|
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports(), is2D);
|
||||||
|
SetDataInMatrix(obj, aArray64.Data(), length, aRv);
|
||||||
|
|
||||||
return obj.forget();
|
return obj.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<DOMMatrix> DOMMatrix::Constructor(
|
already_AddRefed<DOMMatrix> DOMMatrix::Constructor(
|
||||||
const GlobalObject& aGlobal, const nsAString& aTransformList,
|
const GlobalObject& aGlobal,
|
||||||
|
const Optional<UTF8StringOrUnrestrictedDoubleSequenceOrDOMMatrixReadOnly>&
|
||||||
|
aArg,
|
||||||
ErrorResult& aRv) {
|
ErrorResult& aRv) {
|
||||||
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports());
|
if (!aArg.WasPassed()) {
|
||||||
obj = obj->SetMatrixValue(aTransformList, aRv);
|
RefPtr<DOMMatrix> rval = new DOMMatrix(aGlobal.GetAsSupports());
|
||||||
return obj.forget();
|
return rval.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<DOMMatrix> DOMMatrix::Constructor(
|
const auto& arg = aArg.Value();
|
||||||
const GlobalObject& aGlobal, const DOMMatrixReadOnly& aOther,
|
if (arg.IsUTF8String()) {
|
||||||
ErrorResult& aRv) {
|
nsCOMPtr<nsPIDOMWindowInner> win =
|
||||||
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports(), aOther);
|
do_QueryInterface(aGlobal.GetAsSupports());
|
||||||
return obj.forget();
|
if (!win) {
|
||||||
|
aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
RefPtr<DOMMatrix> rval = new DOMMatrix(aGlobal.GetAsSupports());
|
||||||
|
rval->SetMatrixValue(arg.GetAsUTF8String(), aRv);
|
||||||
|
return rval.forget();
|
||||||
|
}
|
||||||
|
if (arg.IsDOMMatrixReadOnly()) {
|
||||||
|
RefPtr<DOMMatrix> obj =
|
||||||
|
new DOMMatrix(aGlobal.GetAsSupports(), arg.GetAsDOMMatrixReadOnly());
|
||||||
|
return obj.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& sequence = arg.GetAsUnrestrictedDoubleSequence();
|
||||||
|
const int length = sequence.Length();
|
||||||
|
const bool is2D = length == 6;
|
||||||
|
RefPtr<DOMMatrix> rval = new DOMMatrix(aGlobal.GetAsSupports(), is2D);
|
||||||
|
SetDataInMatrix(rval, sequence.Elements(), length, aRv);
|
||||||
|
return rval.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -409,76 +731,77 @@ static void SetDataInMatrix(DOMMatrixReadOnly* aMatrix, const T* aData,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<DOMMatrix> DOMMatrix::Constructor(const GlobalObject& aGlobal,
|
already_AddRefed<DOMMatrix> DOMMatrix::ReadStructuredClone(
|
||||||
const Float32Array& aArray32,
|
JSContext* aCx, nsIGlobalObject* aGlobal,
|
||||||
ErrorResult& aRv) {
|
JSStructuredCloneReader* aReader) {
|
||||||
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports());
|
uint8_t is2D;
|
||||||
aArray32.ComputeLengthAndData();
|
|
||||||
SetDataInMatrix(obj, aArray32.Data(), aArray32.Length(), aRv);
|
|
||||||
|
|
||||||
return obj.forget();
|
if (!JS_ReadBytes(aReader, &is2D, 1)) {
|
||||||
}
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
already_AddRefed<DOMMatrix> DOMMatrix::Constructor(const GlobalObject& aGlobal,
|
RefPtr<DOMMatrix> rval = new DOMMatrix(aGlobal, is2D);
|
||||||
const Float64Array& aArray64,
|
|
||||||
ErrorResult& aRv) {
|
|
||||||
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports());
|
|
||||||
aArray64.ComputeLengthAndData();
|
|
||||||
SetDataInMatrix(obj, aArray64.Data(), aArray64.Length(), aRv);
|
|
||||||
|
|
||||||
return obj.forget();
|
if (!ReadStructuredCloneElements(aReader, rval)) {
|
||||||
}
|
return nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
already_AddRefed<DOMMatrix> DOMMatrix::Constructor(
|
return rval.forget();
|
||||||
const GlobalObject& aGlobal, const Sequence<double>& aNumberSequence,
|
|
||||||
ErrorResult& aRv) {
|
|
||||||
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports());
|
|
||||||
SetDataInMatrix(obj, aNumberSequence.Elements(), aNumberSequence.Length(),
|
|
||||||
aRv);
|
|
||||||
|
|
||||||
return obj.forget();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DOMMatrixReadOnly::Ensure3DMatrix() {
|
void DOMMatrixReadOnly::Ensure3DMatrix() {
|
||||||
if (!mMatrix3D) {
|
if (!mMatrix3D) {
|
||||||
mMatrix3D = new gfx::Matrix4x4(gfx::Matrix4x4::From2D(*mMatrix2D));
|
mMatrix3D =
|
||||||
|
new gfx::Matrix4x4Double(gfx::Matrix4x4Double::From2D(*mMatrix2D));
|
||||||
mMatrix2D = nullptr;
|
mMatrix2D = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DOMMatrix* DOMMatrix::MultiplySelf(const DOMMatrix& aOther) {
|
DOMMatrix* DOMMatrix::MultiplySelf(const DOMMatrixInit& aOtherInit,
|
||||||
if (aOther.IsIdentity()) {
|
ErrorResult& aRv) {
|
||||||
|
RefPtr<DOMMatrix> other = FromMatrix(mParent, aOtherInit, aRv);
|
||||||
|
if (aRv.Failed()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
MOZ_ASSERT(other);
|
||||||
|
if (other->IsIdentity()) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aOther.Is2D()) {
|
if (other->Is2D()) {
|
||||||
if (mMatrix3D) {
|
if (mMatrix3D) {
|
||||||
*mMatrix3D = gfx::Matrix4x4::From2D(*aOther.mMatrix2D) * *mMatrix3D;
|
*mMatrix3D = gfx::Matrix4x4Double::From2D(*other->mMatrix2D) * *mMatrix3D;
|
||||||
} else {
|
} else {
|
||||||
*mMatrix2D = *aOther.mMatrix2D * *mMatrix2D;
|
*mMatrix2D = *other->mMatrix2D * *mMatrix2D;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ensure3DMatrix();
|
Ensure3DMatrix();
|
||||||
*mMatrix3D = *aOther.mMatrix3D * *mMatrix3D;
|
*mMatrix3D = *other->mMatrix3D * *mMatrix3D;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
DOMMatrix* DOMMatrix::PreMultiplySelf(const DOMMatrix& aOther) {
|
DOMMatrix* DOMMatrix::PreMultiplySelf(const DOMMatrixInit& aOtherInit,
|
||||||
if (aOther.IsIdentity()) {
|
ErrorResult& aRv) {
|
||||||
|
RefPtr<DOMMatrix> other = FromMatrix(mParent, aOtherInit, aRv);
|
||||||
|
if (aRv.Failed()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
MOZ_ASSERT(other);
|
||||||
|
if (other->IsIdentity()) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aOther.Is2D()) {
|
if (other->Is2D()) {
|
||||||
if (mMatrix3D) {
|
if (mMatrix3D) {
|
||||||
*mMatrix3D = *mMatrix3D * gfx::Matrix4x4::From2D(*aOther.mMatrix2D);
|
*mMatrix3D = *mMatrix3D * gfx::Matrix4x4Double::From2D(*other->mMatrix2D);
|
||||||
} else {
|
} else {
|
||||||
*mMatrix2D = *mMatrix2D * *aOther.mMatrix2D;
|
*mMatrix2D = *mMatrix2D * *other->mMatrix2D;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ensure3DMatrix();
|
Ensure3DMatrix();
|
||||||
*mMatrix3D = *mMatrix3D * *aOther.mMatrix3D;
|
*mMatrix3D = *mMatrix3D * *other->mMatrix3D;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@ -499,40 +822,24 @@ DOMMatrix* DOMMatrix::TranslateSelf(double aTx, double aTy, double aTz) {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
DOMMatrix* DOMMatrix::ScaleSelf(double aScale, double aOriginX,
|
DOMMatrix* DOMMatrix::ScaleSelf(double aScaleX, const Optional<double>& aScaleY,
|
||||||
double aOriginY) {
|
double aScaleZ, double aOriginX,
|
||||||
ScaleNonUniformSelf(aScale, aScale, 1.0, aOriginX, aOriginY, 0);
|
double aOriginY, double aOriginZ) {
|
||||||
|
const double scaleY = aScaleY.WasPassed() ? aScaleY.Value() : aScaleX;
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
DOMMatrix* DOMMatrix::Scale3dSelf(double aScale, double aOriginX,
|
|
||||||
double aOriginY, double aOriginZ) {
|
|
||||||
ScaleNonUniformSelf(aScale, aScale, aScale, aOriginX, aOriginY, aOriginZ);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
DOMMatrix* DOMMatrix::ScaleNonUniformSelf(double aScaleX, double aScaleY,
|
|
||||||
double aScaleZ, double aOriginX,
|
|
||||||
double aOriginY, double aOriginZ) {
|
|
||||||
if (aScaleX == 1.0 && aScaleY == 1.0 && aScaleZ == 1.0) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
TranslateSelf(aOriginX, aOriginY, aOriginZ);
|
TranslateSelf(aOriginX, aOriginY, aOriginZ);
|
||||||
|
|
||||||
if (mMatrix3D || aScaleZ != 1.0 || aOriginZ != 0) {
|
if (mMatrix3D || aScaleZ != 1.0) {
|
||||||
Ensure3DMatrix();
|
Ensure3DMatrix();
|
||||||
gfx::Matrix4x4 m;
|
gfx::Matrix4x4Double m;
|
||||||
m._11 = aScaleX;
|
m._11 = aScaleX;
|
||||||
m._22 = aScaleY;
|
m._22 = scaleY;
|
||||||
m._33 = aScaleZ;
|
m._33 = aScaleZ;
|
||||||
*mMatrix3D = m * *mMatrix3D;
|
*mMatrix3D = m * *mMatrix3D;
|
||||||
} else {
|
} else {
|
||||||
gfx::Matrix m;
|
gfx::MatrixDouble m;
|
||||||
m._11 = aScaleX;
|
m._11 = aScaleX;
|
||||||
m._22 = aScaleY;
|
m._22 = scaleY;
|
||||||
*mMatrix2D = m * *mMatrix2D;
|
*mMatrix2D = m * *mMatrix2D;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,31 +848,60 @@ DOMMatrix* DOMMatrix::ScaleNonUniformSelf(double aScaleX, double aScaleY,
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
DOMMatrix* DOMMatrix::RotateFromVectorSelf(double aX, double aY) {
|
DOMMatrix* DOMMatrix::Scale3dSelf(double aScale, double aOriginX,
|
||||||
if (aX == 0.0 || aY == 0.0) {
|
double aOriginY, double aOriginZ) {
|
||||||
return this;
|
ScaleSelf(aScale, Optional<double>(aScale), aScale, aOriginX, aOriginY,
|
||||||
}
|
aOriginZ);
|
||||||
|
|
||||||
RotateSelf(atan2(aY, aX) / radPerDegree);
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
DOMMatrix* DOMMatrix::RotateSelf(double aAngle, double aOriginX,
|
DOMMatrix* DOMMatrix::RotateFromVectorSelf(double aX, double aY) {
|
||||||
double aOriginY) {
|
const double angle = (aX == 0.0 && aY == 0.0) ? 0 : atan2(aY, aX);
|
||||||
if (fmod(aAngle, 360) == 0) {
|
|
||||||
|
if (fmod(angle, 2 * M_PI) == 0) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
TranslateSelf(aOriginX, aOriginY);
|
|
||||||
|
|
||||||
if (mMatrix3D) {
|
if (mMatrix3D) {
|
||||||
RotateAxisAngleSelf(0, 0, 1, aAngle);
|
RotateAxisAngleSelf(0, 0, 1, angle / radPerDegree);
|
||||||
} else {
|
} else {
|
||||||
*mMatrix2D = mMatrix2D->PreRotate(aAngle * radPerDegree);
|
*mMatrix2D = mMatrix2D->PreRotate(angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
TranslateSelf(-aOriginX, -aOriginY);
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
DOMMatrix* DOMMatrix::RotateSelf(double aRotX, const Optional<double>& aRotY,
|
||||||
|
const Optional<double>& aRotZ) {
|
||||||
|
double rotY;
|
||||||
|
double rotZ;
|
||||||
|
if (!aRotY.WasPassed() && !aRotZ.WasPassed()) {
|
||||||
|
rotZ = aRotX;
|
||||||
|
aRotX = 0;
|
||||||
|
rotY = 0;
|
||||||
|
} else {
|
||||||
|
rotY = aRotY.WasPassed() ? aRotY.Value() : 0;
|
||||||
|
rotZ = aRotZ.WasPassed() ? aRotZ.Value() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aRotX != 0 || rotY != 0) {
|
||||||
|
Ensure3DMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mMatrix3D) {
|
||||||
|
if (fmod(rotZ, 360) != 0) {
|
||||||
|
mMatrix3D->RotateZ(rotZ * radPerDegree);
|
||||||
|
}
|
||||||
|
if (fmod(rotY, 360) != 0) {
|
||||||
|
mMatrix3D->RotateY(rotY * radPerDegree);
|
||||||
|
}
|
||||||
|
if (fmod(aRotX, 360) != 0) {
|
||||||
|
mMatrix3D->RotateX(aRotX * radPerDegree);
|
||||||
|
}
|
||||||
|
} else if (fmod(rotZ, 360) != 0) {
|
||||||
|
*mMatrix2D = mMatrix2D->PreRotate(rotZ * radPerDegree);
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -579,7 +915,7 @@ DOMMatrix* DOMMatrix::RotateAxisAngleSelf(double aX, double aY, double aZ,
|
|||||||
aAngle *= radPerDegree;
|
aAngle *= radPerDegree;
|
||||||
|
|
||||||
Ensure3DMatrix();
|
Ensure3DMatrix();
|
||||||
gfx::Matrix4x4 m;
|
gfx::Matrix4x4Double m;
|
||||||
m.SetRotateAxisAngle(aX, aY, aZ, aAngle);
|
m.SetRotateAxisAngle(aX, aY, aZ, aAngle);
|
||||||
|
|
||||||
*mMatrix3D = m * *mMatrix3D;
|
*mMatrix3D = m * *mMatrix3D;
|
||||||
@ -593,11 +929,11 @@ DOMMatrix* DOMMatrix::SkewXSelf(double aSx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mMatrix3D) {
|
if (mMatrix3D) {
|
||||||
gfx::Matrix4x4 m;
|
gfx::Matrix4x4Double m;
|
||||||
m._21 = tan(aSx * radPerDegree);
|
m._21 = tan(aSx * radPerDegree);
|
||||||
*mMatrix3D = m * *mMatrix3D;
|
*mMatrix3D = m * *mMatrix3D;
|
||||||
} else {
|
} else {
|
||||||
gfx::Matrix m;
|
gfx::MatrixDouble m;
|
||||||
m._21 = tan(aSx * radPerDegree);
|
m._21 = tan(aSx * radPerDegree);
|
||||||
*mMatrix2D = m * *mMatrix2D;
|
*mMatrix2D = m * *mMatrix2D;
|
||||||
}
|
}
|
||||||
@ -611,11 +947,11 @@ DOMMatrix* DOMMatrix::SkewYSelf(double aSy) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mMatrix3D) {
|
if (mMatrix3D) {
|
||||||
gfx::Matrix4x4 m;
|
gfx::Matrix4x4Double m;
|
||||||
m._12 = tan(aSy * radPerDegree);
|
m._12 = tan(aSy * radPerDegree);
|
||||||
*mMatrix3D = m * *mMatrix3D;
|
*mMatrix3D = m * *mMatrix3D;
|
||||||
} else {
|
} else {
|
||||||
gfx::Matrix m;
|
gfx::MatrixDouble m;
|
||||||
m._12 = tan(aSy * radPerDegree);
|
m._12 = tan(aSy * radPerDegree);
|
||||||
*mMatrix2D = m * *mMatrix2D;
|
*mMatrix2D = m * *mMatrix2D;
|
||||||
}
|
}
|
||||||
@ -631,7 +967,7 @@ DOMMatrix* DOMMatrix::InvertSelf() {
|
|||||||
} else if (!mMatrix2D->Invert()) {
|
} else if (!mMatrix2D->Invert()) {
|
||||||
mMatrix2D = nullptr;
|
mMatrix2D = nullptr;
|
||||||
|
|
||||||
mMatrix3D = new gfx::Matrix4x4();
|
mMatrix3D = new gfx::Matrix4x4Double();
|
||||||
mMatrix3D->SetNAN();
|
mMatrix3D->SetNAN();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,7 +975,7 @@ DOMMatrix* DOMMatrix::InvertSelf() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DOMMatrixReadOnly* DOMMatrixReadOnly::SetMatrixValue(
|
DOMMatrixReadOnly* DOMMatrixReadOnly::SetMatrixValue(
|
||||||
const nsAString& aTransformList, ErrorResult& aRv) {
|
const nsACString& aTransformList, ErrorResult& aRv) {
|
||||||
// An empty string is a no-op.
|
// An empty string is a no-op.
|
||||||
if (aTransformList.IsEmpty()) {
|
if (aTransformList.IsEmpty()) {
|
||||||
return this;
|
return this;
|
||||||
@ -655,7 +991,9 @@ DOMMatrixReadOnly* DOMMatrixReadOnly::SetMatrixValue(
|
|||||||
|
|
||||||
if (!contains3dTransform) {
|
if (!contains3dTransform) {
|
||||||
mMatrix3D = nullptr;
|
mMatrix3D = nullptr;
|
||||||
mMatrix2D = new gfx::Matrix();
|
if (!mMatrix2D) {
|
||||||
|
mMatrix2D = new gfx::MatrixDouble();
|
||||||
|
}
|
||||||
|
|
||||||
SetA(transform._11);
|
SetA(transform._11);
|
||||||
SetB(transform._12);
|
SetB(transform._12);
|
||||||
@ -664,14 +1002,14 @@ DOMMatrixReadOnly* DOMMatrixReadOnly::SetMatrixValue(
|
|||||||
SetE(transform._41);
|
SetE(transform._41);
|
||||||
SetF(transform._42);
|
SetF(transform._42);
|
||||||
} else {
|
} else {
|
||||||
mMatrix3D = new gfx::Matrix4x4(transform);
|
mMatrix3D = new gfx::Matrix4x4Double(transform);
|
||||||
mMatrix2D = nullptr;
|
mMatrix2D = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
DOMMatrix* DOMMatrix::SetMatrixValue(const nsAString& aTransformList,
|
DOMMatrix* DOMMatrix::SetMatrixValue(const nsACString& aTransformList,
|
||||||
ErrorResult& aRv) {
|
ErrorResult& aRv) {
|
||||||
DOMMatrixReadOnly::SetMatrixValue(aTransformList, aRv);
|
DOMMatrixReadOnly::SetMatrixValue(aTransformList, aRv);
|
||||||
return this;
|
return this;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#ifndef MOZILLA_DOM_DOMMATRIX_H_
|
#ifndef MOZILLA_DOM_DOMMATRIX_H_
|
||||||
#define MOZILLA_DOM_DOMMATRIX_H_
|
#define MOZILLA_DOM_DOMMATRIX_H_
|
||||||
|
|
||||||
|
#include "js/StructuredClone.h"
|
||||||
#include "nsWrapperCache.h"
|
#include "nsWrapperCache.h"
|
||||||
#include "nsISupports.h"
|
#include "nsISupports.h"
|
||||||
#include "nsCycleCollectionParticipant.h"
|
#include "nsCycleCollectionParticipant.h"
|
||||||
@ -13,7 +14,9 @@
|
|||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "mozilla/dom/BindingDeclarations.h"
|
#include "mozilla/dom/BindingDeclarations.h"
|
||||||
#include "mozilla/dom/TypedArray.h"
|
#include "mozilla/dom/TypedArray.h"
|
||||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
#include "mozilla/gfx/Matrix.h" // for Matrix4x4Double
|
||||||
|
|
||||||
|
class nsIGlobalObject;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
@ -21,26 +24,33 @@ namespace dom {
|
|||||||
class GlobalObject;
|
class GlobalObject;
|
||||||
class DOMMatrix;
|
class DOMMatrix;
|
||||||
class DOMPoint;
|
class DOMPoint;
|
||||||
class StringOrUnrestrictedDoubleSequence;
|
class UTF8StringOrUnrestrictedDoubleSequenceOrDOMMatrixReadOnly;
|
||||||
struct DOMPointInit;
|
struct DOMPointInit;
|
||||||
|
struct DOMMatrixInit;
|
||||||
|
struct DOMMatrix2DInit;
|
||||||
|
|
||||||
class DOMMatrixReadOnly : public nsWrapperCache {
|
class DOMMatrixReadOnly : public nsWrapperCache {
|
||||||
public:
|
public:
|
||||||
explicit DOMMatrixReadOnly(nsISupports* aParent)
|
explicit DOMMatrixReadOnly(nsISupports* aParent)
|
||||||
: mParent(aParent), mMatrix2D(new gfx::Matrix()) {}
|
: mParent(aParent), mMatrix2D(new gfx::MatrixDouble()) {}
|
||||||
|
|
||||||
DOMMatrixReadOnly(nsISupports* aParent, const DOMMatrixReadOnly& other)
|
DOMMatrixReadOnly(nsISupports* aParent, const DOMMatrixReadOnly& other)
|
||||||
: mParent(aParent) {
|
: mParent(aParent) {
|
||||||
if (other.mMatrix2D) {
|
if (other.mMatrix2D) {
|
||||||
mMatrix2D = new gfx::Matrix(*other.mMatrix2D);
|
mMatrix2D = new gfx::MatrixDouble(*other.mMatrix2D);
|
||||||
} else {
|
} else {
|
||||||
mMatrix3D = new gfx::Matrix4x4(*other.mMatrix3D);
|
mMatrix3D = new gfx::Matrix4x4Double(*other.mMatrix3D);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DOMMatrixReadOnly(nsISupports* aParent, const gfx::Matrix4x4& aMatrix)
|
DOMMatrixReadOnly(nsISupports* aParent, const gfx::Matrix4x4& aMatrix)
|
||||||
: mParent(aParent) {
|
: mParent(aParent) {
|
||||||
mMatrix3D = new gfx::Matrix4x4(aMatrix);
|
mMatrix3D = new gfx::Matrix4x4Double(aMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
DOMMatrixReadOnly(nsISupports* aParent, const gfx::Matrix& aMatrix)
|
||||||
|
: mParent(aParent) {
|
||||||
|
mMatrix2D = new gfx::MatrixDouble(aMatrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMMatrixReadOnly)
|
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMMatrixReadOnly)
|
||||||
@ -50,11 +60,35 @@ class DOMMatrixReadOnly : public nsWrapperCache {
|
|||||||
virtual JSObject* WrapObject(JSContext* cx,
|
virtual JSObject* WrapObject(JSContext* cx,
|
||||||
JS::Handle<JSObject*> aGivenProto) override;
|
JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
|
||||||
|
static already_AddRefed<DOMMatrixReadOnly> FromMatrix(
|
||||||
|
nsISupports* aParent, const DOMMatrix2DInit& aMatrixInit,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
static already_AddRefed<DOMMatrixReadOnly> FromMatrix(
|
||||||
|
nsISupports* aParent, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv);
|
||||||
|
|
||||||
|
static already_AddRefed<DOMMatrixReadOnly> FromMatrix(
|
||||||
|
const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
static already_AddRefed<DOMMatrixReadOnly> FromFloat32Array(
|
||||||
|
const GlobalObject& aGlobal, const Float32Array& aArray32,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
static already_AddRefed<DOMMatrixReadOnly> FromFloat64Array(
|
||||||
|
const GlobalObject& aGlobal, const Float64Array& aArray64,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
static already_AddRefed<DOMMatrixReadOnly> Constructor(
|
static already_AddRefed<DOMMatrixReadOnly> Constructor(
|
||||||
const GlobalObject& aGlobal,
|
const GlobalObject& aGlobal,
|
||||||
const Optional<StringOrUnrestrictedDoubleSequence>& aArg,
|
const Optional<UTF8StringOrUnrestrictedDoubleSequenceOrDOMMatrixReadOnly>&
|
||||||
|
aArg,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
static already_AddRefed<DOMMatrixReadOnly> ReadStructuredClone(
|
||||||
|
JSContext* aCx, nsIGlobalObject* aGlobal,
|
||||||
|
JSStructuredCloneReader* aReader);
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#define GetMatrixMember(entry2D, entry3D, default) \
|
#define GetMatrixMember(entry2D, entry3D, default) \
|
||||||
{ \
|
{ \
|
||||||
@ -148,22 +182,25 @@ class DOMMatrixReadOnly : public nsWrapperCache {
|
|||||||
|
|
||||||
already_AddRefed<DOMMatrix> Translate(double aTx, double aTy,
|
already_AddRefed<DOMMatrix> Translate(double aTx, double aTy,
|
||||||
double aTz = 0) const;
|
double aTz = 0) const;
|
||||||
already_AddRefed<DOMMatrix> Scale(double aScale, double aOriginX = 0,
|
already_AddRefed<DOMMatrix> Scale(double aScaleX,
|
||||||
double aOriginY = 0) const;
|
const Optional<double>& aScaleY,
|
||||||
|
double aScaleZ, double aOriginX,
|
||||||
|
double aOriginY, double aOriginZ) const;
|
||||||
already_AddRefed<DOMMatrix> Scale3d(double aScale, double aOriginX = 0,
|
already_AddRefed<DOMMatrix> Scale3d(double aScale, double aOriginX = 0,
|
||||||
double aOriginY = 0,
|
double aOriginY = 0,
|
||||||
double aOriginZ = 0) const;
|
double aOriginZ = 0) const;
|
||||||
already_AddRefed<DOMMatrix> ScaleNonUniform(
|
already_AddRefed<DOMMatrix> ScaleNonUniform(double aScaleX,
|
||||||
double aScaleX, double aScaleY = 1.0, double aScaleZ = 1.0,
|
double aScaleY) const;
|
||||||
double aOriginX = 0, double aOriginY = 0, double aOriginZ = 0) const;
|
already_AddRefed<DOMMatrix> Rotate(double aRotX,
|
||||||
already_AddRefed<DOMMatrix> Rotate(double aAngle, double aOriginX = 0,
|
const Optional<double>& aRotY,
|
||||||
double aOriginY = 0) const;
|
const Optional<double>& aRotZ) const;
|
||||||
already_AddRefed<DOMMatrix> RotateFromVector(double aX, double aY) const;
|
already_AddRefed<DOMMatrix> RotateFromVector(double aX, double aY) const;
|
||||||
already_AddRefed<DOMMatrix> RotateAxisAngle(double aX, double aY, double aZ,
|
already_AddRefed<DOMMatrix> RotateAxisAngle(double aX, double aY, double aZ,
|
||||||
double aAngle) const;
|
double aAngle) const;
|
||||||
already_AddRefed<DOMMatrix> SkewX(double aSx) const;
|
already_AddRefed<DOMMatrix> SkewX(double aSx) const;
|
||||||
already_AddRefed<DOMMatrix> SkewY(double aSy) const;
|
already_AddRefed<DOMMatrix> SkewY(double aSy) const;
|
||||||
already_AddRefed<DOMMatrix> Multiply(const DOMMatrix& aOther) const;
|
already_AddRefed<DOMMatrix> Multiply(const DOMMatrixInit& aOther,
|
||||||
|
ErrorResult& aRv) const;
|
||||||
already_AddRefed<DOMMatrix> FlipX() const;
|
already_AddRefed<DOMMatrix> FlipX() const;
|
||||||
already_AddRefed<DOMMatrix> FlipY() const;
|
already_AddRefed<DOMMatrix> FlipY() const;
|
||||||
already_AddRefed<DOMMatrix> Inverse() const;
|
already_AddRefed<DOMMatrix> Inverse() const;
|
||||||
@ -175,19 +212,46 @@ class DOMMatrixReadOnly : public nsWrapperCache {
|
|||||||
ErrorResult& aRv) const;
|
ErrorResult& aRv) const;
|
||||||
void ToFloat64Array(JSContext* aCx, JS::MutableHandle<JSObject*> aResult,
|
void ToFloat64Array(JSContext* aCx, JS::MutableHandle<JSObject*> aResult,
|
||||||
ErrorResult& aRv) const;
|
ErrorResult& aRv) const;
|
||||||
void Stringify(nsAString& aResult);
|
void Stringify(nsAString& aResult, ErrorResult& aRv);
|
||||||
|
|
||||||
|
bool WriteStructuredClone(JSContext* aCx,
|
||||||
|
JSStructuredCloneWriter* aWriter) const;
|
||||||
|
const gfx::MatrixDouble* GetInternal2D() const {
|
||||||
|
if (Is2D()) {
|
||||||
|
return mMatrix2D;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
nsCOMPtr<nsISupports> mParent;
|
nsCOMPtr<nsISupports> mParent;
|
||||||
nsAutoPtr<gfx::Matrix> mMatrix2D;
|
nsAutoPtr<gfx::MatrixDouble> mMatrix2D;
|
||||||
nsAutoPtr<gfx::Matrix4x4> mMatrix3D;
|
nsAutoPtr<gfx::Matrix4x4Double> mMatrix3D;
|
||||||
|
|
||||||
virtual ~DOMMatrixReadOnly() {}
|
virtual ~DOMMatrixReadOnly() {}
|
||||||
|
|
||||||
DOMMatrixReadOnly* SetMatrixValue(const nsAString& aTransformList,
|
/**
|
||||||
ErrorResult& aRv);
|
* Sets data from a fully validated and fixed-up matrix init,
|
||||||
|
* where all of its members are properly defined.
|
||||||
|
* The init dictionary's dimension must match the matrix one.
|
||||||
|
*/
|
||||||
|
void SetDataFromMatrix2DInit(const DOMMatrix2DInit& aMatrixInit);
|
||||||
|
void SetDataFromMatrixInit(const DOMMatrixInit& aMatrixInit);
|
||||||
|
|
||||||
|
DOMMatrixReadOnly* SetMatrixValue(const nsACString&, ErrorResult&);
|
||||||
void Ensure3DMatrix();
|
void Ensure3DMatrix();
|
||||||
|
|
||||||
|
DOMMatrixReadOnly(nsISupports* aParent, bool is2D) : mParent(aParent) {
|
||||||
|
if (is2D) {
|
||||||
|
mMatrix2D = new gfx::MatrixDouble();
|
||||||
|
} else {
|
||||||
|
mMatrix3D = new gfx::Matrix4x4Double();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ReadStructuredCloneElements(JSStructuredCloneReader* aReader,
|
||||||
|
DOMMatrixReadOnly* matrix);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DOMMatrixReadOnly() = delete;
|
DOMMatrixReadOnly() = delete;
|
||||||
DOMMatrixReadOnly(const DOMMatrixReadOnly&) = delete;
|
DOMMatrixReadOnly(const DOMMatrixReadOnly&) = delete;
|
||||||
@ -204,47 +268,60 @@ class DOMMatrix : public DOMMatrixReadOnly {
|
|||||||
DOMMatrix(nsISupports* aParent, const gfx::Matrix4x4& aMatrix)
|
DOMMatrix(nsISupports* aParent, const gfx::Matrix4x4& aMatrix)
|
||||||
: DOMMatrixReadOnly(aParent, aMatrix) {}
|
: DOMMatrixReadOnly(aParent, aMatrix) {}
|
||||||
|
|
||||||
static already_AddRefed<DOMMatrix> Constructor(const GlobalObject& aGlobal,
|
DOMMatrix(nsISupports* aParent, const gfx::Matrix& aMatrix)
|
||||||
ErrorResult& aRv);
|
: DOMMatrixReadOnly(aParent, aMatrix) {}
|
||||||
static already_AddRefed<DOMMatrix> Constructor(
|
|
||||||
const GlobalObject& aGlobal, const nsAString& aTransformList,
|
static already_AddRefed<DOMMatrix> FromMatrix(
|
||||||
|
nsISupports* aParent, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv);
|
||||||
|
|
||||||
|
static already_AddRefed<DOMMatrix> FromMatrix(
|
||||||
|
const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
static already_AddRefed<DOMMatrix> Constructor(
|
|
||||||
const GlobalObject& aGlobal, const DOMMatrixReadOnly& aOther,
|
static already_AddRefed<DOMMatrix> FromFloat32Array(
|
||||||
|
const GlobalObject& aGlobal, const Float32Array& aArray32,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
static already_AddRefed<DOMMatrix> Constructor(const GlobalObject& aGlobal,
|
|
||||||
const Float32Array& aArray32,
|
static already_AddRefed<DOMMatrix> FromFloat64Array(
|
||||||
ErrorResult& aRv);
|
const GlobalObject& aGlobal, const Float64Array& aArray64,
|
||||||
static already_AddRefed<DOMMatrix> Constructor(const GlobalObject& aGlobal,
|
|
||||||
const Float64Array& aArray64,
|
|
||||||
ErrorResult& aRv);
|
|
||||||
static already_AddRefed<DOMMatrix> Constructor(
|
|
||||||
const GlobalObject& aGlobal, const Sequence<double>& aNumberSequence,
|
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
static already_AddRefed<DOMMatrix> Constructor(
|
||||||
|
const GlobalObject& aGlobal,
|
||||||
|
const Optional<UTF8StringOrUnrestrictedDoubleSequenceOrDOMMatrixReadOnly>&
|
||||||
|
aArg,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
static already_AddRefed<DOMMatrix> ReadStructuredClone(
|
||||||
|
JSContext* aCx, nsIGlobalObject* aGlobal,
|
||||||
|
JSStructuredCloneReader* aReader);
|
||||||
|
|
||||||
virtual JSObject* WrapObject(JSContext* aCx,
|
virtual JSObject* WrapObject(JSContext* aCx,
|
||||||
JS::Handle<JSObject*> aGivenProto) override;
|
JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
|
||||||
DOMMatrix* MultiplySelf(const DOMMatrix& aOther);
|
DOMMatrix* MultiplySelf(const DOMMatrixInit& aOther, ErrorResult& aRv);
|
||||||
DOMMatrix* PreMultiplySelf(const DOMMatrix& aOther);
|
DOMMatrix* PreMultiplySelf(const DOMMatrixInit& aOther, ErrorResult& aRv);
|
||||||
DOMMatrix* TranslateSelf(double aTx, double aTy, double aTz = 0);
|
DOMMatrix* TranslateSelf(double aTx, double aTy, double aTz = 0);
|
||||||
DOMMatrix* ScaleSelf(double aScale, double aOriginX = 0, double aOriginY = 0);
|
DOMMatrix* ScaleSelf(double aScaleX, const Optional<double>& aScaleY,
|
||||||
|
double aScaleZ, double aOriginX, double aOriginY,
|
||||||
|
double aOriginZ);
|
||||||
DOMMatrix* Scale3dSelf(double aScale, double aOriginX = 0,
|
DOMMatrix* Scale3dSelf(double aScale, double aOriginX = 0,
|
||||||
double aOriginY = 0, double aOriginZ = 0);
|
double aOriginY = 0, double aOriginZ = 0);
|
||||||
DOMMatrix* ScaleNonUniformSelf(double aScaleX, double aScaleY = 1,
|
DOMMatrix* RotateSelf(double aRotX, const Optional<double>& aRotY,
|
||||||
double aScaleZ = 1, double aOriginX = 0,
|
const Optional<double>& aRotZ);
|
||||||
double aOriginY = 0, double aOriginZ = 0);
|
|
||||||
DOMMatrix* RotateSelf(double aAngle, double aOriginX = 0,
|
|
||||||
double aOriginY = 0);
|
|
||||||
DOMMatrix* RotateFromVectorSelf(double aX, double aY);
|
DOMMatrix* RotateFromVectorSelf(double aX, double aY);
|
||||||
DOMMatrix* RotateAxisAngleSelf(double aX, double aY, double aZ,
|
DOMMatrix* RotateAxisAngleSelf(double aX, double aY, double aZ,
|
||||||
double aAngle);
|
double aAngle);
|
||||||
DOMMatrix* SkewXSelf(double aSx);
|
DOMMatrix* SkewXSelf(double aSx);
|
||||||
DOMMatrix* SkewYSelf(double aSy);
|
DOMMatrix* SkewYSelf(double aSy);
|
||||||
DOMMatrix* InvertSelf();
|
DOMMatrix* InvertSelf();
|
||||||
DOMMatrix* SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv);
|
DOMMatrix* SetMatrixValue(const nsACString&, ErrorResult&);
|
||||||
|
|
||||||
virtual ~DOMMatrix() {}
|
virtual ~DOMMatrix() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
DOMMatrix(nsISupports* aParent, bool is2D)
|
||||||
|
: DOMMatrixReadOnly(aParent, is2D) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
@ -7,16 +7,16 @@
|
|||||||
#include "nsNetUtil.h"
|
#include "nsNetUtil.h"
|
||||||
#include "nsDOMString.h"
|
#include "nsDOMString.h"
|
||||||
#include "MainThreadUtils.h"
|
#include "MainThreadUtils.h"
|
||||||
|
#include "SystemPrincipal.h"
|
||||||
#include "nsIStreamListener.h"
|
#include "nsIStreamListener.h"
|
||||||
#include "nsStringStream.h"
|
#include "nsStringStream.h"
|
||||||
#include "nsIScriptError.h"
|
|
||||||
#include "nsIScriptSecurityManager.h"
|
|
||||||
#include "nsCRT.h"
|
#include "nsCRT.h"
|
||||||
#include "nsStreamUtils.h"
|
#include "nsStreamUtils.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsDOMJSUtils.h"
|
#include "nsDOMJSUtils.h"
|
||||||
#include "nsError.h"
|
#include "nsError.h"
|
||||||
#include "nsPIDOMWindow.h"
|
#include "nsPIDOMWindow.h"
|
||||||
|
#include "mozilla/BasePrincipal.h"
|
||||||
#include "mozilla/LoadInfo.h"
|
#include "mozilla/LoadInfo.h"
|
||||||
#include "mozilla/NullPrincipal.h"
|
#include "mozilla/NullPrincipal.h"
|
||||||
#include "mozilla/dom/BindingUtils.h"
|
#include "mozilla/dom/BindingUtils.h"
|
||||||
@ -31,7 +31,8 @@ DOMParser::DOMParser(nsIGlobalObject* aOwner, nsIPrincipal* aDocPrincipal,
|
|||||||
mPrincipal(aDocPrincipal),
|
mPrincipal(aDocPrincipal),
|
||||||
mDocumentURI(aDocumentURI),
|
mDocumentURI(aDocumentURI),
|
||||||
mBaseURI(aBaseURI),
|
mBaseURI(aBaseURI),
|
||||||
mForceEnableXULXBL(false) {
|
mForceEnableXULXBL(false),
|
||||||
|
mForceEnableDTD(false) {
|
||||||
MOZ_ASSERT(aDocPrincipal);
|
MOZ_ASSERT(aDocPrincipal);
|
||||||
MOZ_ASSERT(aDocumentURI);
|
MOZ_ASSERT(aDocumentURI);
|
||||||
}
|
}
|
||||||
@ -49,10 +50,6 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMParser, mOwner)
|
|||||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMParser)
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMParser)
|
||||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMParser)
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMParser)
|
||||||
|
|
||||||
static const char* StringFromSupportedType(SupportedType aType) {
|
|
||||||
return SupportedTypeValues::strings[static_cast<int>(aType)].value;
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<Document> DOMParser::ParseFromString(const nsAString& aStr,
|
already_AddRefed<Document> DOMParser::ParseFromString(const nsAString& aStr,
|
||||||
SupportedType aType,
|
SupportedType aType,
|
||||||
ErrorResult& aRv) {
|
ErrorResult& aRv) {
|
||||||
@ -67,6 +64,10 @@ already_AddRefed<Document> DOMParser::ParseFromString(const nsAString& aStr,
|
|||||||
document->ForceEnableXULXBL();
|
document->ForceEnableXULXBL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mForceEnableDTD) {
|
||||||
|
document->ForceSkipDTDSecurityChecks();
|
||||||
|
}
|
||||||
|
|
||||||
nsresult rv = nsContentUtils::ParseDocumentHTML(aStr, document, false);
|
nsresult rv = nsContentUtils::ParseDocumentHTML(aStr, document, false);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
aRv.Throw(rv);
|
aRv.Throw(rv);
|
||||||
@ -96,6 +97,22 @@ already_AddRefed<Document> DOMParser::ParseFromString(const nsAString& aStr,
|
|||||||
aType, aRv);
|
aType, aRv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<Document> DOMParser::ParseFromSafeString(const nsAString& aStr,
|
||||||
|
SupportedType aType,
|
||||||
|
ErrorResult& aRv) {
|
||||||
|
// Since we disable cross docGroup node adoption, it is safe to create
|
||||||
|
// new document with the system principal, then the new document will be
|
||||||
|
// placed in the same docGroup as the chrome document.
|
||||||
|
nsCOMPtr<nsIPrincipal> docPrincipal = mPrincipal;
|
||||||
|
if (!mPrincipal->IsSystemPrincipal()) {
|
||||||
|
mPrincipal = SystemPrincipal::Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<Document> ret = ParseFromString(aStr, aType, aRv);
|
||||||
|
mPrincipal = docPrincipal;
|
||||||
|
return ret.forget();
|
||||||
|
}
|
||||||
|
|
||||||
already_AddRefed<Document> DOMParser::ParseFromBuffer(const Uint8Array& aBuf,
|
already_AddRefed<Document> DOMParser::ParseFromBuffer(const Uint8Array& aBuf,
|
||||||
SupportedType aType,
|
SupportedType aType,
|
||||||
ErrorResult& aRv) {
|
ErrorResult& aRv) {
|
||||||
@ -159,11 +176,12 @@ already_AddRefed<Document> DOMParser::ParseFromStream(nsIInputStream* aStream,
|
|||||||
|
|
||||||
// Create a fake channel
|
// Create a fake channel
|
||||||
nsCOMPtr<nsIChannel> parserChannel;
|
nsCOMPtr<nsIChannel> parserChannel;
|
||||||
NS_NewInputStreamChannel(getter_AddRefs(parserChannel), mDocumentURI,
|
NS_NewInputStreamChannel(
|
||||||
nullptr, // aStream
|
getter_AddRefs(parserChannel), mDocumentURI,
|
||||||
mPrincipal, nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
|
nullptr, // aStream
|
||||||
nsIContentPolicy::TYPE_OTHER,
|
mPrincipal, nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
|
||||||
nsDependentCString(StringFromSupportedType(aType)));
|
nsIContentPolicy::TYPE_OTHER,
|
||||||
|
nsDependentCSubstring(SupportedTypeValues::GetString(aType)));
|
||||||
if (NS_WARN_IF(!parserChannel)) {
|
if (NS_WARN_IF(!parserChannel)) {
|
||||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -181,6 +199,10 @@ already_AddRefed<Document> DOMParser::ParseFromStream(nsIInputStream* aStream,
|
|||||||
document->ForceEnableXULXBL();
|
document->ForceEnableXULXBL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mForceEnableDTD) {
|
||||||
|
document->ForceSkipDTDSecurityChecks();
|
||||||
|
}
|
||||||
|
|
||||||
// Have to pass false for reset here, else the reset will remove
|
// Have to pass false for reset here, else the reset will remove
|
||||||
// our event listener. Should that listener addition move to later
|
// our event listener. Should that listener addition move to later
|
||||||
// than this call?
|
// than this call?
|
||||||
@ -225,7 +247,7 @@ already_AddRefed<DOMParser> DOMParser::Constructor(const GlobalObject& aOwner,
|
|||||||
nsCOMPtr<nsIPrincipal> docPrincipal = aOwner.GetSubjectPrincipal();
|
nsCOMPtr<nsIPrincipal> docPrincipal = aOwner.GetSubjectPrincipal();
|
||||||
nsCOMPtr<nsIURI> documentURI;
|
nsCOMPtr<nsIURI> documentURI;
|
||||||
nsIURI* baseURI = nullptr;
|
nsIURI* baseURI = nullptr;
|
||||||
if (nsContentUtils::IsSystemPrincipal(docPrincipal)) {
|
if (docPrincipal->IsSystemPrincipal()) {
|
||||||
docPrincipal = NullPrincipal::CreateWithoutOriginAttributes();
|
docPrincipal = NullPrincipal::CreateWithoutOriginAttributes();
|
||||||
docPrincipal->GetURI(getter_AddRefs(documentURI));
|
docPrincipal->GetURI(getter_AddRefs(documentURI));
|
||||||
} else {
|
} else {
|
||||||
|
@ -35,6 +35,10 @@ class DOMParser final : public nsISupports, public nsWrapperCache {
|
|||||||
SupportedType aType,
|
SupportedType aType,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
// ChromeOnly API
|
||||||
|
already_AddRefed<Document> ParseFromSafeString(const nsAString& aStr,
|
||||||
|
SupportedType aType,
|
||||||
|
ErrorResult& aRv);
|
||||||
// Sequence converts to Span, so we can use this overload for both
|
// Sequence converts to Span, so we can use this overload for both
|
||||||
// the Sequence case and our internal uses.
|
// the Sequence case and our internal uses.
|
||||||
already_AddRefed<Document> ParseFromBuffer(Span<const uint8_t> aBuf,
|
already_AddRefed<Document> ParseFromBuffer(Span<const uint8_t> aBuf,
|
||||||
@ -51,7 +55,12 @@ class DOMParser final : public nsISupports, public nsWrapperCache {
|
|||||||
SupportedType aType,
|
SupportedType aType,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
|
|
||||||
void ForceEnableXULXBL() { mForceEnableXULXBL = true; }
|
void ForceEnableXULXBL() {
|
||||||
|
mForceEnableXULXBL = true;
|
||||||
|
ForceEnableDTD();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForceEnableDTD() { mForceEnableDTD = true; }
|
||||||
|
|
||||||
nsIGlobalObject* GetParentObject() const { return mOwner; }
|
nsIGlobalObject* GetParentObject() const { return mOwner; }
|
||||||
|
|
||||||
@ -76,6 +85,7 @@ class DOMParser final : public nsISupports, public nsWrapperCache {
|
|||||||
nsCOMPtr<nsIURI> mBaseURI;
|
nsCOMPtr<nsIURI> mBaseURI;
|
||||||
|
|
||||||
bool mForceEnableXULXBL;
|
bool mForceEnableXULXBL;
|
||||||
|
bool mForceEnableDTD;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
@ -23,8 +23,7 @@ already_AddRefed<DOMPointReadOnly> DOMPointReadOnly::FromPoint(
|
|||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<DOMPointReadOnly> DOMPointReadOnly::Constructor(
|
already_AddRefed<DOMPointReadOnly> DOMPointReadOnly::Constructor(
|
||||||
const GlobalObject& aGlobal, double aX, double aY, double aZ, double aW,
|
const GlobalObject& aGlobal, double aX, double aY, double aZ, double aW) {
|
||||||
ErrorResult& aRV) {
|
|
||||||
RefPtr<DOMPointReadOnly> obj =
|
RefPtr<DOMPointReadOnly> obj =
|
||||||
new DOMPointReadOnly(aGlobal.GetAsSupports(), aX, aY, aZ, aW);
|
new DOMPointReadOnly(aGlobal.GetAsSupports(), aX, aY, aZ, aW);
|
||||||
return obj.forget();
|
return obj.forget();
|
||||||
@ -35,6 +34,66 @@ JSObject* DOMPointReadOnly::WrapObject(JSContext* aCx,
|
|||||||
return DOMPointReadOnly_Binding::Wrap(aCx, this, aGivenProto);
|
return DOMPointReadOnly_Binding::Wrap(aCx, this, aGivenProto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<DOMPoint> DOMPointReadOnly::MatrixTransform(
|
||||||
|
const DOMMatrixInit& aInit, ErrorResult& aRv) {
|
||||||
|
RefPtr<DOMMatrixReadOnly> matrix =
|
||||||
|
DOMMatrixReadOnly::FromMatrix(mParent, aInit, aRv);
|
||||||
|
if (aRv.Failed()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
DOMPointInit init;
|
||||||
|
init.mX = this->mX;
|
||||||
|
init.mY = this->mY;
|
||||||
|
init.mZ = this->mZ;
|
||||||
|
init.mW = this->mW;
|
||||||
|
RefPtr<DOMPoint> point = matrix->TransformPoint(init);
|
||||||
|
return point.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://drafts.fxtf.org/geometry/#structured-serialization
|
||||||
|
bool DOMPointReadOnly::WriteStructuredClone(
|
||||||
|
JSContext* aCx, JSStructuredCloneWriter* aWriter) const {
|
||||||
|
#define WriteDouble(d) \
|
||||||
|
JS_WriteUint32Pair(aWriter, (BitwiseCast<uint64_t>(d) >> 32) & 0xffffffff, \
|
||||||
|
BitwiseCast<uint64_t>(d) & 0xffffffff)
|
||||||
|
|
||||||
|
return WriteDouble(mX) && WriteDouble(mY) && WriteDouble(mZ) &&
|
||||||
|
WriteDouble(mW);
|
||||||
|
|
||||||
|
#undef WriteDouble
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
already_AddRefed<DOMPointReadOnly> DOMPointReadOnly::ReadStructuredClone(
|
||||||
|
JSContext* aCx, nsIGlobalObject* aGlobal,
|
||||||
|
JSStructuredCloneReader* aReader) {
|
||||||
|
RefPtr<DOMPointReadOnly> retval = new DOMPointReadOnly(aGlobal);
|
||||||
|
if (!retval->ReadStructuredClone(aReader)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return retval.forget();
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DOMPointReadOnly::ReadStructuredClone(JSStructuredCloneReader* aReader) {
|
||||||
|
uint32_t high;
|
||||||
|
uint32_t low;
|
||||||
|
|
||||||
|
#define ReadDouble(d) \
|
||||||
|
if (!JS_ReadUint32Pair(aReader, &high, &low)) { \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
(*(d) = BitwiseCast<double>(static_cast<uint64_t>(high) << 32 | low))
|
||||||
|
|
||||||
|
ReadDouble(&mX);
|
||||||
|
ReadDouble(&mY);
|
||||||
|
ReadDouble(&mZ);
|
||||||
|
ReadDouble(&mW);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
#undef ReadDouble
|
||||||
|
}
|
||||||
|
|
||||||
already_AddRefed<DOMPoint> DOMPoint::FromPoint(const GlobalObject& aGlobal,
|
already_AddRefed<DOMPoint> DOMPoint::FromPoint(const GlobalObject& aGlobal,
|
||||||
const DOMPointInit& aParams) {
|
const DOMPointInit& aParams) {
|
||||||
RefPtr<DOMPoint> obj = new DOMPoint(aGlobal.GetAsSupports(), aParams.mX,
|
RefPtr<DOMPoint> obj = new DOMPoint(aGlobal.GetAsSupports(), aParams.mX,
|
||||||
@ -44,8 +103,7 @@ already_AddRefed<DOMPoint> DOMPoint::FromPoint(const GlobalObject& aGlobal,
|
|||||||
|
|
||||||
already_AddRefed<DOMPoint> DOMPoint::Constructor(const GlobalObject& aGlobal,
|
already_AddRefed<DOMPoint> DOMPoint::Constructor(const GlobalObject& aGlobal,
|
||||||
double aX, double aY,
|
double aX, double aY,
|
||||||
double aZ, double aW,
|
double aZ, double aW) {
|
||||||
ErrorResult& aRV) {
|
|
||||||
RefPtr<DOMPoint> obj = new DOMPoint(aGlobal.GetAsSupports(), aX, aY, aZ, aW);
|
RefPtr<DOMPoint> obj = new DOMPoint(aGlobal.GetAsSupports(), aX, aY, aZ, aW);
|
||||||
return obj.forget();
|
return obj.forget();
|
||||||
}
|
}
|
||||||
@ -54,3 +112,15 @@ JSObject* DOMPoint::WrapObject(JSContext* aCx,
|
|||||||
JS::Handle<JSObject*> aGivenProto) {
|
JS::Handle<JSObject*> aGivenProto) {
|
||||||
return DOMPoint_Binding::Wrap(aCx, this, aGivenProto);
|
return DOMPoint_Binding::Wrap(aCx, this, aGivenProto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
already_AddRefed<DOMPoint> DOMPoint::ReadStructuredClone(
|
||||||
|
JSContext* aCx, nsIGlobalObject* aGlobal,
|
||||||
|
JSStructuredCloneReader* aReader) {
|
||||||
|
RefPtr<DOMPoint> retval = new DOMPoint(aGlobal);
|
||||||
|
if (!retval->ReadStructuredClone(aReader)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return retval.forget();
|
||||||
|
;
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#ifndef MOZILLA_DOMPOINT_H_
|
#ifndef MOZILLA_DOMPOINT_H_
|
||||||
#define MOZILLA_DOMPOINT_H_
|
#define MOZILLA_DOMPOINT_H_
|
||||||
|
|
||||||
|
#include "js/StructuredClone.h"
|
||||||
#include "nsWrapperCache.h"
|
#include "nsWrapperCache.h"
|
||||||
#include "nsISupports.h"
|
#include "nsISupports.h"
|
||||||
#include "nsCycleCollectionParticipant.h"
|
#include "nsCycleCollectionParticipant.h"
|
||||||
@ -13,23 +14,25 @@
|
|||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "mozilla/dom/BindingDeclarations.h"
|
#include "mozilla/dom/BindingDeclarations.h"
|
||||||
|
|
||||||
|
class nsIGlobalObject;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
class GlobalObject;
|
class GlobalObject;
|
||||||
struct DOMPointInit;
|
struct DOMPointInit;
|
||||||
|
struct DOMMatrixInit;
|
||||||
|
|
||||||
class DOMPointReadOnly : public nsWrapperCache {
|
class DOMPointReadOnly : public nsWrapperCache {
|
||||||
public:
|
public:
|
||||||
DOMPointReadOnly(nsISupports* aParent, double aX, double aY, double aZ,
|
explicit DOMPointReadOnly(nsISupports* aParent, double aX = 0.0,
|
||||||
double aW)
|
double aY = 0.0, double aZ = 0.0, double aW = 1.0)
|
||||||
: mParent(aParent), mX(aX), mY(aY), mZ(aZ), mW(aW) {}
|
: mParent(aParent), mX(aX), mY(aY), mZ(aZ), mW(aW) {}
|
||||||
|
|
||||||
static already_AddRefed<DOMPointReadOnly> FromPoint(
|
static already_AddRefed<DOMPointReadOnly> FromPoint(
|
||||||
const GlobalObject& aGlobal, const DOMPointInit& aParams);
|
const GlobalObject& aGlobal, const DOMPointInit& aParams);
|
||||||
static already_AddRefed<DOMPointReadOnly> Constructor(
|
static already_AddRefed<DOMPointReadOnly> Constructor(
|
||||||
const GlobalObject& aGlobal, double aX, double aY, double aZ, double aW,
|
const GlobalObject& aGlobal, double aX, double aY, double aZ, double aW);
|
||||||
ErrorResult& aRV);
|
|
||||||
|
|
||||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMPointReadOnly)
|
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMPointReadOnly)
|
||||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMPointReadOnly)
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMPointReadOnly)
|
||||||
@ -39,13 +42,27 @@ class DOMPointReadOnly : public nsWrapperCache {
|
|||||||
double Z() const { return mZ; }
|
double Z() const { return mZ; }
|
||||||
double W() const { return mW; }
|
double W() const { return mW; }
|
||||||
|
|
||||||
|
already_AddRefed<DOMPoint> MatrixTransform(const DOMMatrixInit& aInit,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
nsISupports* GetParentObject() const { return mParent; }
|
nsISupports* GetParentObject() const { return mParent; }
|
||||||
virtual JSObject* WrapObject(JSContext* aCx,
|
virtual JSObject* WrapObject(JSContext* aCx,
|
||||||
JS::Handle<JSObject*> aGivenProto) override;
|
JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
|
||||||
|
bool WriteStructuredClone(JSContext* aCx,
|
||||||
|
JSStructuredCloneWriter* aWriter) const;
|
||||||
|
|
||||||
|
static already_AddRefed<DOMPointReadOnly> ReadStructuredClone(
|
||||||
|
JSContext* aCx, nsIGlobalObject* aGlobal,
|
||||||
|
JSStructuredCloneReader* aReader);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~DOMPointReadOnly() {}
|
virtual ~DOMPointReadOnly() {}
|
||||||
|
|
||||||
|
// Shared implementation of ReadStructuredClone for DOMPoint and
|
||||||
|
// DOMPointReadOnly.
|
||||||
|
bool ReadStructuredClone(JSStructuredCloneReader* aReader);
|
||||||
|
|
||||||
nsCOMPtr<nsISupports> mParent;
|
nsCOMPtr<nsISupports> mParent;
|
||||||
double mX, mY, mZ, mW;
|
double mX, mY, mZ, mW;
|
||||||
};
|
};
|
||||||
@ -60,11 +77,16 @@ class DOMPoint final : public DOMPointReadOnly {
|
|||||||
const DOMPointInit& aParams);
|
const DOMPointInit& aParams);
|
||||||
static already_AddRefed<DOMPoint> Constructor(const GlobalObject& aGlobal,
|
static already_AddRefed<DOMPoint> Constructor(const GlobalObject& aGlobal,
|
||||||
double aX, double aY, double aZ,
|
double aX, double aY, double aZ,
|
||||||
double aW, ErrorResult& aRV);
|
double aW);
|
||||||
|
|
||||||
virtual JSObject* WrapObject(JSContext* aCx,
|
virtual JSObject* WrapObject(JSContext* aCx,
|
||||||
JS::Handle<JSObject*> aGivenProto) override;
|
JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
|
||||||
|
static already_AddRefed<DOMPoint> ReadStructuredClone(
|
||||||
|
JSContext* aCx, nsIGlobalObject* aGlobal,
|
||||||
|
JSStructuredCloneReader* aReader);
|
||||||
|
using DOMPointReadOnly::ReadStructuredClone;
|
||||||
|
|
||||||
void SetX(double aX) { mX = aX; }
|
void SetX(double aX) { mX = aX; }
|
||||||
void SetY(double aY) { mY = aY; }
|
void SetY(double aY) { mY = aY; }
|
||||||
void SetZ(double aZ) { mZ = aZ; }
|
void SetZ(double aZ) { mZ = aZ; }
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
/* 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 "DOMPrefs.h"
|
|
||||||
#include "mozilla/Atomics.h"
|
|
||||||
#include "mozilla/Preferences.h"
|
|
||||||
#include "mozilla/StaticPrefs.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace dom {
|
|
||||||
|
|
||||||
void DOMPrefs::Initialize() {
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
// Let's cache all the values on the main-thread.
|
|
||||||
#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
|
|
||||||
DOMPrefs::DumpEnabled();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DOM_WEBIDL_PREF(name)
|
|
||||||
|
|
||||||
#include "DOMPrefsInternal.h"
|
|
||||||
|
|
||||||
#undef DOM_WEBIDL_PREF
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */
|
|
||||||
bool DOMPrefs::DumpEnabled() {
|
|
||||||
#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
|
|
||||||
return StaticPrefs::browser_dom_window_dump_enabled();
|
|
||||||
#else
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DOM_WEBIDL_PREF(name) \
|
|
||||||
/* static */ bool DOMPrefs::name(JSContext* aCx, JSObject* aObj) { \
|
|
||||||
return StaticPrefs::name(); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "DOMPrefsInternal.h"
|
|
||||||
|
|
||||||
#undef DOM_WEBIDL_PREF
|
|
||||||
|
|
||||||
} // namespace dom
|
|
||||||
} // namespace mozilla
|
|
@ -1,29 +0,0 @@
|
|||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#ifndef mozilla_dom_DOMPrefs_h
|
|
||||||
#define mozilla_dom_DOMPrefs_h
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace dom {
|
|
||||||
|
|
||||||
class DOMPrefs final {
|
|
||||||
public:
|
|
||||||
// This must be called on the main-thread.
|
|
||||||
static void Initialize();
|
|
||||||
|
|
||||||
// Returns true if the browser.dom.window.dump.enabled pref is set.
|
|
||||||
static bool DumpEnabled();
|
|
||||||
|
|
||||||
#define DOM_WEBIDL_PREF(name) static bool name(JSContext* aCx, JSObject* aObj);
|
|
||||||
|
|
||||||
#include "DOMPrefsInternal.h"
|
|
||||||
|
|
||||||
#undef DOM_WEBIDL_PREF
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace dom
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#endif // mozilla_dom_DOMPrefs_h
|
|
@ -1,31 +0,0 @@
|
|||||||
/* 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/. */
|
|
||||||
|
|
||||||
// This is the list of the preferences that are exposed to workers and
|
|
||||||
// main-thread in DOM.
|
|
||||||
// The format is as follows:
|
|
||||||
//
|
|
||||||
// DOM_WEBIDL_PREF(foo_bar)
|
|
||||||
//
|
|
||||||
// * This defines DOMPrefs::foo_bar(JSContext* aCx, JSObject* aObj) which
|
|
||||||
// returns the value of StaticPrefs::foo_bar().
|
|
||||||
// This is allows the use of DOMPrefs in WebIDL files.
|
|
||||||
|
|
||||||
DOM_WEBIDL_PREF(dom_caches_enabled)
|
|
||||||
DOM_WEBIDL_PREF(dom_webnotifications_serviceworker_enabled)
|
|
||||||
DOM_WEBIDL_PREF(dom_webnotifications_requireinteraction_enabled)
|
|
||||||
DOM_WEBIDL_PREF(dom_serviceWorkers_enabled)
|
|
||||||
DOM_WEBIDL_PREF(dom_storageManager_enabled)
|
|
||||||
DOM_WEBIDL_PREF(dom_testing_structuredclonetester_enabled)
|
|
||||||
DOM_WEBIDL_PREF(dom_promise_rejection_events_enabled)
|
|
||||||
DOM_WEBIDL_PREF(dom_push_enabled)
|
|
||||||
DOM_WEBIDL_PREF(gfx_offscreencanvas_enabled)
|
|
||||||
DOM_WEBIDL_PREF(dom_webkitBlink_dirPicker_enabled)
|
|
||||||
DOM_WEBIDL_PREF(dom_netinfo_enabled)
|
|
||||||
DOM_WEBIDL_PREF(dom_fetchObserver_enabled)
|
|
||||||
DOM_WEBIDL_PREF(dom_enable_performance_observer)
|
|
||||||
DOM_WEBIDL_PREF(dom_reporting_enabled)
|
|
||||||
DOM_WEBIDL_PREF(dom_reporting_testing_enabled)
|
|
||||||
DOM_WEBIDL_PREF(dom_reporting_featurePolicy_enabled)
|
|
||||||
DOM_WEBIDL_PREF(javascript_options_streams)
|
|
@ -7,14 +7,15 @@
|
|||||||
#include "mozilla/dom/DOMQuadBinding.h"
|
#include "mozilla/dom/DOMQuadBinding.h"
|
||||||
#include "mozilla/dom/DOMPoint.h"
|
#include "mozilla/dom/DOMPoint.h"
|
||||||
#include "mozilla/dom/DOMRect.h"
|
#include "mozilla/dom/DOMRect.h"
|
||||||
|
#include "mozilla/dom/DOMRectBinding.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
using namespace mozilla::gfx;
|
using namespace mozilla::gfx;
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMQuad, mParent, mBounds, mPoints[0],
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMQuad, mParent, mPoints[0], mPoints[1],
|
||||||
mPoints[1], mPoints[2], mPoints[3])
|
mPoints[2], mPoints[3])
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMQuad, AddRef)
|
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMQuad, AddRef)
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMQuad, Release)
|
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMQuad, Release)
|
||||||
@ -34,12 +35,35 @@ JSObject* DOMQuad::WrapObject(JSContext* aCx,
|
|||||||
return DOMQuad_Binding::Wrap(aCx, this, aGivenProto);
|
return DOMQuad_Binding::Wrap(aCx, this, aGivenProto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<DOMQuad> DOMQuad::FromRect(const GlobalObject& aGlobal,
|
||||||
|
const DOMRectInit& aInit) {
|
||||||
|
nsISupports* parent = aGlobal.GetAsSupports();
|
||||||
|
RefPtr<DOMQuad> obj = new DOMQuad(parent);
|
||||||
|
obj->mPoints[0] = new DOMPoint(parent, aInit.mX, aInit.mY, 0, 1);
|
||||||
|
obj->mPoints[1] =
|
||||||
|
new DOMPoint(parent, aInit.mX + aInit.mWidth, aInit.mY, 0, 1);
|
||||||
|
obj->mPoints[2] = new DOMPoint(parent, aInit.mX + aInit.mWidth,
|
||||||
|
aInit.mY + aInit.mHeight, 0, 1);
|
||||||
|
obj->mPoints[3] =
|
||||||
|
new DOMPoint(parent, aInit.mX, aInit.mY + aInit.mHeight, 0, 1);
|
||||||
|
return obj.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<DOMQuad> DOMQuad::FromQuad(const GlobalObject& aGlobal,
|
||||||
|
const DOMQuadInit& aInit) {
|
||||||
|
RefPtr<DOMQuad> obj = new DOMQuad(aGlobal.GetAsSupports());
|
||||||
|
obj->mPoints[0] = DOMPoint::FromPoint(aGlobal, aInit.mP1);
|
||||||
|
obj->mPoints[1] = DOMPoint::FromPoint(aGlobal, aInit.mP2);
|
||||||
|
obj->mPoints[2] = DOMPoint::FromPoint(aGlobal, aInit.mP3);
|
||||||
|
obj->mPoints[3] = DOMPoint::FromPoint(aGlobal, aInit.mP4);
|
||||||
|
return obj.forget();
|
||||||
|
}
|
||||||
|
|
||||||
already_AddRefed<DOMQuad> DOMQuad::Constructor(const GlobalObject& aGlobal,
|
already_AddRefed<DOMQuad> DOMQuad::Constructor(const GlobalObject& aGlobal,
|
||||||
const DOMPointInit& aP1,
|
const DOMPointInit& aP1,
|
||||||
const DOMPointInit& aP2,
|
const DOMPointInit& aP2,
|
||||||
const DOMPointInit& aP3,
|
const DOMPointInit& aP3,
|
||||||
const DOMPointInit& aP4,
|
const DOMPointInit& aP4) {
|
||||||
ErrorResult& aRV) {
|
|
||||||
RefPtr<DOMQuad> obj = new DOMQuad(aGlobal.GetAsSupports());
|
RefPtr<DOMQuad> obj = new DOMQuad(aGlobal.GetAsSupports());
|
||||||
obj->mPoints[0] = DOMPoint::FromPoint(aGlobal, aP1);
|
obj->mPoints[0] = DOMPoint::FromPoint(aGlobal, aP1);
|
||||||
obj->mPoints[1] = DOMPoint::FromPoint(aGlobal, aP2);
|
obj->mPoints[1] = DOMPoint::FromPoint(aGlobal, aP2);
|
||||||
@ -49,8 +73,7 @@ already_AddRefed<DOMQuad> DOMQuad::Constructor(const GlobalObject& aGlobal,
|
|||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<DOMQuad> DOMQuad::Constructor(const GlobalObject& aGlobal,
|
already_AddRefed<DOMQuad> DOMQuad::Constructor(const GlobalObject& aGlobal,
|
||||||
const DOMRectReadOnly& aRect,
|
const DOMRectReadOnly& aRect) {
|
||||||
ErrorResult& aRV) {
|
|
||||||
CSSPoint points[4];
|
CSSPoint points[4];
|
||||||
Float x = aRect.X(), y = aRect.Y(), w = aRect.Width(), h = aRect.Height();
|
Float x = aRect.X(), y = aRect.Y(), w = aRect.Width(), h = aRect.Height();
|
||||||
points[0] = CSSPoint(x, y);
|
points[0] = CSSPoint(x, y);
|
||||||
@ -85,13 +108,6 @@ void DOMQuad::GetVerticalMinMax(double* aY1, double* aY2) const {
|
|||||||
*aY2 = y2;
|
*aY2 = y2;
|
||||||
}
|
}
|
||||||
|
|
||||||
DOMRectReadOnly* DOMQuad::Bounds() {
|
|
||||||
if (!mBounds) {
|
|
||||||
mBounds = GetBounds();
|
|
||||||
}
|
|
||||||
return mBounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<DOMRectReadOnly> DOMQuad::GetBounds() const {
|
already_AddRefed<DOMRectReadOnly> DOMQuad::GetBounds() const {
|
||||||
double x1, x2;
|
double x1, x2;
|
||||||
double y1, y2;
|
double y1, y2;
|
||||||
@ -104,9 +120,27 @@ already_AddRefed<DOMRectReadOnly> DOMQuad::GetBounds() const {
|
|||||||
return rval.forget();
|
return rval.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DOMQuad::ToJSON(DOMQuadJSON& aInit) {
|
// https://drafts.fxtf.org/geometry/#structured-serialization
|
||||||
aInit.mP1.Construct(RefPtr<DOMPoint>(P1()).forget());
|
bool DOMQuad::WriteStructuredClone(JSContext* aCx,
|
||||||
aInit.mP2.Construct(RefPtr<DOMPoint>(P2()).forget());
|
JSStructuredCloneWriter* aWriter) const {
|
||||||
aInit.mP3.Construct(RefPtr<DOMPoint>(P3()).forget());
|
for (const auto& point : mPoints) {
|
||||||
aInit.mP4.Construct(RefPtr<DOMPoint>(P4()).forget());
|
if (!point->WriteStructuredClone(aCx, aWriter)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
already_AddRefed<DOMQuad> DOMQuad::ReadStructuredClone(
|
||||||
|
JSContext* aCx, nsIGlobalObject* aGlobal,
|
||||||
|
JSStructuredCloneReader* aReader) {
|
||||||
|
RefPtr<DOMQuad> quad = new DOMQuad(aGlobal);
|
||||||
|
for (auto& point : quad->mPoints) {
|
||||||
|
point = DOMPoint::ReadStructuredClone(aCx, aGlobal, aReader);
|
||||||
|
if (!point) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return quad.forget();
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#ifndef MOZILLA_DOMQUAD_H_
|
#ifndef MOZILLA_DOMQUAD_H_
|
||||||
#define MOZILLA_DOMQUAD_H_
|
#define MOZILLA_DOMQUAD_H_
|
||||||
|
|
||||||
|
#include "js/StructuredClone.h"
|
||||||
#include "nsWrapperCache.h"
|
#include "nsWrapperCache.h"
|
||||||
#include "nsISupports.h"
|
#include "nsISupports.h"
|
||||||
#include "nsCycleCollectionParticipant.h"
|
#include "nsCycleCollectionParticipant.h"
|
||||||
@ -14,13 +15,16 @@
|
|||||||
#include "mozilla/ErrorResult.h"
|
#include "mozilla/ErrorResult.h"
|
||||||
#include "Units.h"
|
#include "Units.h"
|
||||||
|
|
||||||
|
class nsIGlobalObject;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
class DOMRectReadOnly;
|
class DOMRectReadOnly;
|
||||||
class DOMPoint;
|
class DOMPoint;
|
||||||
struct DOMQuadJSON;
|
|
||||||
struct DOMPointInit;
|
struct DOMPointInit;
|
||||||
|
struct DOMQuadInit;
|
||||||
|
struct DOMRectInit;
|
||||||
|
|
||||||
class DOMQuad final : public nsWrapperCache {
|
class DOMQuad final : public nsWrapperCache {
|
||||||
~DOMQuad();
|
~DOMQuad();
|
||||||
@ -36,17 +40,20 @@ class DOMQuad final : public nsWrapperCache {
|
|||||||
virtual JSObject* WrapObject(JSContext* aCx,
|
virtual JSObject* WrapObject(JSContext* aCx,
|
||||||
JS::Handle<JSObject*> aGivenProto) override;
|
JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
|
||||||
|
static already_AddRefed<DOMQuad> FromRect(const GlobalObject& aGlobal,
|
||||||
|
const DOMRectInit& aInit);
|
||||||
|
|
||||||
|
static already_AddRefed<DOMQuad> FromQuad(const GlobalObject& aGlobal,
|
||||||
|
const DOMQuadInit& aInit);
|
||||||
|
|
||||||
static already_AddRefed<DOMQuad> Constructor(const GlobalObject& aGlobal,
|
static already_AddRefed<DOMQuad> Constructor(const GlobalObject& aGlobal,
|
||||||
const DOMPointInit& aP1,
|
const DOMPointInit& aP1,
|
||||||
const DOMPointInit& aP2,
|
const DOMPointInit& aP2,
|
||||||
const DOMPointInit& aP3,
|
const DOMPointInit& aP3,
|
||||||
const DOMPointInit& aP4,
|
const DOMPointInit& aP4);
|
||||||
ErrorResult& aRV);
|
|
||||||
static already_AddRefed<DOMQuad> Constructor(const GlobalObject& aGlobal,
|
static already_AddRefed<DOMQuad> Constructor(const GlobalObject& aGlobal,
|
||||||
const DOMRectReadOnly& aRect,
|
const DOMRectReadOnly& aRect);
|
||||||
ErrorResult& aRV);
|
|
||||||
|
|
||||||
DOMRectReadOnly* Bounds();
|
|
||||||
already_AddRefed<DOMRectReadOnly> GetBounds() const;
|
already_AddRefed<DOMRectReadOnly> GetBounds() const;
|
||||||
DOMPoint* P1() const { return mPoints[0]; }
|
DOMPoint* P1() const { return mPoints[0]; }
|
||||||
DOMPoint* P2() const { return mPoints[1]; }
|
DOMPoint* P2() const { return mPoints[1]; }
|
||||||
@ -55,7 +62,12 @@ class DOMQuad final : public nsWrapperCache {
|
|||||||
|
|
||||||
DOMPoint* Point(uint32_t aIndex) const { return mPoints[aIndex]; }
|
DOMPoint* Point(uint32_t aIndex) const { return mPoints[aIndex]; }
|
||||||
|
|
||||||
void ToJSON(DOMQuadJSON& aInit);
|
bool WriteStructuredClone(JSContext* aCx,
|
||||||
|
JSStructuredCloneWriter* aWriter) const;
|
||||||
|
|
||||||
|
static already_AddRefed<DOMQuad> ReadStructuredClone(
|
||||||
|
JSContext* aCx, nsIGlobalObject* aGlobal,
|
||||||
|
JSStructuredCloneReader* aReader);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void GetHorizontalMinMax(double* aX1, double* aX2) const;
|
void GetHorizontalMinMax(double* aX1, double* aX2) const;
|
||||||
@ -63,7 +75,6 @@ class DOMQuad final : public nsWrapperCache {
|
|||||||
|
|
||||||
nsCOMPtr<nsISupports> mParent;
|
nsCOMPtr<nsISupports> mParent;
|
||||||
RefPtr<DOMPoint> mPoints[4];
|
RefPtr<DOMPoint> mPoints[4];
|
||||||
RefPtr<DOMRectReadOnly> mBounds;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
@ -25,14 +25,65 @@ JSObject* DOMRectReadOnly::WrapObject(JSContext* aCx,
|
|||||||
return DOMRectReadOnly_Binding::Wrap(aCx, this, aGivenProto);
|
return DOMRectReadOnly_Binding::Wrap(aCx, this, aGivenProto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<DOMRectReadOnly> DOMRectReadOnly::FromRect(
|
||||||
|
const GlobalObject& aGlobal, const DOMRectInit& aInit) {
|
||||||
|
RefPtr<DOMRectReadOnly> obj = new DOMRectReadOnly(
|
||||||
|
aGlobal.GetAsSupports(), aInit.mX, aInit.mY, aInit.mWidth, aInit.mHeight);
|
||||||
|
return obj.forget();
|
||||||
|
}
|
||||||
|
|
||||||
already_AddRefed<DOMRectReadOnly> DOMRectReadOnly::Constructor(
|
already_AddRefed<DOMRectReadOnly> DOMRectReadOnly::Constructor(
|
||||||
const GlobalObject& aGlobal, double aX, double aY, double aWidth,
|
const GlobalObject& aGlobal, double aX, double aY, double aWidth,
|
||||||
double aHeight, ErrorResult& aRv) {
|
double aHeight) {
|
||||||
RefPtr<DOMRectReadOnly> obj =
|
RefPtr<DOMRectReadOnly> obj =
|
||||||
new DOMRectReadOnly(aGlobal.GetAsSupports(), aX, aY, aWidth, aHeight);
|
new DOMRectReadOnly(aGlobal.GetAsSupports(), aX, aY, aWidth, aHeight);
|
||||||
return obj.forget();
|
return obj.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://drafts.fxtf.org/geometry/#structured-serialization
|
||||||
|
bool DOMRectReadOnly::WriteStructuredClone(
|
||||||
|
JSContext* aCx, JSStructuredCloneWriter* aWriter) const {
|
||||||
|
#define WriteDouble(d) \
|
||||||
|
JS_WriteUint32Pair(aWriter, (BitwiseCast<uint64_t>(d) >> 32) & 0xffffffff, \
|
||||||
|
BitwiseCast<uint64_t>(d) & 0xffffffff)
|
||||||
|
|
||||||
|
return WriteDouble(mX) && WriteDouble(mY) && WriteDouble(mWidth) &&
|
||||||
|
WriteDouble(mHeight);
|
||||||
|
|
||||||
|
#undef WriteDouble
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
already_AddRefed<DOMRectReadOnly> DOMRectReadOnly::ReadStructuredClone(
|
||||||
|
JSContext* aCx, nsIGlobalObject* aGlobal,
|
||||||
|
JSStructuredCloneReader* aReader) {
|
||||||
|
RefPtr<DOMRectReadOnly> retval = new DOMRectReadOnly(aGlobal);
|
||||||
|
if (!retval->ReadStructuredClone(aReader)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return retval.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DOMRectReadOnly::ReadStructuredClone(JSStructuredCloneReader* aReader) {
|
||||||
|
uint32_t high;
|
||||||
|
uint32_t low;
|
||||||
|
|
||||||
|
#define ReadDouble(d) \
|
||||||
|
if (!JS_ReadUint32Pair(aReader, &high, &low)) { \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
(*(d) = BitwiseCast<double>(static_cast<uint64_t>(high) << 32 | low))
|
||||||
|
|
||||||
|
ReadDouble(&mX);
|
||||||
|
ReadDouble(&mY);
|
||||||
|
ReadDouble(&mWidth);
|
||||||
|
ReadDouble(&mHeight);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#undef ReadDouble
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
JSObject* DOMRect::WrapObject(JSContext* aCx,
|
JSObject* DOMRect::WrapObject(JSContext* aCx,
|
||||||
@ -41,15 +92,32 @@ JSObject* DOMRect::WrapObject(JSContext* aCx,
|
|||||||
return DOMRect_Binding::Wrap(aCx, this, aGivenProto);
|
return DOMRect_Binding::Wrap(aCx, this, aGivenProto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<DOMRect> DOMRect::FromRect(const GlobalObject& aGlobal,
|
||||||
|
const DOMRectInit& aInit) {
|
||||||
|
RefPtr<DOMRect> obj = new DOMRect(aGlobal.GetAsSupports(), aInit.mX, aInit.mY,
|
||||||
|
aInit.mWidth, aInit.mHeight);
|
||||||
|
return obj.forget();
|
||||||
|
}
|
||||||
|
|
||||||
already_AddRefed<DOMRect> DOMRect::Constructor(const GlobalObject& aGlobal,
|
already_AddRefed<DOMRect> DOMRect::Constructor(const GlobalObject& aGlobal,
|
||||||
double aX, double aY,
|
double aX, double aY,
|
||||||
double aWidth, double aHeight,
|
double aWidth, double aHeight) {
|
||||||
ErrorResult& aRv) {
|
|
||||||
RefPtr<DOMRect> obj =
|
RefPtr<DOMRect> obj =
|
||||||
new DOMRect(aGlobal.GetAsSupports(), aX, aY, aWidth, aHeight);
|
new DOMRect(aGlobal.GetAsSupports(), aX, aY, aWidth, aHeight);
|
||||||
return obj.forget();
|
return obj.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
already_AddRefed<DOMRect> DOMRect::ReadStructuredClone(
|
||||||
|
JSContext* aCx, nsIGlobalObject* aGlobal,
|
||||||
|
JSStructuredCloneReader* aReader) {
|
||||||
|
RefPtr<DOMRect> retval = new DOMRect(aGlobal);
|
||||||
|
if (!retval->ReadStructuredClone(aReader)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return retval.forget();
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMRectList, mParent, mArray)
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMRectList, mParent, mArray)
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#ifndef MOZILLA_DOMRECT_H_
|
#ifndef MOZILLA_DOMRECT_H_
|
||||||
#define MOZILLA_DOMRECT_H_
|
#define MOZILLA_DOMRECT_H_
|
||||||
|
|
||||||
|
#include "js/StructuredClone.h"
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsWrapperCache.h"
|
#include "nsWrapperCache.h"
|
||||||
@ -15,10 +16,13 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
struct nsRect;
|
struct nsRect;
|
||||||
|
class nsIGlobalObject;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
|
struct DOMRectInit;
|
||||||
|
|
||||||
class DOMRectReadOnly : public nsISupports, public nsWrapperCache {
|
class DOMRectReadOnly : public nsISupports, public nsWrapperCache {
|
||||||
protected:
|
protected:
|
||||||
virtual ~DOMRectReadOnly() {}
|
virtual ~DOMRectReadOnly() {}
|
||||||
@ -39,9 +43,12 @@ class DOMRectReadOnly : public nsISupports, public nsWrapperCache {
|
|||||||
virtual JSObject* WrapObject(JSContext* aCx,
|
virtual JSObject* WrapObject(JSContext* aCx,
|
||||||
JS::Handle<JSObject*> aGivenProto) override;
|
JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
|
||||||
|
static already_AddRefed<DOMRectReadOnly> FromRect(const GlobalObject& aGlobal,
|
||||||
|
const DOMRectInit& aInit);
|
||||||
|
|
||||||
static already_AddRefed<DOMRectReadOnly> Constructor(
|
static already_AddRefed<DOMRectReadOnly> Constructor(
|
||||||
const GlobalObject& aGlobal, double aX, double aY, double aWidth,
|
const GlobalObject& aGlobal, double aX, double aY, double aWidth,
|
||||||
double aHeight, ErrorResult& aRv);
|
double aHeight);
|
||||||
|
|
||||||
double X() const { return mX; }
|
double X() const { return mX; }
|
||||||
double Y() const { return mY; }
|
double Y() const { return mY; }
|
||||||
@ -65,7 +72,18 @@ class DOMRectReadOnly : public nsISupports, public nsWrapperCache {
|
|||||||
return std::max(y, y + h);
|
return std::max(y, y + h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WriteStructuredClone(JSContext* aCx,
|
||||||
|
JSStructuredCloneWriter* aWriter) const;
|
||||||
|
|
||||||
|
static already_AddRefed<DOMRectReadOnly> ReadStructuredClone(
|
||||||
|
JSContext* aCx, nsIGlobalObject* aGlobal,
|
||||||
|
JSStructuredCloneReader* aReader);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// Shared implementation of ReadStructuredClone for DOMRect and
|
||||||
|
// DOMRectReadOnly.
|
||||||
|
bool ReadStructuredClone(JSStructuredCloneReader* aReader);
|
||||||
|
|
||||||
nsCOMPtr<nsISupports> mParent;
|
nsCOMPtr<nsISupports> mParent;
|
||||||
double mX, mY, mWidth, mHeight;
|
double mX, mY, mWidth, mHeight;
|
||||||
};
|
};
|
||||||
@ -78,14 +96,21 @@ class DOMRect final : public DOMRectReadOnly {
|
|||||||
|
|
||||||
NS_INLINE_DECL_REFCOUNTING_INHERITED(DOMRect, DOMRectReadOnly)
|
NS_INLINE_DECL_REFCOUNTING_INHERITED(DOMRect, DOMRectReadOnly)
|
||||||
|
|
||||||
|
static already_AddRefed<DOMRect> FromRect(const GlobalObject& aGlobal,
|
||||||
|
const DOMRectInit& aInit);
|
||||||
|
|
||||||
static already_AddRefed<DOMRect> Constructor(const GlobalObject& aGlobal,
|
static already_AddRefed<DOMRect> Constructor(const GlobalObject& aGlobal,
|
||||||
double aX, double aY,
|
double aX, double aY,
|
||||||
double aWidth, double aHeight,
|
double aWidth, double aHeight);
|
||||||
ErrorResult& aRv);
|
|
||||||
|
|
||||||
virtual JSObject* WrapObject(JSContext* aCx,
|
virtual JSObject* WrapObject(JSContext* aCx,
|
||||||
JS::Handle<JSObject*> aGivenProto) override;
|
JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
|
||||||
|
static already_AddRefed<DOMRect> ReadStructuredClone(
|
||||||
|
JSContext* aCx, nsIGlobalObject* aGlobal,
|
||||||
|
JSStructuredCloneReader* aReader);
|
||||||
|
using DOMRectReadOnly::ReadStructuredClone;
|
||||||
|
|
||||||
void SetRect(float aX, float aY, float aWidth, float aHeight) {
|
void SetRect(float aX, float aY, float aWidth, float aHeight) {
|
||||||
mX = aX;
|
mX = aX;
|
||||||
mY = aY;
|
mY = aY;
|
||||||
|
@ -222,11 +222,12 @@
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
using mozilla::dom::Element;
|
using mozilla::dom::Element;
|
||||||
|
using mozilla::dom::HTMLSlotElement;
|
||||||
using mozilla::dom::ShadowRoot;
|
using mozilla::dom::ShadowRoot;
|
||||||
|
|
||||||
static nsIContent* GetParentOrHostOrSlot(
|
static nsIContent* GetParentOrHostOrSlot(
|
||||||
nsIContent* aContent, bool* aCrossedShadowBoundary = nullptr) {
|
nsIContent* aContent, bool* aCrossedShadowBoundary = nullptr) {
|
||||||
HTMLSlotElement* slot = aContent->GetAssignedSlot();
|
mozilla::dom::HTMLSlotElement* slot = aContent->GetAssignedSlot();
|
||||||
if (slot) {
|
if (slot) {
|
||||||
if (aCrossedShadowBoundary) {
|
if (aCrossedShadowBoundary) {
|
||||||
*aCrossedShadowBoundary = true;
|
*aCrossedShadowBoundary = true;
|
||||||
@ -376,14 +377,14 @@ static Directionality GetDirectionFromText(const char* aText,
|
|||||||
return eDir_NotSet;
|
return eDir_NotSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Directionality GetDirectionFromText(const nsTextFragment* aFrag,
|
static Directionality GetDirectionFromText(const mozilla::dom::Text* aTextNode,
|
||||||
uint32_t* aFirstStrong = nullptr) {
|
uint32_t* aFirstStrong = nullptr) {
|
||||||
if (aFrag->Is2b()) {
|
const nsTextFragment* frag = &aTextNode->TextFragment();
|
||||||
return GetDirectionFromText(aFrag->Get2b(), aFrag->GetLength(),
|
if (frag->Is2b()) {
|
||||||
aFirstStrong);
|
return GetDirectionFromText(frag->Get2b(), frag->GetLength(), aFirstStrong);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetDirectionFromText(aFrag->Get1b(), aFrag->GetLength(), aFirstStrong);
|
return GetDirectionFromText(frag->Get1b(), frag->GetLength(), aFirstStrong);
|
||||||
}
|
}
|
||||||
|
|
||||||
static nsTextNode* WalkDescendantsAndGetDirectionFromText(
|
static nsTextNode* WalkDescendantsAndGetDirectionFromText(
|
||||||
@ -397,18 +398,19 @@ static nsTextNode* WalkDescendantsAndGetDirectionFromText(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
HTMLSlotElement* slot = HTMLSlotElement::FromNode(child);
|
mozilla::dom::HTMLSlotElement* slot =
|
||||||
|
mozilla::dom::HTMLSlotElement::FromNode(child);
|
||||||
if (slot) {
|
if (slot) {
|
||||||
const nsTArray<RefPtr<nsINode>>& assignedNodes = slot->AssignedNodes();
|
const nsTArray<RefPtr<nsINode>>& assignedNodes = slot->AssignedNodes();
|
||||||
for (uint32_t i = 0; i < assignedNodes.Length(); ++i) {
|
for (uint32_t i = 0; i < assignedNodes.Length(); ++i) {
|
||||||
nsIContent* assignedNode = assignedNodes[i]->AsContent();
|
nsIContent* assignedNode = assignedNodes[i]->AsContent();
|
||||||
if (assignedNode->NodeType() == nsINode::TEXT_NODE) {
|
if (assignedNode->NodeType() == nsINode::TEXT_NODE) {
|
||||||
|
auto text = static_cast<nsTextNode*>(assignedNode);
|
||||||
if (assignedNode != aSkip) {
|
if (assignedNode != aSkip) {
|
||||||
Directionality textNodeDir =
|
Directionality textNodeDir = GetDirectionFromText(text);
|
||||||
GetDirectionFromText(assignedNode->GetText());
|
|
||||||
if (textNodeDir != eDir_NotSet) {
|
if (textNodeDir != eDir_NotSet) {
|
||||||
*aDirectionality = textNodeDir;
|
*aDirectionality = textNodeDir;
|
||||||
return static_cast<nsTextNode*>(assignedNode);
|
return text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (assignedNode->IsElement() &&
|
} else if (assignedNode->IsElement() &&
|
||||||
@ -424,10 +426,11 @@ static nsTextNode* WalkDescendantsAndGetDirectionFromText(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (child->NodeType() == nsINode::TEXT_NODE && child != aSkip) {
|
if (child->NodeType() == nsINode::TEXT_NODE && child != aSkip) {
|
||||||
Directionality textNodeDir = GetDirectionFromText(child->GetText());
|
auto text = static_cast<nsTextNode*>(child);
|
||||||
|
Directionality textNodeDir = GetDirectionFromText(text);
|
||||||
if (textNodeDir != eDir_NotSet) {
|
if (textNodeDir != eDir_NotSet) {
|
||||||
*aDirectionality = textNodeDir;
|
*aDirectionality = textNodeDir;
|
||||||
return static_cast<nsTextNode*>(child);
|
return text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
child = child->GetNextNode(aRoot);
|
child = child->GetNextNode(aRoot);
|
||||||
@ -724,7 +727,8 @@ static void SetDirectionalityOnDescendantsInternal(nsINode* aNode,
|
|||||||
SetDirectionalityOnDescendantsInternal(shadow, aDir, aNotify);
|
SetDirectionalityOnDescendantsInternal(shadow, aDir, aNotify);
|
||||||
}
|
}
|
||||||
|
|
||||||
HTMLSlotElement* slot = HTMLSlotElement::FromNode(child);
|
mozilla::dom::HTMLSlotElement* slot =
|
||||||
|
mozilla::dom::HTMLSlotElement::FromNode(child);
|
||||||
if (slot) {
|
if (slot) {
|
||||||
const nsTArray<RefPtr<nsINode>>& assignedNodes = slot->AssignedNodes();
|
const nsTArray<RefPtr<nsINode>>& assignedNodes = slot->AssignedNodes();
|
||||||
for (uint32_t i = 0; i < assignedNodes.Length(); ++i) {
|
for (uint32_t i = 0; i < assignedNodes.Length(); ++i) {
|
||||||
@ -816,7 +820,7 @@ void WalkAncestorsResetAutoDirection(Element* aElement, bool aNotify) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SlotStateChanged(HTMLSlotElement* aSlot) {
|
void SlotStateChanged(mozilla::dom::HTMLSlotElement* aSlot) {
|
||||||
if (!aSlot) {
|
if (!aSlot) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -889,7 +893,8 @@ static void SetAncestorHasDirAutoOnDescendants(nsINode* aRoot) {
|
|||||||
if (!child->GetAssignedSlot()) {
|
if (!child->GetAssignedSlot()) {
|
||||||
MaybeSetAncestorHasDirAutoOnShadowDOM(child);
|
MaybeSetAncestorHasDirAutoOnShadowDOM(child);
|
||||||
child->SetAncestorHasDirAuto();
|
child->SetAncestorHasDirAuto();
|
||||||
HTMLSlotElement* slot = HTMLSlotElement::FromNode(child);
|
mozilla::dom::HTMLSlotElement* slot =
|
||||||
|
mozilla::dom::HTMLSlotElement::FromNode(child);
|
||||||
if (slot) {
|
if (slot) {
|
||||||
const nsTArray<RefPtr<nsINode>>& assignedNodes = slot->AssignedNodes();
|
const nsTArray<RefPtr<nsINode>>& assignedNodes = slot->AssignedNodes();
|
||||||
for (uint32_t i = 0; i < assignedNodes.Length(); ++i) {
|
for (uint32_t i = 0; i < assignedNodes.Length(); ++i) {
|
||||||
@ -942,7 +947,8 @@ void WalkDescendantsClearAncestorDirAuto(nsIContent* aContent) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
HTMLSlotElement* slot = HTMLSlotElement::FromNode(child);
|
mozilla::dom::HTMLSlotElement* slot =
|
||||||
|
mozilla::dom::HTMLSlotElement::FromNode(child);
|
||||||
if (slot) {
|
if (slot) {
|
||||||
const nsTArray<RefPtr<nsINode>>& assignedNodes = slot->AssignedNodes();
|
const nsTArray<RefPtr<nsINode>>& assignedNodes = slot->AssignedNodes();
|
||||||
for (uint32_t i = 0; i < assignedNodes.Length(); ++i) {
|
for (uint32_t i = 0; i < assignedNodes.Length(); ++i) {
|
||||||
@ -1050,7 +1056,7 @@ void SetAncestorDirectionIfAuto(nsTextNode* aTextNode, Directionality aDir,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextNodeWillChangeDirection(nsIContent* aTextNode, Directionality* aOldDir,
|
bool TextNodeWillChangeDirection(nsTextNode* aTextNode, Directionality* aOldDir,
|
||||||
uint32_t aOffset) {
|
uint32_t aOffset) {
|
||||||
if (!NodeAffectsDirAutoAncestor(aTextNode)) {
|
if (!NodeAffectsDirAutoAncestor(aTextNode)) {
|
||||||
nsTextNodeDirectionalityMap::EnsureMapIsClearFor(aTextNode);
|
nsTextNodeDirectionalityMap::EnsureMapIsClearFor(aTextNode);
|
||||||
@ -1058,13 +1064,13 @@ bool TextNodeWillChangeDirection(nsIContent* aTextNode, Directionality* aOldDir,
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t firstStrong;
|
uint32_t firstStrong;
|
||||||
*aOldDir = GetDirectionFromText(aTextNode->GetText(), &firstStrong);
|
*aOldDir = GetDirectionFromText(aTextNode, &firstStrong);
|
||||||
return (aOffset <= firstStrong);
|
return (aOffset <= firstStrong);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextNodeChangedDirection(nsTextNode* aTextNode, Directionality aOldDir,
|
void TextNodeChangedDirection(nsTextNode* aTextNode, Directionality aOldDir,
|
||||||
bool aNotify) {
|
bool aNotify) {
|
||||||
Directionality newDir = GetDirectionFromText(aTextNode->GetText());
|
Directionality newDir = GetDirectionFromText(aTextNode);
|
||||||
if (newDir == eDir_NotSet) {
|
if (newDir == eDir_NotSet) {
|
||||||
if (aOldDir != eDir_NotSet && aTextNode->HasTextNodeDirectionalityMap()) {
|
if (aOldDir != eDir_NotSet && aTextNode->HasTextNodeDirectionalityMap()) {
|
||||||
// This node used to have a strong directional character but no
|
// This node used to have a strong directional character but no
|
||||||
@ -1100,7 +1106,7 @@ void SetDirectionFromNewTextNode(nsTextNode* aTextNode) {
|
|||||||
aTextNode->SetAncestorHasDirAuto();
|
aTextNode->SetAncestorHasDirAuto();
|
||||||
}
|
}
|
||||||
|
|
||||||
Directionality dir = GetDirectionFromText(aTextNode->GetText());
|
Directionality dir = GetDirectionFromText(aTextNode);
|
||||||
if (dir != eDir_NotSet) {
|
if (dir != eDir_NotSet) {
|
||||||
SetAncestorDirectionIfAuto(aTextNode, dir);
|
SetAncestorDirectionIfAuto(aTextNode, dir);
|
||||||
}
|
}
|
||||||
@ -1112,7 +1118,7 @@ void ResetDirectionSetByTextNode(nsTextNode* aTextNode) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Directionality dir = GetDirectionFromText(aTextNode->GetText());
|
Directionality dir = GetDirectionFromText(aTextNode);
|
||||||
if (dir != eDir_NotSet && aTextNode->HasTextNodeDirectionalityMap()) {
|
if (dir != eDir_NotSet && aTextNode->HasTextNodeDirectionalityMap()) {
|
||||||
nsTextNodeDirectionalityMap::ResetTextNodeDirection(aTextNode, aTextNode);
|
nsTextNodeDirectionalityMap::ResetTextNodeDirection(aTextNode, aTextNode);
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ void WalkDescendantsClearAncestorDirAuto(nsIContent* aContent);
|
|||||||
*
|
*
|
||||||
* @return whether the text node affects the directionality of any element
|
* @return whether the text node affects the directionality of any element
|
||||||
*/
|
*/
|
||||||
bool TextNodeWillChangeDirection(nsIContent* aTextNode, Directionality* aOldDir,
|
bool TextNodeWillChangeDirection(nsTextNode* aTextNode, Directionality* aOldDir,
|
||||||
uint32_t aOffset);
|
uint32_t aOffset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#include "mozilla/AbstractThread.h"
|
#include "mozilla/AbstractThread.h"
|
||||||
#include "mozilla/SchedulerGroup.h"
|
#include "mozilla/SchedulerGroup.h"
|
||||||
#include "nsINamed.h"
|
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
|
@ -7,9 +7,9 @@
|
|||||||
#include "mozilla/dom/TabGroup.h"
|
#include "mozilla/dom/TabGroup.h"
|
||||||
#include "mozilla/AbstractThread.h"
|
#include "mozilla/AbstractThread.h"
|
||||||
#include "mozilla/PerformanceUtils.h"
|
#include "mozilla/PerformanceUtils.h"
|
||||||
#include "mozilla/StaticPrefs.h"
|
#include "mozilla/ThrottledEventQueue.h"
|
||||||
|
#include "mozilla/StaticPrefs_dom.h"
|
||||||
#include "mozilla/Telemetry.h"
|
#include "mozilla/Telemetry.h"
|
||||||
#include "nsIDocShell.h"
|
|
||||||
#include "nsDOMMutationObserver.h"
|
#include "nsDOMMutationObserver.h"
|
||||||
#include "nsProxyRelease.h"
|
#include "nsProxyRelease.h"
|
||||||
#if defined(XP_WIN)
|
#if defined(XP_WIN)
|
||||||
@ -63,6 +63,10 @@ DocGroup::~DocGroup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mTabGroup->mDocGroups.RemoveEntry(mKey);
|
mTabGroup->mDocGroups.RemoveEntry(mKey);
|
||||||
|
|
||||||
|
if (mIframePostMessageQueue) {
|
||||||
|
FlushIframePostMessageQueue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<PerformanceInfoPromise> DocGroup::ReportPerformanceInfo() {
|
RefPtr<PerformanceInfoPromise> DocGroup::ReportPerformanceInfo() {
|
||||||
@ -99,7 +103,7 @@ RefPtr<PerformanceInfoPromise> DocGroup::ReportPerformanceInfo() {
|
|||||||
if (!win) {
|
if (!win) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
top = win->GetTop();
|
top = win->GetInProcessTop();
|
||||||
if (!top) {
|
if (!top) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -186,6 +190,57 @@ void DocGroup::SignalSlotChange(HTMLSlotElement& aSlot) {
|
|||||||
sPendingDocGroups->AppendElement(this);
|
sPendingDocGroups->AppendElement(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DocGroup::TryToLoadIframesInBackground() {
|
||||||
|
return StaticPrefs::dom_separate_event_queue_for_post_message_enabled() &&
|
||||||
|
StaticPrefs::dom_cross_origin_iframes_loaded_in_background();
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult DocGroup::QueueIframePostMessages(
|
||||||
|
already_AddRefed<nsIRunnable>&& aRunnable, uint64_t aWindowId) {
|
||||||
|
if (DocGroup::TryToLoadIframesInBackground()) {
|
||||||
|
if (!mIframePostMessageQueue) {
|
||||||
|
nsCOMPtr<nsISerialEventTarget> target = GetMainThreadSerialEventTarget();
|
||||||
|
mIframePostMessageQueue = ThrottledEventQueue::Create(
|
||||||
|
target, "Background Loading Iframe PostMessage Queue",
|
||||||
|
nsIRunnablePriority::PRIORITY_DEFERRED_TIMERS);
|
||||||
|
nsresult rv = mIframePostMessageQueue->SetIsPaused(true);
|
||||||
|
MOZ_ALWAYS_SUCCEEDS(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the queue is disabled. Unlike the postMessageEvent queue in
|
||||||
|
// TabGroup, this postMessage queue should always be paused, because if
|
||||||
|
// we leave it open, the postMessage may get dispatched to an unloaded
|
||||||
|
// iframe
|
||||||
|
MOZ_ASSERT(mIframePostMessageQueue);
|
||||||
|
MOZ_ASSERT(mIframePostMessageQueue->IsPaused());
|
||||||
|
|
||||||
|
mIframesUsedPostMessageQueue.PutEntry(aWindowId);
|
||||||
|
|
||||||
|
mIframePostMessageQueue->Dispatch(std::move(aRunnable), NS_DISPATCH_NORMAL);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DocGroup::TryFlushIframePostMessages(uint64_t aWindowId) {
|
||||||
|
if (DocGroup::TryToLoadIframesInBackground()) {
|
||||||
|
mIframesUsedPostMessageQueue.RemoveEntry(aWindowId);
|
||||||
|
if (mIframePostMessageQueue && mIframesUsedPostMessageQueue.IsEmpty()) {
|
||||||
|
MOZ_ASSERT(mIframePostMessageQueue->IsPaused());
|
||||||
|
nsresult rv = mIframePostMessageQueue->SetIsPaused(true);
|
||||||
|
MOZ_ALWAYS_SUCCEEDS(rv);
|
||||||
|
FlushIframePostMessageQueue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DocGroup::FlushIframePostMessageQueue() {
|
||||||
|
nsCOMPtr<nsIRunnable> event;
|
||||||
|
while ((event = mIframePostMessageQueue->GetEvent())) {
|
||||||
|
Dispatch(TaskCategory::Other, event.forget());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DocGroup::MoveSignalSlotListTo(nsTArray<RefPtr<HTMLSlotElement>>& aDest) {
|
void DocGroup::MoveSignalSlotListTo(nsTArray<RefPtr<HTMLSlotElement>>& aDest) {
|
||||||
aDest.SetCapacity(aDest.Length() + mSignalSlotList.Length());
|
aDest.SetCapacity(aDest.Length() + mSignalSlotList.Length());
|
||||||
for (RefPtr<HTMLSlotElement>& slot : mSignalSlotList) {
|
for (RefPtr<HTMLSlotElement>& slot : mSignalSlotList) {
|
||||||
|
@ -103,16 +103,27 @@ class DocGroup final {
|
|||||||
// Returns true if any of its documents are active but not in the bfcache.
|
// Returns true if any of its documents are active but not in the bfcache.
|
||||||
bool IsActive() const;
|
bool IsActive() const;
|
||||||
|
|
||||||
|
nsresult QueueIframePostMessages(already_AddRefed<nsIRunnable>&& aRunnable,
|
||||||
|
uint64_t aWindowId);
|
||||||
|
|
||||||
|
void TryFlushIframePostMessages(uint64_t aWindowId);
|
||||||
|
|
||||||
|
static bool TryToLoadIframesInBackground();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DocGroup(TabGroup* aTabGroup, const nsACString& aKey);
|
DocGroup(TabGroup* aTabGroup, const nsACString& aKey);
|
||||||
~DocGroup();
|
~DocGroup();
|
||||||
|
|
||||||
|
void FlushIframePostMessageQueue();
|
||||||
nsCString mKey;
|
nsCString mKey;
|
||||||
RefPtr<TabGroup> mTabGroup;
|
RefPtr<TabGroup> mTabGroup;
|
||||||
nsTArray<Document*> mDocuments;
|
nsTArray<Document*> mDocuments;
|
||||||
RefPtr<mozilla::dom::CustomElementReactionsStack> mReactionsStack;
|
RefPtr<mozilla::dom::CustomElementReactionsStack> mReactionsStack;
|
||||||
nsTArray<RefPtr<HTMLSlotElement>> mSignalSlotList;
|
nsTArray<RefPtr<HTMLSlotElement>> mSignalSlotList;
|
||||||
RefPtr<mozilla::PerformanceCounter> mPerformanceCounter;
|
RefPtr<mozilla::PerformanceCounter> mPerformanceCounter;
|
||||||
|
|
||||||
|
RefPtr<mozilla::ThrottledEventQueue> mIframePostMessageQueue;
|
||||||
|
nsTHashtable<nsUint64HashKey> mIframesUsedPostMessageQueue;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -57,13 +57,12 @@ class DocumentFragment : public FragmentOrElement {
|
|||||||
|
|
||||||
virtual bool IsNodeOfType(uint32_t aFlags) const override;
|
virtual bool IsNodeOfType(uint32_t aFlags) const override;
|
||||||
|
|
||||||
nsresult BindToTree(Document* aDocument, nsIContent* aParent,
|
nsresult BindToTree(BindContext&, nsINode& aParent) override {
|
||||||
nsIContent* aBindingParent) override {
|
|
||||||
NS_ASSERTION(false, "Trying to bind a fragment to a tree");
|
NS_ASSERTION(false, "Trying to bind a fragment to a tree");
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void UnbindFromTree(bool aDeep, bool aNullParent) override {
|
virtual void UnbindFromTree(bool aNullParent) override {
|
||||||
NS_ASSERTION(false, "Trying to unbind a fragment from a tree");
|
NS_ASSERTION(false, "Trying to unbind a fragment from a tree");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsDOMString.h"
|
#include "nsDOMString.h"
|
||||||
#include "nsNodeInfoManager.h"
|
#include "nsNodeInfoManager.h"
|
||||||
#include "nsIXPConnect.h"
|
|
||||||
#include "xpcpublic.h"
|
#include "xpcpublic.h"
|
||||||
#include "nsWrapperCacheInlines.h"
|
#include "nsWrapperCacheInlines.h"
|
||||||
#include "mozilla/dom/DocumentTypeBinding.h"
|
#include "mozilla/dom/DocumentTypeBinding.h"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -12,7 +12,6 @@
|
|||||||
#define mozilla_dom_Element_h__
|
#define mozilla_dom_Element_h__
|
||||||
|
|
||||||
#include "AttrArray.h"
|
#include "AttrArray.h"
|
||||||
#include "DOMIntersectionObserver.h"
|
|
||||||
#include "nsAttrValue.h"
|
#include "nsAttrValue.h"
|
||||||
#include "nsAttrValueInlines.h"
|
#include "nsAttrValueInlines.h"
|
||||||
#include "nsChangeHint.h"
|
#include "nsChangeHint.h"
|
||||||
@ -20,7 +19,6 @@
|
|||||||
#include "nsDOMAttributeMap.h"
|
#include "nsDOMAttributeMap.h"
|
||||||
#include "nsINodeList.h"
|
#include "nsINodeList.h"
|
||||||
#include "nsIScrollableFrame.h"
|
#include "nsIScrollableFrame.h"
|
||||||
#include "nsNodeUtils.h"
|
|
||||||
#include "nsPresContext.h"
|
#include "nsPresContext.h"
|
||||||
#include "Units.h"
|
#include "Units.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
@ -81,7 +79,7 @@ namespace css {
|
|||||||
struct URLValue;
|
struct URLValue;
|
||||||
} // namespace css
|
} // namespace css
|
||||||
namespace dom {
|
namespace dom {
|
||||||
struct AnimationFilter;
|
struct GetAnimationsOptions;
|
||||||
struct ScrollIntoViewOptions;
|
struct ScrollIntoViewOptions;
|
||||||
struct ScrollToOptions;
|
struct ScrollToOptions;
|
||||||
class DOMIntersectionObserver;
|
class DOMIntersectionObserver;
|
||||||
@ -351,7 +349,7 @@ class Element : public FragmentOrElement {
|
|||||||
* notify the document's pres context, so that the style changes will be
|
* notify the document's pres context, so that the style changes will be
|
||||||
* noticed.
|
* noticed.
|
||||||
*/
|
*/
|
||||||
nsresult SetSMILOverrideStyleDeclaration(DeclarationBlock* aDeclaration);
|
void SetSMILOverrideStyleDeclaration(DeclarationBlock&);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new SMILAttr that allows the caller to animate the given
|
* Returns a new SMILAttr that allows the caller to animate the given
|
||||||
@ -457,7 +455,7 @@ class Element : public FragmentOrElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetBindingURL(Document* aDocument, css::URLValue** aResult);
|
mozilla::StyleUrlOrNone GetBindingURL(Document* aDocument);
|
||||||
|
|
||||||
Directionality GetComputedDirectionality() const;
|
Directionality GetComputedDirectionality() const;
|
||||||
|
|
||||||
@ -650,10 +648,9 @@ class Element : public FragmentOrElement {
|
|||||||
|
|
||||||
void UpdateEditableState(bool aNotify) override;
|
void UpdateEditableState(bool aNotify) override;
|
||||||
|
|
||||||
nsresult BindToTree(Document* aDocument, nsIContent* aParent,
|
nsresult BindToTree(BindContext&, nsINode& aParent) override;
|
||||||
nsIContent* aBindingParent) override;
|
|
||||||
|
|
||||||
void UnbindFromTree(bool aDeep = true, bool aNullParent = true) override;
|
void UnbindFromTree(bool aNullParent = true) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalizes an attribute name and returns it as a nodeinfo if an attribute
|
* Normalizes an attribute name and returns it as a nodeinfo if an attribute
|
||||||
@ -1336,7 +1333,7 @@ class Element : public FragmentOrElement {
|
|||||||
// Note: GetAnimations will flush style while GetAnimationsUnsorted won't.
|
// Note: GetAnimations will flush style while GetAnimationsUnsorted won't.
|
||||||
// Callers must keep this element alive because flushing style may destroy
|
// Callers must keep this element alive because flushing style may destroy
|
||||||
// this element.
|
// this element.
|
||||||
void GetAnimations(const AnimationFilter& filter,
|
void GetAnimations(const GetAnimationsOptions& aOptions,
|
||||||
nsTArray<RefPtr<Animation>>& aAnimations);
|
nsTArray<RefPtr<Animation>>& aAnimations);
|
||||||
static void GetAnimationsUnsorted(Element* aElement,
|
static void GetAnimationsUnsorted(Element* aElement,
|
||||||
PseudoStyleType aPseudoType,
|
PseudoStyleType aPseudoType,
|
||||||
@ -1360,8 +1357,8 @@ class Element : public FragmentOrElement {
|
|||||||
* @param aValue the JS to attach
|
* @param aValue the JS to attach
|
||||||
* @param aDefer indicates if deferred execution is allowed
|
* @param aDefer indicates if deferred execution is allowed
|
||||||
*/
|
*/
|
||||||
nsresult SetEventHandler(nsAtom* aEventName, const nsAString& aValue,
|
void SetEventHandler(nsAtom* aEventName, const nsAString& aValue,
|
||||||
bool aDefer = true);
|
bool aDefer = true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do whatever needs to be done when the mouse leaves a link
|
* Do whatever needs to be done when the mouse leaves a link
|
||||||
@ -1404,6 +1401,14 @@ class Element : public FragmentOrElement {
|
|||||||
return HasServoData() && Servo_Element_IsDisplayContents(this);
|
return HasServoData() && Servo_Element_IsDisplayContents(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* https://html.spec.whatwg.org/#being-rendered
|
||||||
|
*
|
||||||
|
* With a gotcha for display contents:
|
||||||
|
* https://github.com/whatwg/html/issues/1837
|
||||||
|
*/
|
||||||
|
bool IsRendered() const { return GetPrimaryFrame() || IsDisplayContents(); }
|
||||||
|
|
||||||
const nsAttrValue* GetParsedAttr(const nsAtom* aAttr) const {
|
const nsAttrValue* GetParsedAttr(const nsAtom* aAttr) const {
|
||||||
return mAttrs.GetAttr(aAttr);
|
return mAttrs.GetAttr(aAttr);
|
||||||
}
|
}
|
||||||
@ -1459,7 +1464,11 @@ class Element : public FragmentOrElement {
|
|||||||
*
|
*
|
||||||
* If you change this, change also the similar method in Link.
|
* If you change this, change also the similar method in Link.
|
||||||
*/
|
*/
|
||||||
virtual void NodeInfoChanged(Document* aOldDoc) {}
|
virtual void NodeInfoChanged(Document* aOldDoc) {
|
||||||
|
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||||
|
AssertInvariantsOnNodeInfoChange();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a string into an nsAttrValue for a CORS attribute. This
|
* Parse a string into an nsAttrValue for a CORS attribute. This
|
||||||
@ -1486,7 +1495,7 @@ class Element : public FragmentOrElement {
|
|||||||
/**
|
/**
|
||||||
* Locate a TextEditor rooted at this content node, if there is one.
|
* Locate a TextEditor rooted at this content node, if there is one.
|
||||||
*/
|
*/
|
||||||
mozilla::TextEditor* GetTextEditorInternal();
|
MOZ_CAN_RUN_SCRIPT_BOUNDARY mozilla::TextEditor* GetTextEditorInternal();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets value of boolean attribute. Only works for attributes in null
|
* Gets value of boolean attribute. Only works for attributes in null
|
||||||
@ -1579,8 +1588,8 @@ class Element : public FragmentOrElement {
|
|||||||
*/
|
*/
|
||||||
float FontSizeInflation();
|
float FontSizeInflation();
|
||||||
|
|
||||||
net::ReferrerPolicy GetReferrerPolicyAsEnum();
|
ReferrerPolicy GetReferrerPolicyAsEnum();
|
||||||
net::ReferrerPolicy ReferrerPolicyFromAttr(const nsAttrValue* aValue);
|
ReferrerPolicy ReferrerPolicyFromAttr(const nsAttrValue* aValue);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helpers for .dataset. This is implemented on Element, though only some
|
* Helpers for .dataset. This is implemented on Element, though only some
|
||||||
@ -1768,15 +1777,11 @@ class Element : public FragmentOrElement {
|
|||||||
* principal is directly responsible for the attribute change.
|
* principal is directly responsible for the attribute change.
|
||||||
* @param aNotify Whether we plan to notify document observers.
|
* @param aNotify Whether we plan to notify document observers.
|
||||||
*/
|
*/
|
||||||
// Note that this is inlined so that when subclasses call it it gets
|
|
||||||
// inlined. Those calls don't go through a vtable.
|
|
||||||
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
||||||
const nsAttrValue* aValue,
|
const nsAttrValue* aValue,
|
||||||
const nsAttrValue* aOldValue,
|
const nsAttrValue* aOldValue,
|
||||||
nsIPrincipal* aMaybeScriptedPrincipal,
|
nsIPrincipal* aMaybeScriptedPrincipal,
|
||||||
bool aNotify) {
|
bool aNotify);
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function shall be called just before the id attribute changes. It will
|
* This function shall be called just before the id attribute changes. It will
|
||||||
@ -1905,13 +1910,19 @@ class Element : public FragmentOrElement {
|
|||||||
nsAtom* aAtom,
|
nsAtom* aAtom,
|
||||||
const DOMTokenListSupportedTokenArray aSupportedTokens = nullptr);
|
const DOMTokenListSupportedTokenArray aSupportedTokens = nullptr);
|
||||||
|
|
||||||
|
enum class ReparseAttributes { No, Yes };
|
||||||
/**
|
/**
|
||||||
* Copy attributes and state to another element
|
* Copy attributes and state to another element
|
||||||
* @param aDest the object to copy to
|
* @param aDest the object to copy to
|
||||||
*/
|
*/
|
||||||
nsresult CopyInnerTo(Element* aDest);
|
nsresult CopyInnerTo(Element* aDest,
|
||||||
|
ReparseAttributes = ReparseAttributes::Yes);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||||
|
void AssertInvariantsOnNodeInfoChange();
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Slow path for GetClasses, this should only be called for SVG elements.
|
* Slow path for GetClasses, this should only be called for SVG elements.
|
||||||
*/
|
*/
|
||||||
|
@ -24,23 +24,21 @@ inline void Element::UnregisterActivityObserver() {
|
|||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
inline Element* nsINode::GetFlattenedTreeParentElement() const {
|
inline mozilla::dom::Element* nsINode::GetFlattenedTreeParentElement() const {
|
||||||
nsINode* parentNode = GetFlattenedTreeParentNode();
|
nsINode* parentNode = GetFlattenedTreeParentNode();
|
||||||
if
|
if MOZ_LIKELY (parentNode && parentNode->IsElement()) {
|
||||||
MOZ_LIKELY(parentNode && parentNode->IsElement()) {
|
return parentNode->AsElement();
|
||||||
return parentNode->AsElement();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Element* nsINode::GetFlattenedTreeParentElementForStyle() const {
|
inline mozilla::dom::Element* nsINode::GetFlattenedTreeParentElementForStyle()
|
||||||
|
const {
|
||||||
nsINode* parentNode = GetFlattenedTreeParentNodeForStyle();
|
nsINode* parentNode = GetFlattenedTreeParentNodeForStyle();
|
||||||
if
|
if (MOZ_LIKELY(parentNode && parentNode->IsElement())) {
|
||||||
MOZ_LIKELY(parentNode && parentNode->IsElement()) {
|
return parentNode->AsElement();
|
||||||
return parentNode->AsElement();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@
|
|||||||
#include "nsIThreadRetargetableRequest.h"
|
#include "nsIThreadRetargetableRequest.h"
|
||||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||||
#include "nsIScriptError.h"
|
#include "nsIScriptError.h"
|
||||||
#include "nsIContentSecurityPolicy.h"
|
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
#include "xpcpublic.h"
|
#include "xpcpublic.h"
|
||||||
@ -112,8 +111,7 @@ class EventSourceImpl final : public nsIObserver,
|
|||||||
static void TimerCallback(nsITimer* aTimer, void* aClosure);
|
static void TimerCallback(nsITimer* aTimer, void* aClosure);
|
||||||
|
|
||||||
nsresult PrintErrorOnConsole(const char* aBundleURI, const char* aError,
|
nsresult PrintErrorOnConsole(const char* aBundleURI, const char* aError,
|
||||||
const char16_t** aFormatStrings,
|
const nsTArray<nsString>& aFormatStrings);
|
||||||
uint32_t aFormatStringsLen);
|
|
||||||
nsresult ConsoleError();
|
nsresult ConsoleError();
|
||||||
|
|
||||||
static nsresult StreamReaderFunc(nsIInputStream* aInputStream, void* aClosure,
|
static nsresult StreamReaderFunc(nsIInputStream* aInputStream, void* aClosure,
|
||||||
@ -794,11 +792,7 @@ EventSourceImpl::AsyncOnChannelRedirect(
|
|||||||
rv = NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI));
|
rv = NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
bool isValidScheme =
|
bool isValidScheme = newURI->SchemeIs("http") || newURI->SchemeIs("https");
|
||||||
(NS_SUCCEEDED(newURI->SchemeIs("http", &isValidScheme)) &&
|
|
||||||
isValidScheme) ||
|
|
||||||
(NS_SUCCEEDED(newURI->SchemeIs("https", &isValidScheme)) &&
|
|
||||||
isValidScheme);
|
|
||||||
|
|
||||||
rv = mEventSource->CheckCurrentGlobalCorrectness();
|
rv = mEventSource->CheckCurrentGlobalCorrectness();
|
||||||
if (NS_FAILED(rv) || !isValidScheme) {
|
if (NS_FAILED(rv) || !isValidScheme) {
|
||||||
@ -937,8 +931,8 @@ nsresult EventSourceImpl::SetupReferrerInfo() {
|
|||||||
MOZ_ASSERT(!IsShutDown());
|
MOZ_ASSERT(!IsShutDown());
|
||||||
nsCOMPtr<Document> doc = mEventSource->GetDocumentIfCurrent();
|
nsCOMPtr<Document> doc = mEventSource->GetDocumentIfCurrent();
|
||||||
if (doc) {
|
if (doc) {
|
||||||
nsCOMPtr<nsIReferrerInfo> referrerInfo =
|
nsCOMPtr<nsIReferrerInfo> referrerInfo = new ReferrerInfo();
|
||||||
new ReferrerInfo(doc->GetDocumentURI(), doc->GetReferrerPolicy());
|
referrerInfo->InitWithDocument(doc);
|
||||||
nsresult rv = mHttpChannel->SetReferrerInfoWithoutClone(referrerInfo);
|
nsresult rv = mHttpChannel->SetReferrerInfoWithoutClone(referrerInfo);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
@ -952,9 +946,7 @@ nsresult EventSourceImpl::InitChannelAndRequestEventSource() {
|
|||||||
return NS_ERROR_ABORT;
|
return NS_ERROR_ABORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isValidScheme =
|
bool isValidScheme = mSrc->SchemeIs("http") || mSrc->SchemeIs("https");
|
||||||
(NS_SUCCEEDED(mSrc->SchemeIs("http", &isValidScheme)) && isValidScheme) ||
|
|
||||||
(NS_SUCCEEDED(mSrc->SchemeIs("https", &isValidScheme)) && isValidScheme);
|
|
||||||
|
|
||||||
nsresult rv = mEventSource->CheckCurrentGlobalCorrectness();
|
nsresult rv = mEventSource->CheckCurrentGlobalCorrectness();
|
||||||
if (NS_FAILED(rv) || !isValidScheme) {
|
if (NS_FAILED(rv) || !isValidScheme) {
|
||||||
@ -1158,10 +1150,9 @@ nsresult EventSourceImpl::SetReconnectionTimeout() {
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult EventSourceImpl::PrintErrorOnConsole(const char* aBundleURI,
|
nsresult EventSourceImpl::PrintErrorOnConsole(
|
||||||
const char* aError,
|
const char* aBundleURI, const char* aError,
|
||||||
const char16_t** aFormatStrings,
|
const nsTArray<nsString>& aFormatStrings) {
|
||||||
uint32_t aFormatStringsLen) {
|
|
||||||
AssertIsOnMainThread();
|
AssertIsOnMainThread();
|
||||||
MOZ_ASSERT(!IsShutDown());
|
MOZ_ASSERT(!IsShutDown());
|
||||||
nsCOMPtr<nsIStringBundleService> bundleService =
|
nsCOMPtr<nsIStringBundleService> bundleService =
|
||||||
@ -1183,9 +1174,8 @@ nsresult EventSourceImpl::PrintErrorOnConsole(const char* aBundleURI,
|
|||||||
|
|
||||||
// Localize the error message
|
// Localize the error message
|
||||||
nsAutoString message;
|
nsAutoString message;
|
||||||
if (aFormatStrings) {
|
if (!aFormatStrings.IsEmpty()) {
|
||||||
rv = strBundle->FormatStringFromName(aError, aFormatStrings,
|
rv = strBundle->FormatStringFromName(aError, aFormatStrings, message);
|
||||||
aFormatStringsLen, message);
|
|
||||||
} else {
|
} else {
|
||||||
rv = strBundle->GetStringFromName(aError, message);
|
rv = strBundle->GetStringFromName(aError, message);
|
||||||
}
|
}
|
||||||
@ -1210,17 +1200,15 @@ nsresult EventSourceImpl::ConsoleError() {
|
|||||||
nsresult rv = mSrc->GetSpec(targetSpec);
|
nsresult rv = mSrc->GetSpec(targetSpec);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
NS_ConvertUTF8toUTF16 specUTF16(targetSpec);
|
AutoTArray<nsString, 1> formatStrings;
|
||||||
const char16_t* formatStrings[] = {specUTF16.get()};
|
CopyUTF8toUTF16(targetSpec, *formatStrings.AppendElement());
|
||||||
|
|
||||||
if (ReadyState() == CONNECTING) {
|
if (ReadyState() == CONNECTING) {
|
||||||
rv = PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
|
rv = PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
|
||||||
"connectionFailure", formatStrings,
|
"connectionFailure", formatStrings);
|
||||||
ArrayLength(formatStrings));
|
|
||||||
} else {
|
} else {
|
||||||
rv = PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
|
rv = PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
|
||||||
"netInterrupt", formatStrings,
|
"netInterrupt", formatStrings);
|
||||||
ArrayLength(formatStrings));
|
|
||||||
}
|
}
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
@ -14,12 +14,6 @@
|
|||||||
|
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/DOMEventTargetHelper.h"
|
#include "mozilla/DOMEventTargetHelper.h"
|
||||||
#include "nsIObserver.h"
|
|
||||||
#include "nsIStreamListener.h"
|
|
||||||
#include "nsIChannelEventSink.h"
|
|
||||||
#include "nsIInterfaceRequestor.h"
|
|
||||||
#include "nsITimer.h"
|
|
||||||
#include "nsIHttpChannel.h"
|
|
||||||
#include "nsDeque.h"
|
#include "nsDeque.h"
|
||||||
|
|
||||||
class nsIGlobalObject;
|
class nsIGlobalObject;
|
||||||
|
@ -14,10 +14,19 @@
|
|||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
|
|
||||||
FormData::FormData(nsISupports* aOwner)
|
FormData::FormData(nsISupports* aOwner, NotNull<const Encoding*> aEncoding,
|
||||||
: HTMLFormSubmission(nullptr, EmptyString(), UTF_8_ENCODING, nullptr),
|
Element* aOriginatingElement)
|
||||||
|
: HTMLFormSubmission(nullptr, EmptyString(), aEncoding,
|
||||||
|
aOriginatingElement),
|
||||||
mOwner(aOwner) {}
|
mOwner(aOwner) {}
|
||||||
|
|
||||||
|
FormData::FormData(const FormData& aFormData)
|
||||||
|
: HTMLFormSubmission(aFormData.mActionURL, aFormData.mTarget,
|
||||||
|
aFormData.mEncoding, aFormData.mOriginatingElement) {
|
||||||
|
mOwner = aFormData.mOwner;
|
||||||
|
mFormData = aFormData.mFormData;
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
already_AddRefed<File> GetOrCreateFileCalledBlob(Blob& aBlob,
|
already_AddRefed<File> GetOrCreateFileCalledBlob(Blob& aBlob,
|
||||||
@ -288,8 +297,18 @@ already_AddRefed<FormData> FormData::Constructor(
|
|||||||
const Optional<NonNull<HTMLFormElement> >& aFormElement, ErrorResult& aRv) {
|
const Optional<NonNull<HTMLFormElement> >& aFormElement, ErrorResult& aRv) {
|
||||||
RefPtr<FormData> formData = new FormData(aGlobal.GetAsSupports());
|
RefPtr<FormData> formData = new FormData(aGlobal.GetAsSupports());
|
||||||
if (aFormElement.WasPassed()) {
|
if (aFormElement.WasPassed()) {
|
||||||
aRv = aFormElement.Value().WalkFormElements(formData);
|
aRv = aFormElement.Value().ConstructEntryList(formData);
|
||||||
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 9. Return a shallow clone of entry list.
|
||||||
|
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#constructing-form-data-set
|
||||||
|
if (StaticPrefs::dom_formdata_event_enabled()) {
|
||||||
|
formData = formData->Clone();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return formData.forget();
|
return formData.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,23 +319,8 @@ nsresult FormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
|
|||||||
nsACString& aContentTypeWithCharset,
|
nsACString& aContentTypeWithCharset,
|
||||||
nsACString& aCharset) const {
|
nsACString& aCharset) const {
|
||||||
FSMultipartFormData fs(nullptr, EmptyString(), UTF_8_ENCODING, nullptr);
|
FSMultipartFormData fs(nullptr, EmptyString(), UTF_8_ENCODING, nullptr);
|
||||||
|
nsresult rv = CopySubmissionDataTo(&fs);
|
||||||
for (uint32_t i = 0; i < mFormData.Length(); ++i) {
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
if (mFormData[i].wasNullBlob) {
|
|
||||||
MOZ_ASSERT(mFormData[i].value.IsUSVString());
|
|
||||||
fs.AddNameBlobOrNullPair(mFormData[i].name, nullptr);
|
|
||||||
} else if (mFormData[i].value.IsUSVString()) {
|
|
||||||
fs.AddNameValuePair(mFormData[i].name,
|
|
||||||
mFormData[i].value.GetAsUSVString());
|
|
||||||
} else if (mFormData[i].value.IsBlob()) {
|
|
||||||
fs.AddNameBlobOrNullPair(mFormData[i].name,
|
|
||||||
mFormData[i].value.GetAsBlob());
|
|
||||||
} else {
|
|
||||||
MOZ_ASSERT(mFormData[i].value.IsDirectory());
|
|
||||||
fs.AddNameDirectoryPair(mFormData[i].name,
|
|
||||||
mFormData[i].value.GetAsDirectory());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.GetContentType(aContentTypeWithCharset);
|
fs.GetContentType(aContentTypeWithCharset);
|
||||||
aCharset.Truncate();
|
aCharset.Truncate();
|
||||||
@ -325,3 +329,31 @@ nsresult FormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
|
|||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<FormData> FormData::Clone() {
|
||||||
|
RefPtr<FormData> formData = new FormData(*this);
|
||||||
|
return formData.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult FormData::CopySubmissionDataTo(
|
||||||
|
HTMLFormSubmission* aFormSubmission) const {
|
||||||
|
MOZ_ASSERT(aFormSubmission, "Must have FormSubmission!");
|
||||||
|
for (size_t i = 0; i < mFormData.Length(); ++i) {
|
||||||
|
if (mFormData[i].wasNullBlob) {
|
||||||
|
MOZ_ASSERT(mFormData[i].value.IsUSVString());
|
||||||
|
aFormSubmission->AddNameBlobOrNullPair(mFormData[i].name, nullptr);
|
||||||
|
} else if (mFormData[i].value.IsUSVString()) {
|
||||||
|
aFormSubmission->AddNameValuePair(mFormData[i].name,
|
||||||
|
mFormData[i].value.GetAsUSVString());
|
||||||
|
} else if (mFormData[i].value.IsBlob()) {
|
||||||
|
aFormSubmission->AddNameBlobOrNullPair(mFormData[i].name,
|
||||||
|
mFormData[i].value.GetAsBlob());
|
||||||
|
} else {
|
||||||
|
MOZ_ASSERT(mFormData[i].value.IsDirectory());
|
||||||
|
aFormSubmission->AddNameDirectoryPair(
|
||||||
|
mFormData[i].name, mFormData[i].value.GetAsDirectory());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
@ -24,6 +24,7 @@ class FormData final : public nsISupports,
|
|||||||
public HTMLFormSubmission,
|
public HTMLFormSubmission,
|
||||||
public nsWrapperCache {
|
public nsWrapperCache {
|
||||||
private:
|
private:
|
||||||
|
FormData(const FormData& aFormData);
|
||||||
~FormData() {}
|
~FormData() {}
|
||||||
|
|
||||||
struct FormDataTuple {
|
struct FormDataTuple {
|
||||||
@ -47,7 +48,11 @@ class FormData final : public nsISupports,
|
|||||||
Directory* aDirectory);
|
Directory* aDirectory);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit FormData(nsISupports* aOwner = nullptr);
|
explicit FormData(nsISupports* aOwner = nullptr,
|
||||||
|
NotNull<const Encoding*> aEncoding = UTF_8_ENCODING,
|
||||||
|
Element* aOriginatingElement = nullptr);
|
||||||
|
|
||||||
|
already_AddRefed<FormData> Clone();
|
||||||
|
|
||||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FormData)
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FormData)
|
||||||
@ -134,6 +139,8 @@ class FormData final : public nsISupports,
|
|||||||
nsACString& aContentTypeWithCharset,
|
nsACString& aContentTypeWithCharset,
|
||||||
nsACString& aCharset) const;
|
nsACString& aCharset) const;
|
||||||
|
|
||||||
|
nsresult CopySubmissionDataTo(HTMLFormSubmission* aFormSubmission) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsCOMPtr<nsISupports> mOwner;
|
nsCOMPtr<nsISupports> mOwner;
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@
|
|||||||
#include "nsIDocumentEncoder.h"
|
#include "nsIDocumentEncoder.h"
|
||||||
#include "nsFocusManager.h"
|
#include "nsFocusManager.h"
|
||||||
#include "nsIScriptGlobalObject.h"
|
#include "nsIScriptGlobalObject.h"
|
||||||
#include "nsIURL.h"
|
|
||||||
#include "nsNetUtil.h"
|
#include "nsNetUtil.h"
|
||||||
#include "nsIFrame.h"
|
#include "nsIFrame.h"
|
||||||
#include "nsIAnonymousContentCreator.h"
|
#include "nsIAnonymousContentCreator.h"
|
||||||
@ -46,7 +45,6 @@
|
|||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "nsUnicharUtils.h"
|
#include "nsUnicharUtils.h"
|
||||||
#include "nsDOMCID.h"
|
#include "nsDOMCID.h"
|
||||||
#include "nsIServiceManager.h"
|
|
||||||
#include "nsDOMCSSAttrDeclaration.h"
|
#include "nsDOMCSSAttrDeclaration.h"
|
||||||
#include "nsNameSpaceManager.h"
|
#include "nsNameSpaceManager.h"
|
||||||
#include "nsContentList.h"
|
#include "nsContentList.h"
|
||||||
@ -54,10 +52,8 @@
|
|||||||
#include "nsXBLPrototypeBinding.h"
|
#include "nsXBLPrototypeBinding.h"
|
||||||
#include "nsError.h"
|
#include "nsError.h"
|
||||||
#include "nsDOMString.h"
|
#include "nsDOMString.h"
|
||||||
#include "nsIScriptSecurityManager.h"
|
|
||||||
#include "mozilla/InternalMutationEvent.h"
|
#include "mozilla/InternalMutationEvent.h"
|
||||||
#include "mozilla/MouseEvents.h"
|
#include "mozilla/MouseEvents.h"
|
||||||
#include "nsNodeUtils.h"
|
|
||||||
#include "nsAttrValueOrString.h"
|
#include "nsAttrValueOrString.h"
|
||||||
#include "nsQueryObject.h"
|
#include "nsQueryObject.h"
|
||||||
#ifdef MOZ_XUL
|
#ifdef MOZ_XUL
|
||||||
@ -81,16 +77,11 @@
|
|||||||
#include "nsContentCID.h"
|
#include "nsContentCID.h"
|
||||||
#include "nsWindowSizes.h"
|
#include "nsWindowSizes.h"
|
||||||
|
|
||||||
#include "nsIDOMEventListener.h"
|
|
||||||
#include "nsIWebNavigation.h"
|
|
||||||
#include "nsIBaseWindow.h"
|
|
||||||
#include "nsIWidget.h"
|
#include "nsIWidget.h"
|
||||||
|
|
||||||
#include "nsNodeInfoManager.h"
|
#include "nsNodeInfoManager.h"
|
||||||
#include "nsICategoryManager.h"
|
|
||||||
#include "nsGenericHTMLElement.h"
|
#include "nsGenericHTMLElement.h"
|
||||||
#include "nsContentCreatorFunctions.h"
|
#include "nsContentCreatorFunctions.h"
|
||||||
#include "nsIControllers.h"
|
|
||||||
#include "nsView.h"
|
#include "nsView.h"
|
||||||
#include "nsViewManager.h"
|
#include "nsViewManager.h"
|
||||||
#include "nsIScrollableFrame.h"
|
#include "nsIScrollableFrame.h"
|
||||||
@ -107,7 +98,6 @@
|
|||||||
#include "nsWrapperCacheInlines.h"
|
#include "nsWrapperCacheInlines.h"
|
||||||
#include "nsCycleCollector.h"
|
#include "nsCycleCollector.h"
|
||||||
#include "xpcpublic.h"
|
#include "xpcpublic.h"
|
||||||
#include "nsIScriptError.h"
|
|
||||||
#include "mozilla/Telemetry.h"
|
#include "mozilla/Telemetry.h"
|
||||||
|
|
||||||
#include "mozilla/CORSMode.h"
|
#include "mozilla/CORSMode.h"
|
||||||
@ -157,7 +147,7 @@ NS_INTERFACE_MAP_END
|
|||||||
|
|
||||||
NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_ADDREF(nsIContent)
|
NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_ADDREF(nsIContent)
|
||||||
NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(
|
NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(
|
||||||
nsIContent, nsNodeUtils::LastRelease(this))
|
nsIContent, LastRelease())
|
||||||
|
|
||||||
nsIContent* nsIContent::FindFirstNonChromeOnlyAccessContent() const {
|
nsIContent* nsIContent::FindFirstNonChromeOnlyAccessContent() const {
|
||||||
// This handles also nested native anonymous content.
|
// This handles also nested native anonymous content.
|
||||||
@ -326,19 +316,14 @@ nsAtom* nsIContent::GetLang() const {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsIURI> nsIContent::GetBaseURI(
|
nsIURI* nsIContent::GetBaseURI(bool aTryUseXHRDocBaseURI) const {
|
||||||
bool aTryUseXHRDocBaseURI) const {
|
|
||||||
if (SVGUseElement* use = GetContainingSVGUseShadowHost()) {
|
if (SVGUseElement* use = GetContainingSVGUseShadowHost()) {
|
||||||
if (URLExtraData* data = use->GetContentURLData()) {
|
if (URLExtraData* data = use->GetContentURLData()) {
|
||||||
return do_AddRef(data->BaseURI());
|
return data->BaseURI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Document* doc = OwnerDoc();
|
return OwnerDoc()->GetBaseURI(aTryUseXHRDocBaseURI);
|
||||||
// Start with document base
|
|
||||||
nsCOMPtr<nsIURI> base = doc->GetBaseURI(aTryUseXHRDocBaseURI);
|
|
||||||
|
|
||||||
return base.forget();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIURI* nsIContent::GetBaseURIForStyleAttr() const {
|
nsIURI* nsIContent::GetBaseURIForStyleAttr() const {
|
||||||
@ -361,9 +346,10 @@ already_AddRefed<URLExtraData> nsIContent::GetURLDataForStyleAttr(
|
|||||||
}
|
}
|
||||||
if (aSubjectPrincipal && aSubjectPrincipal != NodePrincipal()) {
|
if (aSubjectPrincipal && aSubjectPrincipal != NodePrincipal()) {
|
||||||
// TODO: Cache this?
|
// TODO: Cache this?
|
||||||
return MakeAndAddRef<URLExtraData>(
|
nsCOMPtr<nsIReferrerInfo> referrerInfo =
|
||||||
OwnerDoc()->GetDocBaseURI(), OwnerDoc()->GetDocumentURI(),
|
ReferrerInfo::CreateForInternalCSSResources(OwnerDoc());
|
||||||
aSubjectPrincipal, OwnerDoc()->GetReferrerPolicy());
|
return MakeAndAddRef<URLExtraData>(OwnerDoc()->GetDocBaseURI(),
|
||||||
|
referrerInfo, aSubjectPrincipal);
|
||||||
}
|
}
|
||||||
// This also ignores the case that SVG inside XBL binding.
|
// This also ignores the case that SVG inside XBL binding.
|
||||||
// But it is probably fine.
|
// But it is probably fine.
|
||||||
@ -391,13 +377,9 @@ static bool NeedsScriptTraverse(nsINode* aNode) {
|
|||||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAttrChildContentList)
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAttrChildContentList)
|
||||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAttrChildContentList)
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAttrChildContentList)
|
||||||
|
|
||||||
// If nsAttrChildContentList is changed so that any additional fields are
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsAttrChildContentList, mNode)
|
||||||
// traversed by the cycle collector, then CAN_SKIP must be updated to
|
|
||||||
// check that the additional fields are null.
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsAttrChildContentList)
|
|
||||||
|
|
||||||
// nsAttrChildContentList only ever has a single child, its wrapper, so if
|
// If the wrapper is known-live, the list can't be part of a garbage cycle.
|
||||||
// the wrapper is known-live, the list can't be part of a garbage cycle.
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsAttrChildContentList)
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsAttrChildContentList)
|
||||||
return tmp->HasKnownLiveWrapper();
|
return tmp->HasKnownLiveWrapper();
|
||||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
|
||||||
@ -406,7 +388,6 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsAttrChildContentList)
|
|||||||
return tmp->HasKnownLiveWrapperAndDoesNotNeedTracing(tmp);
|
return tmp->HasKnownLiveWrapperAndDoesNotNeedTracing(tmp);
|
||||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
|
||||||
|
|
||||||
// CanSkipThis returns false to avoid problems with incomplete unlinking.
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsAttrChildContentList)
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsAttrChildContentList)
|
||||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
|
||||||
|
|
||||||
@ -768,7 +749,7 @@ static nsINode* FindChromeAccessOnlySubtreeOwner(nsINode* aNode) {
|
|||||||
aNode = aNode->GetParentNode();
|
aNode = aNode->GetParentNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
return aNode ? aNode->GetParentOrHostNode() : nullptr;
|
return aNode ? aNode->GetParentOrShadowHostNode() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsINode> FindChromeAccessOnlySubtreeOwner(
|
already_AddRefed<nsINode> FindChromeAccessOnlySubtreeOwner(
|
||||||
@ -999,8 +980,8 @@ void nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
|
|||||||
// dispatching event to Window object in a content page and
|
// dispatching event to Window object in a content page and
|
||||||
// propagating the event to a chrome Element.
|
// propagating the event to a chrome Element.
|
||||||
if (targetInKnownToBeHandledScope &&
|
if (targetInKnownToBeHandledScope &&
|
||||||
nsContentUtils::ContentIsShadowIncludingDescendantOf(
|
IsShadowIncludingInclusiveDescendantOf(
|
||||||
this, targetInKnownToBeHandledScope->SubtreeRoot())) {
|
targetInKnownToBeHandledScope->SubtreeRoot())) {
|
||||||
// Part of step 11.4.
|
// Part of step 11.4.
|
||||||
// "If target's root is a shadow-including inclusive ancestor of
|
// "If target's root is a shadow-including inclusive ancestor of
|
||||||
// parent, then"
|
// parent, then"
|
||||||
@ -1120,6 +1101,28 @@ void nsIContent::SetXBLInsertionPoint(nsIContent* aContent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
void nsIContent::AssertAnonymousSubtreeRelatedInvariants() const {
|
||||||
|
NS_ASSERTION(!IsRootOfNativeAnonymousSubtree() ||
|
||||||
|
(GetParent() && GetBindingParent() == GetParent()),
|
||||||
|
"root of native anonymous subtree must have parent equal "
|
||||||
|
"to binding parent");
|
||||||
|
NS_ASSERTION(!GetParent() || !IsInComposedDoc() ||
|
||||||
|
((GetBindingParent() == GetParent()) ==
|
||||||
|
HasFlag(NODE_IS_ANONYMOUS_ROOT)) ||
|
||||||
|
// Unfortunately default content for XBL insertion points
|
||||||
|
// is anonymous content that is bound with the parent of
|
||||||
|
// the insertion point as the parent but the bound element
|
||||||
|
// for the binding as the binding parent. So we have to
|
||||||
|
// complicate the assert a bit here.
|
||||||
|
(GetBindingParent() &&
|
||||||
|
(GetBindingParent() == GetParent()->GetBindingParent()) ==
|
||||||
|
HasFlag(NODE_IS_ANONYMOUS_ROOT)),
|
||||||
|
"For connected nodes, flag and GetBindingParent() check "
|
||||||
|
"should match");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void FragmentOrElement::GetTextContentInternal(nsAString& aTextContent,
|
void FragmentOrElement::GetTextContentInternal(nsAString& aTextContent,
|
||||||
OOMReporter& aError) {
|
OOMReporter& aError) {
|
||||||
if (!nsContentUtils::GetNodeTextContent(this, true, aTextContent, fallible)) {
|
if (!nsContentUtils::GetNodeTextContent(this, true, aTextContent, fallible)) {
|
||||||
@ -2002,7 +2005,7 @@ void FragmentOrElement::SetInnerHTMLInternal(const nsAString& aInnerHTML,
|
|||||||
ErrorResult& aError) {
|
ErrorResult& aError) {
|
||||||
FragmentOrElement* target = this;
|
FragmentOrElement* target = this;
|
||||||
// Handle template case.
|
// Handle template case.
|
||||||
if (nsNodeUtils::IsTemplateElement(target)) {
|
if (target->IsTemplateElement()) {
|
||||||
DocumentFragment* frag =
|
DocumentFragment* frag =
|
||||||
static_cast<HTMLTemplateElement*>(target)->Content();
|
static_cast<HTMLTemplateElement*>(target)->Content();
|
||||||
MOZ_ASSERT(frag);
|
MOZ_ASSERT(frag);
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
#include "mozilla/UniquePtr.h"
|
#include "mozilla/UniquePtr.h"
|
||||||
#include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_*
|
#include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_*
|
||||||
#include "nsIContent.h" // base class
|
#include "nsIContent.h" // base class
|
||||||
#include "nsNodeUtils.h" // class member nsNodeUtils::CloneNodeImpl
|
|
||||||
#include "nsIHTMLCollection.h"
|
#include "nsIHTMLCollection.h"
|
||||||
#include "nsDataHashtable.h"
|
#include "nsDataHashtable.h"
|
||||||
#include "nsXBLBinding.h"
|
#include "nsXBLBinding.h"
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#include "nsJSEnvironment.h"
|
#include "nsJSEnvironment.h"
|
||||||
#include "js/GCAPI.h"
|
#include "js/GCAPI.h"
|
||||||
#include "mozIDOMWindow.h"
|
|
||||||
#include "mozilla/dom/KeyboardEvent.h"
|
#include "mozilla/dom/KeyboardEvent.h"
|
||||||
#include "mozilla/ErrorResult.h"
|
#include "mozilla/ErrorResult.h"
|
||||||
#include "mozilla/TextEvents.h"
|
#include "mozilla/TextEvents.h"
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "mozilla/Encoding.h"
|
#include "mozilla/Encoding.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsIURI.h"
|
#include "nsIURI.h"
|
||||||
|
#include "nsIReferrerInfo.h"
|
||||||
#include "nsBindingManager.h"
|
#include "nsBindingManager.h"
|
||||||
#include "nsEscape.h"
|
#include "nsEscape.h"
|
||||||
#include "nsXBLPrototypeBinding.h"
|
#include "nsXBLPrototypeBinding.h"
|
||||||
@ -31,9 +32,8 @@ static DocumentOrShadowRoot* DocOrShadowFromContent(nsIContent& aContent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IDTracker::ResetToURIFragmentID(nsIContent* aFromContent, nsIURI* aURI,
|
void IDTracker::ResetToURIFragmentID(nsIContent* aFromContent, nsIURI* aURI,
|
||||||
nsIURI* aReferrer,
|
nsIReferrerInfo* aReferrerInfo,
|
||||||
uint32_t aReferrerPolicy, bool aWatch,
|
bool aWatch, bool aReferenceImage) {
|
||||||
bool aReferenceImage) {
|
|
||||||
MOZ_ASSERT(aFromContent,
|
MOZ_ASSERT(aFromContent,
|
||||||
"ResetToURIFragmentID() expects non-null content pointer");
|
"ResetToURIFragmentID() expects non-null content pointer");
|
||||||
|
|
||||||
@ -110,8 +110,8 @@ void IDTracker::ResetToURIFragmentID(nsIContent* aFromContent, nsIURI* aURI,
|
|||||||
rv = aURI->EqualsExceptRef(doc->GetDocumentURI(), &isEqualExceptRef);
|
rv = aURI->EqualsExceptRef(doc->GetDocumentURI(), &isEqualExceptRef);
|
||||||
if (NS_FAILED(rv) || !isEqualExceptRef) {
|
if (NS_FAILED(rv) || !isEqualExceptRef) {
|
||||||
RefPtr<Document::ExternalResourceLoad> load;
|
RefPtr<Document::ExternalResourceLoad> load;
|
||||||
doc = doc->RequestExternalResource(aURI, aReferrer, aReferrerPolicy,
|
doc = doc->RequestExternalResource(aURI, aReferrerInfo, aFromContent,
|
||||||
aFromContent, getter_AddRefs(load));
|
getter_AddRefs(load));
|
||||||
docOrShadow = doc;
|
docOrShadow = doc;
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
if (!load || !aWatch) {
|
if (!load || !aWatch) {
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
|
|
||||||
class nsIURI;
|
class nsIURI;
|
||||||
|
class nsIReferrerInfo;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
@ -53,16 +54,15 @@ class IDTracker {
|
|||||||
* do not trigger ElementChanged.
|
* do not trigger ElementChanged.
|
||||||
* @param aFrom the source element for context
|
* @param aFrom the source element for context
|
||||||
* @param aURI the URI containing a hash-reference to the element
|
* @param aURI the URI containing a hash-reference to the element
|
||||||
* @param aReferrer the referrer URI for loading external resource
|
* @param aReferrerInfo the referrerInfo for loading external resource
|
||||||
* @param aReferrerPolicy the referrer policy for loading external resource
|
|
||||||
* @param aWatch if false, then we do not set up the notifications to track
|
* @param aWatch if false, then we do not set up the notifications to track
|
||||||
* changes, so ElementChanged won't fire and get() will always return the same
|
* changes, so ElementChanged won't fire and get() will always return the same
|
||||||
* value, the current element for the ID.
|
* value, the current element for the ID.
|
||||||
* @param aReferenceImage whether the ID references image elements which are
|
* @param aReferenceImage whether the ID references image elements which are
|
||||||
* subject to the document's mozSetImageElement overriding mechanism.
|
* subject to the document's mozSetImageElement overriding mechanism.
|
||||||
*/
|
*/
|
||||||
void ResetToURIFragmentID(nsIContent* aFrom, nsIURI* aURI, nsIURI* aReferrer,
|
void ResetToURIFragmentID(nsIContent* aFrom, nsIURI* aURI,
|
||||||
uint32_t aReferrerPolicy, bool aWatch = true,
|
nsIReferrerInfo* aReferrerInfo, bool aWatch = true,
|
||||||
bool aReferenceImage = false);
|
bool aReferenceImage = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
#include "mozilla/MemoryReporting.h"
|
#include "mozilla/MemoryReporting.h"
|
||||||
#include "mozilla/Move.h"
|
#include "mozilla/Move.h"
|
||||||
#include "mozilla/dom/TreeOrderedArray.h"
|
#include "mozilla/dom/TreeOrderedArray.h"
|
||||||
#include "mozilla/net/ReferrerPolicy.h"
|
|
||||||
|
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsAtom.h"
|
#include "nsAtom.h"
|
||||||
@ -23,6 +22,7 @@
|
|||||||
#include "nsTHashtable.h"
|
#include "nsTHashtable.h"
|
||||||
|
|
||||||
class nsIContent;
|
class nsIContent;
|
||||||
|
class nsINode;
|
||||||
class nsContentList;
|
class nsContentList;
|
||||||
class nsBaseContentList;
|
class nsBaseContentList;
|
||||||
|
|
||||||
@ -47,7 +47,6 @@ class Element;
|
|||||||
class IdentifierMapEntry : public PLDHashEntryHdr {
|
class IdentifierMapEntry : public PLDHashEntryHdr {
|
||||||
typedef dom::Document Document;
|
typedef dom::Document Document;
|
||||||
typedef dom::Element Element;
|
typedef dom::Element Element;
|
||||||
typedef net::ReferrerPolicy ReferrerPolicy;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Document::IDTargetObserver, this is just here to avoid include hell.
|
* @see Document::IDTargetObserver, this is just here to avoid include hell.
|
||||||
@ -56,24 +55,24 @@ class IdentifierMapEntry : public PLDHashEntryHdr {
|
|||||||
void* aData);
|
void* aData);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct AtomOrString {
|
// We use DependentAtomOrString as our external key interface. This allows
|
||||||
MOZ_IMPLICIT AtomOrString(nsAtom* aAtom) : mAtom(aAtom) {}
|
// consumers to use an nsAString, for example, without forcing a copy.
|
||||||
MOZ_IMPLICIT AtomOrString(const nsAString& aString) : mString(aString) {}
|
struct DependentAtomOrString final {
|
||||||
AtomOrString(const AtomOrString& aOther)
|
MOZ_IMPLICIT DependentAtomOrString(nsAtom* aAtom)
|
||||||
|
: mAtom(aAtom), mString(nullptr) {}
|
||||||
|
MOZ_IMPLICIT DependentAtomOrString(const nsAString& aString)
|
||||||
|
: mAtom(nullptr), mString(&aString) {}
|
||||||
|
DependentAtomOrString(const DependentAtomOrString& aOther)
|
||||||
: mAtom(aOther.mAtom), mString(aOther.mString) {}
|
: mAtom(aOther.mAtom), mString(aOther.mString) {}
|
||||||
|
|
||||||
AtomOrString(AtomOrString&& aOther)
|
nsAtom* mAtom;
|
||||||
: mAtom(aOther.mAtom.forget()), mString(aOther.mString) {}
|
const nsAString* mString;
|
||||||
|
|
||||||
RefPtr<nsAtom> mAtom;
|
|
||||||
const nsString mString;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef const AtomOrString& KeyType;
|
typedef const DependentAtomOrString& KeyType;
|
||||||
typedef const AtomOrString* KeyTypePointer;
|
typedef const DependentAtomOrString* KeyTypePointer;
|
||||||
|
|
||||||
explicit IdentifierMapEntry(const AtomOrString& aKey);
|
explicit IdentifierMapEntry(const DependentAtomOrString* aKey);
|
||||||
explicit IdentifierMapEntry(const AtomOrString* aKey);
|
|
||||||
IdentifierMapEntry(IdentifierMapEntry&& aOther);
|
IdentifierMapEntry(IdentifierMapEntry&& aOther);
|
||||||
~IdentifierMapEntry();
|
~IdentifierMapEntry();
|
||||||
|
|
||||||
@ -91,20 +90,20 @@ class IdentifierMapEntry : public PLDHashEntryHdr {
|
|||||||
return mKey.mAtom == aOtherKey->mAtom;
|
return mKey.mAtom == aOtherKey->mAtom;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mKey.mAtom->Equals(aOtherKey->mString);
|
return mKey.mAtom->Equals(*aOtherKey->mString);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aOtherKey->mAtom) {
|
if (aOtherKey->mAtom) {
|
||||||
return aOtherKey->mAtom->Equals(mKey.mString);
|
return aOtherKey->mAtom->Equals(mKey.mString);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mKey.mString.Equals(aOtherKey->mString);
|
return mKey.mString.Equals(*aOtherKey->mString);
|
||||||
}
|
}
|
||||||
|
|
||||||
static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
|
static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
|
||||||
|
|
||||||
static PLDHashNumber HashKey(const KeyTypePointer aKey) {
|
static PLDHashNumber HashKey(const KeyTypePointer aKey) {
|
||||||
return aKey->mAtom ? aKey->mAtom->hash() : HashString(aKey->mString);
|
return aKey->mAtom ? aKey->mAtom->hash() : HashString(*aKey->mString);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum { ALLOW_MEMMOVE = false };
|
enum { ALLOW_MEMMOVE = false };
|
||||||
@ -155,6 +154,11 @@ class IdentifierMapEntry : public PLDHashEntryHdr {
|
|||||||
void RemoveContentChangeCallback(IDTargetObserver aCallback, void* aData,
|
void RemoveContentChangeCallback(IDTargetObserver aCallback, void* aData,
|
||||||
bool aForImage);
|
bool aForImage);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all elements and notify change listeners.
|
||||||
|
*/
|
||||||
|
void ClearAndNotify();
|
||||||
|
|
||||||
void Traverse(nsCycleCollectionTraversalCallback* aCallback);
|
void Traverse(nsCycleCollectionTraversalCallback* aCallback);
|
||||||
|
|
||||||
struct ChangeCallback {
|
struct ChangeCallback {
|
||||||
@ -189,13 +193,35 @@ class IdentifierMapEntry : public PLDHashEntryHdr {
|
|||||||
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
|
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// We use an OwningAtomOrString as our internal key storage. It needs to own
|
||||||
|
// the key string, whether in atom or string form.
|
||||||
|
struct OwningAtomOrString final {
|
||||||
|
OwningAtomOrString(const OwningAtomOrString& aOther)
|
||||||
|
: mAtom(aOther.mAtom), mString(aOther.mString) {}
|
||||||
|
|
||||||
|
OwningAtomOrString(OwningAtomOrString&& aOther)
|
||||||
|
: mAtom(std::move(aOther.mAtom)), mString(std::move(aOther.mString)) {}
|
||||||
|
|
||||||
|
explicit OwningAtomOrString(const DependentAtomOrString& aOther)
|
||||||
|
// aOther may have a null mString, so jump through a bit of a hoop in
|
||||||
|
// that case. I wish there were a way to just default-initialize
|
||||||
|
// mString in that situation... We could also make mString not const
|
||||||
|
// and only assign to it if aOther.mString is not null, but having it be
|
||||||
|
// const is nice.
|
||||||
|
: mAtom(aOther.mAtom),
|
||||||
|
mString(aOther.mString ? *aOther.mString : EmptyString()) {}
|
||||||
|
|
||||||
|
RefPtr<nsAtom> mAtom;
|
||||||
|
const nsString mString;
|
||||||
|
};
|
||||||
|
|
||||||
IdentifierMapEntry(const IdentifierMapEntry& aOther) = delete;
|
IdentifierMapEntry(const IdentifierMapEntry& aOther) = delete;
|
||||||
IdentifierMapEntry& operator=(const IdentifierMapEntry& aOther) = delete;
|
IdentifierMapEntry& operator=(const IdentifierMapEntry& aOther) = delete;
|
||||||
|
|
||||||
void FireChangeCallbacks(Element* aOldElement, Element* aNewElement,
|
void FireChangeCallbacks(Element* aOldElement, Element* aNewElement,
|
||||||
bool aImageOnly = false);
|
bool aImageOnly = false);
|
||||||
|
|
||||||
AtomOrString mKey;
|
OwningAtomOrString mKey;
|
||||||
dom::TreeOrderedArray<Element> mIdContentList;
|
dom::TreeOrderedArray<Element> mIdContentList;
|
||||||
RefPtr<nsBaseContentList> mNameContentList;
|
RefPtr<nsBaseContentList> mNameContentList;
|
||||||
nsAutoPtr<nsTHashtable<ChangeCallbackEntry> > mChangeCallbacks;
|
nsAutoPtr<nsTHashtable<ChangeCallbackEntry> > mChangeCallbacks;
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
#include "mozilla/dom/WindowBinding.h"
|
#include "mozilla/dom/WindowBinding.h"
|
||||||
#include "nsComponentManagerUtils.h"
|
#include "nsComponentManagerUtils.h"
|
||||||
#include "nsGlobalWindow.h"
|
#include "nsGlobalWindow.h"
|
||||||
#include "nsISupportsPrimitives.h"
|
|
||||||
#include "nsPIDOMWindow.h"
|
#include "nsPIDOMWindow.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#include "nsCycleCollectionParticipant.h"
|
#include "nsCycleCollectionParticipant.h"
|
||||||
#include "nsDOMNavigationTiming.h"
|
#include "nsDOMNavigationTiming.h"
|
||||||
#include "nsICancelableRunnable.h"
|
#include "nsICancelableRunnable.h"
|
||||||
#include "nsIRunnable.h"
|
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
|
|
||||||
class nsPIDOMWindowInner;
|
class nsPIDOMWindowInner;
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#include "mozilla/SyncRunnable.h"
|
#include "mozilla/SyncRunnable.h"
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
#include "gfxUtils.h"
|
#include "gfxUtils.h"
|
||||||
#include "nsThreadPool.h"
|
#include "nsThreadUtils.h"
|
||||||
#include "nsNetUtil.h"
|
#include "nsNetUtil.h"
|
||||||
#include "nsXPCOMCIDInternal.h"
|
#include "nsXPCOMCIDInternal.h"
|
||||||
#include "YCbCrUtils.h"
|
#include "YCbCrUtils.h"
|
||||||
@ -104,6 +104,8 @@ class EncodingCompleteEvent : public CancelableRunnable {
|
|||||||
MOZ_ASSERT(blob);
|
MOZ_ASSERT(blob);
|
||||||
|
|
||||||
rv = callback->ReceiveBlob(blob.forget());
|
rv = callback->ReceiveBlob(blob.forget());
|
||||||
|
} else {
|
||||||
|
rv = callback->ReceiveBlob(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
@ -211,8 +213,6 @@ class EncodingRunnable : public Runnable {
|
|||||||
bool mUsingCustomOptions;
|
bool mUsingCustomOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
StaticRefPtr<nsIThreadPool> ImageEncoder::sThreadPool;
|
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
nsresult ImageEncoder::ExtractData(nsAString& aType, const nsAString& aOptions,
|
nsresult ImageEncoder::ExtractData(nsAString& aType, const nsAString& aOptions,
|
||||||
const nsIntSize aSize, bool aUsePlaceholder,
|
const nsIntSize aSize, bool aUsePlaceholder,
|
||||||
@ -239,11 +239,6 @@ nsresult ImageEncoder::ExtractDataFromLayersImageAsync(
|
|||||||
return NS_IMAGELIB_ERROR_NO_ENCODER;
|
return NS_IMAGELIB_ERROR_NO_ENCODER;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult rv = EnsureThreadPool();
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
RefPtr<EncodingCompleteEvent> completeEvent =
|
RefPtr<EncodingCompleteEvent> completeEvent =
|
||||||
new EncodingCompleteEvent(aEncodeCallback);
|
new EncodingCompleteEvent(aEncodeCallback);
|
||||||
|
|
||||||
@ -252,7 +247,7 @@ nsresult ImageEncoder::ExtractDataFromLayersImageAsync(
|
|||||||
new EncodingRunnable(aType, aOptions, nullptr, aImage, encoder,
|
new EncodingRunnable(aType, aOptions, nullptr, aImage, encoder,
|
||||||
completeEvent, imgIEncoder::INPUT_FORMAT_HOSTARGB,
|
completeEvent, imgIEncoder::INPUT_FORMAT_HOSTARGB,
|
||||||
size, aUsePlaceholder, aUsingCustomOptions);
|
size, aUsePlaceholder, aUsingCustomOptions);
|
||||||
return sThreadPool->Dispatch(event, NS_DISPATCH_NORMAL);
|
return NS_DispatchToBackgroundThread(event.forget());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
@ -265,18 +260,13 @@ nsresult ImageEncoder::ExtractDataAsync(
|
|||||||
return NS_IMAGELIB_ERROR_NO_ENCODER;
|
return NS_IMAGELIB_ERROR_NO_ENCODER;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult rv = EnsureThreadPool();
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
RefPtr<EncodingCompleteEvent> completeEvent =
|
RefPtr<EncodingCompleteEvent> completeEvent =
|
||||||
new EncodingCompleteEvent(aEncodeCallback);
|
new EncodingCompleteEvent(aEncodeCallback);
|
||||||
|
|
||||||
nsCOMPtr<nsIRunnable> event = new EncodingRunnable(
|
nsCOMPtr<nsIRunnable> event = new EncodingRunnable(
|
||||||
aType, aOptions, std::move(aImageBuffer), nullptr, encoder, completeEvent,
|
aType, aOptions, std::move(aImageBuffer), nullptr, encoder, completeEvent,
|
||||||
aFormat, aSize, aUsePlaceholder, aUsingCustomOptions);
|
aFormat, aSize, aUsePlaceholder, aUsingCustomOptions);
|
||||||
return sThreadPool->Dispatch(event, NS_DISPATCH_NORMAL);
|
return NS_DispatchToBackgroundThread(event.forget());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/
|
/*static*/
|
||||||
@ -430,75 +420,5 @@ already_AddRefed<imgIEncoder> ImageEncoder::GetImageEncoder(nsAString& aType) {
|
|||||||
return encoder.forget();
|
return encoder.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
class EncoderThreadPoolTerminator final : public nsIObserver {
|
|
||||||
public:
|
|
||||||
NS_DECL_ISUPPORTS
|
|
||||||
|
|
||||||
NS_IMETHOD Observe(nsISupports*, const char* topic,
|
|
||||||
const char16_t*) override {
|
|
||||||
NS_ASSERTION(!strcmp(topic, "xpcom-shutdown-threads"), "Unexpected topic");
|
|
||||||
if (ImageEncoder::sThreadPool) {
|
|
||||||
ImageEncoder::sThreadPool->Shutdown();
|
|
||||||
ImageEncoder::sThreadPool = nullptr;
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
~EncoderThreadPoolTerminator() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(EncoderThreadPoolTerminator, nsIObserver)
|
|
||||||
|
|
||||||
static void RegisterEncoderThreadPoolTerminatorObserver() {
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
|
||||||
NS_ASSERTION(os, "do_GetService failed");
|
|
||||||
os->AddObserver(new EncoderThreadPoolTerminator(), "xpcom-shutdown-threads",
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */
|
|
||||||
nsresult ImageEncoder::EnsureThreadPool() {
|
|
||||||
if (!sThreadPool) {
|
|
||||||
nsCOMPtr<nsIThreadPool> threadPool = new nsThreadPool();
|
|
||||||
sThreadPool = threadPool;
|
|
||||||
|
|
||||||
if (!NS_IsMainThread()) {
|
|
||||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
|
||||||
"dom::ImageEncoder::EnsureThreadPool",
|
|
||||||
[]() -> void { RegisterEncoderThreadPoolTerminatorObserver(); }));
|
|
||||||
} else {
|
|
||||||
RegisterEncoderThreadPoolTerminatorObserver();
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint32_t kThreadLimit = 2;
|
|
||||||
const uint32_t kIdleThreadLimit = 1;
|
|
||||||
const uint32_t kIdleThreadTimeoutMs = 30000;
|
|
||||||
|
|
||||||
nsresult rv = sThreadPool->SetName(NS_LITERAL_CSTRING("EncodingRunnable"));
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = sThreadPool->SetThreadLimit(kThreadLimit);
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = sThreadPool->SetIdleThreadLimit(kIdleThreadLimit);
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = sThreadPool->SetIdleThreadTimeout(kIdleThreadTimeoutMs);
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
#include "nsSize.h"
|
#include "nsSize.h"
|
||||||
|
|
||||||
class nsICanvasRenderingContextInternal;
|
class nsICanvasRenderingContextInternal;
|
||||||
class nsIThreadPool;
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
@ -95,11 +94,6 @@ class ImageEncoder {
|
|||||||
// undefined in this case.
|
// undefined in this case.
|
||||||
static already_AddRefed<imgIEncoder> GetImageEncoder(nsAString& aType);
|
static already_AddRefed<imgIEncoder> GetImageEncoder(nsAString& aType);
|
||||||
|
|
||||||
static nsresult EnsureThreadPool();
|
|
||||||
|
|
||||||
// Thread pool for dispatching EncodingRunnable.
|
|
||||||
static StaticRefPtr<nsIThreadPool> sThreadPool;
|
|
||||||
|
|
||||||
friend class EncodingRunnable;
|
friend class EncodingRunnable;
|
||||||
friend class EncoderThreadPoolTerminator;
|
friend class EncoderThreadPoolTerminator;
|
||||||
};
|
};
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user