Changeset 146583 in webkit


Ignore:
Timestamp:
Mar 22, 2013 2:54:06 AM (11 years ago)
Author:
morrita@google.com
Message:

Custom Elements: "readyCallback" lifecycle callback should be called.
https://bugs.webkit.org/show_bug.cgi?id=112538

Reviewed by Elliott Sprehn.

Source/WebCore:

This change allows each custom element definition to hook up its instantiation,
namely "readyCallback" lifecycle callback.

The change has two parts:

  • 1. Tracking which Element objects to be created.
  • 2. Invoking appropriate JavaScript functions, which are readyCallback(), before the Element object is visible from page script.

For 1, CustomElementRegistry maintains list of "callback
invocaions". Each list item ("invocation") tracks the element
which has a lifecycle callback to be invoked. Each invocation is
registered when - Any custom element C++ object is instantiated.
See changes on CustomElementConstructor.cpp.

This also happens when @is attribute is set by the parser or node
cloning routine, which can turn a non-custom element into a
type-extended custom element. See changes on Element.cpp.

For 2, CustomElementRegistry basically follows what
MutationObserver is doing, and introduces a method called
deliverLifecycleCallbacks(). This function flushes all pending
callback invocations. You can think it as a dual of
MutationObserver::deliverAllMutations().

The delivery function is called places where MutationObserver's
deliverAllMutations() is called. In addition, it is also called
just before returning from a set of DOM APIs. For example, it is
called just before createElement() returns, so that possibly
created custom element becomes ready through its readyCallback().
Such APIs get "V8DeliverCustomElementCallbacks" IDL attribute. In
principle, APIs which can create new custom element instnaces are
marked. See CustomElementRegistry::CallbackDeliveryScope and
changes on CodeGeneratorV8.pm.

We need this extra work because the readyCallback() needs to give
an illusion so that JavaScript programmers feel like the
readyCallback() callback being called just after it is created,
instead of called on arbitrary late timing like MutationObserver
notifications.

Tests: fast/dom/custom/lifecycle-ready-createElement-recursion.html

fast/dom/custom/lifecycle-ready-createElement-reentrancy.html
fast/dom/custom/lifecycle-ready-creation-api.html
fast/dom/custom/lifecycle-ready-innerHTML.html
fast/dom/custom/lifecycle-ready-parser-only.html
fast/dom/custom/lifecycle-ready-parser-script.html
fast/dom/custom/lifecycle-ready-paste.html

  • bindings/scripts/CodeGeneratorV8.pm:
  • Hooked up CallbackDeliveryScope through V8DeliverCustomElementCallbacks attriute.

(GenerateCustomElementInvocationScopeIfNeeded):
(GenerateNormalAttrSetter):
(GenerateFunction):

  • bindings/scripts/IDLAttributes.txt:
  • bindings/v8/CustomElementHelpers.cpp:

(WebCore::CustomElementHelpers::invokeReadyCallbackIfNeeded):
(WebCore::CustomElementHelpers::invokeReadyCallbacksIfNeeded):

  • bindings/v8/CustomElementHelpers.h:

(CustomElementHelpers):

  • bindings/v8/V8RecursionScope.cpp: Added deliverAllLifecycleCallbacks()

(WebCore::V8RecursionScope::didLeaveScriptContext):

  • dom/CustomElementConstructor.cpp:

(WebCore::CustomElementConstructor::createElement):
(WebCore::CustomElementConstructor::createElementInternal):

  • dom/CustomElementConstructor.h:

(WebCore::CustomElementConstructor::isExtended):
(CustomElementConstructor):

  • dom/CustomElementRegistry.cpp: Adding element tracking and invocation execution.

(WebCore::CustomElementInvocation::CustomElementInvocation):
(WebCore::CustomElementInvocation::~CustomElementInvocation):
(WebCore::activeCustomElementRegistries):
(WebCore::CustomElementRegistry::~CustomElementRegistry):
(WebCore::CustomElementRegistry::didGiveTypeExtension):
(WebCore::CustomElementRegistry::didCreateElement):
(WebCore::CustomElementRegistry::activate):
(WebCore::CustomElementRegistry::deactivate):
(WebCore::CustomElementRegistry::deliverLifecycleCallbacks):
(WebCore::CustomElementRegistry::deliverAllLifecycleCallbacks):

  • dom/CustomElementRegistry.h:

(CustomElementInvocation):
(WebCore::CustomElementInvocation::element):
(CallbackDeliveryScope):
(WebCore::CustomElementRegistry::CallbackDeliveryScope::CallbackDeliveryScope):
(WebCore::CustomElementRegistry::CallbackDeliveryScope::~CallbackDeliveryScope):
(CustomElementRegistry):
(WebCore::CustomElementRegistry::deliverAllLifecycleCallbacksIfNeeded):

  • dom/Document.cpp:

(WebCore::Document::createElement):
(WebCore::Document::didCreateCustomElement):

  • dom/Document.h:

(Document):

  • dom/Document.idl:
  • dom/Element.cpp:

