chore: Made a functioning API for sharing, b=(no-bug), c=common

This commit is contained in:
Mr. M
2025-05-12 19:58:14 +02:00
parent 1a7f9d9ee0
commit e496655953
5 changed files with 119 additions and 66 deletions

View File

@@ -1,4 +1,15 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ZenCommonUtils.h"
#include "nsGlobalWindowOuter.h"
#include "nsQueryObject.h"
#include "nsIWindowMediator.h"
#include "nsServiceManagerUtils.h"
#include "nsISharePicker.h"
#include "mozilla/dom/Promise.h"
#if defined(XP_WIN)
# include "mozilla/WindowsVersion.h"
#endif
@@ -7,11 +18,44 @@ namespace zen {
// Use the macro to inject all of the definitions for nsISupports.
NS_IMPL_ISUPPORTS(ZenCommonUtils, nsIZenCommonUtils)
using WindowGlobalChild = mozilla::dom::WindowGlobalChild;
ZenCommonUtils::ZenCommonUtils(nsGlobalWindowOuter* aWindow) {
nsCOMPtr<nsISupports> supports = do_QueryObject(aWindow);
mWindow = do_GetWeakReference(supports);
namespace {
/**
* @brief Helper function to fetch the most recent window proxy.
* @param aWindow The window to query.
* @returns The most recent window.
*/
static nsresult GetMostRecentWindowProxy(mozIDOMWindowProxy** aWindow) {
nsresult rv;
nsCOMPtr<nsIWindowMediator> med(
do_GetService(NS_WINDOWMEDIATOR_CONTRACTID, &rv));
if (NS_FAILED(rv)) return rv;
if (med) return med->GetMostRecentBrowserWindow(aWindow);
return NS_ERROR_FAILURE;
}
/**
* @brief Helper function to query and get a reference to the window.
* @param aWindow The window to query.
*/
static nsCOMPtr<mozIDOMWindowProxy> GetMostRecentWindow() {
nsCOMPtr<mozIDOMWindowProxy> aWindow;
nsresult rv = GetMostRecentWindowProxy(getter_AddRefs(aWindow));
if (NS_FAILED(rv) || !aWindow) {
return nullptr;
}
return aWindow;
}
}
using mozilla::dom::WindowGlobalChild;
using Promise = mozilla::dom::Promise;
#define NS_ZEN_CAN_SHARE_FAILURE() \
*canShare = false; \
return NS_OK;
/*
* @brief Check if the current context can share data.
@@ -19,73 +63,54 @@ ZenCommonUtils::ZenCommonUtils(nsGlobalWindowOuter* aWindow) {
* @returns True if the current context can share data, false otherwise.
*/
NS_IMETHODIMP
ZenCommonUtils::CanShare(const nsIDOMWindow& aWindow, bool* canShare) {
if (!aWindow || !aWindow->IsFullyActive()) {
*canShare = false;
return NS_OK;
ZenCommonUtils::CanShare(bool* canShare) {
auto aWindow = GetMostRecentWindow();
if (!aWindow) {
NS_ZEN_CAN_SHARE_FAILURE();
}
*canShare = IsSharingSupported();
return NS_OK;
}
NS_IMETHODIMP
ZenCommonUtils::Share(const nsIDOMWindow& aWindow, const nsAString& url,
const nsAString& title, const nsAString& text,
mozilla::dom::Promise** _retval) {
if (!aWindow || !aWindow->IsFullyActive()) {
ZenCommonUtils::Share(nsIURI* url, const nsACString& title,
const nsACString& text, mozilla::dom::Promise** _retval) {
auto aWindow = GetMostRecentWindow();
if (!aWindow) {
return NS_ERROR_NOT_AVAILABLE;
}
if (!IsSharingSupported()) {
return NS_OK; // We don't want to throw an error here
}
if (!IsSharingSupported()) {
return NS_ERROR_NOT_AVAILABLE;
}
if (url.IsEmpty()) {
return NS_ERROR_INVALID_ARG;
}
if (title.IsEmpty() && text.IsEmpty()) {
return NS_ERROR_INVALID_ARG;
}
if (aWindow->GetExtantDoc()) {
nsCOMPtr<nsIURI> uri;
nsresult rv = aWindow->GetExtantDoc()->ResolveWithBaseURI(url, getter_AddRefs(uri));
if (NS_FAILED(rv) || !uri) {
return NS_ERROR_INVALID_ARG;
}
}
if (mSharePromise) {
NS_WARNING("Only one share picker at a time per navigator instance");
return NS_ERROR_INVALID_STATE;
}
mSharePromise = Promise::Create(aWindow, __func__);
if (!mSharePromise) {
return NS_ERROR_FAILURE;
}
IPCWebShareData data(title, text, url);
auto wgc = aWindow->GetWindowGlobalChild();
if (!wgc) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
wgc->SendShare(data)->Then(
GetCurrentSerialEventTarget(), __func__,
[self = RefPtr{this}](
PWindowGlobalChild::SharePromise::ResolveOrRejectValue&& aResult) {
if (aResult.IsResolve()) {
if (NS_SUCCEEDED(aResult.ResolveValue())) {
self->mSharePromise->MaybeResolveWithUndefined();
} else {
self->mSharePromise->MaybeReject(aResult.ResolveValue());
}
} else if (self->mSharePromise) {
// IPC died
self->mSharePromise->MaybeReject(NS_BINDING_ABORTED);
}
self->mSharePromise = nullptr;
});
*_retval = ShareInternal(aWindow, url, title, text);
return NS_OK;
}
mozilla::dom::Promise* ZenCommonUtils::ShareInternal(nsCOMPtr<mozIDOMWindowProxy>& aWindow, nsIURI* url,
const nsACString& title, const nsACString& text) {
// We shoud've had done pointer checks before, so we can assume
// aWindow is valid.
nsCOMPtr<nsISharePicker> sharePicker =
do_GetService("@mozilla.org/sharepicker;1");
if (!sharePicker) {
return nullptr;
}
sharePicker->Init(aWindow);
RefPtr<Promise> promise;
nsresult rv = sharePicker->Share(title, text, url, getter_AddRefs(promise));
if (NS_FAILED(rv)) {
return nullptr;
}
return promise;
}
auto ZenCommonUtils::IsSharingSupported() -> bool {
#if defined(XP_WIN) && !defined(__MINGW32__)
#if defined(XP_UNIX) && !defined(XP_MACOSX)
return false;
#elif defined(XP_WIN) && !defined(__MINGW32__)
// The first public build that supports ShareCanceled API
return IsWindows10BuildOrLater(18956);
#else

View File

@@ -5,9 +5,12 @@
#ifndef mozilla_nsZenCommonUtils_h__
#define mozilla_nsZenCommonUtils_h__
#include "nsIDOMWindow.h"
#include "nsIZenCommonUtils.h"
#include "nsIDOMWindow.h"
#include "nsGlobalWindowOuter.h"
#include "nsIURI.h"
namespace zen {
/**
@@ -22,15 +25,23 @@ class ZenCommonUtils final : public nsIZenCommonUtils {
private:
~ZenCommonUtils() = default;
RefPtr<mozilla::dom::Promise> mSharePromise; // Web Share API related
/**
* @brief Check if the current context can share data.
* @param data The data to share.
* @returns True if the current context can share data, false otherwise.
*/
static auto IsSharingSupported() -> bool;
/**
* @brief Helper function to share data via the native dialogs.
* @param aWindow The window to use for the share dialog.
* @param url The URL to share.
* @param title The title of the share.
* @param text The text to share.
* @returns A promise that resolves when the share is complete.
*/
static auto ShareInternal(nsCOMPtr<mozIDOMWindowProxy>& aWindow, nsIURI* url,
const nsACString& title, const nsACString& text)
-> mozilla::dom::Promise*;
};
} // namespace zen

View File

@@ -5,6 +5,7 @@ Classes = [
'contract_ids': ['@mozilla.org/zen/common-utils;1'],
'type': 'zen::ZenCommonUtils',
'headers': ['mozilla/ZenCommonUtils.h'],
'js_name': 'zenCommonUtils',
'js_name': 'zen',
'processes': ProcessSelector.MAIN_PROCESS_ONLY,
},
]

View File

@@ -1,5 +1,4 @@
XPIDL_MODULE = "zen"
XPIDL_SOURCES += [
"nsIZenCommonUtils.idl",
]
@@ -8,10 +7,28 @@ EXPORTS.mozilla += [
"ZenCommonUtils.h",
]
UNIFIED_SOURCES += [
SOURCES += [
"ZenCommonUtils.cpp",
]
XPCOM_MANIFESTS += [
"components.conf",
]
LOCAL_INCLUDES += [
"/dom/base",
"/dom/ipc",
"/gfx/2d",
"/layout/base",
"/layout/forms",
"/layout/generic",
"/layout/painting",
"/layout/xul",
"/layout/xul/tree/",
"/view",
"/widget",
"/widget/headless",
]
FINAL_LIBRARY = "xul"
XPIDL_MODULE = "zen"

View File

@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
#include "nsIDOMWindow.idl"
#include "nsIURI.idl"
/**
* @brief Common utility functions for Zen.
@@ -18,13 +18,12 @@ interface nsIZenCommonUtils : nsISupports {
* @param text The text to share.
* @returns A promise that resolves when the share is complete.
*/
Promise share(in nsIDOMWindow window, in AString url,
in AString title, in AString text);
Promise share(in nsIURI url, in ACString title, in ACString text);
/*
* @brief Check if the current context can share data.
* @param window The window to check.
* @returns True if the current context can share data, false otherwise.
*/
boolean canShare(in nsIDOMWindow window);
boolean canShare();
};