From a582a668dae802ac3fe4b377d92206fba353d243 Mon Sep 17 00:00:00 2001 From: Yoshi Cheng-Hao Huang Date: Mon, 13 Mar 2023 22:59:41 +0000 Subject: [PATCH] Bug 1572644 - Part 11-2: Preload localized error msg and format it when resolving failed. r=jonco,yulia Depends on D166549 Differential Revision: https://phabricator.services.mozilla.com/D170161 --- dom/worklet/Worklet.cpp | 42 ++++++++++++++++++++++ dom/worklet/Worklet.h | 6 ++++ dom/worklet/WorkletFetchHandler.cpp | 12 +++++-- dom/worklet/loader/WorkletModuleLoader.cpp | 22 ++++++++++++ dom/worklet/loader/WorkletModuleLoader.h | 14 ++++++++ js/loader/ResolveResult.h | 3 +- 6 files changed, 96 insertions(+), 3 deletions(-) diff --git a/dom/worklet/Worklet.cpp b/dom/worklet/Worklet.cpp index 5d4f314fab70..7fc996313999 100644 --- a/dom/worklet/Worklet.cpp +++ b/dom/worklet/Worklet.cpp @@ -11,6 +11,9 @@ #include "mozilla/dom/WorkletImpl.h" #include "xpcprivate.h" +using JS::loader::ResolveError; +using JS::loader::ResolveErrorInfo; + namespace mozilla::dom { // --------------------------------------------------------------------------- // Worklet @@ -52,12 +55,51 @@ JSObject* Worklet::WrapObject(JSContext* aCx, return mImpl->WrapWorklet(aCx, this, aGivenProto); } +static bool LoadLocalizedStrings(nsTArray& aStrings) { + // All enumes in ResolveError. + ResolveError errors[] = {ResolveError::Failure, + ResolveError::FailureMayBeBare, + ResolveError::BlockedByNullEntry, + ResolveError::BlockedByAfterPrefix, + ResolveError::BlockedByBacktrackingPrefix, + ResolveError::InvalidBareSpecifier}; + + static_assert( + ArrayLength(errors) == static_cast(ResolveError::Length), + "The array 'errors' has missing entries in the enum class ResolveError."); + + for (auto i : errors) { + nsAutoString message; + nsresult rv = nsContentUtils::GetLocalizedString( + nsContentUtils::eDOM_PROPERTIES, ResolveErrorInfo::GetString(i), + message); + if (NS_WARN_IF(NS_FAILED(rv))) { + if (NS_WARN_IF(!aStrings.AppendElement(EmptyString(), fallible))) { + return false; + } + } else { + if (NS_WARN_IF(!aStrings.AppendElement(message, fallible))) { + return false; + } + } + } + + return true; +} + already_AddRefed Worklet::AddModule(JSContext* aCx, const nsAString& aModuleURL, const WorkletOptions& aOptions, CallerType aCallerType, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); + if (mLocalizedStrings.IsEmpty()) { + bool result = LoadLocalizedStrings(mLocalizedStrings); + if (!result) { + return nullptr; + } + } + return WorkletFetchHandler::AddModule(this, aCx, aModuleURL, aOptions, aRv); } diff --git a/dom/worklet/Worklet.h b/dom/worklet/Worklet.h index c5920aaa0f09..1c404da18d17 100644 --- a/dom/worklet/Worklet.h +++ b/dom/worklet/Worklet.h @@ -50,6 +50,10 @@ class Worklet final : public nsISupports, public nsWrapperCache { WorkletImpl* Impl() const { return mImpl; } + const nsTArray& GetLocalizedStrings() const { + return mLocalizedStrings; + } + private: ~Worklet(); @@ -65,6 +69,8 @@ class Worklet final : public nsISupports, public nsWrapperCache { const RefPtr mImpl; + nsTArray mLocalizedStrings; + friend class WorkletFetchHandler; friend class WorkletScriptHandler; }; diff --git a/dom/worklet/WorkletFetchHandler.cpp b/dom/worklet/WorkletFetchHandler.cpp index 691236444ee2..471f31d0d251 100644 --- a/dom/worklet/WorkletFetchHandler.cpp +++ b/dom/worklet/WorkletFetchHandler.cpp @@ -36,12 +36,14 @@ class StartModuleLoadRunnable final : public Runnable { StartModuleLoadRunnable( WorkletImpl* aWorkletImpl, const nsMainThreadPtrHandle& aHandlerRef, - nsCOMPtr aURI, nsIURI* aReferrer) + nsCOMPtr aURI, nsIURI* aReferrer, + const nsTArray& aLocalizedStrs) : Runnable("Worklet::StartModuleLoadRunnable"), mWorkletImpl(aWorkletImpl), mHandlerRef(aHandlerRef), mURI(std::move(aURI)), mReferrer(aReferrer), + mLocalizedStrs(aLocalizedStrs), mParentRuntime( JS_GetParentRuntime(CycleCollectedJSContext::Get()->Context())) { MOZ_ASSERT(NS_IsMainThread()); @@ -59,6 +61,7 @@ class StartModuleLoadRunnable final : public Runnable { nsMainThreadPtrHandle mHandlerRef; nsCOMPtr mURI; nsIURI* mReferrer; + const nsTArray& mLocalizedStrs; JSRuntime* mParentRuntime; }; @@ -93,6 +96,10 @@ NS_IMETHODIMP StartModuleLoadRunnable::RunOnWorkletThread() { static_cast(globalScope->GetModuleLoader()); MOZ_ASSERT(moduleLoader); + if (!moduleLoader->HasSetLocalizedStrings()) { + moduleLoader->SetLocalizedStrings(&mLocalizedStrs); + } + RefPtr loadContext = new WorkletLoadContext(mHandlerRef); // Part of Step 2. This sets the Top-level flag to true @@ -297,7 +304,8 @@ already_AddRefed WorkletFetchHandler::AddModule( // Step 1.4. Let referrerSource be document’s URL. nsIURI* referrer = doc->GetDocumentURIAsReferrer(); nsCOMPtr runnable = new StartModuleLoadRunnable( - aWorklet->mImpl, handlerRef, std::move(resolvedURI), referrer); + aWorklet->mImpl, handlerRef, std::move(resolvedURI), referrer, + aWorklet->GetLocalizedStrings()); if (NS_FAILED(aWorklet->mImpl->SendControlMessage(runnable.forget()))) { return nullptr; diff --git a/dom/worklet/loader/WorkletModuleLoader.cpp b/dom/worklet/loader/WorkletModuleLoader.cpp index d0fa4677c4cf..41c4e6f8452d 100644 --- a/dom/worklet/loader/WorkletModuleLoader.cpp +++ b/dom/worklet/loader/WorkletModuleLoader.cpp @@ -12,8 +12,10 @@ #include "mozilla/ScopeExit.h" #include "mozilla/dom/Worklet.h" #include "mozilla/dom/WorkletFetchHandler.h" +#include "nsStringBundle.h" using JS::loader::ModuleLoadRequest; +using JS::loader::ResolveError; namespace mozilla::dom::loader { @@ -188,6 +190,26 @@ void WorkletModuleLoader::OnModuleLoadComplete(ModuleLoadRequest* aRequest) { NS_DispatchToMainThread(runnable.forget()); } +// TODO: Bug 1808301: Call FormatLocalizedString from a worklet thread. +nsresult WorkletModuleLoader::GetResolveFailureMessage( + ResolveError aError, const nsAString& aSpecifier, nsAString& aResult) { + uint8_t index = static_cast(aError); + MOZ_ASSERT(index < static_cast(ResolveError::Length)); + MOZ_ASSERT(mLocalizedStrs); + MOZ_ASSERT(!mLocalizedStrs->IsEmpty()); + if (!mLocalizedStrs || NS_WARN_IF(mLocalizedStrs->IsEmpty())) { + return NS_ERROR_FAILURE; + } + + const nsString& localizedStr = mLocalizedStrs->ElementAt(index); + + AutoTArray params; + params.AppendElement(aSpecifier); + + nsStringBundleBase::FormatString(localizedStr.get(), params, aResult); + return NS_OK; +} + void WorkletModuleLoader::InsertRequest(nsIURI* aURI, ModuleLoadRequest* aRequest) { mFetchingRequests.InsertOrUpdate(aURI, aRequest); diff --git a/dom/worklet/loader/WorkletModuleLoader.h b/dom/worklet/loader/WorkletModuleLoader.h index 8a515743bffa..818720ced841 100644 --- a/dom/worklet/loader/WorkletModuleLoader.h +++ b/dom/worklet/loader/WorkletModuleLoader.h @@ -9,6 +9,7 @@ #include "js/loader/LoadContextBase.h" #include "js/loader/ModuleLoaderBase.h" +#include "js/loader/ResolveResult.h" // For ResolveError #include "mozilla/dom/WorkletFetchHandler.h" namespace mozilla::dom { @@ -54,6 +55,11 @@ class WorkletModuleLoader : public JS::loader::ModuleLoaderBase { void RemoveRequest(nsIURI* aURI); JS::loader::ModuleLoadRequest* GetRequest(nsIURI* aURI) const; + bool HasSetLocalizedStrings() const { return (bool)mLocalizedStrs; } + void SetLocalizedStrings(const nsTArray* aStrings) { + mLocalizedStrs = aStrings; + } + private: ~WorkletModuleLoader() = default; @@ -78,10 +84,18 @@ class WorkletModuleLoader : public JS::loader::ModuleLoaderBase { void OnModuleLoadComplete(JS::loader::ModuleLoadRequest* aRequest) override; + nsresult GetResolveFailureMessage(JS::loader::ResolveError aError, + const nsAString& aSpecifier, + nsAString& aResult) override; + // A hashtable to map a nsIURI(from main thread) to a ModuleLoadRequest(in // worklet thread). nsRefPtrHashtable mFetchingRequests; + + // We get the localized strings on the main thread, and pass it to + // WorkletModuleLoader. + const nsTArray* mLocalizedStrs = nullptr; }; } // namespace loader diff --git a/js/loader/ResolveResult.h b/js/loader/ResolveResult.h index e625e0e43e8c..e7b415198c82 100644 --- a/js/loader/ResolveResult.h +++ b/js/loader/ResolveResult.h @@ -19,7 +19,8 @@ enum class ResolveError : uint8_t { BlockedByNullEntry, BlockedByAfterPrefix, BlockedByBacktrackingPrefix, - InvalidBareSpecifier + InvalidBareSpecifier, + Length }; struct ResolveErrorInfo {