mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-05 23:38:38 +09:00
Bug 1299363 - Part 5-2: Implement new upgrade steps.
Tag UXP Issue #1344
This commit is contained in:
parent
b2e0ae6983
commit
729ffa53f3
2 changed files with 177 additions and 35 deletions
|
|
@ -19,7 +19,7 @@ namespace dom {
|
|||
void
|
||||
CustomElementCallback::Call()
|
||||
{
|
||||
ErrorResult rv;
|
||||
IgnoredErrorResult rv;
|
||||
switch (mType) {
|
||||
case nsIDocument::eCreated:
|
||||
{
|
||||
|
|
@ -55,10 +55,6 @@ CustomElementCallback::Call()
|
|||
mArgs.name, mArgs.oldValue, mArgs.newValue, rv);
|
||||
break;
|
||||
}
|
||||
|
||||
// If callbacks throw exceptions, it'll be handled and reported in
|
||||
// Lifecycle*Callback::Call function.
|
||||
rv.SuppressException();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -82,6 +78,38 @@ CustomElementCallback::CustomElementCallback(Element* aThisObject,
|
|||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
// CustomElementConstructor
|
||||
|
||||
already_AddRefed<Element>
|
||||
CustomElementConstructor::Construct(const char* aExecutionReason,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
CallSetup s(this, aRv, aExecutionReason,
|
||||
CallbackFunction::eRethrowExceptions);
|
||||
|
||||
JSContext* cx = s.GetContext();
|
||||
if (!cx) {
|
||||
MOZ_ASSERT(aRv.Failed());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> result(cx);
|
||||
JS::Rooted<JS::Value> constructor(cx, JS::ObjectValue(*mCallback));
|
||||
if (!JS::Construct(cx, constructor, JS::HandleValueArray::empty(), &result)) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<Element> element;
|
||||
if (NS_FAILED(UNWRAP_OBJECT(Element, &result, element))) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return element.forget();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
// CustomElementData
|
||||
|
||||
|
|
@ -101,6 +129,33 @@ CustomElementData::CustomElementData(nsIAtom* aType, State aState)
|
|||
//-----------------------------------------------------
|
||||
// CustomElementRegistry
|
||||
|
||||
namespace {
|
||||
|
||||
class MOZ_RAII AutoConstructionStackEntry final
|
||||
{
|
||||
public:
|
||||
AutoConstructionStackEntry(nsTArray<RefPtr<nsGenericHTMLElement>>& aStack,
|
||||
nsGenericHTMLElement* aElement)
|
||||
: mStack(aStack)
|
||||
{
|
||||
mIndex = mStack.Length();
|
||||
mStack.AppendElement(aElement);
|
||||
}
|
||||
|
||||
~AutoConstructionStackEntry()
|
||||
{
|
||||
MOZ_ASSERT(mIndex == mStack.Length() - 1,
|
||||
"Removed element should be the last element");
|
||||
mStack.RemoveElementAt(mIndex);
|
||||
}
|
||||
|
||||
private:
|
||||
nsTArray<RefPtr<nsGenericHTMLElement>>& mStack;
|
||||
uint32_t mIndex;
|
||||
};
|
||||
|
||||
} // namespace anonymous
|
||||
|
||||
// Only needed for refcounted objects.
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(CustomElementRegistry)
|
||||
|
||||
|
|
@ -139,6 +194,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CustomElementRegistry)
|
|||
"mCustomDefinitions->mCallbacks->mDetachedCallback");
|
||||
cb.NoteXPCOMChild(callbacks->mDetachedCallback.Value());
|
||||
}
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
|
||||
"mCustomDefinitions->mConstructor");
|
||||
cb.NoteXPCOMChild(iter.UserData()->mConstructor);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWhenDefinedPromiseMap)
|
||||
|
|
@ -147,9 +206,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CustomElementRegistry)
|
||||
for (auto iter = tmp->mCustomDefinitions.Iter(); !iter.Done(); iter.Next()) {
|
||||
aCallbacks.Trace(&iter.UserData()->mConstructor,
|
||||
"mCustomDefinitions constructor",
|
||||
aClosure);
|
||||
aCallbacks.Trace(&iter.UserData()->mPrototype,
|
||||
"mCustomDefinitions prototype",
|
||||
aClosure);
|
||||
|
|
@ -418,6 +474,7 @@ CustomElementRegistry::UpgradeCandidates(nsIAtom* aKey,
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO: Bug 1326028 - Upgrade custom element in shadow-including tree order
|
||||
nsAutoPtr<nsTArray<nsWeakPtr>> candidates;
|
||||
mCandidatesMap.RemoveAndForget(aKey, candidates);
|
||||
if (candidates) {
|
||||
|
|
@ -696,7 +753,7 @@ CustomElementRegistry::Define(const nsAString& aName,
|
|||
CustomElementDefinition* definition =
|
||||
new CustomElementDefinition(nameAtom,
|
||||
localNameAtom,
|
||||
constructor,
|
||||
&aFunctionConstructor,
|
||||
constructorPrototype,
|
||||
callbacks,
|
||||
0 /* TODO dependent on HTML imports. Bug 877072 */);
|
||||
|
|
@ -717,7 +774,6 @@ CustomElementRegistry::Define(const nsAString& aName,
|
|||
/**
|
||||
* 13. 14. 15. Upgrade candidates
|
||||
*/
|
||||
// TODO: Bug 1299363 - Implement custom element v1 upgrade algorithm
|
||||
UpgradeCandidates(nameAtom, definition, aRv);
|
||||
|
||||
/**
|
||||
|
|
@ -748,7 +804,7 @@ CustomElementRegistry::Get(JSContext* aCx, const nsAString& aName,
|
|||
return;
|
||||
}
|
||||
|
||||
aRetVal.setObject(*data->mConstructor);
|
||||
aRetVal.setObjectOrNull(data->mConstructor->Callable());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -782,23 +838,67 @@ CustomElementRegistry::WhenDefined(const nsAString& aName, ErrorResult& aRv)
|
|||
return promise.forget();
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementRegistry::Upgrade(Element* aElement,
|
||||
CustomElementDefinition* aDefinition)
|
||||
{
|
||||
// TODO: This function will be replaced to v1 upgrade in bug 1299363
|
||||
aElement->RemoveStates(NS_EVENT_STATE_UNRESOLVED);
|
||||
namespace {
|
||||
|
||||
// Make sure that the element name matches the name in the definition.
|
||||
// (e.g. a definition for x-button extending button should match
|
||||
// <button is="x-button"> but not <x-button>.
|
||||
if (aElement->NodeInfo()->NameAtom() != aDefinition->mLocalName) {
|
||||
//Skip over this element because definition does not apply.
|
||||
static void
|
||||
DoUpgrade(Element* aElement,
|
||||
CustomElementConstructor* aConstructor,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
// Rethrow the exception since it might actually throw the exception from the
|
||||
// upgrade steps back out to the caller of document.createElement.
|
||||
RefPtr<Element> constructResult =
|
||||
aConstructor->Construct("Custom Element Upgrade", aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aElement->IsHTMLElement(aDefinition->mLocalName));
|
||||
if (constructResult.get() != aElement) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/scripting.html#upgrades
|
||||
void
|
||||
CustomElementRegistry::Upgrade(Element* aElement,
|
||||
CustomElementDefinition* aDefinition,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
aElement->RemoveStates(NS_EVENT_STATE_UNRESOLVED);
|
||||
|
||||
RefPtr<CustomElementData> data = aElement->GetCustomElementData();
|
||||
MOZ_ASSERT(data, "CustomElementData should exist");
|
||||
|
||||
// Step 1 and step 2.
|
||||
if (data->mState == CustomElementData::State::eCustom ||
|
||||
data->mState == CustomElementData::State::eFailed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 3 and Step 4.
|
||||
// TODO: Bug 1334051 - Implement list of observed attributes for custom elements' attributeChanged callbacks
|
||||
// TODO: Bug 1334043 - Implement connected lifecycle callbacks for custom elements
|
||||
|
||||
// Step 5.
|
||||
AutoConstructionStackEntry acs(aDefinition->mConstructionStack,
|
||||
nsGenericHTMLElement::FromContent(aElement));
|
||||
|
||||
// Step 6 and step 7.
|
||||
DoUpgrade(aElement, aDefinition->mConstructor, aRv);
|
||||
if (aRv.Failed()) {
|
||||
data->mState = CustomElementData::State::eFailed;
|
||||
// Empty element's custom element reaction queue.
|
||||
data->mReactionQueue.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 8.
|
||||
data->mState = CustomElementData::State::eCustom;
|
||||
|
||||
// This is for old spec.
|
||||
EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, aDefinition);
|
||||
}
|
||||
|
||||
|
|
@ -824,7 +924,13 @@ CustomElementReactionsStack::PopAndInvokeElementQueue()
|
|||
ElementQueue* elementQueue = mReactionsStack.ElementAt(lastIndex).get();
|
||||
// Check element queue size in order to reduce function call overhead.
|
||||
if (!elementQueue->IsEmpty()) {
|
||||
InvokeReactions(elementQueue);
|
||||
// It is still not clear what error reporting will look like in custom
|
||||
// element, see https://github.com/w3c/webcomponents/issues/635.
|
||||
// We usually report the error to entry global in gecko, so just follow the
|
||||
// same behavior here.
|
||||
nsIGlobalObject* global = GetEntryGlobal();
|
||||
MOZ_ASSERT(global, "Should always have a entry global here!");
|
||||
InvokeReactions(elementQueue, global);
|
||||
}
|
||||
|
||||
// InvokeReactions() might create other custom element reactions, but those
|
||||
|
|
@ -887,13 +993,24 @@ CustomElementReactionsStack::InvokeBackupQueue()
|
|||
{
|
||||
// Check backup queue size in order to reduce function call overhead.
|
||||
if (!mBackupQueue.IsEmpty()) {
|
||||
InvokeReactions(&mBackupQueue);
|
||||
// Upgrade reactions won't be scheduled in backup queue and the exception of
|
||||
// callback reactions will be automatically reported in CallSetup.
|
||||
// If the reactions are invoked from backup queue (in microtask check point),
|
||||
// we don't need to pass global object for error reporting.
|
||||
InvokeReactions(&mBackupQueue, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementReactionsStack::InvokeReactions(ElementQueue* aElementQueue)
|
||||
CustomElementReactionsStack::InvokeReactions(ElementQueue* aElementQueue,
|
||||
nsIGlobalObject* aGlobal)
|
||||
{
|
||||
// This is used for error reporting.
|
||||
Maybe<AutoEntryScript> aes;
|
||||
if (aGlobal) {
|
||||
aes.emplace(aGlobal, "custom elements reaction invocation");
|
||||
}
|
||||
|
||||
// Note: It's possible to re-enter this method.
|
||||
for (uint32_t i = 0; i < aElementQueue->Length(); ++i) {
|
||||
nsCOMPtr<Element> element = do_QueryReferent(aElementQueue->ElementAt(i));
|
||||
|
|
@ -911,7 +1028,16 @@ CustomElementReactionsStack::InvokeReactions(ElementQueue* aElementQueue)
|
|||
// this funciton. The entry will be removed when bug 1379573 is landed.
|
||||
auto reaction(Move(reactions.ElementAt(j)));
|
||||
if (reaction) {
|
||||
reaction->Invoke(element);
|
||||
ErrorResult rv;
|
||||
reaction->Invoke(element, rv);
|
||||
if (aes) {
|
||||
JSContext* cx = aes->cx();
|
||||
if (rv.MaybeSetPendingException(cx)) {
|
||||
aes->ReportException();
|
||||
}
|
||||
MOZ_ASSERT(!JS_IsExceptionPending(cx));
|
||||
}
|
||||
MOZ_ASSERT(!rv.Failed());
|
||||
}
|
||||
}
|
||||
reactions.Clear();
|
||||
|
|
@ -924,13 +1050,13 @@ CustomElementReactionsStack::InvokeReactions(ElementQueue* aElementQueue)
|
|||
|
||||
CustomElementDefinition::CustomElementDefinition(nsIAtom* aType,
|
||||
nsIAtom* aLocalName,
|
||||
JSObject* aConstructor,
|
||||
Function* aConstructor,
|
||||
JSObject* aPrototype,
|
||||
LifecycleCallbacks* aCallbacks,
|
||||
uint32_t aDocOrder)
|
||||
: mType(aType),
|
||||
mLocalName(aLocalName),
|
||||
mConstructor(aConstructor),
|
||||
mConstructor(new CustomElementConstructor(aConstructor)),
|
||||
mPrototype(aPrototype),
|
||||
mCallbacks(aCallbacks),
|
||||
mDocOrder(aDocOrder)
|
||||
|
|
@ -941,16 +1067,16 @@ CustomElementDefinition::CustomElementDefinition(nsIAtom* aType,
|
|||
// CustomElementUpgradeReaction
|
||||
|
||||
/* virtual */ void
|
||||
CustomElementUpgradeReaction::Invoke(Element* aElement)
|
||||
CustomElementUpgradeReaction::Invoke(Element* aElement, ErrorResult& aRv)
|
||||
{
|
||||
mRegistry->Upgrade(aElement, mDefinition);
|
||||
mRegistry->Upgrade(aElement, mDefinition, aRv);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
// CustomElementCallbackReaction
|
||||
|
||||
/* virtual */ void
|
||||
CustomElementCallbackReaction::Invoke(Element* aElement)
|
||||
CustomElementCallbackReaction::Invoke(Element* aElement, ErrorResult& aRv)
|
||||
{
|
||||
mCustomElementCallback->Call();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue