Bug 1546432 - Migrate DocumentL10n to use dom::l10n::Mutations. r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D28981

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Zibi Braniecki 2019-05-21 19:46:32 +00:00
Родитель fbc6e0304a
Коммит 2ee19983ae
4 изменённых файлов: 202 добавлений и 96 удалений

Просмотреть файл

@ -7885,10 +7885,6 @@ void Document::Destroy() {
mIsGoingAway = true; mIsGoingAway = true;
if (mDocumentL10n) {
mDocumentL10n->Destroy();
}
ScriptLoader()->Destroy(); ScriptLoader()->Destroy();
SetScriptGlobalObject(nullptr); SetScriptGlobalObject(nullptr);
RemovedFromDocShell(); RemovedFromDocShell();

Просмотреть файл

@ -224,10 +224,6 @@ DOMInterfaces = {
'headerFile': 'mozilla/dom/DeviceMotionEvent.h', 'headerFile': 'mozilla/dom/DeviceMotionEvent.h',
}, },
'DocumentL10n': {
'implicitJSContext': ['translateFragment'],
},
'DominatorTree': { 'DominatorTree': {
'nativeType': 'mozilla::devtools::DominatorTree' 'nativeType': 'mozilla::devtools::DominatorTree'
}, },

Просмотреть файл

@ -8,12 +8,14 @@
#include "js/JSON.h" // JS_ParseJSON #include "js/JSON.h" // JS_ParseJSON
#include "mozilla/dom/DocumentL10n.h" #include "mozilla/dom/DocumentL10n.h"
#include "mozilla/dom/DocumentL10nBinding.h" #include "mozilla/dom/DocumentL10nBinding.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/L10nUtilsBinding.h" #include "mozilla/dom/L10nUtilsBinding.h"
#include "mozilla/dom/Promise.h" #include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseNativeHandler.h" #include "mozilla/dom/PromiseNativeHandler.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/l10n/DOMOverlays.h" #include "mozilla/dom/l10n/DOMOverlays.h"
#include "mozilla/intl/LocaleService.h"
#include "nsQueryObject.h" #include "nsQueryObject.h"
#include "nsIScriptError.h"
#include "nsISupports.h" #include "nsISupports.h"
#include "nsImportModule.h" #include "nsImportModule.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
@ -27,6 +29,8 @@
static const char* kObservedPrefs[] = {L10N_PSEUDO_PREF, INTL_UI_DIRECTION_PREF, static const char* kObservedPrefs[] = {L10N_PSEUDO_PREF, INTL_UI_DIRECTION_PREF,
nullptr}; nullptr};
using namespace mozilla::intl;
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
@ -51,8 +55,24 @@ void PromiseResolver::RejectedCallback(JSContext* aCx,
PromiseResolver::~PromiseResolver() { mPromise = nullptr; } PromiseResolver::~PromiseResolver() { mPromise = nullptr; }
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DocumentL10n, mDocument, mDOMLocalization, NS_IMPL_CYCLE_COLLECTION_CLASS(DocumentL10n)
mContentSink, mReady) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DocumentL10n)
tmp->DisconnectMutations();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMutations)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMLocalization)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mContentSink)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReady)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DocumentL10n)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMutations)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMLocalization)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContentSink)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReady)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(DocumentL10n)
NS_IMPL_CYCLE_COLLECTING_ADDREF(DocumentL10n) NS_IMPL_CYCLE_COLLECTING_ADDREF(DocumentL10n)
NS_IMPL_CYCLE_COLLECTING_RELEASE(DocumentL10n) NS_IMPL_CYCLE_COLLECTING_RELEASE(DocumentL10n)
@ -66,6 +86,7 @@ NS_INTERFACE_MAP_END
DocumentL10n::DocumentL10n(Document* aDocument) DocumentL10n::DocumentL10n(Document* aDocument)
: mDocument(aDocument), mState(DocumentL10nState::Initialized) { : mDocument(aDocument), mState(DocumentL10nState::Initialized) {
mContentSink = do_QueryInterface(aDocument->GetCurrentContentSink()); mContentSink = do_QueryInterface(aDocument->GetCurrentContentSink());
mMutations = new mozilla::dom::l10n::Mutations(this);
} }
DocumentL10n::~DocumentL10n() { DocumentL10n::~DocumentL10n() {
@ -75,6 +96,15 @@ DocumentL10n::~DocumentL10n() {
} }
Preferences::RemoveObservers(this, kObservedPrefs); Preferences::RemoveObservers(this, kObservedPrefs);
DisconnectMutations();
}
void DocumentL10n::DisconnectMutations() {
if (mMutations) {
mDocument->RemoveMutationObserver(mMutations);
mMutations->Disconnect();
}
} }
bool DocumentL10n::Init(nsTArray<nsString>& aResourceIds) { bool DocumentL10n::Init(nsTArray<nsString>& aResourceIds) {
@ -128,32 +158,19 @@ NS_IMETHODIMP
DocumentL10n::Observe(nsISupports* aSubject, const char* aTopic, DocumentL10n::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) { const char16_t* aData) {
if (!strcmp(aTopic, INTL_APP_LOCALES_CHANGED)) { if (!strcmp(aTopic, INTL_APP_LOCALES_CHANGED)) {
if (mDOMLocalization) { OnChange();
mDOMLocalization->OnChange();
}
} else { } else {
MOZ_ASSERT(!strcmp("nsPref:changed", aTopic)); MOZ_ASSERT(!strcmp("nsPref:changed", aTopic));
nsDependentString pref(aData); nsDependentString pref(aData);
if (pref.EqualsLiteral(L10N_PSEUDO_PREF) || if (pref.EqualsLiteral(L10N_PSEUDO_PREF) ||
pref.EqualsLiteral(INTL_UI_DIRECTION_PREF)) { pref.EqualsLiteral(INTL_UI_DIRECTION_PREF)) {
if (mDOMLocalization) { OnChange();
mDOMLocalization->OnChange();
}
} }
} }
return NS_OK; return NS_OK;
} }
void DocumentL10n::Destroy() {
if (mDOMLocalization) {
Element* elem = mDocument->GetDocumentElement();
if (elem) {
mDOMLocalization->DisconnectRoot(elem);
}
}
}
JSObject* DocumentL10n::WrapObject(JSContext* aCx, JSObject* DocumentL10n::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) { JS::Handle<JSObject*> aGivenProto) {
return DocumentL10n_Binding::Wrap(aCx, this, aGivenProto); return DocumentL10n_Binding::Wrap(aCx, this, aGivenProto);
@ -316,7 +333,9 @@ void DocumentL10n::GetAttributes(JSContext* aCx, Element& aElement,
class LocalizationHandler : public PromiseNativeHandler { class LocalizationHandler : public PromiseNativeHandler {
public: public:
explicit LocalizationHandler(nsINode* aNode) { mNode = aNode; }; explicit LocalizationHandler(DocumentL10n* aDocumentL10n) {
mDocumentL10n = aDocumentL10n;
};
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(LocalizationHandler) NS_DECL_CYCLE_COLLECTION_CLASS(LocalizationHandler)
@ -331,8 +350,6 @@ class LocalizationHandler : public PromiseNativeHandler {
JS::Handle<JS::Value> aValue) override { JS::Handle<JS::Value> aValue) override {
ErrorResult rv; ErrorResult rv;
RefPtr<DocumentL10n> docL10n = mNode->OwnerDoc()->GetL10n();
nsTArray<L10nValue> l10nData; nsTArray<L10nValue> l10nData;
if (aValue.isObject()) { if (aValue.isObject()) {
JS::ForOfIterator iter(aCx); JS::ForOfIterator iter(aCx);
@ -375,12 +392,10 @@ class LocalizationHandler : public PromiseNativeHandler {
return; return;
} }
if (docL10n) { mDocumentL10n->PauseObserving(rv);
docL10n->PauseObserving(rv); if (NS_WARN_IF(rv.Failed())) {
if (NS_WARN_IF(rv.Failed())) { mReturnValuePromise->MaybeRejectWithUndefined();
mReturnValuePromise->MaybeRejectWithUndefined(); return;
return;
}
} }
nsTArray<DOMOverlaysError> errors; nsTArray<DOMOverlaysError> errors;
@ -394,26 +409,15 @@ class LocalizationHandler : public PromiseNativeHandler {
} }
} }
if (docL10n) { mDocumentL10n->ResumeObserving(rv);
docL10n->ResumeObserving(rv); if (NS_WARN_IF(rv.Failed())) {
if (NS_WARN_IF(rv.Failed())) { mReturnValuePromise->MaybeRejectWithUndefined();
mReturnValuePromise->MaybeRejectWithUndefined(); return;
return;
}
} }
nsTArray<JS::Value> jsErrors; DocumentL10n::ReportDOMOverlaysErrors(mDocumentL10n->GetDocument(), errors);
SequenceRooter<JS::Value> rooter(aCx, &jsErrors);
for (auto& error : errors) {
JS::RootedValue jsError(aCx);
if (!ToJSValue(aCx, error, &jsError)) {
mReturnValuePromise->MaybeRejectWithUndefined();
return;
}
jsErrors.AppendElement(jsError);
}
mReturnValuePromise->MaybeResolve(jsErrors); mReturnValuePromise->MaybeResolveWithUndefined();
} }
virtual void RejectedCallback(JSContext* aCx, virtual void RejectedCallback(JSContext* aCx,
@ -425,7 +429,7 @@ class LocalizationHandler : public PromiseNativeHandler {
~LocalizationHandler() = default; ~LocalizationHandler() = default;
nsTArray<nsCOMPtr<Element>> mElements; nsTArray<nsCOMPtr<Element>> mElements;
RefPtr<nsINode> mNode; RefPtr<DocumentL10n> mDocumentL10n;
RefPtr<Promise> mReturnValuePromise; RefPtr<Promise> mReturnValuePromise;
}; };
@ -440,23 +444,28 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(LocalizationHandler)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(LocalizationHandler) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(LocalizationHandler)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mElements) NS_IMPL_CYCLE_COLLECTION_UNLINK(mElements)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mNode) NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentL10n)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReturnValuePromise) NS_IMPL_CYCLE_COLLECTION_UNLINK(mReturnValuePromise)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(LocalizationHandler) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(LocalizationHandler)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElements) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElements)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNode) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentL10n)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReturnValuePromise) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReturnValuePromise)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
already_AddRefed<Promise> DocumentL10n::TranslateFragment(JSContext* aCx, already_AddRefed<Promise> DocumentL10n::TranslateFragment(nsINode& aNode,
nsINode& aNode,
ErrorResult& aRv) { ErrorResult& aRv) {
Sequence<L10nKey> l10nKeys; Sequence<OwningNonNull<Element>> elements;
SequenceRooter<L10nKey> rooter(aCx, &l10nKeys);
RefPtr<LocalizationHandler> nativeHandler = new LocalizationHandler(&aNode); GetTranslatables(aNode, elements, aRv);
nsTArray<nsCOMPtr<Element>>& domElements = nativeHandler->Elements();
return TranslateElements(elements, aRv);
}
void DocumentL10n::GetTranslatables(nsINode& aNode,
Sequence<OwningNonNull<Element>>& aElements,
ErrorResult& aRv) {
nsIContent* node = nsIContent* node =
aNode.IsContent() ? aNode.AsContent() : aNode.GetFirstChild(); aNode.IsContent() ? aNode.AsContent() : aNode.GetFirstChild();
for (; node; node = node->GetNextNode(&aNode)) { for (; node; node = node->GetNextNode(&aNode)) {
@ -470,13 +479,42 @@ already_AddRefed<Promise> DocumentL10n::TranslateFragment(JSContext* aCx,
continue; continue;
} }
if (!aElements.AppendElement(*domElement, fallible)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
}
}
already_AddRefed<Promise> DocumentL10n::TranslateElements(
const Sequence<OwningNonNull<Element>>& aElements, ErrorResult& aRv) {
JS::RootingContext* rcx = RootingCx();
Sequence<L10nKey> l10nKeys;
SequenceRooter<L10nKey> rooter(rcx, &l10nKeys);
RefPtr<LocalizationHandler> nativeHandler = new LocalizationHandler(this);
nsTArray<nsCOMPtr<Element>>& domElements = nativeHandler->Elements();
domElements.SetCapacity(aElements.Length());
nsIGlobalObject* global = mDocument->GetScopeObject();
if (!global) {
return nullptr;
}
AutoEntryScript aes(global, "DocumentL10n GetAttributes");
JSContext* cx = aes.cx();
for (auto& domElement : aElements) {
if (!domElement->HasAttr(kNameSpaceID_None, nsGkAtoms::datal10nid)) {
continue;
}
L10nKey* key = l10nKeys.AppendElement(fallible); L10nKey* key = l10nKeys.AppendElement(fallible);
if (!key) { if (!key) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY); aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr; return nullptr;
} }
GetAttributes(aCx, *domElement, *key, aRv); GetAttributes(cx, *domElement, *key, aRv);
if (aRv.Failed()) { if (aRv.Failed()) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY); aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr; return nullptr;
@ -488,17 +526,12 @@ already_AddRefed<Promise> DocumentL10n::TranslateFragment(JSContext* aCx,
} }
} }
nsIGlobalObject* global = mDocument->GetScopeObject();
if (!global) {
return nullptr;
}
RefPtr<Promise> promise = Promise::Create(global, aRv); RefPtr<Promise> promise = Promise::Create(global, aRv);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return nullptr; return nullptr;
} }
RefPtr<Promise> callbackResult = FormatMessages(aCx, l10nKeys, aRv); RefPtr<Promise> callbackResult = FormatMessages(cx, l10nKeys, aRv);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return nullptr; return nullptr;
} }
@ -509,27 +542,56 @@ already_AddRefed<Promise> DocumentL10n::TranslateFragment(JSContext* aCx,
return MaybeWrapPromise(promise); return MaybeWrapPromise(promise);
} }
already_AddRefed<Promise> DocumentL10n::TranslateElements(
const Sequence<OwningNonNull<Element>>& aElements, ErrorResult& aRv) {
AutoTArray<RefPtr<Element>, 10> elements;
elements.SetCapacity(aElements.Length());
for (auto& element : aElements) {
elements.AppendElement(element);
}
RefPtr<Promise> promise;
aRv = mDOMLocalization->TranslateElements(elements, getter_AddRefs(promise));
if (aRv.Failed()) {
return nullptr;
}
return MaybeWrapPromise(promise);
}
void DocumentL10n::PauseObserving(ErrorResult& aRv) { void DocumentL10n::PauseObserving(ErrorResult& aRv) {
aRv = mDOMLocalization->PauseObserving(); mMutations->PauseObserving();
} }
void DocumentL10n::ResumeObserving(ErrorResult& aRv) { void DocumentL10n::ResumeObserving(ErrorResult& aRv) {
aRv = mDOMLocalization->ResumeObserving(); mMutations->ResumeObserving();
}
/* static */
void DocumentL10n::ReportDOMOverlaysErrors(
Document* aDocument, nsTArray<mozilla::dom::DOMOverlaysError>& aErrors) {
nsAutoString msg;
for (auto& error : aErrors) {
if (error.mCode.WasPassed()) {
msg = NS_LITERAL_STRING("[fluent-dom] ");
switch (error.mCode.Value()) {
case DOMOverlays_Binding::ERROR_FORBIDDEN_TYPE:
msg += NS_LITERAL_STRING("An element of forbidden type \"") +
error.mTranslatedElementName.Value() +
NS_LITERAL_STRING(
"\" was found in the translation. Only safe text-level "
"elements and elements with data-l10n-name are allowed.");
break;
case DOMOverlays_Binding::ERROR_NAMED_ELEMENT_MISSING:
msg += NS_LITERAL_STRING("An element named \"") +
error.mL10nName.Value() +
NS_LITERAL_STRING("\" wasn't found in the source.");
break;
case DOMOverlays_Binding::ERROR_NAMED_ELEMENT_TYPE_MISMATCH:
msg += NS_LITERAL_STRING("An element named \"") +
error.mL10nName.Value() +
NS_LITERAL_STRING(
"\" was found in the translation but its type ") +
error.mTranslatedElementName.Value() +
NS_LITERAL_STRING(
" didn't match the element found in the source ") +
error.mSourceElementName.Value() + NS_LITERAL_STRING(".");
break;
case DOMOverlays_Binding::ERROR_UNKNOWN:
default:
msg += NS_LITERAL_STRING(
"Unknown error happened while translation of an element.");
break;
}
nsContentUtils::ReportToConsoleNonLocalized(
msg, nsIScriptError::warningFlag, NS_LITERAL_CSTRING("DOM"),
aDocument);
}
}
} }
class L10nReadyHandler final : public PromiseNativeHandler { class L10nReadyHandler final : public PromiseNativeHandler {
@ -542,12 +604,12 @@ class L10nReadyHandler final : public PromiseNativeHandler {
void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override { void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override {
mDocumentL10n->InitialDocumentTranslationCompleted(); mDocumentL10n->InitialDocumentTranslationCompleted();
mPromise->MaybeResolveWithClone(aCx, aValue); mPromise->MaybeResolveWithUndefined();
} }
void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override { void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override {
mDocumentL10n->InitialDocumentTranslationCompleted(); mDocumentL10n->InitialDocumentTranslationCompleted();
mPromise->MaybeRejectWithClone(aCx, aValue); mPromise->MaybeRejectWithUndefined();
} }
private: private:
@ -574,12 +636,18 @@ void DocumentL10n::TriggerInitialDocumentTranslation() {
mState = DocumentL10nState::InitialTranslationTriggered; mState = DocumentL10nState::InitialTranslationTriggered;
Element* elem = mDocument->GetDocumentElement(); Element* elem = mDocument->GetDocumentElement();
if (elem) { if (!elem) {
mDOMLocalization->ConnectRoot(elem); return;
} }
RefPtr<Promise> promise; Sequence<OwningNonNull<Element>> elements;
mDOMLocalization->TranslateRoots(getter_AddRefs(promise)); ErrorResult rv;
GetTranslatables(*elem, elements, rv);
mMutations->ConnectRoot(elem);
RefPtr<Promise> promise = TranslateElements(elements, rv);
if (!promise) { if (!promise) {
return; return;
} }
@ -594,6 +662,11 @@ void DocumentL10n::InitialDocumentTranslationCompleted() {
return; return;
} }
Element* documentElement = mDocument->GetDocumentElement();
if (documentElement) {
SetRootInfo(documentElement);
}
mState = DocumentL10nState::InitialTranslationCompleted; mState = DocumentL10nState::InitialTranslationCompleted;
mDocument->InitialDocumentTranslationCompleted(); mDocument->InitialDocumentTranslationCompleted();
@ -603,9 +676,36 @@ void DocumentL10n::InitialDocumentTranslationCompleted() {
mContentSink->InitialDocumentTranslationCompleted(); mContentSink->InitialDocumentTranslationCompleted();
mContentSink = nullptr; mContentSink = nullptr;
} }
mDocument->AddMutationObserverUnlessExists(mMutations);
} }
Promise* DocumentL10n::Ready() { return mReady; } Promise* DocumentL10n::Ready() { return mReady; }
void DocumentL10n::OnChange() {
if (mDOMLocalization) {
mDOMLocalization->OnChange();
}
}
void DocumentL10n::SetRootInfo(Element* aElement) {
nsAutoCString primaryLocale;
LocaleService::GetInstance()->GetAppLocaleAsBCP47(primaryLocale);
aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::lang,
NS_ConvertUTF8toUTF16(primaryLocale), true);
nsAutoString dir;
if (LocaleService::GetInstance()->IsAppLocaleRTL()) {
nsGkAtoms::rtl->ToString(dir);
} else {
nsGkAtoms::ltr->ToString(dir);
}
uint32_t nameSpace = aElement->GetNameSpaceID();
nsAtom* dirAtom =
nameSpace == kNameSpaceID_XUL ? nsGkAtoms::localedir : nsGkAtoms::dir;
aElement->SetAttr(kNameSpaceID_None, dirAtom, dir, true);
}
} // namespace dom } // namespace dom
} // namespace mozilla } // namespace mozilla

