Bug 1455649 - DocumentL10n, part 2 - Extend nsIDocument to use DocumentL10n.
Extend nsIDocument to store DocumentL10n instance for documents which
can be localized.
MozReview-Commit-ID: APXbRPHZxAg
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -206,16 +206,17 @@
#include "nsWrapperCacheInlines.h"
#include "nsSandboxFlags.h"
#include "mozilla/dom/AnimatableBinding.h"
#include "mozilla/dom/AnonymousContent.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/ClientInfo.h"
#include "mozilla/dom/ClientState.h"
#include "mozilla/dom/DocumentFragment.h"
+#include "mozilla/dom/DocumentL10n.h"
#include "mozilla/dom/DocumentTimeline.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/HTMLBodyElement.h"
#include "mozilla/dom/HTMLInputElement.h"
#include "mozilla/dom/ImageTracker.h"
#include "mozilla/dom/MediaQueryList.h"
#include "mozilla/dom/NodeFilterBinding.h"
#include "mozilla/OwningNonNull.h"
@@ -1372,16 +1373,17 @@ nsIDocument::nsIDocument()
mCharacterSet(WINDOWS_1252_ENCODING),
mCharacterSetSource(0),
mParentDocument(nullptr),
mCachedRootElement(nullptr),
mNodeInfoManager(nullptr),
#ifdef DEBUG
mStyledLinksCleared(false),
#endif
+ mDocumentL10n(nullptr),
mBidiEnabled(false),
mMathMLEnabled(false),
mIsInitialDocumentInWindow(false),
mIgnoreDocGroupMismatches(false),
mLoadedAsData(false),
mLoadedAsInteractiveData(false),
mMayStartLayout(true),
mHaveFiredTitleChange(false),
@@ -1548,16 +1550,18 @@ nsIDocument::ClearAllBoxObjects()
}
}
nsIDocument::~nsIDocument()
{
MOZ_ASSERT(mDOMMediaQueryLists.isEmpty(),
"must not have media query lists left");
+ mDocumentL10n = nullptr;
+
if (mNodeInfoManager) {
mNodeInfoManager->DropDocumentReference();
}
if (mDocGroup) {
mDocGroup->RemoveDocument(this);
}
@@ -1871,16 +1875,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
cb.NoteXPCOMChild(tmp->mChildren.ChildAt(indx - 1));
}
// Traverse all nsIDocument pointer members.
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSecurityInfo)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDisplayDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReadyForIdle)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentL10n)
// Traverse all nsDocument nsCOMPtrs.
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptGlobalObject)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetSetList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptLoader)
@@ -2024,16 +2029,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLinks);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mForms);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mScripts);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplets);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnchors);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOrientationPendingPromise)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReadyForIdle);
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentL10n);
tmp->mParentDocument = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPreloadingImages)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntersectionObservers)
tmp->ClearAllBoxObjects();
@@ -2222,16 +2228,44 @@ nsIDocument::Reset(nsIChannel* aChannel,
mDocumentBaseURI = baseURI;
mChromeXHRDocBaseURI = nullptr;
}
}
mChannel = aChannel;
}
+bool
+PrincipalAllowsL10n(nsIPrincipal* principal) {
+ // Fast track privileged contexts
+ if (nsContentUtils::IsSystemPrincipal(principal)) {
+ return true;
+ }
+
+ nsCOMPtr<nsIURI> uri;
+ nsresult rv = principal->GetURI(getter_AddRefs(uri));
+ if (NS_FAILED(rv) || !uri) {
+ return false;
+ }
+
+ bool isAbout;
+ rv = uri->SchemeIs("about", &isAbout);
+ if (NS_FAILED(rv) || (!isAbout)) {
+ return false;
+ }
+
+ bool isNonWeb;
+ rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_DANGEROUS_TO_LOAD, &isNonWeb);
+ if (NS_FAILED(rv) || !isNonWeb) {
+ return false;
+ }
+
+ return true;
+}
+
void
nsIDocument::ResetToURI(nsIURI* aURI,
nsILoadGroup* aLoadGroup,
nsIPrincipal* aPrincipal)
{
MOZ_ASSERT(aURI, "Null URI passed to ResetToURI");
MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug,
@@ -3302,16 +3336,99 @@ nsIDocument::GetAllowPlugins()
FlashClassification classification = DocumentFlashClassification();
if (classification == FlashClassification::Denied) {
return false;
}
return true;
}
+DocumentL10n*
+nsIDocument::GetLocalization(bool initialize)
+{
+ if (!mDocumentL10n && initialize) {
+ auto l10n = new DocumentL10n(this);
+ if (l10n) {
+ mDocumentL10n = l10n;
+ }
+ }
+ return mDocumentL10n;
+}
+
+already_AddRefed<DocumentL10n>
+nsIDocument::GetL10n(ErrorResult& aRv)
+{
+ auto l10n = GetLocalization(false);
+ if (!l10n) {
+ /* aRv.Throw(NS_ERROR_FAILURE); */
+ return nullptr;
+ }
+
+ RefPtr<DocumentL10n> refL10n(l10n);
+ return refL10n.forget();
+}
+
+bool
+nsDocument::DocumentSupportsL10n(JSContext* aCx, JSObject* aObject)
+{
+ return PrincipalAllowsL10n(nsContentUtils::SubjectPrincipal(aCx));
+}
+
+void
+nsIDocument::LocalizationLinkAdded(Element* aLinkElement)
+{
+ nsString href;
+ aLinkElement->GetAttr(kNameSpaceID_None, nsGkAtoms::href, href);
+ auto l10n = GetLocalization(false);
+ if (l10n) {
+ AutoTArray<nsString, 1> resourceIds;
+ resourceIds.AppendElement(href);
+ l10n->AddResourceIds(resourceIds);
+ } else {
+ mL10nResources.AppendElement(href);
+ }
+}
+
+void
+nsIDocument::LocalizationLinkRemoved(Element* aLinkElement)
+{
+ nsString href;
+ aLinkElement->GetAttr(kNameSpaceID_None, nsGkAtoms::href, href);
+ auto l10n = GetLocalization(false);
+ if (l10n) {
+ AutoTArray<nsString, 1> resourceIds;
+ resourceIds.AppendElement(href);
+ uint32_t remaining = l10n->RemoveResourceIds(resourceIds);
+ if (remaining == 0) {
+ mDocumentL10n = nullptr;
+ }
+ }
+}
+
+void
+nsIDocument::OnL10nResourceContainerParsed()
+{
+ if (!mL10nResources.IsEmpty()) {
+ auto l10n = GetLocalization(true);
+ if (l10n) {
+ l10n->AddResourceIds(mL10nResources);
+ mL10nResources.Clear();
+ }
+ }
+}
+
+void
+nsIDocument::OnDocumentParsed()
+{
+ auto l10n = GetLocalization(false);
+ if (l10n) {
+ l10n->OnDocumentParsed();
+ }
+}
+
bool
nsDocument::IsWebAnimationsEnabled(JSContext* aCx, JSObject* /*unused*/)
{
MOZ_ASSERT(NS_IsMainThread());
return nsContentUtils::IsSystemCaller(aCx) ||
nsContentUtils::AnimationsAPICoreEnabled();
}
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -153,16 +153,17 @@ public:
nsILoadGroup* aLoadGroup,
nsISupports* aContainer,
nsIStreamListener **aDocListener,
bool aReset = true,
nsIContentSink* aContentSink = nullptr) override = 0;
virtual void StopDocumentLoad() override;
+ static bool DocumentSupportsL10n(JSContext* aCx, JSObject* aObject);
static bool IsWebAnimationsEnabled(JSContext* aCx, JSObject* aObject);
static bool IsWebAnimationsEnabled(mozilla::dom::CallerType aCallerType);
static bool IsWebAnimationsGetAnimationsEnabled(JSContext* aCx,
JSObject* aObject);
static bool AreWebAnimationsImplicitKeyframesEnabled(JSContext* aCx,
JSObject* aObject);
static bool AreWebAnimationsTimelinesEnabled(JSContext* aCx,
JSObject* aObject);
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -142,16 +142,17 @@ class AnonymousContent;
class Attr;
class BoxObject;
class ClientInfo;
class ClientState;
class CDATASection;
class Comment;
struct CustomElementDefinition;
class DocGroup;
+class DocumentL10n;
class DocumentFragment;
class DocumentTimeline;
class DocumentType;
class DOMImplementation;
class DOMIntersectionObserver;
class DOMStringList;
class Element;
struct ElementCreationOptions;
@@ -3176,16 +3177,22 @@ public:
CreateAttributeNS(const nsAString& aNamespaceURI,
const nsAString& aQualifiedName,
mozilla::ErrorResult& rv);
void GetInputEncoding(nsAString& aInputEncoding) const;
already_AddRefed<mozilla::dom::Location> GetLocation() const;
void GetReferrer(nsAString& aReferrer) const;
void GetLastModified(nsAString& aLastModified) const;
void GetReadyState(nsAString& aReadyState) const;
+ void LocalizationLinkAdded(Element* aLinkElement);
+ void LocalizationLinkRemoved(Element* aLinkElement);
+ mozilla::dom::DocumentL10n* GetLocalization(bool initialize);
+ void OnL10nResourceContainerParsed();
+ void OnDocumentParsed();
+ already_AddRefed<mozilla::dom::DocumentL10n> GetL10n(ErrorResult& aRv);
void GetTitle(nsAString& aTitle);
void SetTitle(const nsAString& aTitle, mozilla::ErrorResult& rv);
void GetDir(nsAString& aDirection) const;
void SetDir(const nsAString& aDirection);
nsIHTMLCollection* Images();
nsIHTMLCollection* Embeds();
nsIHTMLCollection* Plugins()
@@ -3858,16 +3865,19 @@ protected:
// Last time this document or a one of its sub-documents was focused. If
// focus has never occurred then mLastFocusTime.IsNull() will be true.
mozilla::TimeStamp mLastFocusTime;
mozilla::EventStates mDocumentState;
RefPtr<mozilla::dom::Promise> mReadyForIdle;
+ RefPtr<mozilla::dom::DocumentL10n> mDocumentL10n;
+ nsTArray<nsString> mL10nResources;
+
// True if BIDI is enabled.
bool mBidiEnabled : 1;
// True if a MathML element has ever been owned by this document.
bool mMathMLEnabled : 1;
// True if this document is the initial document for a window. This should
// basically be true only for documents that exist in newly-opened windows or
// documents created to satisfy a GetDocument() on a window when there's no
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -488,16 +488,20 @@ enum FlashClassification {
"allowed", // Site is on the Flash whitelist
"denied" // Site is on the Flash blacklist
};
partial interface Document {
[ChromeOnly]
readonly attribute FlashClassification documentFlashClassification;
};
+partial interface Document {
+ [Throws, Func="nsDocument::DocumentSupportsL10n"] readonly attribute DocumentL10n? l10n;
+};
+
Document implements XPathEvaluator;
Document implements GlobalEventHandlers;
Document implements DocumentAndElementEventHandlers;
Document implements TouchEventHandlers;
Document implements ParentNode;
Document implements OnErrorEventHandlerForNodes;
Document implements GeometryUtils;
Document implements FontFaceSource;
--- a/xpcom/ds/nsGkAtomList.h
+++ b/xpcom/ds/nsGkAtomList.h
@@ -543,16 +543,17 @@ GK_ATOM(left, "left")
GK_ATOM(leftmargin, "leftmargin")
GK_ATOM(legend, "legend")
GK_ATOM(length, "length")
GK_ATOM(letterValue, "letter-value")
GK_ATOM(level, "level")
GK_ATOM(li, "li")
GK_ATOM(line, "line")
GK_ATOM(link, "link")
+GK_ATOM(linkset, "linkset")
//GK_ATOM(list, "list") # "list" is present below
GK_ATOM(listbox, "listbox")
GK_ATOM(listener, "listener")
GK_ATOM(listheader, "listheader")
GK_ATOM(listing, "listing")
GK_ATOM(listitem, "listitem")
GK_ATOM(load, "load")
GK_ATOM(triggeringprincipal, "triggeringprincipal")