Chromium Code Reviews| Index: webkit/port/bindings/v8/v8_proxy.cpp |
| =================================================================== |
| --- webkit/port/bindings/v8/v8_proxy.cpp (revision 2436) |
| +++ webkit/port/bindings/v8/v8_proxy.cpp (working copy) |
| @@ -291,9 +291,9 @@ |
| dom_svg_element_instance_map().forget(instance); |
| } |
| -v8::Handle<v8::Object> V8Proxy::SVGElementInstanceToV8Object( |
| +v8::Handle<v8::Value> V8Proxy::SVGElementInstanceToV8Object( |
| SVGElementInstance* instance) { |
| - if (!instance) return v8::Handle<v8::Object>(); |
| + if (!instance) return v8::Null(); |
| v8::Handle<v8::Object> existing_instance = |
| dom_svg_element_instance_map().get(instance); |
| @@ -305,7 +305,9 @@ |
| // Instantiate the V8 object and remember it |
| v8::Handle<v8::Object> result = |
| - InstantiateV8Object(V8ClassIndex::SVGELEMENTINSTANCE, instance); |
| + InstantiateV8Object(V8ClassIndex::SVGELEMENTINSTANCE, |
| + V8ClassIndex::SVGELEMENTINSTANCE, |
| + instance); |
| if (!result.IsEmpty()) { |
| // Only update the DOM SVG element map if the result is non-empty. |
| dom_svg_element_instance_map().set(instance, |
| @@ -332,9 +334,9 @@ |
| return static_svg_object_to_context_map; |
| } |
| -v8::Handle<v8::Object> V8Proxy::SVGObjectWithContextToV8Object( |
| +v8::Handle<v8::Value> V8Proxy::SVGObjectWithContextToV8Object( |
| Peerable* object, V8ClassIndex::V8WrapperType type) { |
| - if (!object) return v8::Handle<v8::Object>(); |
| + if (!object) return v8::Null(); |
| // Special case: SVGPathSegs need to be downcast to their real type |
| if (type == V8ClassIndex::SVGPATHSEG) { |
| @@ -344,7 +346,7 @@ |
| v8::Persistent<v8::Object> result = |
| dom_svg_object_with_context_map().get(object); |
| if (result.IsEmpty()) { |
| - v8::Local<v8::Object> v8obj = InstantiateV8Object(type, object); |
| + v8::Local<v8::Object> v8obj = InstantiateV8Object(type, type, object); |
| if (!v8obj.IsEmpty()) { |
| result = v8::Persistent<v8::Object>::New(v8obj); |
| dom_svg_object_with_context_map().set(object, result); |
| @@ -1108,18 +1110,18 @@ |
| break; |
| case V8ClassIndex::HTMLSELECTELEMENT: |
| desc->InstanceTemplate()->SetNamedPropertyHandler( |
| - CollectionNamedPropertyGetter<HTMLSelectElement>, |
| + NodeCollectionNamedPropertyGetter<HTMLSelectElement>, |
| 0, |
| 0, |
| 0, |
| 0, |
| v8::External::New(reinterpret_cast<void*>(V8ClassIndex::NODE))); |
| desc->InstanceTemplate()->SetIndexedPropertyHandler( |
| - CollectionIndexedPropertyGetter<HTMLSelectElement>, |
| + NodeCollectionIndexedPropertyGetter<HTMLSelectElement>, |
| USE_INDEXED_PROPERTY_SETTER(HTMLSelectElementCollection), |
| 0, |
| 0, |
| - CollectionIndexedPropertyEnumerator<HTMLSelectElement>, |
| + NodeCollectionIndexedPropertyEnumerator<HTMLSelectElement>, |
| v8::External::New(reinterpret_cast<void*>(V8ClassIndex::NODE))); |
| break; |
| case V8ClassIndex::HTMLDOCUMENT: { |
| @@ -1185,7 +1187,7 @@ |
| 0, |
| 0, |
| 0, |
| - CollectionIndexedPropertyEnumerator<HTMLFormElement>, |
| + NodeCollectionIndexedPropertyEnumerator<HTMLFormElement>, |
| v8::External::New(reinterpret_cast<void*>(V8ClassIndex::NODE))); |
| break; |
| case V8ClassIndex::STYLESHEET: // fall through |
| @@ -1808,8 +1810,6 @@ |
| ASSERT(type != V8ClassIndex::EVENTTARGET); |
| ASSERT(type != V8ClassIndex::EVENT); |
| - if (!imp) return v8::Null(); |
| - |
| #define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: |
| switch (type) { |
| @@ -1844,11 +1844,13 @@ |
| #undef MAKE_CASE |
| + if (!imp) return v8::Null(); |
| + |
| // Non DOM node |
| Peerable* obj = static_cast<Peerable*>(imp); |
| v8::Persistent<v8::Object> result = dom_object_map().get(obj); |
| if (result.IsEmpty()) { |
| - v8::Local<v8::Object> v8obj = InstantiateV8Object(type, imp); |
| + v8::Local<v8::Object> v8obj = InstantiateV8Object(type, type, imp); |
| if (!v8obj.IsEmpty()) { |
| result = v8::Persistent<v8::Object>::New(v8obj); |
| dom_object_map().set(obj, result); |
| @@ -1892,17 +1894,16 @@ |
| V8ClassIndex::V8WrapperType V8Proxy::GetDOMWrapperType( |
| v8::Handle<v8::Object> object) { |
| - if (!MaybeDOMWrapper(object)) { |
| - return V8ClassIndex::INVALID_CLASS_INDEX; |
| - } |
| + ASSERT(MaybeDOMWrapper(object)); |
| - v8::Handle<v8::Value> type = object->GetInternalField(1); |
| + v8::Handle<v8::Value> type = |
| + object->GetInternalField(V8Custom::kDOMWrapperTypeIndex); |
| return V8ClassIndex::FromInt(type->Int32Value()); |
| } |
| -void* V8Proxy::FastToNativeObjectImpl(V8ClassIndex::V8WrapperType type, |
| - v8::Handle<v8::Value> object) { |
| +void* V8Proxy::ToNativeObjectImpl(V8ClassIndex::V8WrapperType type, |
| + v8::Handle<v8::Value> object) { |
| // Native event listener is per frame, it cannot be handled |
| // by this generic function. |
| ASSERT(type != V8ClassIndex::EVENTLISTENER); |
| @@ -1910,27 +1911,28 @@ |
| ASSERT(MaybeDOMWrapper(object)); |
| + switch (type) { |
| #define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: |
| - switch (type) { |
| NODE_WRAPPER_TYPES(MAKE_CASE) |
|
Mike Belshe
2008/09/23 00:36:13
I wonder if we shouldn't #ifndef NDEBUG these to a
Feng Qian
2008/09/23 21:46:04
Here I'd like to let it return NULL so the render
|
| HTMLELEMENT_TYPES(MAKE_CASE) |
| #if ENABLE(SVG) |
| SVGNODE_WRAPPER_TYPES(MAKE_CASE) |
| SVGELEMENT_TYPES(MAKE_CASE) |
| #endif |
| - return FastDOMWrapperToNative<Node>(object); |
| + ASSERT(false); |
| + return NULL; |
| case V8ClassIndex::XMLHTTPREQUEST: |
| - return FastDOMWrapperToNative<XMLHttpRequest>(object); |
| + return DOMWrapperToNative<XMLHttpRequest>(object); |
| case V8ClassIndex::EVENT: |
| - return FastDOMWrapperToNative<Event>(object); |
| + return DOMWrapperToNative<Event>(object); |
| case V8ClassIndex::CSSRULE: |
| - return FastDOMWrapperToNative<CSSRule>(object); |
| + return DOMWrapperToNative<CSSRule>(object); |
| default: |
| break; |
| } |
| #undef MAKE_CASE |
| - return FastDOMWrapperToNative<Peerable>(object); |
| + return DOMWrapperToNative<Peerable>(object); |
| } |
| @@ -1950,41 +1952,6 @@ |
| } |
| -void* V8Proxy::ToNativeObjectImpl(V8ClassIndex::V8WrapperType type, |
| - v8::Handle<v8::Value> object) { |
| - // Native event listener is per frame, it cannot be handled |
| - // by this generic function. |
| - ASSERT(type != V8ClassIndex::EVENTLISTENER); |
| - ASSERT(type != V8ClassIndex::EVENTTARGET); |
| - |
| - // It could be null, undefined, etc. |
| - if (!MaybeDOMWrapper(object)) |
| - return 0; |
| - |
| -#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: |
| - switch (type) { |
| - NODE_WRAPPER_TYPES(MAKE_CASE) |
| - HTMLELEMENT_TYPES(MAKE_CASE) |
| -#if ENABLE(SVG) |
| - SVGNODE_WRAPPER_TYPES(MAKE_CASE) |
| - SVGELEMENT_TYPES(MAKE_CASE) |
| -#endif |
| - return DOMWrapperToNative<Node>(object); |
| - case V8ClassIndex::XMLHTTPREQUEST: |
| - return DOMWrapperToNative<XMLHttpRequest>(object); |
| - case V8ClassIndex::EVENT: |
| - return DOMWrapperToNative<Event>(object); |
| - case V8ClassIndex::CSSRULE: |
| - return DOMWrapperToNative<CSSRule>(object); |
| - default: |
| - break; |
| - } |
| -#undef MAKE_CASE |
| - |
| - return DOMWrapperToNative<Peerable>(object); |
| -} |
| - |
| - |
| NodeFilter* V8Proxy::ToNativeNodeFilter(v8::Handle<v8::Value> filter) { |
| // A NodeFilter is used when walking through a DOM tree or iterating tree |
| // nodes. |
| @@ -2002,28 +1969,29 @@ |
| v8::Local<v8::Object> V8Proxy::InstantiateV8Object( |
| - V8ClassIndex::V8WrapperType type, void* imp) { |
| - V8ClassIndex::V8WrapperType wrapper_type = type; |
| + V8ClassIndex::V8WrapperType desc_type, |
| + V8ClassIndex::V8WrapperType cptr_type, |
| + void* imp) { |
| // Make a special case for document.all |
| - if (type == V8ClassIndex::HTMLCOLLECTION && |
| + if (desc_type == V8ClassIndex::HTMLCOLLECTION && |
| static_cast<HTMLCollection*>(imp)->type() == HTMLCollection::DocAll) { |
| - wrapper_type = V8ClassIndex::UNDETECTABLEHTMLCOLLECTION; |
| + desc_type = V8ClassIndex::UNDETECTABLEHTMLCOLLECTION; |
| } |
| // Special case for HTMLInputElements that support selection. |
| - if (type == V8ClassIndex::HTMLINPUTELEMENT) { |
| + if (desc_type == V8ClassIndex::HTMLINPUTELEMENT) { |
| HTMLInputElement* element = static_cast<HTMLInputElement*>(imp); |
| if (element->canHaveSelection()) { |
| - wrapper_type = V8ClassIndex::HTMLSELECTIONINPUTELEMENT; |
| + desc_type = V8ClassIndex::HTMLSELECTIONINPUTELEMENT; |
| } |
| } |
| - v8::Persistent<v8::FunctionTemplate> desc = GetTemplate(wrapper_type); |
| + v8::Persistent<v8::FunctionTemplate> desc = GetTemplate(desc_type); |
| v8::Local<v8::Function> function = desc->GetFunction(); |
| v8::Local<v8::Object> instance = SafeAllocation::NewInstance(function); |
| if (!instance.IsEmpty()) { |
| // Avoid setting the DOM wrapper for failed allocations. |
| - SetDOMWrapper(instance, V8ClassIndex::ToInt(type), imp); |
| + SetDOMWrapper(instance, V8ClassIndex::ToInt(cptr_type), imp); |
| } |
| return instance; |
| } |
| @@ -2040,50 +2008,72 @@ |
| v8::Handle<v8::Value> V8Proxy::WrapCPointer(void* cptr) { |
| // Represent void* as int |
| int addr = reinterpret_cast<int>(cptr); |
| - if ((addr & 0x01) == 0) { |
| - return v8::Number::New(addr >> 1); |
| - } else { |
| - return v8::External::New(cptr); |
| - } |
| + ASSERT((addr & 0x01) == 0); // the address must be aligned. |
| + return v8::Integer::New(addr >> 1); |
| } |
| void* V8Proxy::ExtractCPointerImpl(v8::Handle<v8::Value> obj) { |
| - if (obj->IsNumber()) { |
| - int addr = obj->Int32Value(); |
| - return reinterpret_cast<void*>(addr << 1); |
| - } else if (obj->IsExternal()) { |
| - return v8::Handle<v8::External>::Cast(obj)->Value(); |
| - } |
| - ASSERT(false); |
| - return 0; |
| + ASSERT(obj->IsNumber()); |
| + int addr = obj->Int32Value(); |
| + return reinterpret_cast<void*>(addr << 1); |
| } |
| -bool V8Proxy::SetDOMWrapper(v8::Handle<v8::Object> obj, int type, void* cptr) { |
| +void V8Proxy::SetDOMWrapper(v8::Handle<v8::Object> obj, int type, void* cptr) { |
| ASSERT(obj->InternalFieldCount() >= 2); |
| obj->SetInternalField(V8Custom::kDOMWrapperObjectIndex, WrapCPointer(cptr)); |
| obj->SetInternalField(V8Custom::kDOMWrapperTypeIndex, v8::Integer::New(type)); |
| - return true; |
| } |
| +#ifndef NDEBUG |
| bool V8Proxy::MaybeDOMWrapper(v8::Handle<v8::Value> value) { |
| if (value.IsEmpty() || !value->IsObject()) return false; |
| v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(value); |
| - if (obj->InternalFieldCount() < V8Custom::kDefaultWrapperInternalFieldCount) |
| - return false; |
| + if (obj->InternalFieldCount() == 0) return false; |
| + ASSERT(obj->InternalFieldCount() >= |
| + V8Custom::kDefaultWrapperInternalFieldCount); |
| + |
| + v8::Handle<v8::Value> type = |
| + obj->GetInternalField(V8Custom::kDOMWrapperTypeIndex); |
| + ASSERT(type->IsInt32()); |
| + ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() && |
| + type->Int32Value() < V8ClassIndex::CLASSINDEX_END); |
| + |
| v8::Handle<v8::Value> wrapper = |
| obj->GetInternalField(V8Custom::kDOMWrapperObjectIndex); |
| - if (!wrapper->IsNumber() && !wrapper->IsExternal()) return false; |
| + ASSERT(wrapper->IsNumber() || wrapper->IsExternal()); |
| + return true; |
| +} |
| +#endif |
| + |
| + |
| +bool V8Proxy::IsDOMEventWrapper(v8::Handle<v8::Value> value) { |
| + if (value.IsEmpty() || !value->IsObject()) return false; |
| + |
| + v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(value); |
| + if (obj->InternalFieldCount() == 0) return false; |
| + |
| + ASSERT(obj->InternalFieldCount() >= |
| + V8Custom::kDefaultWrapperInternalFieldCount); |
| + |
| + v8::Handle<v8::Value> wrapper = |
| + obj->GetInternalField(V8Custom::kDOMWrapperObjectIndex); |
| + ASSERT(wrapper->IsNumber() || wrapper->IsExternal()); |
| + |
| v8::Handle<v8::Value> type = |
| obj->GetInternalField(V8Custom::kDOMWrapperTypeIndex); |
| - if (!type->IsNumber()) return false; |
| + ASSERT(type->IsInt32()); |
| + ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() && |
| + type->Int32Value() < V8ClassIndex::CLASSINDEX_END); |
| - return true; |
| + // All kinds of events use EVENT as dom type in JS wrappers. |
| + // See EventToV8Object |
| + return V8ClassIndex::FromInt(type->Int32Value()) == V8ClassIndex::EVENT; |
| } |
| @@ -2329,7 +2319,8 @@ |
| type = V8ClassIndex::PROGRESSEVENT; |
| // Set the peer object for future access. |
| - v8::Handle<v8::Object> result = InstantiateV8Object(type, event); |
| + v8::Handle<v8::Object> result = |
| + InstantiateV8Object(type, V8ClassIndex::EVENT, event); |
| if (result.IsEmpty()) { |
| // Instantiation failed. Avoid updating the DOM object map and |
| // return null which is already handled by callers of this function |
| @@ -2343,8 +2334,9 @@ |
| } |
| -v8::Handle<v8::Object> V8Proxy::NodeToV8Object(Node* node) { |
| - if (!node) return v8::Handle<v8::Object>(); |
| +// Caller checks node is not null. |
| +v8::Handle<v8::Value> V8Proxy::NodeToV8Object(Node* node) { |
| + if (!node) return v8::Null(); |
| v8::Handle<v8::Object> peer = dom_node_map().get(node); |
| if (!peer.IsEmpty()) { |
| @@ -2416,7 +2408,8 @@ |
| // Set the peer object for future access. |
| // InstantiateV8Object automatically casts node to Peerable*. |
| - v8::Local<v8::Object> result = InstantiateV8Object(type, node); |
| + v8::Local<v8::Object> result = |
| + InstantiateV8Object(type, V8ClassIndex::NODE, node); |
| if (result.IsEmpty()) { |
| // If instantiation failed it's important not to add the result |
| // to the DOM node map. Instead we return an empty handle, which |
| @@ -2507,7 +2500,9 @@ |
| v8::Handle<v8::Value> V8Proxy::DOMImplementationToV8Object( |
| DOMImplementation* impl) { |
| v8::Handle<v8::Object> result = |
| - InstantiateV8Object(V8ClassIndex::DOMIMPLEMENTATION, impl); |
| + InstantiateV8Object(V8ClassIndex::DOMIMPLEMENTATION, |
| + V8ClassIndex::DOMIMPLEMENTATION, |
| + impl); |
| if (result.IsEmpty()) { |
| // If the instantiation failed, we ignore it and return null instead |
| // of returning an empty handle. |
| @@ -2517,8 +2512,8 @@ |
| } |
| -v8::Handle<v8::Object> V8Proxy::StyleSheetToV8Object(StyleSheet* sheet) { |
| - if (!sheet) return v8::Handle<v8::Object>(); |
| +v8::Handle<v8::Value> V8Proxy::StyleSheetToV8Object(StyleSheet* sheet) { |
| + if (!sheet) return v8::Null(); |
| v8::Handle<v8::Object> peer = dom_object_map().get(sheet); |
| if (!peer.IsEmpty()) { |
| @@ -2528,7 +2523,8 @@ |
| V8ClassIndex::V8WrapperType type = V8ClassIndex::STYLESHEET; |
| if (sheet->isCSSStyleSheet()) type = V8ClassIndex::CSSSTYLESHEET; |
| - v8::Handle<v8::Object> result = InstantiateV8Object(type, sheet); |
| + v8::Handle<v8::Object> result = |
| + InstantiateV8Object(type, V8ClassIndex::STYLESHEET, sheet); |
| if (!result.IsEmpty()) { |
| // Only update the DOM object map if the result is non-empty. |
| dom_object_map().set(sheet, v8::Persistent<v8::Object>::New(result)); |
| @@ -2537,7 +2533,8 @@ |
| // Add a hidden reference from stylesheet object to its owner node. |
| Node* owner_node = sheet->ownerNode(); |
| if (owner_node) { |
| - v8::Handle<v8::Object> owner = NodeToV8Object(owner_node); |
| + v8::Handle<v8::Object> owner = |
| + v8::Handle<v8::Object>::Cast(NodeToV8Object(owner_node)); |
| result->SetInternalField(V8Custom::kStyleSheetOwnerNodeIndex, owner); |
| } |
| @@ -2545,8 +2542,8 @@ |
| } |
| -v8::Handle<v8::Object> V8Proxy::CSSValueToV8Object(CSSValue* value) { |
| - if (!value) return v8::Handle<v8::Object>(); |
| +v8::Handle<v8::Value> V8Proxy::CSSValueToV8Object(CSSValue* value) { |
| + if (!value) return v8::Null(); |
| v8::Handle<v8::Object> peer = dom_object_map().get(value); |
| if (!peer.IsEmpty()) { |
| @@ -2568,7 +2565,8 @@ |
| else |
| type = V8ClassIndex::CSSVALUE; |
| - v8::Handle<v8::Object> result = InstantiateV8Object(type, value); |
| + v8::Handle<v8::Object> result = |
| + InstantiateV8Object(type, V8ClassIndex::CSSVALUE, value); |
| if (!result.IsEmpty()) { |
| // Only update the DOM object map if the result is non-empty. |
| dom_object_map().set(value, v8::Persistent<v8::Object>::New(result)); |
| @@ -2577,8 +2575,8 @@ |
| } |
| -v8::Handle<v8::Object> V8Proxy::CSSRuleToV8Object(CSSRule* rule) { |
| - if (!rule) return v8::Handle<v8::Object>(); |
| +v8::Handle<v8::Value> V8Proxy::CSSRuleToV8Object(CSSRule* rule) { |
| + if (!rule) return v8::Null(); |
| v8::Handle<v8::Object> peer = dom_object_map().get(rule); |
| if (!peer.IsEmpty()) { |
| @@ -2611,7 +2609,8 @@ |
| } |
| // Set the peer object for future access. |
| - v8::Handle<v8::Object> result = InstantiateV8Object(type, rule); |
| + v8::Handle<v8::Object> result = |
| + InstantiateV8Object(type, V8ClassIndex::CSSRULE, rule); |
| if (!result.IsEmpty()) { |
| // Only update the DOM object map if the result is non-empty. |
| dom_object_map().set(rule, v8::Persistent<v8::Object>::New(result)); |
| @@ -2619,7 +2618,9 @@ |
| return result; |
| } |
| -v8::Handle<v8::Object> V8Proxy::WindowToV8Object(DOMWindow* window) { |
| +v8::Handle<v8::Value> V8Proxy::WindowToV8Object(DOMWindow* window) { |
| + if (!window) return v8::Null(); |
| + |
| // Initializes environment of a frame, and return the global object |
| // of the frame. |
| Frame* frame = window->frame(); |