Просмотреть файл

@ -19,14 +19,18 @@
#include "mozilla/ErrorResult.h" #include "mozilla/ErrorResult.h"
#include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/Document.h" #include "mozilla/dom/Document.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Promise.h" #include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseNativeHandler.h" #include "mozilla/dom/PromiseNativeHandler.h"
#include "mozilla/dom/l10n/Mutations.h"
#include "mozilla/dom/DOMOverlaysBinding.h"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
class Document; namespace l10n {
class Element; class Mutations;
}
struct L10nKey; struct L10nKey;
class PromiseResolver final : public PromiseNativeHandler { class PromiseResolver final : public PromiseNativeHandler {
@ -71,7 +75,6 @@ class DocumentL10n final : public nsIObserver,
public: public:
explicit DocumentL10n(Document* aDocument); explicit DocumentL10n(Document* aDocument);
bool Init(nsTArray<nsString>& aResourceIds); bool Init(nsTArray<nsString>& aResourceIds);
void Destroy();
protected: protected:
virtual ~DocumentL10n(); virtual ~DocumentL10n();
@ -81,9 +84,11 @@ class DocumentL10n final : public nsIObserver,
DocumentL10nState mState; DocumentL10nState mState;
nsCOMPtr<mozIDOMLocalization> mDOMLocalization; nsCOMPtr<mozIDOMLocalization> mDOMLocalization;
nsCOMPtr<nsIContentSink> mContentSink; nsCOMPtr<nsIContentSink> mContentSink;
RefPtr<l10n::Mutations> mMutations;
already_AddRefed<Promise> MaybeWrapPromise(Promise* aPromise); already_AddRefed<Promise> MaybeWrapPromise(Promise* aPromise);
void RegisterObservers(); void RegisterObservers();
void DisconnectMutations();
public: public:
Document* GetParentObject() const { return mDocument; }; Document* GetParentObject() const { return mDocument; };
@ -121,13 +126,19 @@ class DocumentL10n final : public nsIObserver,
void GetAttributes(JSContext* aCx, Element& aElement, L10nKey& aResult, void GetAttributes(JSContext* aCx, Element& aElement, L10nKey& aResult,
ErrorResult& aRv); ErrorResult& aRv);
already_AddRefed<Promise> TranslateFragment(JSContext* aCx, nsINode& aNode, already_AddRefed<Promise> TranslateFragment(nsINode& aNode, ErrorResult& aRv);
ErrorResult& aRv);
void GetTranslatables(nsINode& aNode,
Sequence<OwningNonNull<Element>>& aElements,
ErrorResult& aRv);
already_AddRefed<Promise> TranslateElements( already_AddRefed<Promise> TranslateElements(
const Sequence<OwningNonNull<Element>>& aElements, ErrorResult& aRv); const Sequence<OwningNonNull<Element>>& aElements, ErrorResult& aRv);
void PauseObserving(ErrorResult& aRv); void PauseObserving(ErrorResult& aRv);
void ResumeObserving(ErrorResult& aRv); void ResumeObserving(ErrorResult& aRv);
static void ReportDOMOverlaysErrors(
Document* aDocument, nsTArray<mozilla::dom::DOMOverlaysError>& aErrors);
Promise* Ready(); Promise* Ready();
@ -136,6 +147,9 @@ class DocumentL10n final : public nsIObserver,
void InitialDocumentTranslationCompleted(); void InitialDocumentTranslationCompleted();
Document* GetDocument() { return mDocument; }; Document* GetDocument() { return mDocument; };
void OnChange();
protected:
}; };
} // namespace dom } // namespace dom