зеркало из https://github.com/mozilla/gecko-dev.git
Bug 968766 - Part a: Move the custom HTMLAllCollection code from nsDOMClassInfo.cpp to HTMLAllCollection.cpp; r=jst
This commit is contained in:
Родитель
6d9389fa9c
Коммит
1da7d7fb7c
|
@ -6,11 +6,48 @@
|
|||
|
||||
#include "mozilla/dom/HTMLAllCollection.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/HTMLCollectionBinding.h"
|
||||
#include "mozilla/HoldDropJSObjects.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "nsHTMLDocument.h"
|
||||
#include "jsapi.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsWrapperCacheInlines.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
class nsHTMLDocumentSH
|
||||
{
|
||||
protected:
|
||||
static bool GetDocumentAllNodeList(JSContext *cx, JS::Handle<JSObject*> obj,
|
||||
nsDocument *doc,
|
||||
nsContentList **nodeList);
|
||||
public:
|
||||
static bool DocumentAllGetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JS::Value> vp);
|
||||
static bool DocumentAllNewResolve(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
|
||||
unsigned flags, JS::MutableHandle<JSObject*> objp);
|
||||
static void ReleaseDocument(JSFreeOp *fop, JSObject *obj);
|
||||
static bool CallToGetPropMapper(JSContext *cx, unsigned argc, JS::Value *vp);
|
||||
};
|
||||
|
||||
const JSClass sHTMLDocumentAllClass = {
|
||||
"HTML document.all class",
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_NEW_RESOLVE |
|
||||
JSCLASS_EMULATES_UNDEFINED | JSCLASS_HAS_RESERVED_SLOTS(1),
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_DeletePropertyStub, /* delProperty */
|
||||
nsHTMLDocumentSH::DocumentAllGetProperty, /* getProperty */
|
||||
JS_StrictPropertyStub, /* setProperty */
|
||||
JS_EnumerateStub,
|
||||
(JSResolveOp)nsHTMLDocumentSH::DocumentAllNewResolve,
|
||||
JS_ConvertStub,
|
||||
nsHTMLDocumentSH::ReleaseDocument,
|
||||
nsHTMLDocumentSH::CallToGetPropMapper
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -75,3 +112,295 @@ HTMLAllCollection::GetObject(JSContext* aCx, ErrorResult& aRv)
|
|||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
static nsHTMLDocument*
|
||||
GetDocument(JSObject *obj)
|
||||
{
|
||||
MOZ_ASSERT(js::GetObjectJSClass(obj) == &sHTMLDocumentAllClass);
|
||||
return static_cast<nsHTMLDocument*>(
|
||||
static_cast<nsINode*>(JS_GetPrivate(obj)));
|
||||
}
|
||||
|
||||
static inline nsresult
|
||||
WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
|
||||
nsWrapperCache *cache, const nsIID* aIID, JS::MutableHandle<JS::Value> vp,
|
||||
bool aAllowWrapping)
|
||||
{
|
||||
if (!native) {
|
||||
vp.setNull();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JSObject *wrapper = xpc_FastGetCachedWrapper(cache, scope, vp);
|
||||
if (wrapper) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return nsDOMClassInfo::XPConnect()->WrapNativeToJSVal(cx, scope, native,
|
||||
cache, aIID,
|
||||
aAllowWrapping, vp);
|
||||
}
|
||||
|
||||
static inline nsresult
|
||||
WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
|
||||
nsWrapperCache *cache, bool aAllowWrapping,
|
||||
JS::MutableHandle<JS::Value> vp)
|
||||
{
|
||||
return WrapNative(cx, scope, native, cache, nullptr, vp, aAllowWrapping);
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
nsHTMLDocumentSH::GetDocumentAllNodeList(JSContext *cx,
|
||||
JS::Handle<JSObject*> obj,
|
||||
nsDocument *domdoc,
|
||||
nsContentList **nodeList)
|
||||
{
|
||||
// The document.all object is a mix of the node list returned by
|
||||
// document.getElementsByTagName("*") and a map of elements in the
|
||||
// document exposed by their id and/or name. To make access to the
|
||||
// node list part (i.e. access to elements by index) not walk the
|
||||
// document each time, we create a nsContentList and hold on to it
|
||||
// in a reserved slot (0) on the document.all JSObject.
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
JS::Rooted<JS::Value> collection(cx, JS_GetReservedSlot(obj, 0));
|
||||
|
||||
if (!JSVAL_IS_PRIMITIVE(collection)) {
|
||||
// We already have a node list in our reserved slot, use it.
|
||||
JS::Rooted<JSObject*> obj(cx, JSVAL_TO_OBJECT(collection));
|
||||
nsIHTMLCollection* htmlCollection;
|
||||
rv = UNWRAP_OBJECT(HTMLCollection, obj, htmlCollection);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
NS_ADDREF(*nodeList = static_cast<nsContentList*>(htmlCollection));
|
||||
}
|
||||
else {
|
||||
nsISupports *native = nsDOMClassInfo::XPConnect()->GetNativeOfWrapper(cx, obj);
|
||||
if (native) {
|
||||
NS_ADDREF(*nodeList = nsContentList::FromSupports(native));
|
||||
rv = NS_OK;
|
||||
}
|
||||
else {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No node list for this document.all yet, create one...
|
||||
|
||||
nsRefPtr<nsContentList> list =
|
||||
domdoc->GetElementsByTagName(NS_LITERAL_STRING("*"));
|
||||
if (!list) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsresult tmp = WrapNative(cx, JS::CurrentGlobalOrNull(cx),
|
||||
static_cast<nsINodeList*>(list), list, false,
|
||||
&collection);
|
||||
if (NS_FAILED(tmp)) {
|
||||
rv = tmp;
|
||||
}
|
||||
|
||||
list.forget(nodeList);
|
||||
|
||||
// ... and store it in our reserved slot.
|
||||
JS_SetReservedSlot(obj, 0, collection);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(cx, NS_ERROR_FAILURE);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return *nodeList != nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLDocumentSH::DocumentAllGetProperty(JSContext *cx, JS::Handle<JSObject*> obj_,
|
||||
JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp)
|
||||
{
|
||||
JS::Rooted<JSObject*> obj(cx, obj_);
|
||||
|
||||
// document.all.item and .namedItem get their value in the
|
||||
// newResolve hook, so nothing to do for those properties here. And
|
||||
// we need to return early to prevent <div id="item"> from shadowing
|
||||
// document.all.item(), etc.
|
||||
if (nsDOMClassInfo::sItem_id == id || nsDOMClassInfo::sNamedItem_id == id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> proto(cx);
|
||||
while (js::GetObjectJSClass(obj) != &sHTMLDocumentAllClass) {
|
||||
if (!js::GetObjectProto(cx, obj, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!proto) {
|
||||
NS_ERROR("The JS engine lies!");
|
||||
return true;
|
||||
}
|
||||
|
||||
obj = proto;
|
||||
}
|
||||
|
||||
nsHTMLDocument *doc = GetDocument(obj);
|
||||
nsISupports *result;
|
||||
nsWrapperCache *cache;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (JSID_IS_STRING(id)) {
|
||||
if (nsDOMClassInfo::sLength_id == id) {
|
||||
// Map document.all.length to the length of the collection
|
||||
// document.getElementsByTagName("*"), and make sure <div
|
||||
// id="length"> doesn't shadow document.all.length.
|
||||
|
||||
nsRefPtr<nsContentList> nodeList;
|
||||
if (!GetDocumentAllNodeList(cx, obj, doc, getter_AddRefs(nodeList))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t length;
|
||||
rv = nodeList->GetLength(&length);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(cx, rv);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
vp.set(INT_TO_JSVAL(length));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// For all other strings, look for an element by id or name.
|
||||
nsDependentJSString str(id);
|
||||
result = doc->GetDocumentAllResult(str, &cache, &rv);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(cx, rv);
|
||||
return false;
|
||||
}
|
||||
} else if (JSID_IS_INT(id) && JSID_TO_INT(id) >= 0) {
|
||||
// Map document.all[n] (where n is a number) to the n:th item in
|
||||
// the document.all node list.
|
||||
|
||||
nsRefPtr<nsContentList> nodeList;
|
||||
if (!GetDocumentAllNodeList(cx, obj, doc, getter_AddRefs(nodeList))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIContent *node = nodeList->Item(JSID_TO_INT(id));
|
||||
|
||||
result = node;
|
||||
cache = node;
|
||||
} else {
|
||||
result = nullptr;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
rv = WrapNative(cx, JS::CurrentGlobalOrNull(cx), result, cache, true, vp);
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(cx, rv);
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
vp.setUndefined();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLDocumentSH::DocumentAllNewResolve(JSContext *cx, JS::Handle<JSObject*> obj,
|
||||
JS::Handle<jsid> id, unsigned flags,
|
||||
JS::MutableHandle<JSObject*> objp)
|
||||
{
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
|
||||
if (nsDOMClassInfo::sItem_id == id || nsDOMClassInfo::sNamedItem_id == id) {
|
||||
// Define the item() or namedItem() method.
|
||||
|
||||
JSFunction *fnc = ::JS_DefineFunctionById(cx, obj, id, CallToGetPropMapper,
|
||||
0, JSPROP_ENUMERATE);
|
||||
objp.set(obj);
|
||||
|
||||
return fnc != nullptr;
|
||||
}
|
||||
|
||||
if (nsDOMClassInfo::sLength_id == id) {
|
||||
// document.all.length. Any jsval other than undefined would do
|
||||
// here, all we need is to get into the code below that defines
|
||||
// this propery on obj, the rest happens in
|
||||
// DocumentAllGetProperty().
|
||||
|
||||
v = JSVAL_ONE;
|
||||
} else {
|
||||
if (!DocumentAllGetProperty(cx, obj, id, &v)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
|
||||
if (v.get() != JSVAL_VOID) {
|
||||
ok = ::JS_DefinePropertyById(cx, obj, id, v, nullptr, nullptr, 0);
|
||||
objp.set(obj);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLDocumentSH::ReleaseDocument(JSFreeOp *fop, JSObject *obj)
|
||||
{
|
||||
nsIHTMLDocument* doc = GetDocument(obj);
|
||||
if (doc) {
|
||||
nsContentUtils::DeferredFinalize(doc);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLDocumentSH::CallToGetPropMapper(JSContext *cx, unsigned argc, jsval *vp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
// Handle document.all("foo") style access to document.all.
|
||||
|
||||
if (args.length() != 1) {
|
||||
// XXX: Should throw NS_ERROR_XPC_NOT_ENOUGH_ARGS for argc < 1,
|
||||
// and create a new NS_ERROR_XPC_TOO_MANY_ARGS for argc > 1? IE
|
||||
// accepts nothing other than one arg.
|
||||
xpc::Throw(cx, NS_ERROR_INVALID_ARG);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert all types to string.
|
||||
JS::Rooted<JSString*> str(cx, JS::ToString(cx, args[0]));
|
||||
if (!str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we are called via document.all(id) instead of document.all.item(i) or
|
||||
// another method, use the document.all callee object as self.
|
||||
JS::Rooted<JSObject*> self(cx);
|
||||
if (args.calleev().isObject() &&
|
||||
JS_GetClass(&args.calleev().toObject()) == &sHTMLDocumentAllClass) {
|
||||
self = &args.calleev().toObject();
|
||||
} else {
|
||||
self = JS_THIS_OBJECT(cx, vp);
|
||||
if (!self)
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t length;
|
||||
JS::Anchor<JSString *> anchor(str);
|
||||
const jschar *chars = ::JS_GetStringCharsAndLength(cx, str, &length);
|
||||
if (!chars) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ::JS_GetUCProperty(cx, self, chars, length, args.rval());
|
||||
}
|
||||
|
|
|
@ -38,8 +38,7 @@
|
|||
#include "xptcall.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "nsContentList.h"
|
||||
#include "nsHTMLDocument.h"
|
||||
#include "nsDocument.h" // nsDOMStyleSheetList
|
||||
#include "nsDOMBlobBuilder.h"
|
||||
|
||||
// General helper includes
|
||||
|
@ -1909,14 +1908,6 @@ nsWindowSH::PostCreate(nsIXPConnectWrappedNative *wrapper,
|
|||
NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
static nsHTMLDocument*
|
||||
GetDocument(JSObject *obj)
|
||||
{
|
||||
MOZ_ASSERT(js::GetObjectJSClass(obj) == &sHTMLDocumentAllClass);
|
||||
return static_cast<nsHTMLDocument*>(
|
||||
static_cast<nsINode*>(JS_GetPrivate(obj)));
|
||||
}
|
||||
|
||||
struct ResolveGlobalNameClosure
|
||||
{
|
||||
JSContext* cx;
|
||||
|
@ -3748,279 +3739,6 @@ nsStringListSH::GetStringAt(nsISupports *aNative, int32_t aIndex,
|
|||
}
|
||||
|
||||
|
||||
// HTMLAllCollection
|
||||
|
||||
const JSClass sHTMLDocumentAllClass = {
|
||||
"HTML document.all class",
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_NEW_RESOLVE |
|
||||
JSCLASS_EMULATES_UNDEFINED | JSCLASS_HAS_RESERVED_SLOTS(1),
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_DeletePropertyStub, /* delProperty */
|
||||
nsHTMLDocumentSH::DocumentAllGetProperty, /* getProperty */
|
||||
JS_StrictPropertyStub, /* setProperty */
|
||||
JS_EnumerateStub,
|
||||
(JSResolveOp)nsHTMLDocumentSH::DocumentAllNewResolve,
|
||||
JS_ConvertStub,
|
||||
nsHTMLDocumentSH::ReleaseDocument,
|
||||
nsHTMLDocumentSH::CallToGetPropMapper
|
||||
};
|
||||
|
||||
|
||||
// static
|
||||
bool
|
||||
nsHTMLDocumentSH::GetDocumentAllNodeList(JSContext *cx,
|
||||
JS::Handle<JSObject*> obj,
|
||||
nsDocument *domdoc,
|
||||
nsContentList **nodeList)
|
||||
{
|
||||
// The document.all object is a mix of the node list returned by
|
||||
// document.getElementsByTagName("*") and a map of elements in the
|
||||
// document exposed by their id and/or name. To make access to the
|
||||
// node list part (i.e. access to elements by index) not walk the
|
||||
// document each time, we create a nsContentList and hold on to it
|
||||
// in a reserved slot (0) on the document.all JSObject.
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
JS::Rooted<JS::Value> collection(cx, JS_GetReservedSlot(obj, 0));
|
||||
|
||||
if (!JSVAL_IS_PRIMITIVE(collection)) {
|
||||
// We already have a node list in our reserved slot, use it.
|
||||
JS::Rooted<JSObject*> obj(cx, JSVAL_TO_OBJECT(collection));
|
||||
nsIHTMLCollection* htmlCollection;
|
||||
rv = UNWRAP_OBJECT(HTMLCollection, obj, htmlCollection);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
NS_ADDREF(*nodeList = static_cast<nsContentList*>(htmlCollection));
|
||||
}
|
||||
else {
|
||||
nsISupports *native = nsDOMClassInfo::XPConnect()->GetNativeOfWrapper(cx, obj);
|
||||
if (native) {
|
||||
NS_ADDREF(*nodeList = nsContentList::FromSupports(native));
|
||||
rv = NS_OK;
|
||||
}
|
||||
else {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No node list for this document.all yet, create one...
|
||||
|
||||
nsRefPtr<nsContentList> list =
|
||||
domdoc->GetElementsByTagName(NS_LITERAL_STRING("*"));
|
||||
if (!list) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsresult tmp = WrapNative(cx, JS::CurrentGlobalOrNull(cx),
|
||||
static_cast<nsINodeList*>(list), list, false,
|
||||
&collection);
|
||||
if (NS_FAILED(tmp)) {
|
||||
rv = tmp;
|
||||
}
|
||||
|
||||
list.forget(nodeList);
|
||||
|
||||
// ... and store it in our reserved slot.
|
||||
JS_SetReservedSlot(obj, 0, collection);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(cx, NS_ERROR_FAILURE);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return *nodeList != nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLDocumentSH::DocumentAllGetProperty(JSContext *cx, JS::Handle<JSObject*> obj_,
|
||||
JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp)
|
||||
{
|
||||
JS::Rooted<JSObject*> obj(cx, obj_);
|
||||
|
||||
// document.all.item and .namedItem get their value in the
|
||||
// newResolve hook, so nothing to do for those properties here. And
|
||||
// we need to return early to prevent <div id="item"> from shadowing
|
||||
// document.all.item(), etc.
|
||||
if (nsDOMClassInfo::sItem_id == id || nsDOMClassInfo::sNamedItem_id == id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> proto(cx);
|
||||
while (js::GetObjectJSClass(obj) != &sHTMLDocumentAllClass) {
|
||||
if (!js::GetObjectProto(cx, obj, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!proto) {
|
||||
NS_ERROR("The JS engine lies!");
|
||||
return true;
|
||||
}
|
||||
|
||||
obj = proto;
|
||||
}
|
||||
|
||||
nsHTMLDocument *doc = GetDocument(obj);
|
||||
nsISupports *result;
|
||||
nsWrapperCache *cache;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (JSID_IS_STRING(id)) {
|
||||
if (nsDOMClassInfo::sLength_id == id) {
|
||||
// Map document.all.length to the length of the collection
|
||||
// document.getElementsByTagName("*"), and make sure <div
|
||||
// id="length"> doesn't shadow document.all.length.
|
||||
|
||||
nsRefPtr<nsContentList> nodeList;
|
||||
if (!GetDocumentAllNodeList(cx, obj, doc, getter_AddRefs(nodeList))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t length;
|
||||
rv = nodeList->GetLength(&length);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(cx, rv);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
vp.set(INT_TO_JSVAL(length));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// For all other strings, look for an element by id or name.
|
||||
nsDependentJSString str(id);
|
||||
result = doc->GetDocumentAllResult(str, &cache, &rv);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(cx, rv);
|
||||
return false;
|
||||
}
|
||||
} else if (JSID_IS_INT(id) && JSID_TO_INT(id) >= 0) {
|
||||
// Map document.all[n] (where n is a number) to the n:th item in
|
||||
// the document.all node list.
|
||||
|
||||
nsRefPtr<nsContentList> nodeList;
|
||||
if (!GetDocumentAllNodeList(cx, obj, doc, getter_AddRefs(nodeList))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIContent *node = nodeList->Item(JSID_TO_INT(id));
|
||||
|
||||
result = node;
|
||||
cache = node;
|
||||
} else {
|
||||
result = nullptr;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
rv = WrapNative(cx, JS::CurrentGlobalOrNull(cx), result, cache, true, vp);
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(cx, rv);
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
vp.setUndefined();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLDocumentSH::DocumentAllNewResolve(JSContext *cx, JS::Handle<JSObject*> obj,
|
||||
JS::Handle<jsid> id, unsigned flags,
|
||||
JS::MutableHandle<JSObject*> objp)
|
||||
{
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
|
||||
if (nsDOMClassInfo::sItem_id == id || nsDOMClassInfo::sNamedItem_id == id) {
|
||||
// Define the item() or namedItem() method.
|
||||
|
||||
JSFunction *fnc = ::JS_DefineFunctionById(cx, obj, id, CallToGetPropMapper,
|
||||
0, JSPROP_ENUMERATE);
|
||||
objp.set(obj);
|
||||
|
||||
return fnc != nullptr;
|
||||
}
|
||||
|
||||
if (nsDOMClassInfo::sLength_id == id) {
|
||||
// document.all.length. Any jsval other than undefined would do
|
||||
// here, all we need is to get into the code below that defines
|
||||
// this propery on obj, the rest happens in
|
||||
// DocumentAllGetProperty().
|
||||
|
||||
v = JSVAL_ONE;
|
||||
} else {
|
||||
if (!DocumentAllGetProperty(cx, obj, id, &v)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
|
||||
if (v.get() != JSVAL_VOID) {
|
||||
ok = ::JS_DefinePropertyById(cx, obj, id, v, nullptr, nullptr, 0);
|
||||
objp.set(obj);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLDocumentSH::ReleaseDocument(JSFreeOp *fop, JSObject *obj)
|
||||
{
|
||||
nsIHTMLDocument* doc = GetDocument(obj);
|
||||
if (doc) {
|
||||
nsContentUtils::DeferredFinalize(doc);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLDocumentSH::CallToGetPropMapper(JSContext *cx, unsigned argc, jsval *vp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
// Handle document.all("foo") style access to document.all.
|
||||
|
||||
if (args.length() != 1) {
|
||||
// XXX: Should throw NS_ERROR_XPC_NOT_ENOUGH_ARGS for argc < 1,
|
||||
// and create a new NS_ERROR_XPC_TOO_MANY_ARGS for argc > 1? IE
|
||||
// accepts nothing other than one arg.
|
||||
xpc::Throw(cx, NS_ERROR_INVALID_ARG);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert all types to string.
|
||||
JS::Rooted<JSString*> str(cx, JS::ToString(cx, args[0]));
|
||||
if (!str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we are called via document.all(id) instead of document.all.item(i) or
|
||||
// another method, use the document.all callee object as self.
|
||||
JS::Rooted<JSObject*> self(cx);
|
||||
if (args.calleev().isObject() &&
|
||||
JS_GetClass(&args.calleev().toObject()) == &sHTMLDocumentAllClass) {
|
||||
self = &args.calleev().toObject();
|
||||
} else {
|
||||
self = JS_THIS_OBJECT(cx, vp);
|
||||
if (!self)
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t length;
|
||||
JS::Anchor<JSString *> anchor(str);
|
||||
const jschar *chars = ::JS_GetStringCharsAndLength(cx, str, &length);
|
||||
if (!chars) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ::JS_GetUCProperty(cx, self, chars, length, args.rval());
|
||||
}
|
||||
|
||||
// StringArray helper
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -374,26 +374,6 @@ private:
|
|||
};
|
||||
|
||||
|
||||
// HTMLAllCollection
|
||||
|
||||
extern const JSClass sHTMLDocumentAllClass;
|
||||
|
||||
class nsHTMLDocumentSH
|
||||
{
|
||||
protected:
|
||||
static bool GetDocumentAllNodeList(JSContext *cx, JS::Handle<JSObject*> obj,
|
||||
nsDocument *doc,
|
||||
nsContentList **nodeList);
|
||||
public:
|
||||
static bool DocumentAllGetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JS::Value> vp);
|
||||
static bool DocumentAllNewResolve(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
|
||||
unsigned flags, JS::MutableHandle<JSObject*> objp);
|
||||
static void ReleaseDocument(JSFreeOp *fop, JSObject *obj);
|
||||
static bool CallToGetPropMapper(JSContext *cx, unsigned argc, JS::Value *vp);
|
||||
};
|
||||
|
||||
|
||||
// String array helper
|
||||
|
||||
class nsStringArraySH : public nsGenericArraySH
|
||||
|
|
Загрузка…
Ссылка в новой задаче