michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 sw=2 et tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * Base class for all our document implementations. michael@0: */ michael@0: michael@0: #ifndef nsDocument_h___ michael@0: #define nsDocument_h___ michael@0: michael@0: #include "nsIDocument.h" michael@0: michael@0: #include "nsCOMPtr.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsCRT.h" michael@0: #include "nsWeakReference.h" michael@0: #include "nsWeakPtr.h" michael@0: #include "nsVoidArray.h" michael@0: #include "nsTArray.h" michael@0: #include "nsIDOMXMLDocument.h" michael@0: #include "nsIDOMDocumentXBL.h" michael@0: #include "nsStubDocumentObserver.h" michael@0: #include "nsIScriptGlobalObject.h" michael@0: #include "nsIContent.h" michael@0: #include "nsIPrincipal.h" michael@0: #include "nsIParser.h" michael@0: #include "nsBindingManager.h" michael@0: #include "nsINodeInfo.h" michael@0: #include "nsInterfaceHashtable.h" michael@0: #include "nsJSThingHashtable.h" michael@0: #include "nsIBoxObject.h" michael@0: #include "nsPIBoxObject.h" michael@0: #include "nsIScriptObjectPrincipal.h" michael@0: #include "nsIURI.h" michael@0: #include "nsScriptLoader.h" michael@0: #include "nsIRadioGroupContainer.h" michael@0: #include "nsILayoutHistoryState.h" michael@0: #include "nsIRequest.h" michael@0: #include "nsILoadGroup.h" michael@0: #include "nsTObserverArray.h" michael@0: #include "nsStubMutationObserver.h" michael@0: #include "nsIChannel.h" michael@0: #include "nsCycleCollectionParticipant.h" michael@0: #include "nsContentList.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsIApplicationCache.h" michael@0: #include "nsIApplicationCacheContainer.h" michael@0: #include "nsStyleSet.h" michael@0: #include "pldhash.h" michael@0: #include "nsAttrAndChildArray.h" michael@0: #include "nsDOMAttributeMap.h" michael@0: #include "nsIContentViewer.h" michael@0: #include "nsIDOMXPathNSResolver.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsILoadContext.h" michael@0: #include "nsIProgressEventSink.h" michael@0: #include "nsISecurityEventSink.h" michael@0: #include "nsIChannelEventSink.h" michael@0: #include "imgIRequest.h" michael@0: #include "mozilla/EventListenerManager.h" michael@0: #include "mozilla/EventStates.h" michael@0: #include "mozilla/MemoryReporting.h" michael@0: #include "mozilla/dom/DOMImplementation.h" michael@0: #include "mozilla/dom/StyleSheetList.h" michael@0: #include "nsIDOMTouchEvent.h" michael@0: #include "nsDataHashtable.h" michael@0: #include "mozilla/TimeStamp.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "nsIDOMXPathEvaluator.h" michael@0: #include "jsfriendapi.h" michael@0: michael@0: #define XML_DECLARATION_BITS_DECLARATION_EXISTS (1 << 0) michael@0: #define XML_DECLARATION_BITS_ENCODING_EXISTS (1 << 1) michael@0: #define XML_DECLARATION_BITS_STANDALONE_EXISTS (1 << 2) michael@0: #define XML_DECLARATION_BITS_STANDALONE_YES (1 << 3) michael@0: michael@0: michael@0: class nsDOMStyleSheetSetList; michael@0: class nsIOutputStream; michael@0: class nsDocument; michael@0: class nsIDTD; michael@0: class nsIRadioVisitor; michael@0: class nsIFormControl; michael@0: struct nsRadioGroupStruct; michael@0: class nsOnloadBlocker; michael@0: class nsUnblockOnloadEvent; michael@0: class nsChildContentList; michael@0: class nsHTMLStyleSheet; michael@0: class nsHTMLCSSStyleSheet; michael@0: class nsDOMNavigationTiming; michael@0: class nsWindowSizes; michael@0: class nsHtml5TreeOpExecutor; michael@0: class nsDocumentOnStack; michael@0: class nsPointerLockPermissionRequest; michael@0: class nsISecurityConsoleMessage; michael@0: michael@0: namespace mozilla { michael@0: class EventChainPreVisitor; michael@0: namespace dom { michael@0: class UndoManager; michael@0: class LifecycleCallbacks; michael@0: class CallbackFunction; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Right now our identifier map entries contain information for 'name' michael@0: * and 'id' mappings of a given string. This is so that michael@0: * nsHTMLDocument::ResolveName only has to do one hash lookup instead michael@0: * of two. It's not clear whether this still matters for performance. michael@0: * michael@0: * We also store the document.all result list here. This is mainly so that michael@0: * when all elements with the given ID are removed and we remove michael@0: * the ID's nsIdentifierMapEntry, the document.all result is released too. michael@0: * Perhaps the document.all results should have their own hashtable michael@0: * in nsHTMLDocument. michael@0: */ michael@0: class nsIdentifierMapEntry : public nsStringHashKey michael@0: { michael@0: public: michael@0: typedef mozilla::dom::Element Element; michael@0: michael@0: nsIdentifierMapEntry(const nsAString& aKey) : michael@0: nsStringHashKey(&aKey), mNameContentList(nullptr) michael@0: { michael@0: } michael@0: nsIdentifierMapEntry(const nsAString *aKey) : michael@0: nsStringHashKey(aKey), mNameContentList(nullptr) michael@0: { michael@0: } michael@0: nsIdentifierMapEntry(const nsIdentifierMapEntry& aOther) : michael@0: nsStringHashKey(&aOther.GetKey()) michael@0: { michael@0: NS_ERROR("Should never be called"); michael@0: } michael@0: ~nsIdentifierMapEntry(); michael@0: michael@0: void AddNameElement(nsINode* aDocument, Element* aElement); michael@0: void RemoveNameElement(Element* aElement); michael@0: bool IsEmpty(); michael@0: nsBaseContentList* GetNameContentList() { michael@0: return mNameContentList; michael@0: } michael@0: bool HasNameElement() const { michael@0: return mNameContentList && mNameContentList->Length() != 0; michael@0: } michael@0: michael@0: /** michael@0: * Returns the element if we know the element associated with this michael@0: * id. Otherwise returns null. michael@0: */ michael@0: Element* GetIdElement(); michael@0: /** michael@0: * Returns the list of all elements associated with this id. michael@0: */ michael@0: const nsSmallVoidArray* GetIdElements() const { michael@0: return &mIdContentList; michael@0: } michael@0: /** michael@0: * If this entry has a non-null image element set (using SetImageElement), michael@0: * the image element will be returned, otherwise the same as GetIdElement(). michael@0: */ michael@0: Element* GetImageIdElement(); michael@0: /** michael@0: * Append all the elements with this id to aElements michael@0: */ michael@0: void AppendAllIdContent(nsCOMArray* aElements); michael@0: /** michael@0: * This can fire ID change callbacks. michael@0: * @return true if the content could be added, false if we failed due michael@0: * to OOM. michael@0: */ michael@0: bool AddIdElement(Element* aElement); michael@0: /** michael@0: * This can fire ID change callbacks. michael@0: */ michael@0: void RemoveIdElement(Element* aElement); michael@0: /** michael@0: * Set the image element override for this ID. This will be returned by michael@0: * GetIdElement(true) if non-null. michael@0: */ michael@0: void SetImageElement(Element* aElement); michael@0: bool HasIdElementExposedAsHTMLDocumentProperty(); michael@0: michael@0: bool HasContentChangeCallback() { return mChangeCallbacks != nullptr; } michael@0: void AddContentChangeCallback(nsIDocument::IDTargetObserver aCallback, michael@0: void* aData, bool aForImage); michael@0: void RemoveContentChangeCallback(nsIDocument::IDTargetObserver aCallback, michael@0: void* aData, bool aForImage); michael@0: michael@0: void Traverse(nsCycleCollectionTraversalCallback* aCallback); michael@0: michael@0: struct ChangeCallback { michael@0: nsIDocument::IDTargetObserver mCallback; michael@0: void* mData; michael@0: bool mForImage; michael@0: }; michael@0: michael@0: struct ChangeCallbackEntry : public PLDHashEntryHdr { michael@0: typedef const ChangeCallback KeyType; michael@0: typedef const ChangeCallback* KeyTypePointer; michael@0: michael@0: ChangeCallbackEntry(const ChangeCallback* key) : michael@0: mKey(*key) { } michael@0: ChangeCallbackEntry(const ChangeCallbackEntry& toCopy) : michael@0: mKey(toCopy.mKey) { } michael@0: michael@0: KeyType GetKey() const { return mKey; } michael@0: bool KeyEquals(KeyTypePointer aKey) const { michael@0: return aKey->mCallback == mKey.mCallback && michael@0: aKey->mData == mKey.mData && michael@0: aKey->mForImage == mKey.mForImage; michael@0: } michael@0: michael@0: static KeyTypePointer KeyToPointer(KeyType& aKey) { return &aKey; } michael@0: static PLDHashNumber HashKey(KeyTypePointer aKey) michael@0: { michael@0: return mozilla::HashGeneric(aKey->mCallback, aKey->mData); michael@0: } michael@0: enum { ALLOW_MEMMOVE = true }; michael@0: michael@0: ChangeCallback mKey; michael@0: }; michael@0: michael@0: static size_t SizeOfExcludingThis(nsIdentifierMapEntry* aEntry, michael@0: mozilla::MallocSizeOf aMallocSizeOf, michael@0: void* aArg); michael@0: michael@0: private: michael@0: void FireChangeCallbacks(Element* aOldElement, Element* aNewElement, michael@0: bool aImageOnly = false); michael@0: michael@0: // empty if there are no elements with this ID. michael@0: // The elements are stored as weak pointers. michael@0: nsSmallVoidArray mIdContentList; michael@0: nsRefPtr mNameContentList; michael@0: nsAutoPtr > mChangeCallbacks; michael@0: nsRefPtr mImageElement; michael@0: }; michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: class CustomElementHashKey : public PLDHashEntryHdr michael@0: { michael@0: public: michael@0: typedef CustomElementHashKey *KeyType; michael@0: typedef const CustomElementHashKey *KeyTypePointer; michael@0: michael@0: CustomElementHashKey(int32_t aNamespaceID, nsIAtom *aAtom) michael@0: : mNamespaceID(aNamespaceID), michael@0: mAtom(aAtom) michael@0: {} michael@0: CustomElementHashKey(const CustomElementHashKey *aKey) michael@0: : mNamespaceID(aKey->mNamespaceID), michael@0: mAtom(aKey->mAtom) michael@0: {} michael@0: ~CustomElementHashKey() michael@0: {} michael@0: michael@0: KeyType GetKey() const { return const_cast(this); } michael@0: bool KeyEquals(const KeyTypePointer aKey) const michael@0: { michael@0: MOZ_ASSERT(mNamespaceID != kNameSpaceID_Unknown, michael@0: "This equals method is not transitive, nor symmetric. " michael@0: "A key with a namespace of kNamespaceID_Unknown should " michael@0: "not be stored in a hashtable."); michael@0: return (kNameSpaceID_Unknown == aKey->mNamespaceID || michael@0: mNamespaceID == aKey->mNamespaceID) && michael@0: aKey->mAtom == mAtom; michael@0: } michael@0: michael@0: static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; } michael@0: static PLDHashNumber HashKey(const KeyTypePointer aKey) michael@0: { michael@0: return aKey->mAtom->hash(); michael@0: } michael@0: enum { ALLOW_MEMMOVE = true }; michael@0: michael@0: private: michael@0: int32_t mNamespaceID; michael@0: nsCOMPtr mAtom; michael@0: }; michael@0: michael@0: struct LifecycleCallbackArgs michael@0: { michael@0: nsString name; michael@0: nsString oldValue; michael@0: nsString newValue; michael@0: }; michael@0: michael@0: struct CustomElementData; michael@0: michael@0: class CustomElementCallback michael@0: { michael@0: public: michael@0: CustomElementCallback(Element* aThisObject, michael@0: nsIDocument::ElementCallbackType aCallbackType, michael@0: mozilla::dom::CallbackFunction* aCallback, michael@0: CustomElementData* aOwnerData); michael@0: void Traverse(nsCycleCollectionTraversalCallback& aCb) const; michael@0: void Call(); michael@0: void SetArgs(LifecycleCallbackArgs& aArgs) michael@0: { michael@0: MOZ_ASSERT(mType == nsIDocument::eAttributeChanged, michael@0: "Arguments are only used by attribute changed callback."); michael@0: mArgs = aArgs; michael@0: } michael@0: michael@0: private: michael@0: // The this value to use for invocation of the callback. michael@0: nsRefPtr mThisObject; michael@0: nsRefPtr mCallback; michael@0: // The type of callback (eCreated, eAttached, etc.) michael@0: nsIDocument::ElementCallbackType mType; michael@0: // Arguments to be passed to the callback, michael@0: // used by the attribute changed callback. michael@0: LifecycleCallbackArgs mArgs; michael@0: // CustomElementData that contains this callback in the michael@0: // callback queue. michael@0: CustomElementData* mOwnerData; michael@0: }; michael@0: michael@0: // Each custom element has an associated callback queue and an element is michael@0: // being created flag. michael@0: struct CustomElementData michael@0: { michael@0: CustomElementData(nsIAtom* aType); michael@0: // Objects in this array are transient and empty after each microtask michael@0: // checkpoint. michael@0: nsTArray> mCallbackQueue; michael@0: // Custom element type, for