During the last weeks, I landed the custom element creation PR and implemented custom element callback reactions. I also spent some time in Hawaii! Anyways, back to business...
After finishing the remaining work on custom element creation, I began to implement custom element callback reactions. CE Reactions are complex and I initially split the task into three parts:
After reading the spec more closely and begining on an initial implementation, I realized that it
might not be possible to implement steps 1 and 2 without also imeplementing step 3. After more
implementation, I finally concluded that the two can be implemented separately, but step 3 is a
relatively easy step to implement anyways; however, I have decided to keep step 3 separate as it
[CEReactions] in many
webidl files and would be cleaner to review separately. I
have allocated less than a week for that work.
To understand my initial confusion, we will need to dive into the custom element reactions spec and understand how reactions actually work. The implementation requires multiple stacks and queus which each have their own function. I will go over them briefly.
This stack is the "master" stack. Each unit of related similar-origin browsing contexts (In Servo-land, a single script thread) contains one of these. Each item in this stack is an element queue. If the stack is not empty, it has a current element queue and it always has a special element queue called the backup element queue.
Each item in this queue is an
Element. If an element is placed in this queue, it means that the
element has reactions that need to be invoked.
Element owns a custom element reaction queue. Each item in this queue is a reaction which
is an enum with the following variants:
[CEReactions]and Reaction Flow
All these queues and stacks make it seem like the reactions are overcomplicated; however, it was designed this way for a reason. When reactions are invoked, user script is also invoked. This could be very dangerous as the browser may be in the middle of an operation that could be messed up by the user script. The main goals of this implementation are to:
To maintain both invariants, the idea is to mark all operations in the webidl interfaces that may trigger reactions. Before any of these operations are ran, a new element queue is pushed onto the custom element reaction stack. Whenever a reactions should be invoked, the reaction is queued on its associated element's custom element reaction queue and the element is added to the current element queue of the custom element reaction stack. After the operation is finished, the current element queue is popped and each element in the queue invokes all of the reactions in its queue in the proper order.
This is where my confusion occurred with the necessity of
[CEReactions] for step 1. There is one
piece of information I did miss and that is the backup element queue. There are some
user-initiated operations that may cause a reaction but do not go through a DOM interface. This
would mean that the custom element reaction stack may not have a current element queue;
instead the backup element queue is used and the reactions are invoked via a microtask.
My current implementation does not have the
[CEReactions] attribute added to the webidl
files. It relies on the backup element queue instead. The reactions are also invoked instantly
rather than by a microtask. These changes are large and I think it is best to try to split the work
into smaller chunks.
I have adjusted my roadmap to account for vacation and the change of order as I plan to finish
[CEReactions] before implementing the upgrade reaction.