from shadowing
+ // document.all.item(), etc.
+ if (nsDOMClassInfo::sItem_id == id || nsDOMClassInfo::sNamedItem_id == id) {
+ return true;
+ }
+
+ JS::Rooted
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;
+ }
+
+ HTMLAllCollection* allCollection = GetDocument(obj)->All();
+ nsISupports *result;
+ nsWrapperCache *cache;
+
+ if (JSID_IS_STRING(id)) {
+ if (nsDOMClassInfo::sLength_id == id) {
+ // Make sure doesn't shadow document.all.length.
+ vp.setNumber(allCollection->Length());
+ return true;
+ }
+
+ // For all other strings, look for an element by id or name.
+ nsDependentJSString str(id);
+ result = allCollection->GetNamedItem(str, &cache);
+ } 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.
+
+ nsIContent* node = allCollection->Item(SafeCast(JSID_TO_INT(id)));
+
+ result = node;
+ cache = node;
+ } else {
+ result = nullptr;
+ }
+
+ if (result) {
+ nsresult rv = nsContentUtils::WrapNative(cx, result, cache, vp);
+ if (NS_FAILED(rv)) {
+ xpc::Throw(cx, rv);
+
+ return false;
+ }
+ } else {
+ vp.setUndefined();
+ }
+
+ return true;
+}
+
+bool
+nsHTMLDocumentSH::DocumentAllNewResolve(JSContext *cx, JS::Handle obj,
+ JS::Handle id,
+ JS::MutableHandle objp)
+{
+ JS::Rooted 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 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 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 anchor(str);
+ const jschar *chars = ::JS_GetStringCharsAndLength(cx, str, &length);
+ if (!chars) {
+ return false;
+ }
+
+ return ::JS_GetUCProperty(cx, self, chars, length, args.rval());
+}