(WebCore::Element::attributeChangedFromParserOrByCloning): Added to catch @is attribute
(WebCore::Element::parserSetAttributes):
(WebCore::Element::cloneAttributesFromElement):

  • dom/Element.h:
  • dom/Node.idl:
  • dom/ShadowRoot.idl:
  • html/HTMLElement.idl:
  • html/parser/HTMLScriptRunner.cpp: Added deliverAllLifecycleCallbacks()

(WebCore::HTMLScriptRunner::executePendingScriptAndDispatchEvent):
(WebCore::HTMLScriptRunner::runScript):

Source/WebKit/chromium:

  • src/WebKit.cpp: Added deliverAllLifecycleCallbacks()

Source/WTF:

  • wtf/HashSet.h:

(WTF::copyToVector): Generalized to let it accept variants like ListHahsSet instead of only HashSet.

LayoutTests:

  • fast/dom/custom/lifecycle-ready-createElement-recursion-expected.txt: Added.
  • fast/dom/custom/lifecycle-ready-createElement-recursion.html: Added.
  • fast/dom/custom/lifecycle-ready-createElement-reentrancy-expected.txt: Added.
  • fast/dom/custom/lifecycle-ready-createElement-reentrancy.html: Added.
  • fast/dom/custom/lifecycle-ready-creation-api-expected.txt: Added.
  • fast/dom/custom/lifecycle-ready-creation-api.html: Added.
  • fast/dom/custom/lifecycle-ready-innerHTML-expected.txt: Added.
  • fast/dom/custom/lifecycle-ready-innerHTML.html: Added.
  • fast/dom/custom/lifecycle-ready-parser-only-expected.html: Added.
  • fast/dom/custom/lifecycle-ready-parser-only.html: Added.
  • fast/dom/custom/lifecycle-ready-parser-script-expected.txt: Added.
  • fast/dom/custom/lifecycle-ready-parser-script.html: Added.
  • fast/dom/custom/lifecycle-ready-paste-expected.txt: Added.
  • fast/dom/custom/lifecycle-ready-paste.html: Added.
