/* static */ nsresult
nsContentPermissionUtils::AskPermission(nsIContentPermissionRequest* aRequest,
                                        nsPIDOMWindowInner* aWindow)
{
  NS_ENSURE_STATE(aWindow && aWindow->IsCurrentInnerWindow());

  // for content process
  if (XRE_IsContentProcess()) {

    RefPtr<RemotePermissionRequest> req =
      new RemotePermissionRequest(aRequest, aWindow);

    MOZ_ASSERT(NS_IsMainThread()); // IPC can only be execute on main thread.

    TabChild* child = TabChild::GetFrom(aWindow->GetDocShell());
    NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);

    nsCOMPtr<nsIArray> typeArray;
    nsresult rv = aRequest->GetTypes(getter_AddRefs(typeArray));
    NS_ENSURE_SUCCESS(rv, rv);

    nsTArray<PermissionRequest> permArray;
    ConvertArrayToPermissionRequest(typeArray, permArray);

    nsCOMPtr<nsIPrincipal> principal;
    rv = aRequest->GetPrincipal(getter_AddRefs(principal));
    NS_ENSURE_SUCCESS(rv, rv);

    bool isHandlingUserInput;
    rv = aRequest->GetIsHandlingUserInput(&isHandlingUserInput);
    NS_ENSURE_SUCCESS(rv, rv);

    ContentChild::GetSingleton()->SetEventTargetForActor(
      req, aWindow->EventTargetFor(TaskCategory::Other));

    req->IPDLAddRef();
    ContentChild::GetSingleton()->SendPContentPermissionRequestConstructor(
      req,
      permArray,
      IPC::Principal(principal),
      isHandlingUserInput,
      child->GetTabId());
    ContentPermissionRequestChildMap()[req.get()] = child->GetTabId();

    req->Sendprompt();
    return NS_OK;
  }

  // for chrome process
  nsCOMPtr<nsIContentPermissionPrompt> prompt =
    do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
  if (prompt) {
    if (NS_FAILED(prompt->Prompt(aRequest))) {
      return NS_ERROR_FAILURE;
    }
  }
  return NS_OK;
}
NS_IMETHODIMP
nsScreenManagerProxy::ScreenForNativeWidget(void* aWidget,
                                            nsIScreen** outScreen)
{
  // Because ScreenForNativeWidget can be called numerous times
  // indirectly from content via the DOM Screen API, we cache the
  // results for this tick of the event loop.
  TabChild* tabChild = static_cast<TabChild*>(aWidget);

  // Enumerate the cached screen array, looking for one that has
  // the TabChild that we're looking for...
  for (uint32_t i = 0; i < mScreenCache.Length(); ++i) {
      ScreenCacheEntry& curr = mScreenCache[i];
      if (curr.mTabChild == aWidget) {
          NS_ADDREF(*outScreen = static_cast<nsIScreen*>(curr.mScreenProxy));
          return NS_OK;
      }
  }

  // Never cached this screen, so we have to ask the parent process
  // for it.
  bool success = false;
  ScreenDetails details;
  Unused << SendScreenForBrowser(tabChild->GetTabId(), &details, &success);
  if (!success) {
    return NS_ERROR_FAILURE;
  }

  ScreenCacheEntry newEntry;
  RefPtr<ScreenProxy> screen = new ScreenProxy(this, details);

  newEntry.mScreenProxy = screen;
  newEntry.mTabChild = tabChild;

  mScreenCache.AppendElement(newEntry);

  NS_ADDREF(*outScreen = screen);

  InvalidateCacheOnNextTick();
  return NS_OK;
}
NS_IMETHODIMP
OfflineCacheUpdateChild::Schedule()
{
    LOG(("OfflineCacheUpdateChild::Schedule [%p]", this));

    NS_ASSERTION(mWindow, "Window must be provided to the offline cache update child");

    nsCOMPtr<nsPIDOMWindow> piWindow = 
        do_QueryInterface(mWindow);
    mWindow = nullptr;

    nsIDocShell *docshell = piWindow->GetDocShell();

    nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(docshell);
    if (!item) {
      NS_WARNING("doc shell tree item is null");
      return NS_ERROR_FAILURE;
    }

    nsCOMPtr<nsIDocShellTreeOwner> owner;
    item->GetTreeOwner(getter_AddRefs(owner));

    nsCOMPtr<nsITabChild> tabchild = do_GetInterface(owner);
    // because owner implements nsITabChild, we can assume that it is
    // the one and only TabChild.
    TabChild* child = tabchild ? static_cast<TabChild*>(tabchild.get()) : nullptr;

    if (MissingRequiredTabChild(child, "offlinecacheupdate")) {
      return NS_ERROR_FAILURE;
    }

    URIParams manifestURI, documentURI;
    SerializeURI(mManifestURI, manifestURI);
    SerializeURI(mDocumentURI, documentURI);

    nsresult rv = NS_OK;
    PrincipalInfo loadingPrincipalInfo;
    rv = PrincipalToPrincipalInfo(mLoadingPrincipal,
                                  &loadingPrincipalInfo);
    NS_ENSURE_SUCCESS(rv, rv);

    nsCOMPtr<nsIObserverService> observerService =
      mozilla::services::GetObserverService();
    if (observerService) {
      LOG(("Calling offline-cache-update-added"));
      observerService->NotifyObservers(static_cast<nsIOfflineCacheUpdate*>(this),
                                       "offline-cache-update-added",
                                       nullptr);
      LOG(("Done offline-cache-update-added"));
    }

    // mDocument is non-null if both:
    // 1. this update was initiated by a document that referred a manifest
    // 2. the document has not already been loaded from the application cache
    // This tells the update to cache this document even in case the manifest
    // has not been changed since the last fetch.
    // See also nsOfflineCacheUpdate::ScheduleImplicit.
    bool stickDocument = mDocument != nullptr; 

    // Need to addref ourself here, because the IPC stack doesn't hold
    // a reference to us. Will be released in RecvFinish() that identifies 
    // the work has been done.
    ContentChild::GetSingleton()->SendPOfflineCacheUpdateConstructor(
        this, manifestURI, documentURI, loadingPrincipalInfo,
        stickDocument, child->GetTabId());

    // ContentChild::DeallocPOfflineCacheUpdate will release this.
    NS_ADDREF_THIS();

    return NS_OK;
}