bool
WindowNamedPropertiesHandler::getOwnPropDescriptor(JSContext* aCx,
                                                   JS::Handle<JSObject*> aProxy,
                                                   JS::Handle<jsid> aId,
                                                   bool /* unused */,
                                                   JS::MutableHandle<JS::PropertyDescriptor> aDesc)
                                                   const
{
  if (!JSID_IS_STRING(aId)) {
    // Nothing to do if we're resolving a non-string property.
    return true;
  }

  bool hasOnPrototype;
  if (!HasPropertyOnPrototype(aCx, aProxy, aId, &hasOnPrototype)) {
    return false;
  }
  if (hasOnPrototype) {
    return true;
  }

  nsAutoJSString str;
  if (!str.init(aCx, JSID_TO_STRING(aId))) {
    return false;
  }

  if(str.IsEmpty()) {
    return true;
  }

  // Grab the DOM window.
  JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, aProxy));
  nsGlobalWindow* win = xpc::WindowOrNull(global);
  if (win->Length() > 0) {
    nsCOMPtr<nsPIDOMWindowOuter> childWin = win->GetChildWindow(str);
    if (childWin && ShouldExposeChildWindow(str, childWin)) {
      // We found a subframe of the right name. Shadowing via |var foo| in
      // global scope is still allowed, since |var| only looks up |own|
      // properties. But unqualified shadowing will fail, per-spec.
      JS::Rooted<JS::Value> v(aCx);
      if (!WrapObject(aCx, childWin, &v)) {
        return false;
      }
      FillPropertyDescriptor(aDesc, aProxy, 0, v);
      return true;
    }
  }

  // The rest of this function is for HTML documents only.
  nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(win->GetExtantDoc());
  if (!htmlDoc) {
    return true;
  }
  nsHTMLDocument* document = static_cast<nsHTMLDocument*>(htmlDoc.get());

  Element* element = document->GetElementById(str);
  if (element) {
    JS::Rooted<JS::Value> v(aCx);
    if (!WrapObject(aCx, element, &v)) {
      return false;
    }
    FillPropertyDescriptor(aDesc, aProxy, 0, v);
    return true;
  }

  nsWrapperCache* cache;
  nsISupports* result = document->ResolveName(str, &cache);
  if (!result) {
    return true;
  }

  JS::Rooted<JS::Value> v(aCx);
  if (!WrapObject(aCx, result, cache, nullptr, &v)) {
    return false;
  }
  FillPropertyDescriptor(aDesc, aProxy, 0, v);
  return true;
}
/* static */
bool WebIDLGlobalNameHash::DefineIfEnabled(
    JSContext* aCx, JS::Handle<JSObject*> aObj, JS::Handle<jsid> aId,
    JS::MutableHandle<JS::PropertyDescriptor> aDesc, bool* aFound) {
  MOZ_ASSERT(JSID_IS_STRING(aId), "Check for string id before calling this!");

  const WebIDLNameTableEntry* entry;
  { entry = GetEntry(JSID_TO_FLAT_STRING(aId)); }

  if (!entry) {
    *aFound = false;
    return true;
  }

  *aFound = true;

  ConstructorEnabled checkEnabledForScope = entry->mEnabled;
  // We do the enabled check on the current Realm of aCx, but for the
  // actual object we pass in the underlying object in the Xray case.  That
  // way the callee can decide whether to allow access based on the caller
  // or the window being touched.
  //
  // Using aCx to represent the current Realm for CheckedUnwrapDynamic
  // purposes is OK here, because that's the Realm where we plan to do
  // our property-defining.
  JS::Rooted<JSObject*> global(
      aCx,
      js::CheckedUnwrapDynamic(aObj, aCx, /* stopAtWindowProxy = */ false));
  if (!global) {
    return Throw(aCx, NS_ERROR_DOM_SECURITY_ERR);
  }

  {
    // It's safe to pass "&global" here, because we've already unwrapped it, but
    // for general sanity better to not have debug code even having the
    // appearance of mutating things that opt code uses.
#ifdef DEBUG
    JS::Rooted<JSObject*> temp(aCx, global);
    DebugOnly<nsGlobalWindowInner*> win;
    MOZ_ASSERT(NS_SUCCEEDED(
        UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT(Window, &temp, win, aCx)));
#endif
  }

  if (checkEnabledForScope && !checkEnabledForScope(aCx, global)) {
    return true;
  }

  // The DOM constructor resolve machinery interacts with Xrays in tricky
  // ways, and there are some asymmetries that are important to understand.
  //
  // In the regular (non-Xray) case, we only want to resolve constructors
  // once (so that if they're deleted, they don't reappear). We do this by
  // stashing the constructor in a slot on the global, such that we can see
  // during resolve whether we've created it already. This is rather
  // memory-intensive, so we don't try to maintain these semantics when
  // manipulating a global over Xray (so the properties just re-resolve if
  // they've been deleted).
  //
  // Unfortunately, there's a bit of an impedance-mismatch between the Xray
  // and non-Xray machinery. The Xray machinery wants an API that returns a
  // JS::PropertyDescriptor, so that the resolve hook doesn't have to get
  // snared up with trying to define a property on the Xray holder. At the
  // same time, the DefineInterface callbacks are set up to define things
  // directly on the global.  And re-jiggering them to return property
  // descriptors is tricky, because some DefineInterface callbacks define
  // multiple things (like the Image() alias for HTMLImageElement).
  //
  // So the setup is as-follows:
  //
  // * The resolve function takes a JS::PropertyDescriptor, but in the
  //   non-Xray case, callees may define things directly on the global, and
  //   set the value on the property descriptor to |undefined| to indicate
  //   that there's nothing more for the caller to do. We assert against
  //   this behavior in the Xray case.
  //
  // * We make sure that we do a non-Xray resolve first, so that all the
  //   slots are set up. In the Xray case, this means unwrapping and doing
  //   a non-Xray resolve before doing the Xray resolve.
  //
  // This all could use some grand refactoring, but for now we just limp
  // along.
  if (xpc::WrapperFactory::IsXrayWrapper(aObj)) {
    JS::Rooted<JSObject*> constructor(aCx);
    {
      JSAutoRealm ar(aCx, global);
      constructor = FindNamedConstructorForXray(aCx, aId, entry);
    }
    if (NS_WARN_IF(!constructor)) {
      return Throw(aCx, NS_ERROR_FAILURE);
    }
    if (!JS_WrapObject(aCx, &constructor)) {
      return Throw(aCx, NS_ERROR_FAILURE);
    }

    FillPropertyDescriptor(aDesc, aObj, 0, JS::ObjectValue(*constructor));
    return true;
  }

  JS::Rooted<JSObject*> interfaceObject(
      aCx,
      GetPerInterfaceObjectHandle(aCx, entry->mConstructorId, entry->mCreate,
                                  /* aDefineOnGlobal = */ true));
  if (NS_WARN_IF(!interfaceObject)) {
    return Throw(aCx, NS_ERROR_FAILURE);
  }

  // We've already defined the property.  We indicate this to the caller
  // by filling a property descriptor with JS::UndefinedValue() as the
  // value.  We still have to fill in a property descriptor, though, so
  // that the caller knows the property is in fact on this object.  It
  // doesn't matter what we pass for the "readonly" argument here.
  FillPropertyDescriptor(aDesc, aObj, JS::UndefinedValue(), false);

  return true;
}