Location:
trunk
Files:
14 added
24 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r146582 r146583  
     12013-03-22  Hajime Morrita  <morrita@google.com>
     2
     3        Custom Elements: "readyCallback" lifecycle callback should be called.
     4        https://bugs.webkit.org/show_bug.cgi?id=112538
     5
     6        Reviewed by Elliott Sprehn.
     7
     8        * fast/dom/custom/lifecycle-ready-createElement-recursion-expected.txt: Added.
     9        * fast/dom/custom/lifecycle-ready-createElement-recursion.html: Added.
     10        * fast/dom/custom/lifecycle-ready-createElement-reentrancy-expected.txt: Added.
     11        * fast/dom/custom/lifecycle-ready-createElement-reentrancy.html: Added.
     12        * fast/dom/custom/lifecycle-ready-creation-api-expected.txt: Added.
     13        * fast/dom/custom/lifecycle-ready-creation-api.html: Added.
     14        * fast/dom/custom/lifecycle-ready-innerHTML-expected.txt: Added.
     15        * fast/dom/custom/lifecycle-ready-innerHTML.html: Added.
     16        * fast/dom/custom/lifecycle-ready-parser-only-expected.html: Added.
     17        * fast/dom/custom/lifecycle-ready-parser-only.html: Added.
     18        * fast/dom/custom/lifecycle-ready-parser-script-expected.txt: Added.
     19        * fast/dom/custom/lifecycle-ready-parser-script.html: Added.
     20        * fast/dom/custom/lifecycle-ready-paste-expected.txt: Added.
     21        * fast/dom/custom/lifecycle-ready-paste.html: Added.
     22
    1232013-03-22  Tommy Widenflycht  <tommyw@google.com>
    224
  • trunk/Source/WTF/ChangeLog

    r146572 r146583  
     12013-03-22  Hajime Morrita  <morrita@google.com>
     2
     3        Custom Elements: "readyCallback" lifecycle callback should be called.
     4        https://bugs.webkit.org/show_bug.cgi?id=112538
     5
     6        Reviewed by Elliott Sprehn.
     7
     8        * wtf/HashSet.h:
     9        (WTF::copyToVector): Generalized to let it accept variants like ListHahsSet instead of only HashSet.
     10
    1112013-03-22  Sheriff Bot  <webkit.review.bot@gmail.com>
    212
  • trunk/Source/WTF/wtf/HashSet.h

    r146572 r146583  
    244244    }
    245245
    246     template<typename T, typename U, typename V, typename W>
    247     inline void copyToVector(const HashSet<T, U, V>& collection, W& vector)
    248     {
    249         typedef typename HashSet<T, U, V>::const_iterator iterator;
     246    template<typename C, typename W>
     247    inline void copyToVector(const C& collection, W& vector)
     248    {
     249        typedef typename C::const_iterator iterator;
    250250       
    251251        vector.resize(collection.size());
  • trunk/Source/WebCore/ChangeLog

    r146582 r146583  
     12013-03-22  Hajime Morrita  <morrita@google.com>
     2
     3        Custom Elements: "readyCallback" lifecycle callback should be called.
     4        https://bugs.webkit.org/show_bug.cgi?id=112538
     5
     6        Reviewed by Elliott Sprehn.
     7
     8        This change allows each custom element definition to hook up its instantiation,
     9        namely "readyCallback" lifecycle callback.
     10
     11        The change has two parts:
     12        - 1. Tracking which Element objects to be created.
     13        - 2. Invoking appropriate JavaScript functions, which are readyCallback(),
     14          before the Element object is visible from page script.
     15
     16        For 1, CustomElementRegistry maintains list of "callback
     17        invocaions".  Each list item ("invocation") tracks the element
     18        which has a lifecycle callback to be invoked. Each invocation is
     19        registered when - Any custom element C++ object is instantiated.
     20        See changes on CustomElementConstructor.cpp.
     21
     22        This also happens when @is attribute is set by the parser or node
     23        cloning routine, which can turn a non-custom element into a
     24        type-extended custom element. See changes on Element.cpp.
     25
     26        For 2, CustomElementRegistry basically follows what
     27        MutationObserver is doing, and introduces a method called
     28        deliverLifecycleCallbacks(). This function flushes all pending
     29        callback invocations. You can think it as a dual of
     30        MutationObserver::deliverAllMutations().
     31
     32        The delivery function is called places where MutationObserver's
     33        deliverAllMutations() is called. In addition, it is also called
     34        just before returning from a set of DOM APIs. For example, it is
     35        called just before createElement() returns, so that possibly
     36        created custom element becomes ready through its readyCallback().
     37        Such APIs get "V8DeliverCustomElementCallbacks" IDL attribute. In
     38        principle, APIs which can create new custom element instnaces are
     39        marked. See CustomElementRegistry::CallbackDeliveryScope and
     40        changes on CodeGeneratorV8.pm.
     41
     42        We need this extra work because the readyCallback() needs to give
     43        an illusion so that JavaScript programmers feel like the
     44        readyCallback() callback being called just after it is created,
     45        instead of called on arbitrary late timing like MutationObserver
     46        notifications.
     47
     48        Tests: fast/dom/custom/lifecycle-ready-createElement-recursion.html
     49               fast/dom/custom/lifecycle-ready-createElement-reentrancy.html
     50               fast/dom/custom/lifecycle-ready-creation-api.html
     51               fast/dom/custom/lifecycle-ready-innerHTML.html
     52               fast/dom/custom/lifecycle-ready-parser-only.html
     53               fast/dom/custom/lifecycle-ready-parser-script.html
     54               fast/dom/custom/lifecycle-ready-paste.html
     55
     56        * bindings/scripts/CodeGeneratorV8.pm:
     57        - Hooked up CallbackDeliveryScope through V8DeliverCustomElementCallbacks attriute.
     58        (GenerateCustomElementInvocationScopeIfNeeded):
     59        (GenerateNormalAttrSetter):
     60        (GenerateFunction):
     61        * bindings/scripts/IDLAttributes.txt:
     62        * bindings/v8/CustomElementHelpers.cpp:
     63        (WebCore::CustomElementHelpers::invokeReadyCallbackIfNeeded):
     64        (WebCore::CustomElementHelpers::invokeReadyCallbacksIfNeeded):
     65        * bindings/v8/CustomElementHelpers.h:
     66        (CustomElementHelpers):
     67        * bindings/v8/V8RecursionScope.cpp: Added deliverAllLifecycleCallbacks()
     68        (WebCore::V8RecursionScope::didLeaveScriptContext):
     69        * dom/CustomElementConstructor.cpp:
     70        (WebCore::CustomElementConstructor::createElement):
     71        (WebCore::CustomElementConstructor::createElementInternal):
     72        * dom/CustomElementConstructor.h:
     73        (WebCore::CustomElementConstructor::isExtended):
     74        (CustomElementConstructor):
     75        * dom/CustomElementRegistry.cpp: Adding element tracking and invocation execution.
     76        (WebCore::CustomElementInvocation::CustomElementInvocation):
     77        (WebCore::CustomElementInvocation::~CustomElementInvocation):
     78        (WebCore::activeCustomElementRegistries):
     79        (WebCore::CustomElementRegistry::~CustomElementRegistry):
     80        (WebCore::CustomElementRegistry::didGiveTypeExtension):
     81        (WebCore::CustomElementRegistry::didCreateElement):
     82        (WebCore::CustomElementRegistry::activate):
     83        (WebCore::CustomElementRegistry::deactivate):
     84        (WebCore::CustomElementRegistry::deliverLifecycleCallbacks):
     85        (WebCore::CustomElementRegistry::deliverAllLifecycleCallbacks):
     86        * dom/CustomElementRegistry.h:
     87        (CustomElementInvocation):
     88        (WebCore::CustomElementInvocation::element):
     89        (CallbackDeliveryScope):
     90        (WebCore::CustomElementRegistry::CallbackDeliveryScope::CallbackDeliveryScope):
     91        (WebCore::CustomElementRegistry::CallbackDeliveryScope::~CallbackDeliveryScope):
     92        (CustomElementRegistry):
     93        (WebCore::CustomElementRegistry::deliverAllLifecycleCallbacksIfNeeded):
     94        * dom/Document.cpp:
     95        (WebCore::Document::createElement):
     96        (WebCore::Document::didCreateCustomElement):
     97        * dom/Document.h:
     98        (Document):
     99        * dom/Document.idl:
     100        * dom/Element.cpp:
     101        (WebCore::Element::attributeChangedFromParserOrByCloning): Added to catch @is attribute
     102        (WebCore::Element::parserSetAttributes):
     103        (WebCore::Element::cloneAttributesFromElement):
     104        * dom/Element.h:
     105        * dom/Node.idl:
     106        * dom/ShadowRoot.idl:
     107        * html/HTMLElement.idl:
     108        * html/parser/HTMLScriptRunner.cpp: Added deliverAllLifecycleCallbacks()
     109        (WebCore::HTMLScriptRunner::executePendingScriptAndDispatchEvent):
     110        (WebCore::HTMLScriptRunner::runScript):
     111
    11122013-03-22  Tommy Widenflycht  <tommyw@google.com>
    2113
  • trunk/Source/WebCore/bindings/scripts/CodeGeneratorV8.pm

    r146572 r146583  
    12571257}
    12581258
     1259sub GenerateCustomElementInvocationScopeIfNeeded
     1260{
     1261    my $out = shift;
     1262    my $ext = shift;
     1263
     1264    if ($ext->{"V8DeliverCustomElementCallbacks"}) {
     1265        if ($ext->{"Reflect"}) {
     1266            die "IDL error: Reflect and V8DeliverCustomElementCallbacks cannot coexist yet";
     1267        }
     1268
     1269        AddToImplIncludes("CustomElementRegistry.h", "CUSTOM_ELEMENTS");
     1270        push(@$out, <<END);
     1271#if ENABLE(CUSTOM_ELEMENTS)
     1272    CustomElementRegistry::CallbackDeliveryScope deliveryScope;
     1273#endif
     1274END
     1275    }
     1276}
     1277
    12591278sub GenerateNormalAttrSetterCallback
    12601279{
     
    14041423        $result = "WTF::getPtr(" . $result . ")";
    14051424    }
     1425
     1426    GenerateCustomElementInvocationScopeIfNeeded(\@implContentInternals, $attribute->signature->extendedAttributes);
    14061427
    14071428    my $useExceptions = 1 if @{$attribute->setterExceptions};
     
    17011722END
    17021723    }
     1724
     1725    GenerateCustomElementInvocationScopeIfNeeded(\@implContentInternals, $funcExt);
    17031726
    17041727    # Check domain security if needed
  • trunk/Source/WebCore/bindings/scripts/IDLAttributes.txt

    r146572 r146583  
    134134V8Unforgeable
    135135V8WrapAsFunction
     136V8DeliverCustomElementCallbacks
  • trunk/Source/WebCore/bindings/v8/CustomElementHelpers.cpp

    r146572 r146583  
    3232#include "CustomElementHelpers.h"
    3333
     34#include "CustomElementRegistry.h"
    3435#include "DOMWrapperWorld.h"
     36#include "ScriptController.h"
    3537#include "V8CustomElementConstructor.h"
    3638#include "V8HTMLElementWrapperFactory.h"
     
    139141}
    140142
     143void CustomElementHelpers::invokeReadyCallbackIfNeeded(Element* element, v8::Handle<v8::Context> context)
     144{
     145    v8::Handle<v8::Value> wrapperValue = toV8(element, context->Global(), context->GetIsolate());
     146    if (wrapperValue.IsEmpty() || !wrapperValue->IsObject())
     147        return;
     148    v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(wrapperValue);
     149    v8::Handle<v8::Value> prototypeValue = wrapper->GetPrototype();
     150    if (prototypeValue.IsEmpty() || !prototypeValue->IsObject())
     151        return;
     152    v8::Handle<v8::Object> prototype = v8::Handle<v8::Object>::Cast(prototypeValue);
     153    v8::Handle<v8::Value> functionValue = prototype->Get(v8::String::NewSymbol("readyCallback"));
     154    if (functionValue.IsEmpty() || !functionValue->IsFunction())
     155        return;
     156
     157    v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(functionValue);
     158    v8::TryCatch exceptionCatcher;
     159    exceptionCatcher.SetVerbose(true);
     160    v8::Handle<v8::Value> args[] = { };
     161    ScriptController::callFunctionWithInstrumentation(element->document(), function, wrapper, 0, args);
     162}
     163
     164
     165void CustomElementHelpers::invokeReadyCallbacksIfNeeded(ScriptExecutionContext* executionContext, const Vector<CustomElementInvocation>& invocations)
     166{
     167    ASSERT(!invocations.isEmpty());
     168
     169    v8::HandleScope handleScope;
     170    v8::Handle<v8::Context> context = toV8Context(executionContext, mainThreadNormalWorld());
     171    if (context.IsEmpty())
     172        return;
     173    v8::Context::Scope scope(context);
     174
     175    for (size_t i = 0; i < invocations.size(); ++i) {
     176        ASSERT(executionContext == invocations[i].element()->document());
     177        invokeReadyCallbackIfNeeded(invocations[i].element(), context);
     178    }
     179}
     180
    141181#endif // ENABLE(CUSTOM_ELEMENTS)
    142182
  • trunk/Source/WebCore/bindings/v8/CustomElementHelpers.h

    r146572 r146583  
    3434#include "ExceptionCode.h"
    3535#include "ScriptValue.h"
     36#include <wtf/Forward.h>
    3637
    3738namespace WebCore {
     
    4041
    4142class CustomElementConstructor;
     43class CustomElementInvocation;
     44class Element;
    4245class QualifiedName;
    4346class ScriptState;
     
    5356    static WrapperTypeInfo* findWrapperType(v8::Handle<v8::Value> chain);
    5457    static const QualifiedName* findLocalName(v8::Handle<v8::Object> chain);
     58
     59    static void invokeReadyCallbacksIfNeeded(ScriptExecutionContext*, const Vector<CustomElementInvocation>&);
     60
     61private:
     62    static void invokeReadyCallbackIfNeeded(Element*, v8::Handle<v8::Context>);
    5563};
    5664
  • trunk/Source/WebCore/bindings/v8/V8RecursionScope.cpp

    r146572 r146583  
    3232#include "V8RecursionScope.h"
    3333
     34#include "CustomElementRegistry.h"
    3435#include "IDBPendingTransactionMonitor.h"
    3536#include "MutationObserver.h"
     
    4748#endif
    4849
    49     if (m_isDocumentContext)
     50    if (m_isDocumentContext) {
    5051        MutationObserver::deliverAllMutations();
     52#if ENABLE(CUSTOM_ELEMENTS)
     53        CustomElementRegistry::deliverAllLifecycleCallbacks();
     54#endif
     55    }
    5156}
    5257
  • trunk/Source/WebCore/dom/CustomElementConstructor.cpp

    r146572 r146583  
    6464}
    6565
    66 PassRefPtr<Element> CustomElementConstructor::createElement() const
     66PassRefPtr<Element> CustomElementConstructor::createElement()
     67{
     68    RefPtr<Element> element = createElementInternal();
     69    if (element)
     70        document()->didCreateCustomElement(element.get(), this);
     71    return element.release();
     72}
     73
     74PassRefPtr<Element> CustomElementConstructor::createElementInternal()
    6775{
    6876    if (!document())
  • trunk/Source/WebCore/dom/CustomElementConstructor.h

    r146572 r146583  
    6060    const QualifiedName& typeName() const { return m_typeName; }
    6161    const QualifiedName& localName() const { return m_localName; }
     62    bool isExtended() const { return m_typeName != m_localName; }
    6263
    63     PassRefPtr<Element> createElement() const;
     64    PassRefPtr<Element> createElement();
    6465
    6566private:
    6667    CustomElementConstructor(Document*, const QualifiedName& typeName, const QualifiedName& localName);
     68
     69    PassRefPtr<Element> createElementInternal();
    6770
    6871    QualifiedName m_typeName;
  • trunk/Source/WebCore/dom/CustomElementRegistry.cpp

    r146572 r146583  
    4444#include "RuntimeEnabledFeatures.h"
    4545#include <wtf/ASCIICType.h>
     46#include <wtf/HashSet.h>
    4647
    4748#if ENABLE(SVG)
     
    5556namespace WebCore {
    5657
     58CustomElementInvocation::CustomElementInvocation(PassRefPtr<Element> element)
     59    : m_element(element)
     60{
     61}
     62
     63CustomElementInvocation::~CustomElementInvocation()
     64{
     65}
     66
    5767CustomElementRegistry::CustomElementRegistry(Document* document)
    5868    : ContextDestructionObserver(document)
     
    6272CustomElementRegistry::~CustomElementRegistry()
    6373{
     74    deactivate();
    6475}
    6576
     
    194205}
    195206
     207void CustomElementRegistry::didGiveTypeExtension(Element* element)
     208{
     209    RefPtr<CustomElementConstructor> constructor = findFor(element);
     210    if (!constructor || !constructor->isExtended())
     211        return;
     212    activate(CustomElementInvocation(element));
     213}
     214
     215void CustomElementRegistry::didCreateElement(Element* element)
     216{
     217    activate(CustomElementInvocation(element));
     218}
     219
     220void CustomElementRegistry::activate(const CustomElementInvocation& invocation)
     221{
     222    bool wasInactive = m_invocations.isEmpty();
     223    m_invocations.append(invocation);
     224    if (wasInactive)
     225        activeCustomElementRegistries().add(this);
     226}
     227
     228void CustomElementRegistry::deactivate()
     229{
     230    ASSERT(m_invocations.isEmpty());
     231    if (activeCustomElementRegistries().contains(this))
     232        activeCustomElementRegistries().remove(this);
     233}
     234
    196235inline Document* CustomElementRegistry::document() const
    197236{
     
    199238}
    200239
     240void CustomElementRegistry::deliverLifecycleCallbacks()
     241{
     242    ASSERT(!m_invocations.isEmpty());
     243
     244    if (!m_invocations.isEmpty()) {
     245        Vector<CustomElementInvocation> invocations;
     246        m_invocations.swap(invocations);
     247        CustomElementHelpers::invokeReadyCallbacksIfNeeded(m_scriptExecutionContext, invocations);
     248    }
     249
     250    ASSERT(m_invocations.isEmpty());
     251    deactivate();
     252}
     253
     254void CustomElementRegistry::deliverAllLifecycleCallbacks()
     255{
     256    while (!activeCustomElementRegistries().isEmpty()) {
     257        Vector<RefPtr<CustomElementRegistry> > registries;
     258        copyToVector(activeCustomElementRegistries(), registries);
     259        activeCustomElementRegistries().clear();
     260        for (size_t i = 0; i < registries.size(); ++i)
     261            registries[i]->deliverLifecycleCallbacks();
     262    }
     263}
     264
    201265}
    202266
  • trunk/Source/WebCore/dom/CustomElementRegistry.h

    r146572 r146583  
    4141#include <wtf/Forward.h>
    4242#include <wtf/HashSet.h>
     43#include <wtf/ListHashSet.h>
    4344#include <wtf/PassRefPtr.h>
    4445#include <wtf/RefCounted.h>
    4546#include <wtf/RefPtr.h>
     47#include <wtf/Vector.h>
    4648
    4749namespace WebCore {
     
    5456class QualifiedName;
    5557
     58class CustomElementInvocation {
     59public:
     60    explicit CustomElementInvocation(PassRefPtr<Element>);
     61    ~CustomElementInvocation();
     62
     63    Element* element() const { return m_element.get(); }
     64
     65private:
     66    RefPtr<Element> m_element;
     67};
     68
    5669class CustomElementRegistry : public RefCounted<CustomElementRegistry> , public ContextDestructionObserver {
    5770    WTF_MAKE_NONCOPYABLE(CustomElementRegistry); WTF_MAKE_FAST_ALLOCATED;
    5871public:
     72    class CallbackDeliveryScope {
     73    public:
     74        CallbackDeliveryScope() { }
     75        ~CallbackDeliveryScope() { CustomElementRegistry::deliverAllLifecycleCallbacksIfNeeded(); }
     76    };
     77
    5978    explicit CustomElementRegistry(Document*);
    6079    ~CustomElementRegistry();
     
    6786    Document* document() const;
    6887
     88    void didGiveTypeExtension(Element*);
     89    void didCreateElement(Element*);
     90
     91    static void deliverAllLifecycleCallbacks();
     92    static void deliverAllLifecycleCallbacksIfNeeded();
     93
    6994private:
    70     static bool isValidName(const AtomicString&);
    71 
    7295    typedef HashMap<std::pair<QualifiedName, QualifiedName>, RefPtr<CustomElementConstructor> > ConstructorMap;
    7396    typedef HashSet<QualifiedName> NameSet;
     97    typedef ListHashSet<CustomElementRegistry*> InstanceSet;
     98
     99    static bool isValidName(const AtomicString&);
     100    static InstanceSet& activeCustomElementRegistries();
     101
     102    void activate(const CustomElementInvocation&);
     103    void deactivate();
     104    void deliverLifecycleCallbacks();
    74105
    75106    ConstructorMap m_constructors;
    76107    NameSet m_names;
     108    Vector<CustomElementInvocation> m_invocations;
    77109};
     110
     111inline void CustomElementRegistry::deliverAllLifecycleCallbacksIfNeeded()
     112{
     113    if (!activeCustomElementRegistries().isEmpty())
     114        deliverAllLifecycleCallbacks();
     115    ASSERT(activeCustomElementRegistries().isEmpty());
     116}
     117
     118inline CustomElementRegistry::InstanceSet& CustomElementRegistry::activeCustomElementRegistries()
     119{
     120    DEFINE_STATIC_LOCAL(InstanceSet, activeInstances, ());
     121    return activeInstances;
     122}
     123
    78124
    79125} // namespace WebCore
  • trunk/Source/WebCore/dom/Document.cpp

    r146580 r146583  
    855855    }
    856856
    857     return setTypeExtension(createElement(localName, ec), typeExtension); //  FIXME: take care of @is
     857    return setTypeExtension(createElement(localName, ec), typeExtension);
    858858}
    859859
     
    893893        m_registry = adoptRef(new CustomElementRegistry(this));
    894894    return m_registry->registerElement(state, name, options, ec);
     895}
     896
     897void Document::didCreateCustomElement(Element* element, CustomElementConstructor* constructor)
     898{
     899    // m_registry is cleared Document::dispose() and can be null here.
     900    if (m_registry)
     901        m_registry->didCreateElement(element);
    895902}
    896903#endif // ENABLE(CUSTOM_ELEMENTS)
  • trunk/Source/WebCore/dom/Document.h

    r146572 r146583  
    11691169    PassRefPtr<CustomElementConstructor> registerElement(WebCore::ScriptState*, const AtomicString& name, const Dictionary& options, ExceptionCode&);
    11701170    CustomElementRegistry* registry() const { return m_registry.get(); }
     1171    void didCreateCustomElement(Element*, CustomElementConstructor*);
    11711172#endif
    11721173
  • trunk/Source/WebCore/dom/Document.idl

    r146572 r146583  
    3030    readonly attribute Element documentElement;
    3131
    32     [ReturnNewObject] Element createElement(in [TreatNullAs=NullString,Optional=DefaultIsUndefined] DOMString tagName)
     32    [ReturnNewObject, V8DeliverCustomElementCallbacks]
     33    Element createElement(in [TreatNullAs=NullString,Optional=DefaultIsUndefined] DOMString tagName)
    3334        raises (DOMException);
    3435    DocumentFragment   createDocumentFragment();
     
    4849    // Introduced in DOM Level 2:
    4950
    50     [ObjCLegacyUnnamedParameters, ReturnNewObject] Node importNode(in [Optional=DefaultIsUndefined] Node importedNode,
    51                                                in [Optional] boolean deep)
    52         raises (DOMException);
    53     [ObjCLegacyUnnamedParameters, ReturnNewObject] Element createElementNS(in [TreatNullAs=NullString,Optional=DefaultIsUndefined] DOMString namespaceURI,
    54                                                        in [TreatNullAs=NullString,Optional=DefaultIsUndefined] DOMString qualifiedName)
     51    [ObjCLegacyUnnamedParameters, ReturnNewObject, V8DeliverCustomElementCallbacks]
     52    Node importNode(in [Optional=DefaultIsUndefined] Node importedNode,
     53                    in [Optional] boolean deep)
     54        raises (DOMException);
     55    [ObjCLegacyUnnamedParameters, ReturnNewObject, V8DeliverCustomElementCallbacks]
     56    Element createElementNS(in [TreatNullAs=NullString,Optional=DefaultIsUndefined] DOMString namespaceURI,
     57                            in [TreatNullAs=NullString,Optional=DefaultIsUndefined] DOMString qualifiedName)
    5558        raises (DOMException);
    5659    [ObjCLegacyUnnamedParameters, ReturnNewObject] Attr createAttributeNS(in [TreatNullAs=NullString,Optional=DefaultIsUndefined] DOMString namespaceURI,
    57                                                       in [TreatNullAs=NullString,Optional=DefaultIsUndefined] DOMString qualifiedName)
     60                                                                          in [TreatNullAs=NullString,Optional=DefaultIsUndefined] DOMString qualifiedName)
    5861        raises (DOMException);
    5962    [ObjCLegacyUnnamedParameters] NodeList getElementsByTagNameNS(in [TreatNullAs=NullString,Optional=DefaultIsUndefined] DOMString namespaceURI,
     
    132135
    133136    // Common extensions
    134 
     137    [V8DeliverCustomElementCallbacks]
    135138    boolean            execCommand(in [Optional=DefaultIsUndefined] DOMString command,
    136139                                   in [Optional=DefaultIsUndefined] boolean userInterface,
     
    363366
    364367#if defined(ENABLE_CUSTOM_ELEMENTS) && ENABLE_CUSTOM_ELEMENTS
    365     [V8EnabledAtRuntime=customDOMElements, Conditional=CUSTOM_ELEMENTS, ImplementedAs=registerElement, CallWith=ScriptState]
     368    [V8EnabledAtRuntime=customDOMElements, Conditional=CUSTOM_ELEMENTS, ImplementedAs=registerElement, CallWith=ScriptState, V8DeliverCustomElementCallbacks]
    366369    CustomElementConstructor webkitRegister(in DOMString name, in [Optional] Dictionary options) raises(DOMException);
    367     [ReturnNewObject] Element createElement(in DOMString localName, in [TreatNullAs=NullString] DOMString typeExtension) raises (DOMException);
    368     [ReturnNewObject] Element createElementNS(in [TreatNullAs=NullString] DOMString namespaceURI, in DOMString qualifiedName,
    369                                               in [TreatNullAs=NullString] DOMString typeExtension) raises (DOMException);
     370    [ReturnNewObject, V8DeliverCustomElementCallbacks]
     371    Element createElement(in DOMString localName, in [TreatNullAs=NullString] DOMString typeExtension) raises (DOMException);
     372    [ReturnNewObject, V8DeliverCustomElementCallbacks]
     373    Element createElementNS(in [TreatNullAs=NullString] DOMString namespaceURI, in DOMString qualifiedName,
     374                            in [TreatNullAs=NullString] DOMString typeExtension) raises (DOMException);
    370375#endif
    371376
  • trunk/Source/WebCore/dom/Element.cpp

    r146572 r146583  
    3434#include "ClientRect.h"
    3535#include "ClientRectList.h"
     36#include "CustomElementRegistry.h"
    3637#include "DOMTokenList.h"
    3738#include "DatasetDOMStringMap.h"
     
    888889}
    889890
     891inline void Element::attributeChangedFromParserOrByCloning(const QualifiedName& name, const AtomicString& newValue)
     892{
     893#if ENABLE(CUSTOM_ELEMENTS)
     894    if (name == isAttr) {
     895        if (CustomElementRegistry* registry = document()->registry())
     896            registry->didGiveTypeExtension(this);
     897    }
     898#endif
     899    attributeChanged(name, newValue);
     900}
     901
    890902template <typename CharacterType>
    891903static inline bool classStringHasClassName(const CharacterType* characters, unsigned length)
     
    10741086    // Use attributeVector instead of m_elementData because attributeChanged might modify m_elementData.
    10751087    for (unsigned i = 0; i < attributeVector.size(); ++i)
    1076         attributeChanged(attributeVector[i].name(), attributeVector[i].value());
     1088        attributeChangedFromParserOrByCloning(attributeVector[i].name(), attributeVector[i].value());
    10771089}
    10781090
     
    28582870    for (unsigned i = 0; i < m_elementData->length(); ++i) {
    28592871        const Attribute* attribute = const_cast<const ElementData*>(m_elementData.get())->attributeItem(i);
    2860         attributeChanged(attribute->name(), attribute->value());
     2872        attributeChangedFromParserOrByCloning(attribute->name(), attribute->value());
    28612873    }
    28622874}
  • trunk/Source/WebCore/dom/Element.h

    r146572 r146583  
    673673    void addAttributeInternal(const QualifiedName&, const AtomicString& value, SynchronizationOfLazyAttribute);
    674674    void removeAttributeInternal(size_t index, SynchronizationOfLazyAttribute);
     675    void attributeChangedFromParserOrByCloning(const QualifiedName&, const AtomicString&);
    675676
    676677#ifndef NDEBUG
  • trunk/Source/WebCore/dom/Node.idl

    r146572 r146583  
    7777
    7878    boolean            hasChildNodes();
     79    [V8DeliverCustomElementCallbacks]
    7980    Node               cloneNode(in [Optional=DefaultIsUndefined] boolean deep);
    8081    void               normalize();
  • trunk/Source/WebCore/dom/ShadowRoot.idl

    r146572 r146583  
    3333    attribute boolean resetStyleInheritance;
    3434
    35     [TreatNullAs=NullString] attribute DOMString innerHTML
    36         setter raises(DOMException);
     35    [TreatNullAs=NullString, V8DeliverCustomElementCallbacks]
     36    attribute DOMString innerHTML setter raises(DOMException);
    3737
    3838#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT
  • trunk/Source/WebCore/html/HTMLElement.idl

    r146572 r146583  
    4040
    4141    // Extensions
    42              [TreatNullAs=NullString] attribute DOMString innerHTML
     42             [TreatNullAs=NullString, V8DeliverCustomElementCallbacks] attribute DOMString innerHTML
    4343                 setter raises(DOMException);
    4444             [TreatNullAs=NullString] attribute DOMString innerText
  • trunk/Source/WebCore/html/parser/HTMLScriptRunner.cpp

    r146572 r146583  
    3030#include "CachedScript.h"
    3131#include "CachedResourceLoader.h"
     32#include "CustomElementRegistry.h"
    3233#include "Element.h"
    3334#include "Event.h"
     
    129130        stopWatchingForLoad(pendingScript);
    130131
    131     if (!isExecutingScript())
     132    if (!isExecutingScript()) {
     133#if ENABLE(CUSTOM_ELEMENTS)
     134        CustomElementRegistry::deliverAllLifecycleCallbacks();
     135#endif
    132136        MutationObserver::deliverAllMutations();
     137    }
    133138
    134139    // Clear the pending script before possible rentrancy from executeScript()
     
    293298        // unfortuantely no obvious way to tell if prepareScript is going to
    294299        // execute the script from out here.
    295         if (!isExecutingScript())
     300        if (!isExecutingScript()) {
     301#if ENABLE(CUSTOM_ELEMENTS)
     302            CustomElementRegistry::deliverAllLifecycleCallbacks();
     303#endif
    296304            MutationObserver::deliverAllMutations();
     305        }
    297306
    298307        InsertionPointRecord insertionPointRecord(m_host->inputStream());
  • trunk/Source/WebKit/chromium/ChangeLog

    r146582 r146583  
     12013-03-22  Hajime Morrita  <morrita@google.com>
     2
     3        Custom Elements: "readyCallback" lifecycle callback should be called.
     4        https://bugs.webkit.org/show_bug.cgi?id=112538
     5
     6        Reviewed by Elliott Sprehn.
     7
     8        * src/WebKit.cpp: Added deliverAllLifecycleCallbacks()
     9
    1102013-03-22  Tommy Widenflycht  <tommyw@google.com>
    211
  • trunk/Source/WebKit/chromium/src/WebKit.cpp

    r146572 r146583  
    3232#include "WebKit.h"
    3333
     34#include "CustomElementRegistry.h"
    3435#include "EventTracer.h"
    3536#include "ImageDecodingStore.h"
     
    8182    virtual void didProcessTask()
    8283    {
     84#if ENABLE(CUSTOM_ELEMENTS)
     85        WebCore::CustomElementRegistry::deliverAllLifecycleCallbacks();
     86#endif
    8387        WebCore::MutationObserver::deliverAllMutations();
    8488    }
Note: See TracChangeset for help on using the changeset viewer.