| Index: third_party/WebKit/WebCore/bindings/v8/V8EventListenerList.cpp | 
| =================================================================== | 
| --- third_party/WebKit/WebCore/bindings/v8/V8EventListenerList.cpp	(revision 14992) | 
| +++ third_party/WebKit/WebCore/bindings/v8/V8EventListenerList.cpp	(working copy) | 
| @@ -35,96 +35,149 @@ | 
|  | 
| namespace WebCore { | 
|  | 
| -V8EventListenerList::V8EventListenerList(const char* name) | 
| +V8EventListenerListIterator::V8EventListenerListIterator(V8EventListenerList* list) | 
| +    : m_list(list) | 
| +    , m_vectorIndex(0) | 
| +    , m_iter(list->m_table.begin()) | 
| { | 
| -    ASSERT(strlen(name) <= maxKeyNameLength); | 
| -    v8::HandleScope handleScope; | 
| +} | 
|  | 
| -    // Write the name into a temporary buffer, leaving 1 space at the beginning | 
| -    // for a prefix we'll vary between the inline and non-inline keys. | 
| -    char keyBuffer[maxKeyNameLength + 2] = { 0 }; | 
| -    strncpy(keyBuffer + 1, name, maxKeyNameLength); | 
| -    keyBuffer[0] = '1'; | 
| -    m_inlineKey = v8::Persistent<v8::String>::New(v8::String::New(keyBuffer)); | 
| -    keyBuffer[0] = '2'; | 
| -    m_nonInlineKey = v8::Persistent<v8::String>::New(v8::String::New(keyBuffer)); | 
| +V8EventListenerListIterator::V8EventListenerListIterator(V8EventListenerList* list, bool shouldSeekToEnd) | 
| +    : m_list(list) | 
| +    , m_vectorIndex(0) | 
| +    , m_iter(list->m_table.begin()) | 
| +{ | 
| +    if (shouldSeekToEnd) | 
| +        seekToEnd(); | 
| } | 
|  | 
| +V8EventListenerListIterator::~V8EventListenerListIterator() { } | 
| + | 
| +void V8EventListenerListIterator::operator++() | 
| +{ | 
| +    if (m_iter != m_list->m_table.end()) { | 
| +        Vector<V8EventListener*>* vector = m_iter->second; | 
| +        if (m_vectorIndex + 1 < vector->size()) { | 
| +            m_vectorIndex++; | 
| +            return; | 
| +        } | 
| +        m_vectorIndex = 0; | 
| +        ++m_iter; | 
| +    } | 
| +} | 
| + | 
| +bool V8EventListenerListIterator::operator==(const V8EventListenerListIterator& other) | 
| +{ | 
| +    return other.m_iter == m_iter && other.m_vectorIndex == m_vectorIndex && other.m_list == m_list; | 
| +} | 
| + | 
| +bool V8EventListenerListIterator::operator!=(const V8EventListenerListIterator& other) | 
| +{ | 
| +    return !operator==(other); | 
| +} | 
| + | 
| +V8EventListener* V8EventListenerListIterator::operator*() | 
| +{ | 
| +    if (m_iter != m_list->m_table.end()) { | 
| +        Vector<V8EventListener*>* vector = m_iter->second; | 
| +        if (m_vectorIndex < vector->size()) | 
| +            return vector->at(m_vectorIndex); | 
| +    } | 
| +    return 0; | 
| +} | 
| + | 
| +void V8EventListenerListIterator::seekToEnd() | 
| +{ | 
| +    m_iter = m_list->m_table.end(); | 
| +    m_vectorIndex = 0; | 
| +} | 
| + | 
| + | 
| +V8EventListenerList::V8EventListenerList() | 
| +{ | 
| +} | 
| + | 
| V8EventListenerList::~V8EventListenerList() | 
| { | 
| -    m_inlineKey.Dispose(); | 
| -    m_nonInlineKey.Dispose(); | 
| } | 
|  | 
| -V8EventListenerList::iterator V8EventListenerList::begin() | 
| +V8EventListenerListIterator V8EventListenerList::begin() | 
| { | 
| -    return m_list.begin(); | 
| +    return iterator(this); | 
| } | 
|  | 
| -V8EventListenerList::iterator V8EventListenerList::end() | 
| +V8EventListenerListIterator V8EventListenerList::end() | 
| { | 
| -    return m_list.end(); | 
| +    return iterator(this, true); | 
| } | 
|  | 
| -v8::Handle<v8::String> V8EventListenerList::getKey(bool isInline) | 
| + | 
| +int getKey(v8::Local<v8::Object> object) | 
| { | 
| -    return isInline ? m_inlineKey : m_nonInlineKey; | 
| +    // 0 is a sentinel value for the HashMap key, so we map it to 1. | 
| +    int hash = object->GetIdentityHash(); | 
| +    if (!hash) | 
| +        return 1; | 
| +    return hash; | 
| } | 
|  | 
| -// See comment in .h file for this function, and update accordingly if implementation details change here. | 
| void V8EventListenerList::add(V8EventListener* listener) | 
| { | 
| -    // FIXME: http://crbug.com/10562 | 
| -    //ASSERT(v8::Context::InContext()); | 
| -    m_list.append(listener); | 
| +    ASSERT(v8::Context::InContext()); | 
| +    v8::HandleScope handleScope; | 
|  | 
| -    v8::HandleScope handleScope; | 
| v8::Local<v8::Object> object = listener->getListenerObject(); | 
| -    v8::Local<v8::Value> value = v8::External::Wrap(listener); | 
| -    object->SetHiddenValue(getKey(listener->isAttribute()), value); | 
| +    int key = getKey(object); | 
| +    Vector<V8EventListener*>* vector = m_table.get(key); | 
| +    if (!vector) { | 
| +        vector = new Vector<V8EventListener*>(); | 
| +        m_table.set(key, vector); | 
| +    } | 
| +    vector->append(listener); | 
| +    m_reverseTable.set(listener, key); | 
| } | 
|  | 
| void V8EventListenerList::remove(V8EventListener* listener) | 
| { | 
| -    // FIXME: http://crbug.com/10562 | 
| -    //ASSERT(v8::Context::InContext()); | 
| -    v8::HandleScope handleScope; | 
| -    v8::Handle<v8::String> key = getKey(listener->isAttribute()); | 
| -    for (size_t i = 0; i < m_list.size(); i++) { | 
| -        V8EventListener* element = m_list.at(i); | 
| -        if (element->isAttribute() == listener->isAttribute() && element == listener) { | 
| -            v8::Local<v8::Object> object = listener->getListenerObject(); | 
| +    if (m_reverseTable.contains(listener)) { | 
| +        int key = m_reverseTable.get(listener); | 
| +        Vector<V8EventListener*>* vector = m_table.get(key); | 
| +        if (!vector) | 
| +            return; | 
| +        for (size_t j = 0; j < vector->size(); j++) { | 
| +            if (vector->at(j) == listener) { | 
| +                vector->remove(j); | 
| +                if (!vector->size()) | 
| +                    m_table.remove(key); | 
|  | 
| -            // FIXME(asargent) this check for hidden value being !empty is a workaround for | 
| -            // http://code.google.com/p/v8/issues/detail?id=300 | 
| -            // Once the fix for that is pulled into chromium we can remove the check here. | 
| -            if (!object->GetHiddenValue(key).IsEmpty()) | 
| -                object->DeleteHiddenValue(getKey(listener->isAttribute())); | 
| -            m_list.remove(i); | 
| -            break; | 
| +                m_reverseTable.remove(listener); | 
| +                return; | 
| +            } | 
| } | 
| } | 
| } | 
|  | 
| void V8EventListenerList::clear() | 
| { | 
| -    // FIXME: http://crbug.com/10562 | 
| -    //ASSERT(v8::Context::InContext()); | 
| -    v8::HandleScope handleScope; | 
| -    for (size_t i = 0; i < m_list.size(); i++) { | 
| -        V8EventListener* element = m_list.at(i); | 
| -        v8::Local<v8::Object> object = element->getListenerObject(); | 
| -        object->DeleteHiddenValue(getKey(element->isAttribute())); | 
| -    } | 
| -    m_list.clear(); | 
| +    m_table.clear(); | 
| +    m_reverseTable.clear(); | 
| } | 
|  | 
| -V8EventListener* V8EventListenerList::find(v8::Local<v8::Object> object, bool isInline) | 
| +V8EventListener* V8EventListenerList::find(v8::Local<v8::Object> object, bool isAttribute) | 
| { | 
| -    v8::Local<v8::Value> value = object->GetHiddenValue(getKey(isInline)); | 
| -    if (value.IsEmpty()) | 
| +    ASSERT(v8::Context::InContext()); | 
| +    int key = getKey(object); | 
| + | 
| +    Vector<V8EventListener*>* vector = m_table.get(key); | 
| +    if (!vector) | 
| return 0; | 
| -    return reinterpret_cast<V8EventListener*>(v8::External::Unwrap(value)); | 
| + | 
| +    for (size_t i = 0; i < vector->size(); i++) { | 
| +        V8EventListener* element = vector->at(i); | 
| +        if (isAttribute == element->isAttribute() && object == element->getListenerObject()) | 
| +            return element; | 
| +    } | 
| +    return 0; | 
| } | 
|  | 
| } // namespace WebCore | 
|  |