From fd148cf57dae85322b0f0966cbda8cb84b147aa1 Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Tue, 31 Jul 2012 18:24:38 +0300 Subject: [PATCH 001/114] Bug 779122 - nsXPCComponents_Utils::RecomputeWrappers should return nsresult, not bool; r=bholley --- js/xpconnect/src/XPCComponents.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index b467fd4e84f4..45e5e4961e03 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -4322,11 +4322,13 @@ nsXPCComponents_Utils::RecomputeWrappers(const jsval &vobj, JSContext *cx) // If no compartment was given, recompute all. if (!c) - return js::RecomputeWrappers(cx, js::AllCompartments(), js::AllCompartments()); - + js::RecomputeWrappers(cx, js::AllCompartments(), js::AllCompartments()); // Otherwise, recompute wrappers for the given compartment. - return js::RecomputeWrappers(cx, js::SingleCompartment(c), js::AllCompartments()) && - js::RecomputeWrappers(cx, js::AllCompartments(), js::SingleCompartment(c)); + else + js::RecomputeWrappers(cx, js::SingleCompartment(c), js::AllCompartments()) && + js::RecomputeWrappers(cx, js::AllCompartments(), js::SingleCompartment(c)); + + return NS_OK; } /* string canCreateWrapper (in nsIIDPtr iid); */ From 27da1ba521aabf0c19b711a64b8f97e025199f1f Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Fri, 15 Jun 2012 15:16:20 +0300 Subject: [PATCH 002/114] Bug 563659 part 1 - Override GetNameSpaceElement in nsDocumentFragment; r=bz --- content/base/src/nsDocumentFragment.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/content/base/src/nsDocumentFragment.cpp b/content/base/src/nsDocumentFragment.cpp index 73aa613c252b..2a97b31dfdb0 100644 --- a/content/base/src/nsDocumentFragment.cpp +++ b/content/base/src/nsDocumentFragment.cpp @@ -73,6 +73,11 @@ public: virtual nsIAtom* DoGetID() const; virtual nsIAtom *GetIDAttributeName() const; + virtual Element* GetNameSpaceElement() + { + return nullptr; + } + protected: nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const; }; From 23180b27f17aeb93fbd3496b3312aeffcde5c98d Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Wed, 27 Jun 2012 16:01:55 +0300 Subject: [PATCH 003/114] Bug 563659 part 2 - Create FragmentOrElement and move all nsGenericElement functionality to it; r=bz --HG-- rename : content/base/src/nsGenericElement.h => content/base/public/FragmentOrElement.h rename : content/base/src/nsGenericElement.cpp => content/base/src/FragmentOrElement.cpp --- content/base/public/FragmentOrElement.h | 1128 ++++++ content/base/public/Makefile.in | 1 + content/base/src/FragmentOrElement.cpp | 4812 +++++++++++++++++++++++ content/base/src/Makefile.in | 1 + content/base/src/nsDOMTokenList.cpp | 4 +- content/base/src/nsDOMTokenList.h | 4 +- content/base/src/nsGenericElement.cpp | 15 +- content/base/src/nsGenericElement.h | 21 +- content/base/src/nsStyledElement.h | 2 +- 9 files changed, 5973 insertions(+), 15 deletions(-) create mode 100644 content/base/public/FragmentOrElement.h create mode 100644 content/base/src/FragmentOrElement.cpp diff --git a/content/base/public/FragmentOrElement.h b/content/base/public/FragmentOrElement.h new file mode 100644 index 000000000000..6f2fbc7af104 --- /dev/null +++ b/content/base/public/FragmentOrElement.h @@ -0,0 +1,1128 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +/* + * Base class for all element classes; this provides an implementation + * of DOM Core's nsIDOMElement, implements nsIContent, provides + * utility methods for subclasses, and so forth. + */ + +#ifndef FragmentOrElement_h___ +#define FragmentOrElement_h___ + +#include "nsCOMPtr.h" +#include "nsAutoPtr.h" +#include "mozilla/dom/Element.h" +#include "nsIDOMElement.h" +#include "nsIDOMDocumentFragment.h" +#include "nsILinkHandler.h" +#include "nsNodeUtils.h" +#include "nsAttrAndChildArray.h" +#include "mozFlushType.h" +#include "nsDOMAttributeMap.h" +#include "nsIWeakReference.h" +#include "nsCycleCollectionParticipant.h" +#include "nsIDocument.h" +#include "nsIDOMNodeSelector.h" +#include "nsIDOMXPathNSResolver.h" +#include "nsPresContext.h" +#include "nsIDOMDOMStringMap.h" +#include "nsContentList.h" +#include "nsDOMClassInfoID.h" // DOMCI_DATA +#include "nsIDOMTouchEvent.h" +#include "nsIInlineEventHandlers.h" +#include "mozilla/CORSMode.h" +#include "mozilla/Attributes.h" + +#include "nsISMILAttr.h" + +class nsIDOMAttr; +class nsIDOMEventListener; +class nsIFrame; +class nsIDOMNamedNodeMap; +class nsICSSDeclaration; +class nsIDOMCSSStyleDeclaration; +class nsIURI; +class nsINodeInfo; +class nsIControllers; +class nsEventListenerManager; +class nsIScrollableFrame; +class nsAttrValueOrString; +class nsContentList; +class nsDOMTokenList; +class ContentUnbinder; +struct nsRect; + +typedef PRUptrdiff PtrBits; + +/** + * Class that implements the nsIDOMNodeList interface (a list of children of + * the content), by holding a reference to the content and delegating GetLength + * and Item to its existing child list. + * @see nsIDOMNodeList + */ +class nsChildContentList MOZ_FINAL : public nsINodeList +{ +public: + nsChildContentList(nsINode* aNode) + : mNode(aNode) + { + SetIsDOMBinding(); + } + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsChildContentList) + + // nsWrapperCache + virtual JSObject* WrapObject(JSContext *cx, JSObject *scope, + bool *triedToWrap); + + // nsIDOMNodeList interface + NS_DECL_NSIDOMNODELIST + + // nsINodeList interface + virtual PRInt32 IndexOf(nsIContent* aContent); + + void DropReference() + { + mNode = nullptr; + } + + virtual nsINode* GetParentObject() + { + return mNode; + } + +private: + // The node whose children make up the list (weak reference) + nsINode* mNode; +}; + +/** + * A tearoff class for FragmentOrElement to implement additional interfaces + */ +class nsNode3Tearoff : public nsIDOMXPathNSResolver +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + + NS_DECL_CYCLE_COLLECTION_CLASS(nsNode3Tearoff) + + NS_DECL_NSIDOMXPATHNSRESOLVER + + nsNode3Tearoff(nsINode *aNode) : mNode(aNode) + { + } + +protected: + virtual ~nsNode3Tearoff() {} + +private: + nsCOMPtr mNode; +}; + +/** + * A class that implements nsIWeakReference + */ + +class nsNodeWeakReference MOZ_FINAL : public nsIWeakReference +{ +public: + nsNodeWeakReference(nsINode* aNode) + : mNode(aNode) + { + } + + ~nsNodeWeakReference(); + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIWeakReference + NS_DECL_NSIWEAKREFERENCE + + void NoticeNodeDestruction() + { + mNode = nullptr; + } + +private: + nsINode* mNode; +}; + +/** + * Tearoff to use for nodes to implement nsISupportsWeakReference + */ +class nsNodeSupportsWeakRefTearoff MOZ_FINAL : public nsISupportsWeakReference +{ +public: + nsNodeSupportsWeakRefTearoff(nsINode* aNode) + : mNode(aNode) + { + } + + // nsISupports + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + + // nsISupportsWeakReference + NS_DECL_NSISUPPORTSWEAKREFERENCE + + NS_DECL_CYCLE_COLLECTION_CLASS(nsNodeSupportsWeakRefTearoff) + +private: + nsCOMPtr mNode; +}; + +/** + * A tearoff class for FragmentOrElement to implement NodeSelector + */ +class nsNodeSelectorTearoff MOZ_FINAL : public nsIDOMNodeSelector +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + + NS_DECL_NSIDOMNODESELECTOR + + NS_DECL_CYCLE_COLLECTION_CLASS(nsNodeSelectorTearoff) + + nsNodeSelectorTearoff(nsINode *aNode) : mNode(aNode) + { + } + +private: + ~nsNodeSelectorTearoff() {} + +private: + nsCOMPtr mNode; +}; + +// Forward declare to allow being a friend +class nsTouchEventReceiverTearoff; +class nsInlineEventHandlersTearoff; + +/** + * A generic base class for DOM elements, implementing many nsIContent, + * nsIDOMNode and nsIDOMElement methods. + */ +namespace mozilla { +namespace dom { + +class FragmentOrElement : public mozilla::dom::Element +{ +public: + FragmentOrElement(already_AddRefed aNodeInfo); + virtual ~FragmentOrElement(); + + friend class ::nsTouchEventReceiverTearoff; + friend class ::nsInlineEventHandlersTearoff; + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + + NS_DECL_SIZEOF_EXCLUDING_THIS + + /** + * Called during QueryInterface to give the binding manager a chance to + * get an interface for this element. + */ + nsresult PostQueryInterface(REFNSIID aIID, void** aInstancePtr); + + // nsINode interface methods + virtual PRUint32 GetChildCount() const; + virtual nsIContent *GetChildAt(PRUint32 aIndex) const; + virtual nsIContent * const * GetChildArray(PRUint32* aChildCount) const; + virtual PRInt32 IndexOf(nsINode* aPossibleChild) const; + virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex, + bool aNotify); + virtual void RemoveChildAt(PRUint32 aIndex, bool aNotify); + NS_IMETHOD GetTextContent(nsAString &aTextContent); + NS_IMETHOD SetTextContent(const nsAString& aTextContent); + + // nsIContent interface methods + virtual void UpdateEditableState(bool aNotify); + + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + bool aCompileEventHandlers); + virtual void UnbindFromTree(bool aDeep = true, + bool aNullParent = true); + virtual already_AddRefed GetChildren(PRUint32 aFilter); + virtual nsIAtom *GetClassAttributeName() const; + virtual already_AddRefed GetExistingAttrNameFromQName(const nsAString& aStr) const; + nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, + const nsAString& aValue, bool aNotify) + { + return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify); + } + /** + * Helper for SetAttr/SetParsedAttr. This method will return true if aNotify + * is true or there are mutation listeners that must be triggered, the + * attribute is currently set, and the new value that is about to be set is + * different to the current value. As a perf optimization the new and old + * values will not actually be compared if we aren't notifying and we don't + * have mutation listeners (in which case it's cheap to just return false + * and let the caller go ahead and set the value). + * @param aOldValue Set to the old value of the attribute, but only if there + * are event listeners. If set, the type of aOldValue will be either + * nsAttrValue::eString or nsAttrValue::eAtom. + * @param aModType Set to nsIDOMMutationEvent::MODIFICATION or to + * nsIDOMMutationEvent::ADDITION, but only if this helper returns true + * @param aHasListeners Set to true if there are mutation event listeners + * listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED + */ + bool MaybeCheckSameAttrVal(PRInt32 aNamespaceID, nsIAtom* aName, + nsIAtom* aPrefix, + const nsAttrValueOrString& aValue, + bool aNotify, nsAttrValue& aOldValue, + PRUint8* aModType, bool* aHasListeners); + virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix, + const nsAString& aValue, bool aNotify); + virtual nsresult SetParsedAttr(PRInt32 aNameSpaceID, nsIAtom* aName, + nsIAtom* aPrefix, nsAttrValue& aParsedValue, + bool aNotify); + virtual bool GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, + nsAString& aResult) const; + virtual bool HasAttr(PRInt32 aNameSpaceID, nsIAtom* aName) const; + virtual bool AttrValueIs(PRInt32 aNameSpaceID, nsIAtom* aName, + const nsAString& aValue, + nsCaseTreatment aCaseSensitive) const; + virtual bool AttrValueIs(PRInt32 aNameSpaceID, nsIAtom* aName, + nsIAtom* aValue, + nsCaseTreatment aCaseSensitive) const; + virtual PRInt32 FindAttrValueIn(PRInt32 aNameSpaceID, + nsIAtom* aName, + AttrValuesArray* aValues, + nsCaseTreatment aCaseSensitive) const; + virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute, + bool aNotify); + virtual const nsAttrName* GetAttrNameAt(PRUint32 aIndex) const; + virtual PRUint32 GetAttrCount() const; + virtual const nsTextFragment *GetText(); + virtual PRUint32 TextLength() const; + virtual nsresult SetText(const PRUnichar* aBuffer, PRUint32 aLength, + bool aNotify); + // Need to implement this here too to avoid hiding. + nsresult SetText(const nsAString& aStr, bool aNotify) + { + return SetText(aStr.BeginReading(), aStr.Length(), aNotify); + } + virtual nsresult AppendText(const PRUnichar* aBuffer, PRUint32 aLength, + bool aNotify); + virtual bool TextIsOnlyWhitespace(); + virtual void AppendTextTo(nsAString& aResult); + virtual nsIContent *GetBindingParent() const; + virtual bool IsNodeOfType(PRUint32 aFlags) const; + virtual bool IsLink(nsIURI** aURI) const; + + virtual void DestroyContent(); + virtual void SaveSubtreeState(); + + virtual nsISMILAttr* GetAnimatedAttr(PRInt32 /*aNamespaceID*/, nsIAtom* /*aName*/) + { + return nullptr; + } + virtual nsICSSDeclaration* GetSMILOverrideStyle(); + virtual mozilla::css::StyleRule* GetSMILOverrideStyleRule(); + virtual nsresult SetSMILOverrideStyleRule(mozilla::css::StyleRule* aStyleRule, + bool aNotify); + virtual bool IsLabelable() const; + +#ifdef DEBUG + virtual void List(FILE* out, PRInt32 aIndent) const + { + List(out, aIndent, EmptyCString()); + } + virtual void DumpContent(FILE* out, PRInt32 aIndent, bool aDumpAll) const; + void List(FILE* out, PRInt32 aIndent, const nsCString& aPrefix) const; + void ListAttributes(FILE* out) const; +#endif + + virtual const nsAttrValue* DoGetClasses() const; + NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker); + virtual mozilla::css::StyleRule* GetInlineStyleRule(); + virtual nsresult SetInlineStyleRule(mozilla::css::StyleRule* aStyleRule, + const nsAString* aSerialized, + bool aNotify); + NS_IMETHOD_(bool) + IsAttributeMapped(const nsIAtom* aAttribute) const; + virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, + PRInt32 aModType) const; + /* + * Attribute Mapping Helpers + */ + struct MappedAttributeEntry { + nsIAtom** attribute; + }; + + /** + * A common method where you can just pass in a list of maps to check + * for attribute dependence. Most implementations of + * IsAttributeMapped should use this function as a default + * handler. + */ + template + static bool + FindAttributeDependence(const nsIAtom* aAttribute, + const MappedAttributeEntry* const (&aMaps)[N]) + { + return FindAttributeDependence(aAttribute, aMaps, N); + } + +private: + static bool + FindAttributeDependence(const nsIAtom* aAttribute, + const MappedAttributeEntry* const aMaps[], + PRUint32 aMapCount); + +public: + // nsIDOMNode method implementation + NS_IMETHOD GetNodeName(nsAString& aNodeName); + NS_IMETHOD GetLocalName(nsAString& aLocalName); + NS_IMETHOD GetNodeValue(nsAString& aNodeValue); + NS_IMETHOD SetNodeValue(const nsAString& aNodeValue); + NS_IMETHOD GetNodeType(PRUint16* aNodeType); + NS_IMETHOD GetAttributes(nsIDOMNamedNodeMap** aAttributes); + NS_IMETHOD GetNamespaceURI(nsAString& aNamespaceURI); + NS_IMETHOD GetPrefix(nsAString& aPrefix); + NS_IMETHOD IsSupported(const nsAString& aFeature, + const nsAString& aVersion, bool* aReturn); + NS_IMETHOD HasAttributes(bool* aHasAttributes); + NS_IMETHOD HasChildNodes(bool* aHasChildNodes); + nsresult InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild, + nsIDOMNode** aReturn) + { + return ReplaceOrInsertBefore(false, aNewChild, aRefChild, aReturn); + } + nsresult ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild, + nsIDOMNode** aReturn) + { + return ReplaceOrInsertBefore(true, aNewChild, aOldChild, aReturn); + } + nsresult RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn) + { + return nsINode::RemoveChild(aOldChild, aReturn); + } + nsresult AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn) + { + return InsertBefore(aNewChild, nullptr, aReturn); + } + + // nsIDOMElement method implementation + NS_DECL_NSIDOMELEMENT + + nsresult CloneNode(bool aDeep, PRUint8 aOptionalArgc, nsIDOMNode **aResult) + { + if (!aOptionalArgc) { + aDeep = true; + } + + return nsNodeUtils::CloneNodeImpl(this, aDeep, true, aResult); + } + + //---------------------------------------- + + /** + * Add a script event listener with the given event handler name + * (like onclick) and with the value as JS + * @param aEventName the event listener name + * @param aValue the JS to attach + * @param aDefer indicates if deferred execution is allowed + */ + nsresult AddScriptEventListener(nsIAtom* aEventName, + const nsAString& aValue, + bool aDefer = true); + + /** + * Do whatever needs to be done when the mouse leaves a link + */ + nsresult LeaveLink(nsPresContext* aPresContext); + + /** + * Check whether a spec feature/version is supported. + * @param aObject the object, which should support the feature, + * for example nsIDOMNode or nsIDOMDOMImplementation + * @param aFeature the feature ("Views", "Core", "HTML", "Range" ...) + * @param aVersion the version ("1.0", "2.0", ...) + * @param aReturn whether the feature is supported or not [OUT] + */ + static nsresult InternalIsSupported(nsISupports* aObject, + const nsAString& aFeature, + const nsAString& aVersion, + bool* aReturn); + + static bool ShouldBlur(nsIContent *aContent); + + /** + * If there are listeners for DOMNodeInserted event, fires the event on all + * aNodes + */ + static void FireNodeInserted(nsIDocument* aDoc, + nsINode* aParent, + nsTArray >& aNodes); + + /** + * Helper methods for implementing querySelector/querySelectorAll + */ + static nsIContent* doQuerySelector(nsINode* aRoot, const nsAString& aSelector, + nsresult *aResult); + static nsresult doQuerySelectorAll(nsINode* aRoot, + const nsAString& aSelector, + nsIDOMNodeList **aReturn); + + /** + * Method to create and dispatch a left-click event loosely based on + * aSourceEvent. If aFullDispatch is true, the event will be dispatched + * through the full dispatching of the presshell of the aPresContext; if it's + * false the event will be dispatched only as a DOM event. + * If aPresContext is nullptr, this does nothing. + */ + static nsresult DispatchClickEvent(nsPresContext* aPresContext, + nsInputEvent* aSourceEvent, + nsIContent* aTarget, + bool aFullDispatch, + PRUint32 aFlags, + nsEventStatus* aStatus); + + /** + * Method to dispatch aEvent to aTarget. If aFullDispatch is true, the event + * will be dispatched through the full dispatching of the presshell of the + * aPresContext; if it's false the event will be dispatched only as a DOM + * event. + * If aPresContext is nullptr, this does nothing. + */ + using nsIContent::DispatchEvent; + static nsresult DispatchEvent(nsPresContext* aPresContext, + nsEvent* aEvent, + nsIContent* aTarget, + bool aFullDispatch, + nsEventStatus* aStatus); + + /** + * Get the primary frame for this content with flushing + * + * @param aType the kind of flush to do, typically Flush_Frames or + * Flush_Layout + * @return the primary frame + */ + nsIFrame* GetPrimaryFrame(mozFlushType aType); + // Work around silly C++ name hiding stuff + nsIFrame* GetPrimaryFrame() const { return nsIContent::GetPrimaryFrame(); } + + /** + * Struct that stores info on an attribute. The name and value must + * either both be null or both be non-null. + */ + struct nsAttrInfo { + nsAttrInfo(const nsAttrName* aName, const nsAttrValue* aValue) : + mName(aName), mValue(aValue) {} + nsAttrInfo(const nsAttrInfo& aOther) : + mName(aOther.mName), mValue(aOther.mValue) {} + + const nsAttrName* mName; + const nsAttrValue* mValue; + }; + + // Be careful when using this method. This does *NOT* handle + // XUL prototypes. You may want to use GetAttrInfo. + const nsAttrValue* GetParsedAttr(nsIAtom* aAttr) const + { + return mAttrsAndChildren.GetAttr(aAttr); + } + + /** + * Returns the attribute map, if there is one. + * + * @return existing attribute map or nullptr. + */ + nsDOMAttributeMap *GetAttributeMap() + { + nsDOMSlots *slots = GetExistingDOMSlots(); + + return slots ? slots->mAttributeMap.get() : nullptr; + } + + virtual void RecompileScriptEventListeners() + { + } + + PRInt32 GetScrollTop(); + PRInt32 GetScrollLeft(); + PRInt32 GetScrollHeight(); + PRInt32 GetScrollWidth(); + PRInt32 GetScrollLeftMax(); + PRInt32 GetScrollTopMax(); + PRInt32 GetClientTop() + { + return nsPresContext::AppUnitsToIntCSSPixels(GetClientAreaRect().y); + } + PRInt32 GetClientLeft() + { + return nsPresContext::AppUnitsToIntCSSPixels(GetClientAreaRect().x); + } + PRInt32 GetClientHeight() + { + return nsPresContext::AppUnitsToIntCSSPixels(GetClientAreaRect().height); + } + PRInt32 GetClientWidth() + { + return nsPresContext::AppUnitsToIntCSSPixels(GetClientAreaRect().width); + } + nsIContent* GetFirstElementChild(); + nsIContent* GetLastElementChild(); + nsIContent* GetPreviousElementSibling(); + nsIContent* GetNextElementSibling(); + nsDOMTokenList* GetClassList(nsresult *aResult); + bool MozMatchesSelector(const nsAString& aSelector, nsresult* aResult); + + /** + * Get the attr info for the given namespace ID and attribute name. The + * namespace ID must not be kNameSpaceID_Unknown and the name must not be + * null. Note that this can only return info on attributes that actually + * live on this element (and is only virtual to handle XUL prototypes). That + * is, this should only be called from methods that only care about attrs + * that effectively live in mAttrsAndChildren. + */ + virtual nsAttrInfo GetAttrInfo(PRInt32 aNamespaceID, nsIAtom* aName) const; + + NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(FragmentOrElement) + + virtual void NodeInfoChanged(nsINodeInfo* aOldNodeInfo) + { + } + + /** + * Fire a DOMNodeRemoved mutation event for all children of this node + */ + void FireNodeRemovedForChildren(); + + virtual bool OwnedOnlyByTheDOMTree() + { + PRUint32 rc = mRefCnt.get(); + if (GetParent()) { + --rc; + } + rc -= mAttrsAndChildren.ChildCount(); + return rc == 0; + } + + virtual bool IsPurple() + { + return mRefCnt.IsPurple(); + } + + virtual void RemovePurple() + { + mRefCnt.RemovePurple(); + } + + static void ClearContentUnbinder(); + static bool CanSkip(nsINode* aNode, bool aRemovingAllowed); + static bool CanSkipInCC(nsINode* aNode); + static bool CanSkipThis(nsINode* aNode); + static void MarkNodeChildren(nsINode* aNode); + static void InitCCCallbacks(); + static void MarkUserData(void* aObject, nsIAtom* aKey, void* aChild, + void *aData); + static void MarkUserDataHandler(void* aObject, nsIAtom* aKey, void* aChild, + void* aData); + + /** + * Parse a string into an nsAttrValue for a CORS attribute. This + * never fails. The resulting value is an enumerated value whose + * GetEnumValue() returns one of the above constants. + */ + static void ParseCORSValue(const nsAString& aValue, nsAttrValue& aResult); + + /** + * Return the CORS mode for a given string + */ + static mozilla::CORSMode StringToCORSMode(const nsAString& aValue); + + /** + * Return the CORS mode for a given nsAttrValue (which may be null, + * but if not should have been parsed via ParseCORSValue). + */ + static mozilla::CORSMode AttrValueToCORSMode(const nsAttrValue* aValue); + +protected: + /* + * Named-bools for use with SetAttrAndNotify to make call sites easier to + * read. + */ + static const bool kFireMutationEvent = true; + static const bool kDontFireMutationEvent = false; + static const bool kNotifyDocumentObservers = true; + static const bool kDontNotifyDocumentObservers = false; + static const bool kCallAfterSetAttr = true; + static const bool kDontCallAfterSetAttr = false; + + /** + * Set attribute and (if needed) notify documentobservers and fire off + * mutation events. This will send the AttributeChanged notification. + * Callers of this method are responsible for calling AttributeWillChange, + * since that needs to happen before the new attr value has been set, and + * in particular before it has been parsed. + * + * For the boolean parameters, consider using the named bools above to aid + * code readability. + * + * @param aNamespaceID namespace of attribute + * @param aAttribute local-name of attribute + * @param aPrefix aPrefix of attribute + * @param aOldValue previous value of attribute. Only needed if + * aFireMutation is true. + * @param aParsedValue parsed new value of attribute + * @param aModType nsIDOMMutationEvent::MODIFICATION or ADDITION. Only + * needed if aFireMutation or aNotify is true. + * @param aFireMutation should mutation-events be fired? + * @param aNotify should we notify document-observers? + * @param aCallAfterSetAttr should we call AfterSetAttr? + */ + nsresult SetAttrAndNotify(PRInt32 aNamespaceID, + nsIAtom* aName, + nsIAtom* aPrefix, + const nsAttrValue& aOldValue, + nsAttrValue& aParsedValue, + PRUint8 aModType, + bool aFireMutation, + bool aNotify, + bool aCallAfterSetAttr); + + /** + * Convert an attribute string value to attribute type based on the type of + * attribute. Called by SetAttr(). Note that at the moment we only do this + * for attributes in the null namespace (kNameSpaceID_None). + * + * @param aNamespaceID the namespace of the attribute to convert + * @param aAttribute the attribute to convert + * @param aValue the string value to convert + * @param aResult the nsAttrValue [OUT] + * @return true if the parsing was successful, false otherwise + */ + virtual bool ParseAttribute(PRInt32 aNamespaceID, + nsIAtom* aAttribute, + const nsAString& aValue, + nsAttrValue& aResult); + + /** + * Try to set the attribute as a mapped attribute, if applicable. This will + * only be called for attributes that are in the null namespace and only on + * attributes that returned true when passed to IsAttributeMapped. The + * caller will not try to set the attr in any other way if this method + * returns true (the value of aRetval does not matter for that purpose). + * + * @param aDocument the current document of this node (an optimization) + * @param aName the name of the attribute + * @param aValue the nsAttrValue to set + * @param [out] aRetval the nsresult status of the operation, if any. + * @return true if the setting was attempted, false otherwise. + */ + virtual bool SetMappedAttribute(nsIDocument* aDocument, + nsIAtom* aName, + nsAttrValue& aValue, + nsresult* aRetval); + + /** + * Hook that is called by FragmentOrElement::SetAttr to allow subclasses to + * deal with attribute sets. This will only be called after we verify that + * we're actually doing an attr set and will be called before + * AttributeWillChange and before ParseAttribute and hence before we've set + * the new value. + * + * @param aNamespaceID the namespace of the attr being set + * @param aName the localname of the attribute being set + * @param aValue the value it's being set to represented as either a string or + * a parsed nsAttrValue. Alternatively, if the attr is being removed it + * will be null. + * @param aNotify Whether we plan to notify document observers. + */ + // Note that this is inlined so that when subclasses call it it gets + // inlined. Those calls don't go through a vtable. + virtual nsresult BeforeSetAttr(PRInt32 aNamespaceID, nsIAtom* aName, + const nsAttrValueOrString* aValue, + bool aNotify) + { + return NS_OK; + } + + /** + * Hook that is called by FragmentOrElement::SetAttr to allow subclasses to + * deal with attribute sets. This will only be called after we have called + * SetAndTakeAttr and AttributeChanged (that is, after we have actually set + * the attr). It will always be called under a scriptblocker. + * + * @param aNamespaceID the namespace of the attr being set + * @param aName the localname of the attribute being set + * @param aValue the value it's being set to. If null, the attr is being + * removed. + * @param aNotify Whether we plan to notify document observers. + */ + // Note that this is inlined so that when subclasses call it it gets + // inlined. Those calls don't go through a vtable. + virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName, + const nsAttrValue* aValue, bool aNotify) + { + return NS_OK; + } + + /** + * Hook to allow subclasses to produce a different nsEventListenerManager if + * needed for attachment of attribute-defined handlers + */ + virtual nsEventListenerManager* + GetEventListenerManagerForAttr(nsIAtom* aAttrName, bool* aDefer); + + /** + * Copy attributes and state to another element + * @param aDest the object to copy to + */ + nsresult CopyInnerTo(FragmentOrElement* aDest); + + /** + * Internal hook for converting an attribute name-string to an atomized name + */ + virtual const nsAttrName* InternalGetExistingAttrNameFromQName(const nsAString& aStr) const; + + /** + * Retrieve the rectangle for the offsetX properties, which + * are coordinates relative to the returned aOffsetParent. + * + * @param aRect offset rectangle + * @param aOffsetParent offset parent + */ + virtual void GetOffsetRect(nsRect& aRect, nsIContent** aOffsetParent); + + /** + * Retrieve the size of the padding rect of this element. + * + * @param aSize the size of the padding rect + */ + nsIntSize GetPaddingRectSize(); + + nsIFrame* GetStyledFrame(); + + virtual mozilla::dom::Element* GetNameSpaceElement() + { + return this; + } + + nsresult GetAttributeNodeNSInternal(const nsAString& aNamespaceURI, + const nsAString& aLocalName, + nsIDOMAttr** aReturn); + +public: + // Because of a bug in MS C++ compiler nsDOMSlots must be declared public, + // otherwise nsXULElement::nsXULSlots doesn't compile. + /** + * There are a set of DOM- and scripting-specific instance variables + * that may only be instantiated when a content object is accessed + * through the DOM. Rather than burn actual slots in the content + * objects for each of these instance variables, we put them off + * in a side structure that's only allocated when the content is + * accessed through the DOM. + */ + class nsDOMSlots : public nsINode::nsSlots + { + public: + nsDOMSlots(); + virtual ~nsDOMSlots(); + + void Traverse(nsCycleCollectionTraversalCallback &cb, bool aIsXUL); + void Unlink(bool aIsXUL); + + /** + * The .style attribute (an interface that forwards to the actual + * style rules) + * @see nsGenericHTMLElement::GetStyle + */ + nsCOMPtr mStyle; + + /** + * The .dataset attribute. + * @see nsGenericHTMLElement::GetDataset + */ + nsIDOMDOMStringMap* mDataset; // [Weak] + + /** + * SMIL Overridde style rules (for SMIL animation of CSS properties) + * @see nsIContent::GetSMILOverrideStyle + */ + nsCOMPtr mSMILOverrideStyle; + + /** + * Holds any SMIL override style rules for this element. + */ + nsRefPtr mSMILOverrideStyleRule; + + /** + * An object implementing nsIDOMNamedNodeMap for this content (attributes) + * @see FragmentOrElement::GetAttributes + */ + nsRefPtr mAttributeMap; + + union { + /** + * The nearest enclosing content node with a binding that created us. + * @see FragmentOrElement::GetBindingParent + */ + nsIContent* mBindingParent; // [Weak] + + /** + * The controllers of the XUL Element. + */ + nsIControllers* mControllers; // [OWNER] + }; + + /** + * An object implementing the .children property for this element. + */ + nsRefPtr mChildrenList; + + /** + * An object implementing the .classList property for this element. + */ + nsRefPtr mClassList; + }; + +protected: + // Override from nsINode + virtual nsINode::nsSlots* CreateSlots(); + + nsDOMSlots *DOMSlots() + { + return static_cast(GetSlots()); + } + + nsDOMSlots *GetExistingDOMSlots() const + { + return static_cast(GetExistingSlots()); + } + + void RegisterFreezableElement() { + OwnerDoc()->RegisterFreezableElement(this); + } + void UnregisterFreezableElement() { + OwnerDoc()->UnregisterFreezableElement(this); + } + + /** + * Add/remove this element to the documents id cache + */ + void AddToIdTable(nsIAtom* aId) { + NS_ASSERTION(HasID(), "Node doesn't have an ID?"); + nsIDocument* doc = GetCurrentDoc(); + if (doc && (!IsInAnonymousSubtree() || doc->IsXUL())) { + doc->AddToIdTable(this, aId); + } + } + void RemoveFromIdTable() { + if (HasID()) { + nsIDocument* doc = GetCurrentDoc(); + if (doc) { + nsIAtom* id = DoGetID(); + // id can be null during mutation events evilness. Also, XUL elements + // loose their proto attributes during cc-unlink, so this can happen + // during cc-unlink too. + if (id) { + doc->RemoveFromIdTable(this, DoGetID()); + } + } + } + } + + /** + * Functions to carry out event default actions for links of all types + * (HTML links, XLinks, SVG "XLinks", etc.) + */ + + /** + * Check that we meet the conditions to handle a link event + * and that we are actually on a link. + * + * @param aVisitor event visitor + * @param aURI the uri of the link, set only if the return value is true [OUT] + * @return true if we can handle the link event, false otherwise + */ + bool CheckHandleEventForLinksPrecondition(nsEventChainVisitor& aVisitor, + nsIURI** aURI) const; + + /** + * Handle status bar updates before they can be cancelled. + */ + nsresult PreHandleEventForLinks(nsEventChainPreVisitor& aVisitor); + + /** + * Handle default actions for link event if the event isn't consumed yet. + */ + nsresult PostHandleEventForLinks(nsEventChainPostVisitor& aVisitor); + + /** + * Get the target of this link element. Consumers should established that + * this element is a link (probably using IsLink) before calling this + * function (or else why call it?) + * + * Note: for HTML this gets the value of the 'target' attribute; for XLink + * this gets the value of the xlink:_moz_target attribute, or failing that, + * the value of xlink:show, converted to a suitably equivalent named target + * (e.g. _blank). + */ + virtual void GetLinkTarget(nsAString& aTarget); + + friend class ::ContentUnbinder; + /** + * Array containing all attributes and children for this element + */ + nsAttrAndChildArray mAttrsAndChildren; + +private: + /** + * Get this element's client area rect in app units. + * @return the frame's client area + */ + nsRect GetClientAreaRect(); + + nsIScrollableFrame* GetScrollFrame(nsIFrame **aStyledFrame = nullptr); + + nsContentList* GetChildrenList(); +}; + +} // namespace dom +} // namespace mozilla + +/** + * Macros to implement Clone(). _elementName is the class for which to implement + * Clone. + */ +#define NS_IMPL_ELEMENT_CLONE(_elementName) \ +nsresult \ +_elementName::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const \ +{ \ + *aResult = nullptr; \ + nsCOMPtr ni = aNodeInfo; \ + _elementName *it = new _elementName(ni.forget()); \ + if (!it) { \ + return NS_ERROR_OUT_OF_MEMORY; \ + } \ + \ + nsCOMPtr kungFuDeathGrip = it; \ + nsresult rv = const_cast<_elementName*>(this)->CopyInnerTo(it); \ + if (NS_SUCCEEDED(rv)) { \ + kungFuDeathGrip.swap(*aResult); \ + } \ + \ + return rv; \ +} + +#define NS_IMPL_ELEMENT_CLONE_WITH_INIT(_elementName) \ +nsresult \ +_elementName::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const \ +{ \ + *aResult = nullptr; \ + nsCOMPtr ni = aNodeInfo; \ + _elementName *it = new _elementName(ni.forget()); \ + if (!it) { \ + return NS_ERROR_OUT_OF_MEMORY; \ + } \ + \ + nsCOMPtr kungFuDeathGrip = it; \ + nsresult rv = it->Init(); \ + nsresult rv2 = const_cast<_elementName*>(this)->CopyInnerTo(it); \ + if (NS_FAILED(rv2)) { \ + rv = rv2; \ + } \ + if (NS_SUCCEEDED(rv)) { \ + kungFuDeathGrip.swap(*aResult); \ + } \ + \ + return rv; \ +} + +#define DOMCI_NODE_DATA(_interface, _class) \ + DOMCI_DATA(_interface, _class) \ + nsXPCClassInfo* _class::GetClassInfo() \ + { \ + return static_cast( \ + NS_GetDOMClassInfoInstance(eDOMClassInfo_##_interface##_id)); \ + } + +/** + * A macro to implement the getter and setter for a given string + * valued content property. The method uses the generic GetAttr and + * SetAttr methods. We use the 5-argument form of SetAttr, because + * some consumers only implement that one, hiding superclass + * 4-argument forms. + */ +#define NS_IMPL_STRING_ATTR(_class, _method, _atom) \ + NS_IMETHODIMP \ + _class::Get##_method(nsAString& aValue) \ + { \ + GetAttr(kNameSpaceID_None, nsGkAtoms::_atom, aValue); \ + return NS_OK; \ + } \ + NS_IMETHODIMP \ + _class::Set##_method(const nsAString& aValue) \ + { \ + return SetAttr(kNameSpaceID_None, nsGkAtoms::_atom, nullptr, aValue, true); \ + } + +/** + * Tearoff class to implement nsITouchEventReceiver + */ +class nsTouchEventReceiverTearoff MOZ_FINAL : public nsITouchEventReceiver +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + + NS_FORWARD_NSITOUCHEVENTRECEIVER(mElement->) + + NS_DECL_CYCLE_COLLECTION_CLASS(nsTouchEventReceiverTearoff) + + nsTouchEventReceiverTearoff(mozilla::dom::FragmentOrElement *aElement) : mElement(aElement) + { + } + +private: + nsRefPtr mElement; +}; + +/** + * Tearoff class to implement nsIInlineEventHandlers + */ +class nsInlineEventHandlersTearoff MOZ_FINAL : public nsIInlineEventHandlers +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + + NS_FORWARD_NSIINLINEEVENTHANDLERS(mElement->) + + NS_DECL_CYCLE_COLLECTION_CLASS(nsInlineEventHandlersTearoff) + + nsInlineEventHandlersTearoff(mozilla::dom::FragmentOrElement *aElement) : mElement(aElement) + { + } + +private: + nsRefPtr mElement; +}; + +#define NS_ELEMENT_INTERFACE_TABLE_TO_MAP_SEGUE \ + rv = FragmentOrElement::QueryInterface(aIID, aInstancePtr); \ + if (NS_SUCCEEDED(rv)) \ + return rv; \ + \ + NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE + +#define NS_ELEMENT_INTERFACE_MAP_END \ + { \ + return PostQueryInterface(aIID, aInstancePtr); \ + } \ + \ + NS_ADDREF(foundInterface); \ + \ + *aInstancePtr = foundInterface; \ + \ + return NS_OK; \ + } + +#endif /* FragmentOrElement_h___ */ diff --git a/content/base/public/Makefile.in b/content/base/public/Makefile.in index 981782ed6f51..532c68bac148 100644 --- a/content/base/public/Makefile.in +++ b/content/base/public/Makefile.in @@ -49,6 +49,7 @@ EXPORTS_NAMESPACES = mozilla/dom mozilla EXPORTS_mozilla/dom = \ Element.h \ + FragmentOrElement.h \ FromParser.h \ $(NULL) diff --git a/content/base/src/FragmentOrElement.cpp b/content/base/src/FragmentOrElement.cpp new file mode 100644 index 000000000000..21359310857f --- /dev/null +++ b/content/base/src/FragmentOrElement.cpp @@ -0,0 +1,4812 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 sw=2 et tw=79: */ +/* 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/. */ + +/* + * Base class for all element classes; this provides an implementation + * of DOM Core's nsIDOMElement, implements nsIContent, provides + * utility methods for subclasses, and so forth. + */ + +#include "mozilla/Util.h" + +#include "mozilla/dom/FragmentOrElement.h" + +#include "nsDOMAttribute.h" +#include "nsDOMAttributeMap.h" +#include "nsIAtom.h" +#include "nsINodeInfo.h" +#include "nsIDocument.h" +#include "nsIDOMNodeList.h" +#include "nsIDOMDocument.h" +#include "nsIContentIterator.h" +#include "nsEventListenerManager.h" +#include "nsFocusManager.h" +#include "nsILinkHandler.h" +#include "nsIScriptGlobalObject.h" +#include "nsIURL.h" +#include "nsNetUtil.h" +#include "nsIFrame.h" +#include "nsIAnonymousContentCreator.h" +#include "nsIPresShell.h" +#include "nsPresContext.h" +#include "nsStyleConsts.h" +#include "nsString.h" +#include "nsUnicharUtils.h" +#include "nsEventStateManager.h" +#include "nsIDOMEvent.h" +#include "nsDOMCID.h" +#include "nsIServiceManager.h" +#include "nsIDOMCSSStyleDeclaration.h" +#include "nsDOMCSSAttrDeclaration.h" +#include "nsINameSpaceManager.h" +#include "nsContentList.h" +#include "nsDOMTokenList.h" +#include "nsXBLPrototypeBinding.h" +#include "nsDOMError.h" +#include "nsDOMString.h" +#include "nsIScriptSecurityManager.h" +#include "nsIDOMMutationEvent.h" +#include "nsMutationEvent.h" +#include "nsNodeUtils.h" +#include "nsDocument.h" +#include "nsAttrValueOrString.h" +#ifdef MOZ_XUL +#include "nsXULElement.h" +#endif /* MOZ_XUL */ +#include "nsFrameManager.h" +#include "nsFrameSelection.h" +#ifdef DEBUG +#include "nsRange.h" +#endif + +#include "nsBindingManager.h" +#include "nsXBLBinding.h" +#include "nsPIDOMWindow.h" +#include "nsPIBoxObject.h" +#include "nsClientRect.h" +#include "nsSVGUtils.h" +#include "nsLayoutUtils.h" +#include "nsGkAtoms.h" +#include "nsContentUtils.h" +#include "nsIJSContextStack.h" + +#include "nsIDOMEventListener.h" +#include "nsIWebNavigation.h" +#include "nsIBaseWindow.h" +#include "nsIWidget.h" + +#include "jsapi.h" + +#include "nsNodeInfoManager.h" +#include "nsICategoryManager.h" +#include "nsIDOMDocumentType.h" +#include "nsIDOMUserDataHandler.h" +#include "nsGenericHTMLElement.h" +#include "nsIEditor.h" +#include "nsIEditorIMESupport.h" +#include "nsIEditorDocShell.h" +#include "nsEventDispatcher.h" +#include "nsContentCreatorFunctions.h" +#include "nsIControllers.h" +#include "nsIView.h" +#include "nsIViewManager.h" +#include "nsIScrollableFrame.h" +#include "nsXBLInsertionPoint.h" +#include "mozilla/css/StyleRule.h" /* For nsCSSSelectorList */ +#include "nsCSSRuleProcessor.h" +#include "nsRuleProcessorData.h" +#include "nsAsyncDOMEvent.h" +#include "nsTextNode.h" +#include "dombindings.h" + +#ifdef MOZ_XUL +#include "nsIXULDocument.h" +#endif /* MOZ_XUL */ + +#include "nsCycleCollectionParticipant.h" +#include "nsCCUncollectableMarker.h" + +#include "mozAutoDocUpdate.h" + +#include "nsCSSParser.h" +#include "prprf.h" +#include "nsDOMMutationObserver.h" +#include "nsSVGFeatures.h" +#include "nsWrapperCacheInlines.h" +#include "nsCycleCollector.h" +#include "xpcpublic.h" +#include "nsIScriptError.h" +#include "nsLayoutStatics.h" +#include "mozilla/Telemetry.h" + +#include "mozilla/CORSMode.h" + +#include "nsStyledElement.h" + +using namespace mozilla; +using namespace mozilla::dom; + +NS_DEFINE_IID(kThisPtrOffsetsSID, NS_THISPTROFFSETS_SID); + +PRInt32 nsIContent::sTabFocusModel = eTabFocus_any; +bool nsIContent::sTabFocusModelAppliesToXUL = false; +PRUint32 nsMutationGuard::sMutationCount = 0; + +nsEventStates +Element::IntrinsicState() const +{ + return IsEditable() ? NS_EVENT_STATE_MOZ_READWRITE : + NS_EVENT_STATE_MOZ_READONLY; +} + +void +Element::NotifyStateChange(nsEventStates aStates) +{ + nsIDocument* doc = GetCurrentDoc(); + if (doc) { + nsAutoScriptBlocker scriptBlocker; + doc->ContentStateChanged(this, aStates); + } +} + +void +Element::UpdateLinkState(nsEventStates aState) +{ + NS_ABORT_IF_FALSE(!aState.HasAtLeastOneOfStates(~(NS_EVENT_STATE_VISITED | + NS_EVENT_STATE_UNVISITED)), + "Unexpected link state bits"); + mState = + (mState & ~(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED)) | + aState; +} + +void +Element::UpdateState(bool aNotify) +{ + nsEventStates oldState = mState; + mState = IntrinsicState() | (oldState & ESM_MANAGED_STATES); + if (aNotify) { + nsEventStates changedStates = oldState ^ mState; + if (!changedStates.IsEmpty()) { + nsIDocument* doc = GetCurrentDoc(); + if (doc) { + nsAutoScriptBlocker scriptBlocker; + doc->ContentStateChanged(this, changedStates); + } + } + } +} + +void +nsIContent::UpdateEditableState(bool aNotify) +{ + // Guaranteed to be non-element content + NS_ASSERTION(!IsElement(), "What happened here?"); + nsIContent *parent = GetParent(); + + SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE)); +} + +void +FragmentOrElement::UpdateEditableState(bool aNotify) +{ + nsIContent *parent = GetParent(); + + SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE)); + if (aNotify) { + UpdateState(aNotify); + } else { + // Avoid calling UpdateState in this very common case, because + // this gets called for pretty much every single element on + // insertion into the document and UpdateState can be slow for + // some kinds of elements even when not notifying. + if (IsEditable()) { + RemoveStatesSilently(NS_EVENT_STATE_MOZ_READONLY); + AddStatesSilently(NS_EVENT_STATE_MOZ_READWRITE); + } else { + RemoveStatesSilently(NS_EVENT_STATE_MOZ_READWRITE); + AddStatesSilently(NS_EVENT_STATE_MOZ_READONLY); + } + } +} + +nsEventStates +Element::StyleStateFromLocks() const +{ + nsEventStates locks = LockedStyleStates(); + nsEventStates state = mState | locks; + + if (locks.HasState(NS_EVENT_STATE_VISITED)) { + return state & ~NS_EVENT_STATE_UNVISITED; + } + if (locks.HasState(NS_EVENT_STATE_UNVISITED)) { + return state & ~NS_EVENT_STATE_VISITED; + } + return state; +} + +nsEventStates +Element::LockedStyleStates() const +{ + nsEventStates *locks = + static_cast (GetProperty(nsGkAtoms::lockedStyleStates)); + if (locks) { + return *locks; + } + return nsEventStates(); +} + +static void +nsEventStatesPropertyDtor(void *aObject, nsIAtom *aProperty, + void *aPropertyValue, void *aData) +{ + nsEventStates *states = static_cast(aPropertyValue); + delete states; +} + +void +Element::NotifyStyleStateChange(nsEventStates aStates) +{ + nsIDocument* doc = GetCurrentDoc(); + if (doc) { + nsIPresShell *presShell = doc->GetShell(); + if (presShell) { + nsAutoScriptBlocker scriptBlocker; + presShell->ContentStateChanged(doc, this, aStates); + } + } +} + +void +Element::LockStyleStates(nsEventStates aStates) +{ + nsEventStates *locks = new nsEventStates(LockedStyleStates()); + + *locks |= aStates; + + if (aStates.HasState(NS_EVENT_STATE_VISITED)) { + *locks &= ~NS_EVENT_STATE_UNVISITED; + } + if (aStates.HasState(NS_EVENT_STATE_UNVISITED)) { + *locks &= ~NS_EVENT_STATE_VISITED; + } + + SetProperty(nsGkAtoms::lockedStyleStates, locks, nsEventStatesPropertyDtor); + SetHasLockedStyleStates(); + + NotifyStyleStateChange(aStates); +} + +void +Element::UnlockStyleStates(nsEventStates aStates) +{ + nsEventStates *locks = new nsEventStates(LockedStyleStates()); + + *locks &= ~aStates; + + if (locks->IsEmpty()) { + DeleteProperty(nsGkAtoms::lockedStyleStates); + ClearHasLockedStyleStates(); + delete locks; + } + else { + SetProperty(nsGkAtoms::lockedStyleStates, locks, nsEventStatesPropertyDtor); + } + + NotifyStyleStateChange(aStates); +} + +void +Element::ClearStyleStateLocks() +{ + nsEventStates locks = LockedStyleStates(); + + DeleteProperty(nsGkAtoms::lockedStyleStates); + ClearHasLockedStyleStates(); + + NotifyStyleStateChange(locks); +} + +nsIContent* +nsIContent::FindFirstNonNativeAnonymous() const +{ + // This handles also nested native anonymous content. + for (const nsIContent *content = this; content; + content = content->GetBindingParent()) { + if (!content->IsInNativeAnonymousSubtree()) { + // Oops, this function signature allows casting const to + // non-const. (Then again, so does GetChildAt(0)->GetParent().) + return const_cast(content); + } + } + return nullptr; +} + +nsIContent* +nsIContent::GetFlattenedTreeParent() const +{ + nsIContent *parent = GetParent(); + if (parent && parent->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) { + nsIDocument *doc = parent->OwnerDoc(); + nsIContent* insertionElement = + doc->BindingManager()->GetNestedInsertionPoint(parent, this); + if (insertionElement) { + parent = insertionElement; + } + } + return parent; +} + +nsIContent::IMEState +nsIContent::GetDesiredIMEState() +{ + if (!IsEditableInternal()) { + // Check for the special case where we're dealing with elements which don't + // have the editable flag set, but are readwrite (such as text controls). + if (!IsElement() || + !AsElement()->State().HasState(NS_EVENT_STATE_MOZ_READWRITE)) { + return IMEState(IMEState::DISABLED); + } + } + // NOTE: The content for independent editors (e.g., input[type=text], + // textarea) must override this method, so, we don't need to worry about + // that here. + nsIContent *editableAncestor = GetEditingHost(); + + // This is in another editable content, use the result of it. + if (editableAncestor && editableAncestor != this) { + return editableAncestor->GetDesiredIMEState(); + } + nsIDocument* doc = GetCurrentDoc(); + if (!doc) { + return IMEState(IMEState::DISABLED); + } + nsIPresShell* ps = doc->GetShell(); + if (!ps) { + return IMEState(IMEState::DISABLED); + } + nsPresContext* pc = ps->GetPresContext(); + if (!pc) { + return IMEState(IMEState::DISABLED); + } + nsIEditor* editor = nsContentUtils::GetHTMLEditor(pc); + nsCOMPtr imeEditor = do_QueryInterface(editor); + if (!imeEditor) { + return IMEState(IMEState::DISABLED); + } + IMEState state; + imeEditor->GetPreferredIMEState(&state); + return state; +} + +bool +nsIContent::HasIndependentSelection() +{ + nsIFrame* frame = GetPrimaryFrame(); + return (frame && frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION); +} + +dom::Element* +nsIContent::GetEditingHost() +{ + // If this isn't editable, return NULL. + NS_ENSURE_TRUE(IsEditableInternal(), nullptr); + + nsIDocument* doc = GetCurrentDoc(); + NS_ENSURE_TRUE(doc, nullptr); + // If this is in designMode, we should return + if (doc->HasFlag(NODE_IS_EDITABLE)) { + return doc->GetBodyElement(); + } + + nsIContent* content = this; + for (dom::Element* parent = GetElementParent(); + parent && parent->HasFlag(NODE_IS_EDITABLE); + parent = content->GetElementParent()) { + content = parent; + } + return content->AsElement(); +} + +nsresult +nsIContent::LookupNamespaceURIInternal(const nsAString& aNamespacePrefix, + nsAString& aNamespaceURI) const +{ + if (aNamespacePrefix.EqualsLiteral("xml")) { + // Special-case for xml prefix + aNamespaceURI.AssignLiteral("http://www.w3.org/XML/1998/namespace"); + return NS_OK; + } + + if (aNamespacePrefix.EqualsLiteral("xmlns")) { + // Special-case for xmlns prefix + aNamespaceURI.AssignLiteral("http://www.w3.org/2000/xmlns/"); + return NS_OK; + } + + nsCOMPtr name; + if (!aNamespacePrefix.IsEmpty()) { + name = do_GetAtom(aNamespacePrefix); + NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY); + } + else { + name = nsGkAtoms::xmlns; + } + // Trace up the content parent chain looking for the namespace + // declaration that declares aNamespacePrefix. + const nsIContent* content = this; + do { + if (content->GetAttr(kNameSpaceID_XMLNS, name, aNamespaceURI)) + return NS_OK; + } while ((content = content->GetParent())); + return NS_ERROR_FAILURE; +} + +already_AddRefed +nsIContent::GetBaseURI() const +{ + nsIDocument* doc = OwnerDoc(); + // Start with document base + nsCOMPtr base = doc->GetDocBaseURI(); + + // Collect array of xml:base attribute values up the parent chain. This + // is slightly slower for the case when there are xml:base attributes, but + // faster for the far more common case of there not being any such + // attributes. + // Also check for SVG elements which require special handling + nsAutoTArray baseAttrs; + nsString attr; + const nsIContent *elem = this; + do { + // First check for SVG specialness (why is this SVG specific?) + if (elem->IsSVG()) { + nsIContent* bindingParent = elem->GetBindingParent(); + if (bindingParent) { + nsXBLBinding* binding = + bindingParent->OwnerDoc()->BindingManager()->GetBinding(bindingParent); + if (binding) { + // XXX sXBL/XBL2 issue + // If this is an anonymous XBL element use the binding + // document for the base URI. + // XXX Will fail with xml:base + base = binding->PrototypeBinding()->DocURI(); + break; + } + } + } + + nsIURI* explicitBaseURI = elem->GetExplicitBaseURI(); + if (explicitBaseURI) { + base = explicitBaseURI; + break; + } + + // Otherwise check for xml:base attribute + elem->GetAttr(kNameSpaceID_XML, nsGkAtoms::base, attr); + if (!attr.IsEmpty()) { + baseAttrs.AppendElement(attr); + } + elem = elem->GetParent(); + } while(elem); + + // Now resolve against all xml:base attrs + for (PRUint32 i = baseAttrs.Length() - 1; i != PRUint32(-1); --i) { + nsCOMPtr newBase; + nsresult rv = NS_NewURI(getter_AddRefs(newBase), baseAttrs[i], + doc->GetDocumentCharacterSet().get(), base); + // Do a security check, almost the same as nsDocument::SetBaseURL() + // Only need to do this on the final uri + if (NS_SUCCEEDED(rv) && i == 0) { + rv = nsContentUtils::GetSecurityManager()-> + CheckLoadURIWithPrincipal(NodePrincipal(), newBase, + nsIScriptSecurityManager::STANDARD); + } + if (NS_SUCCEEDED(rv)) { + base.swap(newBase); + } + } + + return base.forget(); +} + +//---------------------------------------------------------------------- + +static inline JSObject* +GetJSObjectChild(nsWrapperCache* aCache) +{ + return aCache->PreservingWrapper() ? aCache->GetWrapperPreserveColor() : NULL; +} + +static bool +NeedsScriptTraverse(nsWrapperCache* aCache) +{ + JSObject* o = GetJSObjectChild(aCache); + return o && xpc_IsGrayGCThing(o); +} + +//---------------------------------------------------------------------- + +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsChildContentList) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsChildContentList) + +// If nsChildContentList is changed so that any additional fields are +// traversed by the cycle collector, then CAN_SKIP must be updated to +// check that the additional fields are null. +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsChildContentList) + +// nsChildContentList only ever has a single child, its wrapper, so if +// the wrapper is black, the list can't be part of a garbage cycle. +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsChildContentList) + return !NeedsScriptTraverse(tmp); +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END + +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsChildContentList) + return !NeedsScriptTraverse(tmp); +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END + +// CanSkipThis returns false to avoid problems with incomplete unlinking. +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsChildContentList) +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END + +NS_INTERFACE_TABLE_HEAD(nsChildContentList) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_NODELIST_OFFSET_AND_INTERFACE_TABLE_BEGIN(nsChildContentList) + NS_INTERFACE_TABLE_ENTRY(nsChildContentList, nsINodeList) + NS_INTERFACE_TABLE_ENTRY(nsChildContentList, nsIDOMNodeList) + NS_OFFSET_AND_INTERFACE_TABLE_END + NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE + NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsChildContentList) + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(NodeList) +NS_INTERFACE_MAP_END + +JSObject* +nsChildContentList::WrapObject(JSContext *cx, JSObject *scope, + bool *triedToWrap) +{ + return mozilla::dom::binding::NodeList::create(cx, scope, this, triedToWrap); +} + +NS_IMETHODIMP +nsChildContentList::GetLength(PRUint32* aLength) +{ + *aLength = mNode ? mNode->GetChildCount() : 0; + + return NS_OK; +} + +NS_IMETHODIMP +nsChildContentList::Item(PRUint32 aIndex, nsIDOMNode** aReturn) +{ + nsINode* node = GetNodeAt(aIndex); + if (!node) { + *aReturn = nullptr; + + return NS_OK; + } + + return CallQueryInterface(node, aReturn); +} + +nsIContent* +nsChildContentList::GetNodeAt(PRUint32 aIndex) +{ + if (mNode) { + return mNode->GetChildAt(aIndex); + } + + return nullptr; +} + +PRInt32 +nsChildContentList::IndexOf(nsIContent* aContent) +{ + if (mNode) { + return mNode->IndexOf(aContent); + } + + return -1; +} + +//---------------------------------------------------------------------- + +NS_IMPL_CYCLE_COLLECTION_1(nsNode3Tearoff, mNode) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNode3Tearoff) + NS_INTERFACE_MAP_ENTRY(nsIDOMXPathNSResolver) +NS_INTERFACE_MAP_END_AGGREGATED(mNode) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNode3Tearoff) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsNode3Tearoff) + +NS_IMETHODIMP +nsNode3Tearoff::LookupNamespaceURI(const nsAString& aNamespacePrefix, + nsAString& aNamespaceURI) +{ + return mNode->LookupNamespaceURI(aNamespacePrefix, aNamespaceURI); +} + +nsIContent* +FragmentOrElement::GetFirstElementChild() +{ + nsAttrAndChildArray& children = mAttrsAndChildren; + PRUint32 i, count = children.ChildCount(); + for (i = 0; i < count; ++i) { + nsIContent* child = children.ChildAt(i); + if (child->IsElement()) { + return child; + } + } + + return nullptr; +} + +nsIContent* +FragmentOrElement::GetLastElementChild() +{ + nsAttrAndChildArray& children = mAttrsAndChildren; + PRUint32 i = children.ChildCount(); + while (i > 0) { + nsIContent* child = children.ChildAt(--i); + if (child->IsElement()) { + return child; + } + } + + return nullptr; +} + +nsIContent* +FragmentOrElement::GetPreviousElementSibling() +{ + nsIContent* parent = GetParent(); + if (!parent) { + return nullptr; + } + + NS_ASSERTION(parent->IsElement() || + parent->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT), + "Parent content must be an element or a doc fragment"); + + nsAttrAndChildArray& children = + static_cast(parent)->mAttrsAndChildren; + PRInt32 index = children.IndexOfChild(this); + if (index < 0) { + return nullptr; + } + + PRUint32 i = index; + while (i > 0) { + nsIContent* child = children.ChildAt((PRUint32)--i); + if (child->IsElement()) { + return child; + } + } + + return nullptr; +} + +nsIContent* +FragmentOrElement::GetNextElementSibling() +{ + nsIContent* parent = GetParent(); + if (!parent) { + return nullptr; + } + + NS_ASSERTION(parent->IsElement() || + parent->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT), + "Parent content must be an element or a doc fragment"); + + nsAttrAndChildArray& children = + static_cast(parent)->mAttrsAndChildren; + PRInt32 index = children.IndexOfChild(this); + if (index < 0) { + return nullptr; + } + + PRUint32 i, count = children.ChildCount(); + for (i = (PRUint32)index + 1; i < count; ++i) { + nsIContent* child = children.ChildAt(i); + if (child->IsElement()) { + return child; + } + } + + return nullptr; +} + +NS_IMETHODIMP +FragmentOrElement::GetChildElementCount(PRUint32* aResult) +{ + *aResult = GetChildrenList()->Length(true); + return NS_OK; +} + +// readonly attribute nsIDOMNodeList children +NS_IMETHODIMP +FragmentOrElement::GetChildElements(nsIDOMNodeList** aResult) +{ + NS_ADDREF(*aResult = GetChildrenList()); + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::GetFirstElementChild(nsIDOMElement** aResult) +{ + *aResult = nullptr; + + nsIContent *result = GetFirstElementChild(); + + return result ? CallQueryInterface(result, aResult) : NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::GetLastElementChild(nsIDOMElement** aResult) +{ + *aResult = nullptr; + + nsIContent *result = GetLastElementChild(); + + return result ? CallQueryInterface(result, aResult) : NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::GetPreviousElementSibling(nsIDOMElement** aResult) +{ + *aResult = nullptr; + + nsIContent *result = GetPreviousElementSibling(); + + return result ? CallQueryInterface(result, aResult) : NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::GetNextElementSibling(nsIDOMElement** aResult) +{ + *aResult = nullptr; + + nsIContent *result = GetNextElementSibling(); + + return result ? CallQueryInterface(result, aResult) : NS_OK; +} + +nsContentList* +FragmentOrElement::GetChildrenList() +{ + FragmentOrElement::nsDOMSlots *slots = DOMSlots(); + + if (!slots->mChildrenList) { + slots->mChildrenList = new nsContentList(this, kNameSpaceID_Wildcard, + nsGkAtoms::_asterix, nsGkAtoms::_asterix, + false); + } + + return slots->mChildrenList; +} + +nsDOMTokenList* +FragmentOrElement::GetClassList(nsresult *aResult) +{ + *aResult = NS_ERROR_OUT_OF_MEMORY; + + FragmentOrElement::nsDOMSlots *slots = DOMSlots(); + + if (!slots->mClassList) { + nsCOMPtr classAttr = GetClassAttributeName(); + if (!classAttr) { + *aResult = NS_OK; + + return nullptr; + } + + slots->mClassList = new nsDOMTokenList(this, classAttr); + } + + *aResult = NS_OK; + + return slots->mClassList; +} + +NS_IMETHODIMP +FragmentOrElement::GetClassList(nsIDOMDOMTokenList** aResult) +{ + *aResult = nullptr; + + nsresult rv; + nsIDOMDOMTokenList* list = GetClassList(&rv); + NS_ENSURE_TRUE(list, rv); + + NS_ADDREF(*aResult = list); + + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::SetCapture(bool aRetargetToElement) +{ + // If there is already an active capture, ignore this request. This would + // occur if a splitter, frame resizer, etc had already captured and we don't + // want to override those. + if (nsIPresShell::GetCapturingContent()) + return NS_OK; + + nsIPresShell::SetCapturingContent(this, CAPTURE_PREVENTDRAG | + (aRetargetToElement ? CAPTURE_RETARGETTOELEMENT : 0)); + + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::ReleaseCapture() +{ + if (nsIPresShell::GetCapturingContent() == this) { + nsIPresShell::SetCapturingContent(nullptr, 0); + } + + return NS_OK; +} + +nsIFrame* +FragmentOrElement::GetStyledFrame() +{ + nsIFrame *frame = GetPrimaryFrame(Flush_Layout); + return frame ? nsLayoutUtils::GetStyleFrame(frame) : nullptr; +} + +void +FragmentOrElement::GetOffsetRect(nsRect& aRect, nsIContent** aOffsetParent) +{ + *aOffsetParent = nullptr; + aRect = nsRect(); + + nsIFrame* frame = GetStyledFrame(); + if (!frame) { + return; + } + + nsPoint origin = frame->GetPosition(); + aRect.x = nsPresContext::AppUnitsToIntCSSPixels(origin.x); + aRect.y = nsPresContext::AppUnitsToIntCSSPixels(origin.y); + + // Get the union of all rectangles in this and continuation frames. + // It doesn't really matter what we use as aRelativeTo here, since + // we only care about the size. Using 'parent' might make things + // a bit faster by speeding up the internal GetOffsetTo operations. + nsIFrame* parent = frame->GetParent() ? frame->GetParent() : frame; + nsRect rcFrame = nsLayoutUtils::GetAllInFlowRectsUnion(frame, parent); + aRect.width = nsPresContext::AppUnitsToIntCSSPixels(rcFrame.width); + aRect.height = nsPresContext::AppUnitsToIntCSSPixels(rcFrame.height); +} + +nsIntSize +FragmentOrElement::GetPaddingRectSize() +{ + nsIFrame* frame = GetStyledFrame(); + if (!frame) { + return nsIntSize(0, 0); + } + + NS_ASSERTION(frame->GetParent(), "Styled frame has no parent"); + nsRect rcFrame = nsLayoutUtils::GetAllInFlowPaddingRectsUnion(frame, frame->GetParent()); + return nsIntSize(nsPresContext::AppUnitsToIntCSSPixels(rcFrame.width), + nsPresContext::AppUnitsToIntCSSPixels(rcFrame.height)); +} + +nsIScrollableFrame* +FragmentOrElement::GetScrollFrame(nsIFrame **aStyledFrame) +{ + // it isn't clear what to return for SVG nodes, so just return nothing + if (IsSVG()) { + if (aStyledFrame) { + *aStyledFrame = nullptr; + } + return nullptr; + } + + nsIFrame* frame = GetStyledFrame(); + + if (aStyledFrame) { + *aStyledFrame = frame; + } + if (!frame) { + return nullptr; + } + + // menu frames implement GetScrollTargetFrame but we don't want + // to use it here. Similar for comboboxes. + if (frame->GetType() != nsGkAtoms::menuFrame && + frame->GetType() != nsGkAtoms::comboboxControlFrame) { + nsIScrollableFrame *scrollFrame = frame->GetScrollTargetFrame(); + if (scrollFrame) + return scrollFrame; + } + + nsIDocument* doc = OwnerDoc(); + bool quirksMode = doc->GetCompatibilityMode() == eCompatibility_NavQuirks; + Element* elementWithRootScrollInfo = + quirksMode ? doc->GetBodyElement() : doc->GetRootElement(); + if (this == elementWithRootScrollInfo) { + // In quirks mode, the scroll info for the body element should map to the + // root scrollable frame. + // In strict mode, the scroll info for the root element should map to the + // the root scrollable frame. + return frame->PresContext()->PresShell()->GetRootScrollFrameAsScrollable(); + } + + return nullptr; +} + +PRInt32 +FragmentOrElement::GetScrollTop() +{ + nsIScrollableFrame* sf = GetScrollFrame(); + + return sf ? + nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollPosition().y) : + 0; +} + +NS_IMETHODIMP +FragmentOrElement::GetScrollTop(PRInt32* aScrollTop) +{ + *aScrollTop = GetScrollTop(); + + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::SetScrollTop(PRInt32 aScrollTop) +{ + nsIScrollableFrame* sf = GetScrollFrame(); + if (sf) { + nsPoint pt = sf->GetScrollPosition(); + sf->ScrollToCSSPixels(nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x), + aScrollTop)); + } + return NS_OK; +} + +PRInt32 +FragmentOrElement::GetScrollLeft() +{ + nsIScrollableFrame* sf = GetScrollFrame(); + + return sf ? + nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollPosition().x) : + 0; +} + +NS_IMETHODIMP +FragmentOrElement::GetScrollLeft(PRInt32* aScrollLeft) +{ + *aScrollLeft = GetScrollLeft(); + + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::SetScrollLeft(PRInt32 aScrollLeft) +{ + nsIScrollableFrame* sf = GetScrollFrame(); + if (sf) { + nsPoint pt = sf->GetScrollPosition(); + sf->ScrollToCSSPixels(nsIntPoint(aScrollLeft, + nsPresContext::AppUnitsToIntCSSPixels(pt.y))); + } + return NS_OK; +} + +PRInt32 +FragmentOrElement::GetScrollHeight() +{ + if (IsSVG()) + return 0; + + nsIScrollableFrame* sf = GetScrollFrame(); + if (!sf) { + return GetPaddingRectSize().height; + } + + nscoord height = sf->GetScrollRange().height + sf->GetScrollPortRect().height; + return nsPresContext::AppUnitsToIntCSSPixels(height); +} + +NS_IMETHODIMP +FragmentOrElement::GetScrollHeight(PRInt32* aScrollHeight) +{ + *aScrollHeight = GetScrollHeight(); + + return NS_OK; +} + +PRInt32 +FragmentOrElement::GetScrollWidth() +{ + if (IsSVG()) + return 0; + + nsIScrollableFrame* sf = GetScrollFrame(); + if (!sf) { + return GetPaddingRectSize().width; + } + + nscoord width = sf->GetScrollRange().width + sf->GetScrollPortRect().width; + return nsPresContext::AppUnitsToIntCSSPixels(width); +} + +NS_IMETHODIMP +FragmentOrElement::GetScrollWidth(PRInt32 *aScrollWidth) +{ + *aScrollWidth = GetScrollWidth(); + + return NS_OK; +} + +PRInt32 +nsGenericElement::GetScrollLeftMax() +{ + nsIScrollableFrame* sf = GetScrollFrame(); + if (!sf) { + return 0; + } + + return nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollRange().XMost()); +} + +NS_IMETHODIMP +nsGenericElement::GetScrollLeftMax(PRInt32 *aScrollLeftMax) +{ + *aScrollLeftMax = GetScrollLeftMax(); + + return NS_OK; +} + +PRInt32 +nsGenericElement::GetScrollTopMax() +{ + nsIScrollableFrame* sf = GetScrollFrame(); + if (!sf) { + return 0; + } + + return nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollRange().YMost()); +} + +NS_IMETHODIMP +nsGenericElement::GetScrollTopMax(PRInt32 *aScrollTopMax) +{ + *aScrollTopMax = GetScrollTopMax(); + + return NS_OK; +} + +nsRect +FragmentOrElement::GetClientAreaRect() +{ + nsIFrame* styledFrame; + nsIScrollableFrame* sf = GetScrollFrame(&styledFrame); + + if (sf) { + return sf->GetScrollPortRect(); + } + + if (styledFrame && + (styledFrame->GetStyleDisplay()->mDisplay != NS_STYLE_DISPLAY_INLINE || + styledFrame->IsFrameOfType(nsIFrame::eReplaced))) { + // Special case code to make client area work even when there isn't + // a scroll view, see bug 180552, bug 227567. + return styledFrame->GetPaddingRect() - styledFrame->GetPositionIgnoringScrolling(); + } + + // SVG nodes reach here and just return 0 + return nsRect(0, 0, 0, 0); +} + +NS_IMETHODIMP +FragmentOrElement::GetClientTop(PRInt32 *aClientTop) +{ + *aClientTop = GetClientTop(); + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::GetClientLeft(PRInt32 *aClientLeft) +{ + *aClientLeft = GetClientLeft(); + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::GetClientHeight(PRInt32 *aClientHeight) +{ + *aClientHeight = GetClientHeight(); + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::GetClientWidth(PRInt32 *aClientWidth) +{ + *aClientWidth = GetClientWidth(); + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::GetBoundingClientRect(nsIDOMClientRect** aResult) +{ + // Weak ref, since we addref it below + nsClientRect* rect = new nsClientRect(); + NS_ADDREF(*aResult = rect); + + nsIFrame* frame = GetPrimaryFrame(Flush_Layout); + if (!frame) { + // display:none, perhaps? Return the empty rect + return NS_OK; + } + + nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion(frame, + nsLayoutUtils::GetContainingBlockForClientRect(frame), + nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS); + rect->SetLayoutRect(r); + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::GetElementsByClassName(const nsAString& aClasses, + nsIDOMNodeList** aReturn) +{ + return nsContentUtils::GetElementsByClassName(this, aClasses, aReturn); +} + +NS_IMETHODIMP +FragmentOrElement::GetClientRects(nsIDOMClientRectList** aResult) +{ + *aResult = nullptr; + + nsRefPtr rectList = new nsClientRectList(this); + + nsIFrame* frame = GetPrimaryFrame(Flush_Layout); + if (!frame) { + // display:none, perhaps? Return an empty list + *aResult = rectList.forget().get(); + return NS_OK; + } + + nsLayoutUtils::RectListBuilder builder(rectList); + nsLayoutUtils::GetAllInFlowRects(frame, + nsLayoutUtils::GetContainingBlockForClientRect(frame), &builder, + nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS); + if (NS_FAILED(builder.mRV)) + return builder.mRV; + *aResult = rectList.forget().get(); + return NS_OK; +} + + +//---------------------------------------------------------------------- + + +NS_IMPL_ISUPPORTS1(nsNodeWeakReference, + nsIWeakReference) + +nsNodeWeakReference::~nsNodeWeakReference() +{ + if (mNode) { + NS_ASSERTION(mNode->GetSlots() && + mNode->GetSlots()->mWeakReference == this, + "Weak reference has wrong value"); + mNode->GetSlots()->mWeakReference = nullptr; + } +} + +NS_IMETHODIMP +nsNodeWeakReference::QueryReferent(const nsIID& aIID, void** aInstancePtr) +{ + return mNode ? mNode->QueryInterface(aIID, aInstancePtr) : + NS_ERROR_NULL_POINTER; +} + + +NS_IMPL_CYCLE_COLLECTION_1(nsNodeSupportsWeakRefTearoff, mNode) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNodeSupportsWeakRefTearoff) + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) +NS_INTERFACE_MAP_END_AGGREGATED(mNode) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNodeSupportsWeakRefTearoff) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsNodeSupportsWeakRefTearoff) + +NS_IMETHODIMP +nsNodeSupportsWeakRefTearoff::GetWeakReference(nsIWeakReference** aInstancePtr) +{ + nsINode::nsSlots* slots = mNode->GetSlots(); + NS_ENSURE_TRUE(slots, NS_ERROR_OUT_OF_MEMORY); + + if (!slots->mWeakReference) { + slots->mWeakReference = new nsNodeWeakReference(mNode); + NS_ENSURE_TRUE(slots->mWeakReference, NS_ERROR_OUT_OF_MEMORY); + } + + NS_ADDREF(*aInstancePtr = slots->mWeakReference); + + return NS_OK; +} + +//---------------------------------------------------------------------- + +NS_IMPL_CYCLE_COLLECTION_1(nsNodeSelectorTearoff, mNode) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNodeSelectorTearoff) + NS_INTERFACE_MAP_ENTRY(nsIDOMNodeSelector) +NS_INTERFACE_MAP_END_AGGREGATED(mNode) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNodeSelectorTearoff) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsNodeSelectorTearoff) + +NS_IMETHODIMP +nsNodeSelectorTearoff::QuerySelector(const nsAString& aSelector, + nsIDOMElement **aReturn) +{ + nsresult rv; + nsIContent* result = FragmentOrElement::doQuerySelector(mNode, aSelector, &rv); + return result ? CallQueryInterface(result, aReturn) : rv; +} + +NS_IMETHODIMP +nsNodeSelectorTearoff::QuerySelectorAll(const nsAString& aSelector, + nsIDOMNodeList **aReturn) +{ + return FragmentOrElement::doQuerySelectorAll(mNode, aSelector, aReturn); +} + +//---------------------------------------------------------------------- + +NS_IMPL_CYCLE_COLLECTION_1(nsTouchEventReceiverTearoff, mElement) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTouchEventReceiverTearoff) + NS_INTERFACE_MAP_ENTRY(nsITouchEventReceiver) +NS_INTERFACE_MAP_END_AGGREGATED(mElement) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTouchEventReceiverTearoff) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTouchEventReceiverTearoff) + +//---------------------------------------------------------------------- + +NS_IMPL_CYCLE_COLLECTION_1(nsInlineEventHandlersTearoff, mElement) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsInlineEventHandlersTearoff) + NS_INTERFACE_MAP_ENTRY(nsIInlineEventHandlers) +NS_INTERFACE_MAP_END_AGGREGATED(mElement) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsInlineEventHandlersTearoff) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsInlineEventHandlersTearoff) + +//---------------------------------------------------------------------- +FragmentOrElement::nsDOMSlots::nsDOMSlots() + : nsINode::nsSlots(), + mDataset(nullptr), + mBindingParent(nullptr) +{ +} + +FragmentOrElement::nsDOMSlots::~nsDOMSlots() +{ + if (mAttributeMap) { + mAttributeMap->DropReference(); + } + + if (mClassList) { + mClassList->DropReference(); + } +} + +void +FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb, bool aIsXUL) +{ + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mStyle"); + cb.NoteXPCOMChild(mStyle.get()); + + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mSMILOverrideStyle"); + cb.NoteXPCOMChild(mSMILOverrideStyle.get()); + + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mAttributeMap"); + cb.NoteXPCOMChild(mAttributeMap.get()); + + if (aIsXUL) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mControllers"); + cb.NoteXPCOMChild(mControllers); + } + + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildrenList"); + cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mChildrenList)); + + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mClassList"); + cb.NoteXPCOMChild(mClassList.get()); +} + +void +FragmentOrElement::nsDOMSlots::Unlink(bool aIsXUL) +{ + mStyle = nullptr; + mSMILOverrideStyle = nullptr; + if (mAttributeMap) { + mAttributeMap->DropReference(); + mAttributeMap = nullptr; + } + if (aIsXUL) + NS_IF_RELEASE(mControllers); + mChildrenList = nullptr; + if (mClassList) { + mClassList->DropReference(); + mClassList = nullptr; + } +} + +FragmentOrElement::FragmentOrElement(already_AddRefed aNodeInfo) + : Element(aNodeInfo) +{ + NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::ELEMENT_NODE || + (mNodeInfo->NodeType() == + nsIDOMNode::DOCUMENT_FRAGMENT_NODE && + mNodeInfo->Equals(nsGkAtoms::documentFragmentNodeName, + kNameSpaceID_None)), + "Bad NodeType in aNodeInfo"); + + SetIsElement(); +} + +FragmentOrElement::~FragmentOrElement() +{ + NS_PRECONDITION(!IsInDoc(), + "Please remove this from the document properly"); + if (GetParent()) { + NS_RELEASE(mParent); + } +} + +NS_IMETHODIMP +FragmentOrElement::GetNodeName(nsAString& aNodeName) +{ + aNodeName = NodeName(); + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::GetLocalName(nsAString& aLocalName) +{ + aLocalName = LocalName(); + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::GetNodeValue(nsAString& aNodeValue) +{ + SetDOMStringToNull(aNodeValue); + + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::SetNodeValue(const nsAString& aNodeValue) +{ + // The DOM spec says that when nodeValue is defined to be null "setting it + // has no effect", so we don't throw an exception. + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::GetNodeType(PRUint16* aNodeType) +{ + *aNodeType = NodeType(); + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::GetNamespaceURI(nsAString& aNamespaceURI) +{ + return mNodeInfo->GetNamespaceURI(aNamespaceURI); +} + +NS_IMETHODIMP +FragmentOrElement::GetPrefix(nsAString& aPrefix) +{ + mNodeInfo->GetPrefix(aPrefix); + return NS_OK; +} + +nsresult +FragmentOrElement::InternalIsSupported(nsISupports* aObject, + const nsAString& aFeature, + const nsAString& aVersion, + bool* aReturn) +{ + NS_ENSURE_ARG_POINTER(aReturn); + *aReturn = false; + + // Convert the incoming UTF16 strings to raw char*'s to save us some + // code when doing all those string compares. + NS_ConvertUTF16toUTF8 feature(aFeature); + NS_ConvertUTF16toUTF8 version(aVersion); + + const char *f = feature.get(); + const char *v = version.get(); + + if (PL_strcasecmp(f, "XML") == 0 || + PL_strcasecmp(f, "HTML") == 0) { + if (aVersion.IsEmpty() || + PL_strcmp(v, "1.0") == 0 || + PL_strcmp(v, "2.0") == 0) { + *aReturn = true; + } + } else if (PL_strcasecmp(f, "Views") == 0 || + PL_strcasecmp(f, "StyleSheets") == 0 || + PL_strcasecmp(f, "Core") == 0 || + PL_strcasecmp(f, "CSS") == 0 || + PL_strcasecmp(f, "CSS2") == 0 || + PL_strcasecmp(f, "Events") == 0 || + PL_strcasecmp(f, "UIEvents") == 0 || + PL_strcasecmp(f, "MouseEvents") == 0 || + // Non-standard! + PL_strcasecmp(f, "MouseScrollEvents") == 0 || + PL_strcasecmp(f, "HTMLEvents") == 0 || + PL_strcasecmp(f, "Range") == 0 || + PL_strcasecmp(f, "XHTML") == 0) { + if (aVersion.IsEmpty() || + PL_strcmp(v, "2.0") == 0) { + *aReturn = true; + } + } else if (PL_strcasecmp(f, "XPath") == 0) { + if (aVersion.IsEmpty() || + PL_strcmp(v, "3.0") == 0) { + *aReturn = true; + } + } else if (PL_strcasecmp(f, "SVGEvents") == 0 || + PL_strcasecmp(f, "SVGZoomEvents") == 0 || + nsSVGFeatures::HasFeature(aObject, aFeature)) { + if (aVersion.IsEmpty() || + PL_strcmp(v, "1.0") == 0 || + PL_strcmp(v, "1.1") == 0) { + *aReturn = true; + } + } + else if (NS_SMILEnabled() && PL_strcasecmp(f, "TimeControl") == 0) { + if (aVersion.IsEmpty() || PL_strcmp(v, "1.0") == 0) { + *aReturn = true; + } + } + + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::IsSupported(const nsAString& aFeature, + const nsAString& aVersion, + bool* aReturn) +{ + return InternalIsSupported(this, aFeature, aVersion, aReturn); +} + +NS_IMETHODIMP +FragmentOrElement::HasAttributes(bool* aReturn) +{ + NS_ENSURE_ARG_POINTER(aReturn); + + *aReturn = GetAttrCount() > 0; + + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::GetAttributes(nsIDOMNamedNodeMap** aAttributes) +{ + if (!IsElement()) { + *aAttributes = nullptr; + return NS_OK; + } + + nsDOMSlots *slots = DOMSlots(); + + if (!slots->mAttributeMap) { + slots->mAttributeMap = new nsDOMAttributeMap(this); + } + + NS_ADDREF(*aAttributes = slots->mAttributeMap); + + return NS_OK; +} + +nsresult +FragmentOrElement::HasChildNodes(bool* aReturn) +{ + *aReturn = mAttrsAndChildren.ChildCount() > 0; + + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::GetTagName(nsAString& aTagName) +{ + aTagName = NodeName(); + return NS_OK; +} + +nsresult +FragmentOrElement::GetAttribute(const nsAString& aName, + nsAString& aReturn) +{ + const nsAttrValue* val = + mAttrsAndChildren.GetAttr(aName, + IsHTML() && IsInHTMLDocument() ? + eIgnoreCase : eCaseMatters); + if (val) { + val->ToString(aReturn); + } else { + if (IsXUL()) { + // XXX should be SetDOMStringToNull(aReturn); + // See bug 232598 + aReturn.Truncate(); + } else { + SetDOMStringToNull(aReturn); + } + } + + return NS_OK; +} + +nsresult +FragmentOrElement::SetAttribute(const nsAString& aName, + const nsAString& aValue) +{ + const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName); + + if (!name) { + nsresult rv = nsContentUtils::CheckQName(aName, false); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr nameAtom = do_GetAtom(aName); + NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY); + + return SetAttr(kNameSpaceID_None, nameAtom, aValue, true); + } + + return SetAttr(name->NamespaceID(), name->LocalName(), name->GetPrefix(), + aValue, true); +} + +nsresult +FragmentOrElement::RemoveAttribute(const nsAString& aName) +{ + const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName); + + if (!name) { + // If there is no canonical nsAttrName for this attribute name, then the + // attribute does not exist and we can't get its namespace ID and + // local name below, so we return early. + return NS_OK; + } + + // Hold a strong reference here so that the atom or nodeinfo doesn't go + // away during UnsetAttr. If it did UnsetAttr would be left with a + // dangling pointer as argument without knowing it. + nsAttrName tmp(*name); + + return UnsetAttr(name->NamespaceID(), name->LocalName(), true); +} + +nsresult +FragmentOrElement::GetAttributeNode(const nsAString& aName, + nsIDOMAttr** aReturn) +{ + NS_ENSURE_ARG_POINTER(aReturn); + *aReturn = nullptr; + + nsIDocument* document = OwnerDoc(); + if (document) { + document->WarnOnceAbout(nsIDocument::eGetAttributeNode); + } + + nsCOMPtr map; + nsresult rv = GetAttributes(getter_AddRefs(map)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr node; + rv = map->GetNamedItem(aName, getter_AddRefs(node)); + + if (NS_SUCCEEDED(rv) && node) { + rv = CallQueryInterface(node, aReturn); + } + + return rv; +} + +nsresult +FragmentOrElement::SetAttributeNode(nsIDOMAttr* aAttribute, + nsIDOMAttr** aReturn) +{ + NS_ENSURE_ARG_POINTER(aReturn); + NS_ENSURE_ARG_POINTER(aAttribute); + + *aReturn = nullptr; + + OwnerDoc()->WarnOnceAbout(nsIDocument::eSetAttributeNode); + + nsCOMPtr map; + nsresult rv = GetAttributes(getter_AddRefs(map)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr returnNode; + rv = map->SetNamedItem(aAttribute, getter_AddRefs(returnNode)); + NS_ENSURE_SUCCESS(rv, rv); + + if (returnNode) { + rv = CallQueryInterface(returnNode, aReturn); + } + + return rv; +} + +nsresult +FragmentOrElement::RemoveAttributeNode(nsIDOMAttr* aAttribute, + nsIDOMAttr** aReturn) +{ + NS_ENSURE_ARG_POINTER(aReturn); + NS_ENSURE_ARG_POINTER(aAttribute); + + *aReturn = nullptr; + + OwnerDoc()->WarnOnceAbout(nsIDocument::eRemoveAttributeNode); + + nsCOMPtr map; + nsresult rv = GetAttributes(getter_AddRefs(map)); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoString name; + + rv = aAttribute->GetName(name); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr node; + rv = map->RemoveNamedItem(name, getter_AddRefs(node)); + + if (NS_SUCCEEDED(rv) && node) { + rv = CallQueryInterface(node, aReturn); + } + } + + return rv; +} + +nsresult +FragmentOrElement::GetElementsByTagName(const nsAString& aTagname, + nsIDOMNodeList** aReturn) +{ + nsContentList *list = NS_GetContentList(this, kNameSpaceID_Unknown, + aTagname).get(); + + // transfer ref to aReturn + *aReturn = list; + return NS_OK; +} + +nsresult +FragmentOrElement::GetAttributeNS(const nsAString& aNamespaceURI, + const nsAString& aLocalName, + nsAString& aReturn) +{ + PRInt32 nsid = + nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI); + + if (nsid == kNameSpaceID_Unknown) { + // Unknown namespace means no attribute. + SetDOMStringToNull(aReturn); + return NS_OK; + } + + nsCOMPtr name = do_GetAtom(aLocalName); + bool hasAttr = GetAttr(nsid, name, aReturn); + if (!hasAttr) { + SetDOMStringToNull(aReturn); + } + + return NS_OK; +} + +nsresult +FragmentOrElement::SetAttributeNS(const nsAString& aNamespaceURI, + const nsAString& aQualifiedName, + const nsAString& aValue) +{ + nsCOMPtr ni; + nsresult rv = + nsContentUtils::GetNodeInfoFromQName(aNamespaceURI, aQualifiedName, + mNodeInfo->NodeInfoManager(), + nsIDOMNode::ATTRIBUTE_NODE, + getter_AddRefs(ni)); + NS_ENSURE_SUCCESS(rv, rv); + + return SetAttr(ni->NamespaceID(), ni->NameAtom(), ni->GetPrefixAtom(), + aValue, true); +} + +nsresult +FragmentOrElement::RemoveAttributeNS(const nsAString& aNamespaceURI, + const nsAString& aLocalName) +{ + nsCOMPtr name = do_GetAtom(aLocalName); + PRInt32 nsid = + nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI); + + if (nsid == kNameSpaceID_Unknown) { + // If the namespace ID is unknown, it means there can't possibly be an + // existing attribute. We would need a known namespace ID to pass into + // UnsetAttr, so we return early if we don't have one. + return NS_OK; + } + + UnsetAttr(nsid, name, true); + + return NS_OK; +} + +nsresult +FragmentOrElement::GetAttributeNodeNS(const nsAString& aNamespaceURI, + const nsAString& aLocalName, + nsIDOMAttr** aReturn) +{ + NS_ENSURE_ARG_POINTER(aReturn); + *aReturn = nullptr; + + OwnerDoc()->WarnOnceAbout(nsIDocument::eGetAttributeNodeNS); + + return GetAttributeNodeNSInternal(aNamespaceURI, aLocalName, aReturn); +} + +nsresult +FragmentOrElement::GetAttributeNodeNSInternal(const nsAString& aNamespaceURI, + const nsAString& aLocalName, + nsIDOMAttr** aReturn) +{ + nsCOMPtr map; + nsresult rv = GetAttributes(getter_AddRefs(map)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr node; + rv = map->GetNamedItemNS(aNamespaceURI, aLocalName, getter_AddRefs(node)); + + if (NS_SUCCEEDED(rv) && node) { + rv = CallQueryInterface(node, aReturn); + } + + return rv; +} + +nsresult +FragmentOrElement::SetAttributeNodeNS(nsIDOMAttr* aNewAttr, + nsIDOMAttr** aReturn) +{ + NS_ENSURE_ARG_POINTER(aReturn); + NS_ENSURE_ARG_POINTER(aNewAttr); + *aReturn = nullptr; + + OwnerDoc()->WarnOnceAbout(nsIDocument::eSetAttributeNodeNS); + + nsCOMPtr map; + nsresult rv = GetAttributes(getter_AddRefs(map)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr returnNode; + rv = map->SetNamedItemNS(aNewAttr, getter_AddRefs(returnNode)); + NS_ENSURE_SUCCESS(rv, rv); + + if (returnNode) { + rv = CallQueryInterface(returnNode, aReturn); + } + + return rv; +} + +nsresult +FragmentOrElement::GetElementsByTagNameNS(const nsAString& aNamespaceURI, + const nsAString& aLocalName, + nsIDOMNodeList** aReturn) +{ + PRInt32 nameSpaceId = kNameSpaceID_Wildcard; + + if (!aNamespaceURI.EqualsLiteral("*")) { + nsresult rv = + nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI, + nameSpaceId); + NS_ENSURE_SUCCESS(rv, rv); + } + + NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!"); + + nsContentList *list = NS_GetContentList(this, nameSpaceId, aLocalName).get(); + + // transfer ref to aReturn + *aReturn = list; + return NS_OK; +} + +nsresult +FragmentOrElement::HasAttribute(const nsAString& aName, bool* aReturn) +{ + NS_ENSURE_ARG_POINTER(aReturn); + + const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName); + *aReturn = (name != nullptr); + + return NS_OK; +} + +nsresult +FragmentOrElement::HasAttributeNS(const nsAString& aNamespaceURI, + const nsAString& aLocalName, + bool* aReturn) +{ + NS_ENSURE_ARG_POINTER(aReturn); + + PRInt32 nsid = + nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI); + + if (nsid == kNameSpaceID_Unknown) { + // Unknown namespace means no attr... + + *aReturn = false; + + return NS_OK; + } + + nsCOMPtr name = do_GetAtom(aLocalName); + *aReturn = HasAttr(nsid, name); + + return NS_OK; +} + +static nsXBLBinding* +GetFirstBindingWithContent(nsBindingManager* aBmgr, nsIContent* aBoundElem) +{ + nsXBLBinding* binding = aBmgr->GetBinding(aBoundElem); + while (binding) { + if (binding->GetAnonymousContent()) { + return binding; + } + binding = binding->GetBaseBinding(); + } + + return nullptr; +} + +static nsresult +BindNodesInInsertPoints(nsXBLBinding* aBinding, nsIContent* aInsertParent, + nsIDocument* aDocument) +{ + NS_PRECONDITION(aBinding && aInsertParent, "Missing arguments"); + + nsresult rv; + // These should be refcounted or otherwise protectable. + nsInsertionPointList* inserts = + aBinding->GetExistingInsertionPointsFor(aInsertParent); + if (inserts) { + bool allowScripts = aBinding->AllowScripts(); +#ifdef MOZ_XUL + nsCOMPtr xulDoc = do_QueryInterface(aDocument); +#endif + PRUint32 i; + for (i = 0; i < inserts->Length(); ++i) { + nsCOMPtr insertRoot = + inserts->ElementAt(i)->GetDefaultContent(); + if (insertRoot) { + for (nsCOMPtr child = insertRoot->GetFirstChild(); + child; + child = child->GetNextSibling()) { + rv = child->BindToTree(aDocument, aInsertParent, + aBinding->GetBoundElement(), allowScripts); + NS_ENSURE_SUCCESS(rv, rv); + +#ifdef MOZ_XUL + if (xulDoc) { + xulDoc->AddSubtreeToDocument(child); + } +#endif + } + } + } + } + + return NS_OK; +} + +nsresult +FragmentOrElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + bool aCompileEventHandlers) +{ + NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!"); + NS_PRECONDITION(HasSameOwnerDoc(NODE_FROM(aParent, aDocument)), + "Must have the same owner document"); + NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(), + "aDocument must be current doc of aParent"); + NS_PRECONDITION(!GetCurrentDoc(), "Already have a document. Unbind first!"); + // Note that as we recurse into the kids, they'll have a non-null parent. So + // only assert if our parent is _changing_ while we have a parent. + NS_PRECONDITION(!GetParent() || aParent == GetParent(), + "Already have a parent. Unbind first!"); + NS_PRECONDITION(!GetBindingParent() || + aBindingParent == GetBindingParent() || + (!aBindingParent && aParent && + aParent->GetBindingParent() == GetBindingParent()), + "Already have a binding parent. Unbind first!"); + NS_PRECONDITION(!aParent || !aDocument || + !aParent->HasFlag(NODE_FORCE_XBL_BINDINGS), + "Parent in document but flagged as forcing XBL"); + NS_PRECONDITION(aBindingParent != this, + "Content must not be its own binding parent"); + NS_PRECONDITION(!IsRootOfNativeAnonymousSubtree() || + aBindingParent == aParent, + "Native anonymous content must have its parent as its " + "own binding parent"); + NS_PRECONDITION(aBindingParent || !aParent || + aBindingParent == aParent->GetBindingParent(), + "We should be passed the right binding parent"); + +#ifdef MOZ_XUL + // First set the binding parent + nsXULElement* xulElem = nsXULElement::FromContent(this); + if (xulElem) { + xulElem->SetXULBindingParent(aBindingParent); + } + else +#endif + { + if (aBindingParent) { + nsDOMSlots *slots = DOMSlots(); + + slots->mBindingParent = aBindingParent; // Weak, so no addref happens. + } + } + NS_ASSERTION(!aBindingParent || IsRootOfNativeAnonymousSubtree() || + !HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE) || + (aParent && aParent->IsInNativeAnonymousSubtree()), + "Trying to re-bind content from native anonymous subtree to " + "non-native anonymous parent!"); + if (aParent && aParent->IsInNativeAnonymousSubtree()) { + SetFlags(NODE_IS_IN_ANONYMOUS_SUBTREE); + } + + bool hadForceXBL = HasFlag(NODE_FORCE_XBL_BINDINGS); + + // Now set the parent and set the "Force attach xbl" flag if needed. + if (aParent) { + if (!GetParent()) { + NS_ADDREF(aParent); + } + mParent = aParent; + + if (aParent->HasFlag(NODE_FORCE_XBL_BINDINGS)) { + SetFlags(NODE_FORCE_XBL_BINDINGS); + } + } + else { + mParent = aDocument; + } + SetParentIsContent(aParent); + + // XXXbz sXBL/XBL2 issue! + + // Finally, set the document + if (aDocument) { + // Notify XBL- & nsIAnonymousContentCreator-generated + // anonymous content that the document is changing. + // XXXbz ordering issues here? Probably not, since ChangeDocumentFor is + // just pretty broken anyway.... Need to get it working. + // XXXbz XBL doesn't handle this (asserts), and we don't really want + // to be doing this during parsing anyway... sort this out. + // aDocument->BindingManager()->ChangeDocumentFor(this, nullptr, + // aDocument); + + // We no longer need to track the subtree pointer (and in fact we'll assert + // if we do this any later). + ClearSubtreeRootPointer(); + + // Being added to a document. + SetInDocument(); + + // Unset this flag since we now really are in a document. + UnsetFlags(NODE_FORCE_XBL_BINDINGS | + // And clear the lazy frame construction bits. + NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES | + // And the restyle bits + ELEMENT_ALL_RESTYLE_FLAGS); + } else { + // If we're not in the doc, update our subtree pointer. + SetSubtreeRootPointer(aParent->SubtreeRoot()); + } + + // If NODE_FORCE_XBL_BINDINGS was set we might have anonymous children + // that also need to be told that they are moving. + nsresult rv; + if (hadForceXBL) { + nsBindingManager* bmgr = OwnerDoc()->BindingManager(); + + // First check if we have a binding... + nsXBLBinding* contBinding = + GetFirstBindingWithContent(bmgr, this); + if (contBinding) { + nsCOMPtr anonRoot = contBinding->GetAnonymousContent(); + bool allowScripts = contBinding->AllowScripts(); + for (nsCOMPtr child = anonRoot->GetFirstChild(); + child; + child = child->GetNextSibling()) { + rv = child->BindToTree(aDocument, this, this, allowScripts); + NS_ENSURE_SUCCESS(rv, rv); + } + + // ...then check if we have content in insertion points that are + // direct children of the + rv = BindNodesInInsertPoints(contBinding, this, aDocument); + NS_ENSURE_SUCCESS(rv, rv); + } + + // ...and finally check if we're in a binding where we have content in + // insertion points. + if (aBindingParent) { + nsXBLBinding* binding = bmgr->GetBinding(aBindingParent); + if (binding) { + rv = BindNodesInInsertPoints(binding, this, aDocument); + NS_ENSURE_SUCCESS(rv, rv); + } + } + } + + UpdateEditableState(false); + + // Now recurse into our kids + for (nsIContent* child = GetFirstChild(); child; + child = child->GetNextSibling()) { + rv = child->BindToTree(aDocument, this, aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); + } + + nsNodeUtils::ParentChainChanged(this); + + if (aDocument && HasID() && !aBindingParent) { + aDocument->AddToIdTable(this, DoGetID()); + } + + if (MayHaveStyle() && !IsXUL()) { + // XXXbz if we already have a style attr parsed, this won't do + // anything... need to fix that. + // If MayHaveStyle() is true, we must be an nsStyledElement + static_cast(this)->ReparseStyleAttribute(false); + } + + if (aDocument) { + // If we're in a document now, let our mapped attrs know what their new + // sheet is. This is safe to run for non-mapped-attribute elements too; + // it'll just do a small bit of unnecessary work. But most elements in + // practice are mapped-attribute elements. + nsHTMLStyleSheet* sheet = aDocument->GetAttributeStyleSheet(); + if (sheet) { + mAttrsAndChildren.SetMappedAttrStyleSheet(sheet); + } + } + + // XXXbz script execution during binding can trigger some of these + // postcondition asserts.... But we do want that, since things will + // generally be quite broken when that happens. + NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document"); + NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent"); + NS_POSTCONDITION(aBindingParent == GetBindingParent(), + "Bound to wrong binding parent"); + + return NS_OK; +} + +class RemoveFromBindingManagerRunnable : public nsRunnable { +public: + RemoveFromBindingManagerRunnable(nsBindingManager* aManager, + Element* aElement, + nsIDocument* aDoc, + nsIContent* aBindingParent): + mManager(aManager), mElement(aElement), mDoc(aDoc), + mBindingParent(aBindingParent) + {} + + NS_IMETHOD Run() + { + mManager->RemovedFromDocumentInternal(mElement, mDoc, mBindingParent); + return NS_OK; + } + +private: + nsRefPtr mManager; + nsRefPtr mElement; + nsCOMPtr mDoc; + nsCOMPtr mBindingParent; +}; + +void +FragmentOrElement::UnbindFromTree(bool aDeep, bool aNullParent) +{ + NS_PRECONDITION(aDeep || (!GetCurrentDoc() && !GetBindingParent()), + "Shallow unbind won't clear document and binding parent on " + "kids!"); + + RemoveFromIdTable(); + + // Make sure to unbind this node before doing the kids + nsIDocument *document = + HasFlag(NODE_FORCE_XBL_BINDINGS) ? OwnerDoc() : GetCurrentDoc(); + + if (aNullParent) { + if (IsFullScreenAncestor()) { + // The element being removed is an ancestor of the full-screen element, + // exit full-screen state. + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, + "DOM", OwnerDoc(), + nsContentUtils::eDOM_PROPERTIES, + "RemovedFullScreenElement"); + // Fully exit full-screen. + nsIDocument::ExitFullScreen(false); + } + if (HasPointerLock()) { + nsIDocument::UnlockPointer(); + } + if (GetParent()) { + NS_RELEASE(mParent); + } else { + mParent = nullptr; + } + SetParentIsContent(false); + } + ClearInDocument(); + + // Begin keeping track of our subtree root. + SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot()); + + if (document) { + // Notify XBL- & nsIAnonymousContentCreator-generated + // anonymous content that the document is changing. + if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) { + nsContentUtils::AddScriptRunner( + new RemoveFromBindingManagerRunnable(document->BindingManager(), this, + document, GetBindingParent())); + } + + document->ClearBoxObjectFor(this); + } + + // Ensure that CSS transitions don't continue on an element at a + // different place in the tree (even if reinserted before next + // animation refresh). + // FIXME (Bug 522599): Need a test for this. + if (HasFlag(NODE_HAS_PROPERTIES)) { + DeleteProperty(nsGkAtoms::transitionsOfBeforeProperty); + DeleteProperty(nsGkAtoms::transitionsOfAfterProperty); + DeleteProperty(nsGkAtoms::transitionsProperty); + DeleteProperty(nsGkAtoms::animationsOfBeforeProperty); + DeleteProperty(nsGkAtoms::animationsOfAfterProperty); + DeleteProperty(nsGkAtoms::animationsProperty); + } + + // Unset this since that's what the old code effectively did. + UnsetFlags(NODE_FORCE_XBL_BINDINGS); + +#ifdef MOZ_XUL + nsXULElement* xulElem = nsXULElement::FromContent(this); + if (xulElem) { + xulElem->SetXULBindingParent(nullptr); + } + else +#endif + { + nsDOMSlots *slots = GetExistingDOMSlots(); + if (slots) { + slots->mBindingParent = nullptr; + } + } + + if (aDeep) { + // Do the kids. Don't call GetChildCount() here since that'll force + // XUL to generate template children, which there is no need for since + // all we're going to do is unbind them anyway. + PRUint32 i, n = mAttrsAndChildren.ChildCount(); + + for (i = 0; i < n; ++i) { + // Note that we pass false for aNullParent here, since we don't want + // the kids to forget us. We _do_ want them to forget their binding + // parent, though, since this only walks non-anonymous kids. + mAttrsAndChildren.ChildAt(i)->UnbindFromTree(true, false); + } + } + + nsNodeUtils::ParentChainChanged(this); +} + +already_AddRefed +FragmentOrElement::GetChildren(PRUint32 aFilter) +{ + nsRefPtr list = new nsSimpleContentList(this); + if (!list) { + return nullptr; + } + + nsIFrame *frame = GetPrimaryFrame(); + + // Append :before generated content. + if (frame) { + nsIFrame *beforeFrame = nsLayoutUtils::GetBeforeFrame(frame); + if (beforeFrame) { + list->AppendElement(beforeFrame->GetContent()); + } + } + + // If XBL is bound to this node then append XBL anonymous content including + // explict content altered by insertion point if we were requested for XBL + // anonymous content, otherwise append explicit content with respect to + // insertion point if any. + nsINodeList *childList = nullptr; + + nsIDocument* document = OwnerDoc(); + if (!(aFilter & eAllButXBL)) { + childList = document->BindingManager()->GetXBLChildNodesFor(this); + if (!childList) { + childList = GetChildNodesList(); + } + + } else { + childList = document->BindingManager()->GetContentListFor(this); + } + + if (childList) { + PRUint32 length = 0; + childList->GetLength(&length); + for (PRUint32 idx = 0; idx < length; idx++) { + nsIContent* child = childList->GetNodeAt(idx); + list->AppendElement(child); + } + } + + if (frame) { + // Append native anonymous content to the end. + nsIAnonymousContentCreator* creator = do_QueryFrame(frame); + if (creator) { + creator->AppendAnonymousContentTo(*list, aFilter); + } + + // Append :after generated content. + nsIFrame *afterFrame = nsLayoutUtils::GetAfterFrame(frame); + if (afterFrame) { + list->AppendElement(afterFrame->GetContent()); + } + } + + nsINodeList* returnList = nullptr; + list.forget(&returnList); + return returnList; +} + +static nsIContent* +FindNativeAnonymousSubtreeOwner(nsIContent* aContent) +{ + if (aContent->IsInNativeAnonymousSubtree()) { + bool isNativeAnon = false; + while (aContent && !isNativeAnon) { + isNativeAnon = aContent->IsRootOfNativeAnonymousSubtree(); + aContent = aContent->GetParent(); + } + } + return aContent; +} + +nsresult +nsIContent::PreHandleEvent(nsEventChainPreVisitor& aVisitor) +{ + //FIXME! Document how this event retargeting works, Bug 329124. + aVisitor.mCanHandle = true; + aVisitor.mMayHaveListenerManager = HasListenerManager(); + + // Don't propagate mouseover and mouseout events when mouse is moving + // inside native anonymous content. + bool isAnonForEvents = IsRootOfNativeAnonymousSubtree(); + if ((aVisitor.mEvent->message == NS_MOUSE_ENTER_SYNTH || + aVisitor.mEvent->message == NS_MOUSE_EXIT_SYNTH) && + // Check if we should stop event propagation when event has just been + // dispatched or when we're about to propagate from + // native anonymous subtree. + ((this == aVisitor.mEvent->originalTarget && + !IsInNativeAnonymousSubtree()) || isAnonForEvents)) { + nsCOMPtr relatedTarget = + do_QueryInterface(static_cast + (aVisitor.mEvent)->relatedTarget); + if (relatedTarget && + relatedTarget->OwnerDoc() == OwnerDoc()) { + + // If current target is anonymous for events or we know that related + // target is descendant of an element which is anonymous for events, + // we may want to stop event propagation. + // If this is the original target, aVisitor.mRelatedTargetIsInAnon + // must be updated. + if (isAnonForEvents || aVisitor.mRelatedTargetIsInAnon || + (aVisitor.mEvent->originalTarget == this && + (aVisitor.mRelatedTargetIsInAnon = + relatedTarget->IsInNativeAnonymousSubtree()))) { + nsIContent* anonOwner = FindNativeAnonymousSubtreeOwner(this); + if (anonOwner) { + nsIContent* anonOwnerRelated = + FindNativeAnonymousSubtreeOwner(relatedTarget); + if (anonOwnerRelated) { + // Note, anonOwnerRelated may still be inside some other + // native anonymous subtree. The case where anonOwner is still + // inside native anonymous subtree will be handled when event + // propagates up in the DOM tree. + while (anonOwner != anonOwnerRelated && + anonOwnerRelated->IsInNativeAnonymousSubtree()) { + anonOwnerRelated = FindNativeAnonymousSubtreeOwner(anonOwnerRelated); + } + if (anonOwner == anonOwnerRelated) { +#ifdef DEBUG_smaug + nsCOMPtr originalTarget = + do_QueryInterface(aVisitor.mEvent->originalTarget); + nsAutoString ot, ct, rt; + if (originalTarget) { + originalTarget->Tag()->ToString(ot); + } + Tag()->ToString(ct); + relatedTarget->Tag()->ToString(rt); + printf("Stopping %s propagation:" + "\n\toriginalTarget=%s \n\tcurrentTarget=%s %s" + "\n\trelatedTarget=%s %s \n%s", + (aVisitor.mEvent->message == NS_MOUSE_ENTER_SYNTH) + ? "mouseover" : "mouseout", + NS_ConvertUTF16toUTF8(ot).get(), + NS_ConvertUTF16toUTF8(ct).get(), + isAnonForEvents + ? "(is native anonymous)" + : (IsInNativeAnonymousSubtree() + ? "(is in native anonymous subtree)" : ""), + NS_ConvertUTF16toUTF8(rt).get(), + relatedTarget->IsInNativeAnonymousSubtree() + ? "(is in native anonymous subtree)" : "", + (originalTarget && relatedTarget->FindFirstNonNativeAnonymous() == + originalTarget->FindFirstNonNativeAnonymous()) + ? "" : "Wrong event propagation!?!\n"); +#endif + aVisitor.mParentTarget = nullptr; + // Event should not propagate to non-anon content. + aVisitor.mCanHandle = isAnonForEvents; + return NS_OK; + } + } + } + } + } + } + + nsIContent* parent = GetParent(); + // Event may need to be retargeted if this is the root of a native + // anonymous content subtree or event is dispatched somewhere inside XBL. + if (isAnonForEvents) { + // If a DOM event is explicitly dispatched using node.dispatchEvent(), then + // all the events are allowed even in the native anonymous content.. + NS_ASSERTION(aVisitor.mEvent->eventStructType != NS_MUTATION_EVENT || + aVisitor.mDOMEvent, + "Mutation event dispatched in native anonymous content!?!"); + aVisitor.mEventTargetAtParent = parent; + } else if (parent && aVisitor.mOriginalTargetIsInAnon) { + nsCOMPtr content(do_QueryInterface(aVisitor.mEvent->target)); + if (content && content->GetBindingParent() == parent) { + aVisitor.mEventTargetAtParent = parent; + } + } + + // check for an anonymous parent + // XXX XBL2/sXBL issue + if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) { + nsIContent* insertionParent = OwnerDoc()->BindingManager()-> + GetInsertionParent(this); + NS_ASSERTION(!(aVisitor.mEventTargetAtParent && insertionParent && + aVisitor.mEventTargetAtParent != insertionParent), + "Retargeting and having insertion parent!"); + if (insertionParent) { + parent = insertionParent; + } + } + + if (parent) { + aVisitor.mParentTarget = parent; + } else { + aVisitor.mParentTarget = GetCurrentDoc(); + } + return NS_OK; +} + +const nsAttrValue* +FragmentOrElement::DoGetClasses() const +{ + NS_NOTREACHED("Shouldn't ever be called"); + return nullptr; +} + +NS_IMETHODIMP +FragmentOrElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker) +{ + return NS_OK; +} + +nsICSSDeclaration* +FragmentOrElement::GetSMILOverrideStyle() +{ + FragmentOrElement::nsDOMSlots *slots = DOMSlots(); + + if (!slots->mSMILOverrideStyle) { + slots->mSMILOverrideStyle = new nsDOMCSSAttributeDeclaration(this, true); + } + + return slots->mSMILOverrideStyle; +} + +css::StyleRule* +FragmentOrElement::GetSMILOverrideStyleRule() +{ + FragmentOrElement::nsDOMSlots *slots = GetExistingDOMSlots(); + return slots ? slots->mSMILOverrideStyleRule.get() : nullptr; +} + +nsresult +FragmentOrElement::SetSMILOverrideStyleRule(css::StyleRule* aStyleRule, + bool aNotify) +{ + FragmentOrElement::nsDOMSlots *slots = DOMSlots(); + + slots->mSMILOverrideStyleRule = aStyleRule; + + if (aNotify) { + nsIDocument* doc = GetCurrentDoc(); + // Only need to request a restyle if we're in a document. (We might not + // be in a document, if we're clearing animation effects on a target node + // that's been detached since the previous animation sample.) + if (doc) { + nsCOMPtr shell = doc->GetShell(); + if (shell) { + shell->RestyleForAnimation(this, eRestyle_Self); + } + } + } + + return NS_OK; +} + +bool +FragmentOrElement::IsLabelable() const +{ + return false; +} + +css::StyleRule* +FragmentOrElement::GetInlineStyleRule() +{ + return nullptr; +} + +nsresult +FragmentOrElement::SetInlineStyleRule(css::StyleRule* aStyleRule, + const nsAString* aSerialized, + bool aNotify) +{ + NS_NOTYETIMPLEMENTED("FragmentOrElement::SetInlineStyleRule"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP_(bool) +FragmentOrElement::IsAttributeMapped(const nsIAtom* aAttribute) const +{ + return false; +} + +nsChangeHint +FragmentOrElement::GetAttributeChangeHint(const nsIAtom* aAttribute, + PRInt32 aModType) const +{ + return nsChangeHint(0); +} + +nsIAtom * +FragmentOrElement::GetClassAttributeName() const +{ + return nullptr; +} + +bool +FragmentOrElement::FindAttributeDependence(const nsIAtom* aAttribute, + const MappedAttributeEntry* const aMaps[], + PRUint32 aMapCount) +{ + for (PRUint32 mapindex = 0; mapindex < aMapCount; ++mapindex) { + for (const MappedAttributeEntry* map = aMaps[mapindex]; + map->attribute; ++map) { + if (aAttribute == *map->attribute) { + return true; + } + } + } + + return false; +} + +already_AddRefed +FragmentOrElement::GetExistingAttrNameFromQName(const nsAString& aStr) const +{ + const nsAttrName* name = InternalGetExistingAttrNameFromQName(aStr); + if (!name) { + return nullptr; + } + + nsINodeInfo* nodeInfo; + if (name->IsAtom()) { + nodeInfo = mNodeInfo->NodeInfoManager()-> + GetNodeInfo(name->Atom(), nullptr, kNameSpaceID_None, + nsIDOMNode::ATTRIBUTE_NODE).get(); + } + else { + NS_ADDREF(nodeInfo = name->NodeInfo()); + } + + return nodeInfo; +} + +bool +FragmentOrElement::IsLink(nsIURI** aURI) const +{ + *aURI = nullptr; + return false; +} + +// static +bool +FragmentOrElement::ShouldBlur(nsIContent *aContent) +{ + // Determine if the current element is focused, if it is not focused + // then we should not try to blur + nsIDocument *document = aContent->GetDocument(); + if (!document) + return false; + + nsCOMPtr window = do_QueryInterface(document->GetWindow()); + if (!window) + return false; + + nsCOMPtr focusedFrame; + nsIContent* contentToBlur = + nsFocusManager::GetFocusedDescendant(window, false, getter_AddRefs(focusedFrame)); + if (contentToBlur == aContent) + return true; + + // if focus on this element would get redirected, then check the redirected + // content as well when blurring. + return (contentToBlur && nsFocusManager::GetRedirectedFocus(aContent) == contentToBlur); +} + +nsIContent* +FragmentOrElement::GetBindingParent() const +{ + nsDOMSlots *slots = GetExistingDOMSlots(); + + if (slots) { + return slots->mBindingParent; + } + return nullptr; +} + +bool +FragmentOrElement::IsNodeOfType(PRUint32 aFlags) const +{ + return !(aFlags & ~eCONTENT); +} + +nsresult +FragmentOrElement::InsertChildAt(nsIContent* aKid, + PRUint32 aIndex, + bool aNotify) +{ + NS_PRECONDITION(aKid, "null ptr"); + + return doInsertChildAt(aKid, aIndex, aNotify, mAttrsAndChildren); +} + +void +FragmentOrElement::RemoveChildAt(PRUint32 aIndex, bool aNotify) +{ + nsCOMPtr oldKid = mAttrsAndChildren.GetSafeChildAt(aIndex); + NS_ASSERTION(oldKid == GetChildAt(aIndex), "Unexpected child in RemoveChildAt"); + + if (oldKid) { + doRemoveChildAt(aIndex, aNotify, oldKid, mAttrsAndChildren); + } +} + +NS_IMETHODIMP +FragmentOrElement::GetTextContent(nsAString &aTextContent) +{ + nsContentUtils::GetNodeTextContent(this, true, aTextContent); + return NS_OK; +} + +NS_IMETHODIMP +FragmentOrElement::SetTextContent(const nsAString& aTextContent) +{ + return nsContentUtils::SetNodeTextContent(this, aTextContent, false); +} + +/* static */ +nsresult +FragmentOrElement::DispatchEvent(nsPresContext* aPresContext, + nsEvent* aEvent, + nsIContent* aTarget, + bool aFullDispatch, + nsEventStatus* aStatus) +{ + NS_PRECONDITION(aTarget, "Must have target"); + NS_PRECONDITION(aEvent, "Must have source event"); + NS_PRECONDITION(aStatus, "Null out param?"); + + if (!aPresContext) { + return NS_OK; + } + + nsCOMPtr shell = aPresContext->GetPresShell(); + if (!shell) { + return NS_OK; + } + + if (aFullDispatch) { + return shell->HandleEventWithTarget(aEvent, nullptr, aTarget, aStatus); + } + + return shell->HandleDOMEventWithTarget(aTarget, aEvent, aStatus); +} + +/* static */ +nsresult +FragmentOrElement::DispatchClickEvent(nsPresContext* aPresContext, + nsInputEvent* aSourceEvent, + nsIContent* aTarget, + bool aFullDispatch, + PRUint32 aFlags, + nsEventStatus* aStatus) +{ + NS_PRECONDITION(aTarget, "Must have target"); + NS_PRECONDITION(aSourceEvent, "Must have source event"); + NS_PRECONDITION(aStatus, "Null out param?"); + + nsMouseEvent event(NS_IS_TRUSTED_EVENT(aSourceEvent), NS_MOUSE_CLICK, + aSourceEvent->widget, nsMouseEvent::eReal); + event.refPoint = aSourceEvent->refPoint; + PRUint32 clickCount = 1; + float pressure = 0; + PRUint16 inputSource = 0; + if (aSourceEvent->eventStructType == NS_MOUSE_EVENT) { + clickCount = static_cast(aSourceEvent)->clickCount; + pressure = static_cast(aSourceEvent)->pressure; + inputSource = static_cast(aSourceEvent)->inputSource; + } else if (aSourceEvent->eventStructType == NS_KEY_EVENT) { + inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD; + } + event.pressure = pressure; + event.clickCount = clickCount; + event.inputSource = inputSource; + event.modifiers = aSourceEvent->modifiers; + event.flags |= aFlags; // Be careful not to overwrite existing flags! + + return DispatchEvent(aPresContext, &event, aTarget, aFullDispatch, aStatus); +} + +nsIFrame* +FragmentOrElement::GetPrimaryFrame(mozFlushType aType) +{ + nsIDocument* doc = GetCurrentDoc(); + if (!doc) { + return nullptr; + } + + // Cause a flush, so we get up-to-date frame + // information + doc->FlushPendingNotifications(aType); + + return GetPrimaryFrame(); +} + +void +FragmentOrElement::DestroyContent() +{ + nsIDocument *document = OwnerDoc(); + document->BindingManager()->RemovedFromDocument(this, document); + document->ClearBoxObjectFor(this); + + // XXX We really should let cycle collection do this, but that currently still + // leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684). + nsContentUtils::ReleaseWrapper(this, this); + + PRUint32 i, count = mAttrsAndChildren.ChildCount(); + for (i = 0; i < count; ++i) { + // The child can remove itself from the parent in BindToTree. + mAttrsAndChildren.ChildAt(i)->DestroyContent(); + } +} + +void +FragmentOrElement::SaveSubtreeState() +{ + PRUint32 i, count = mAttrsAndChildren.ChildCount(); + for (i = 0; i < count; ++i) { + mAttrsAndChildren.ChildAt(i)->SaveSubtreeState(); + } +} + +//---------------------------------------------------------------------- + +// Generic DOMNode implementations + +void +FragmentOrElement::FireNodeInserted(nsIDocument* aDoc, + nsINode* aParent, + nsTArray >& aNodes) +{ + PRUint32 count = aNodes.Length(); + for (PRUint32 i = 0; i < count; ++i) { + nsIContent* childContent = aNodes[i]; + + if (nsContentUtils::HasMutationListeners(childContent, + NS_EVENT_BITS_MUTATION_NODEINSERTED, aParent)) { + nsMutationEvent mutation(true, NS_MUTATION_NODEINSERTED); + mutation.mRelatedNode = do_QueryInterface(aParent); + + mozAutoSubtreeModified subtree(aDoc, aParent); + (new nsAsyncDOMEvent(childContent, mutation))->RunDOMEventWhenSafe(); + } + } +} + +//---------------------------------------------------------------------- + +// nsISupports implementation + +NS_IMPL_CYCLE_COLLECTION_CLASS(FragmentOrElement) + +#define SUBTREE_UNBINDINGS_PER_RUNNABLE 500 + +class ContentUnbinder : public nsRunnable +{ +public: + ContentUnbinder() + { + nsLayoutStatics::AddRef(); + mLast = this; + } + + ~ContentUnbinder() + { + Run(); + nsLayoutStatics::Release(); + } + + void UnbindSubtree(nsIContent* aNode) + { + if (aNode->NodeType() != nsIDOMNode::ELEMENT_NODE && + aNode->NodeType() != nsIDOMNode::DOCUMENT_FRAGMENT_NODE) { + return; + } + FragmentOrElement* container = static_cast(aNode); + PRUint32 childCount = container->mAttrsAndChildren.ChildCount(); + if (childCount) { + while (childCount-- > 0) { + // Hold a strong ref to the node when we remove it, because we may be + // the last reference to it. We need to call TakeChildAt() and + // update mFirstChild before calling UnbindFromTree, since this last + // can notify various observers and they should really see consistent + // tree state. + nsCOMPtr child = + container->mAttrsAndChildren.TakeChildAt(childCount); + if (childCount == 0) { + container->mFirstChild = nullptr; + } + UnbindSubtree(child); + child->UnbindFromTree(); + } + } + } + + NS_IMETHOD Run() + { + nsAutoScriptBlocker scriptBlocker; + PRUint32 len = mSubtreeRoots.Length(); + if (len) { + PRTime start = PR_Now(); + for (PRUint32 i = 0; i < len; ++i) { + UnbindSubtree(mSubtreeRoots[i]); + } + mSubtreeRoots.Clear(); + Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_CONTENT_UNBIND, + PRUint32(PR_Now() - start) / PR_USEC_PER_MSEC); + } + if (this == sContentUnbinder) { + sContentUnbinder = nullptr; + if (mNext) { + nsRefPtr next; + next.swap(mNext); + sContentUnbinder = next; + next->mLast = mLast; + mLast = nullptr; + NS_DispatchToMainThread(next); + } + } + return NS_OK; + } + + static void UnbindAll() + { + nsRefPtr ub = sContentUnbinder; + sContentUnbinder = nullptr; + while (ub) { + ub->Run(); + ub = ub->mNext; + } + } + + static void Append(nsIContent* aSubtreeRoot) + { + if (!sContentUnbinder) { + sContentUnbinder = new ContentUnbinder(); + nsCOMPtr e = sContentUnbinder; + NS_DispatchToMainThread(e); + } + + if (sContentUnbinder->mLast->mSubtreeRoots.Length() >= + SUBTREE_UNBINDINGS_PER_RUNNABLE) { + sContentUnbinder->mLast->mNext = new ContentUnbinder(); + sContentUnbinder->mLast = sContentUnbinder->mLast->mNext; + } + sContentUnbinder->mLast->mSubtreeRoots.AppendElement(aSubtreeRoot); + } + +private: + nsAutoTArray, + SUBTREE_UNBINDINGS_PER_RUNNABLE> mSubtreeRoots; + nsRefPtr mNext; + ContentUnbinder* mLast; + static ContentUnbinder* sContentUnbinder; +}; + +ContentUnbinder* ContentUnbinder::sContentUnbinder = nullptr; + +void +FragmentOrElement::ClearContentUnbinder() +{ + ContentUnbinder::UnbindAll(); +} + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FragmentOrElement) + nsINode::Unlink(tmp); + + if (tmp->HasProperties()) { + if (tmp->IsHTML()) { + tmp->DeleteProperty(nsGkAtoms::microdataProperties); + tmp->DeleteProperty(nsGkAtoms::itemtype); + tmp->DeleteProperty(nsGkAtoms::itemref); + tmp->DeleteProperty(nsGkAtoms::itemprop); + } else if (tmp->IsXUL()) { + tmp->DeleteProperty(nsGkAtoms::contextmenulistener); + tmp->DeleteProperty(nsGkAtoms::popuplistener); + } + } + + // Unlink child content (and unbind our subtree). + if (tmp->UnoptimizableCCNode() || !nsCCUncollectableMarker::sGeneration) { + PRUint32 childCount = tmp->mAttrsAndChildren.ChildCount(); + if (childCount) { + // Don't allow script to run while we're unbinding everything. + nsAutoScriptBlocker scriptBlocker; + while (childCount-- > 0) { + // Hold a strong ref to the node when we remove it, because we may be + // the last reference to it. We need to call TakeChildAt() and + // update mFirstChild before calling UnbindFromTree, since this last + // can notify various observers and they should really see consistent + // tree state. + nsCOMPtr child = tmp->mAttrsAndChildren.TakeChildAt(childCount); + if (childCount == 0) { + tmp->mFirstChild = nullptr; + } + child->UnbindFromTree(); + } + } + } else if (!tmp->GetParent() && tmp->mAttrsAndChildren.ChildCount()) { + ContentUnbinder::Append(tmp); + } /* else { + The subtree root will end up to a ContentUnbinder, and that will + unbind the child nodes. + } */ + + // Unlink any DOM slots of interest. + { + nsDOMSlots *slots = tmp->GetExistingDOMSlots(); + if (slots) { + slots->Unlink(tmp->IsXUL()); + } + } + + { + nsIDocument *doc; + if (!tmp->GetNodeParent() && (doc = tmp->OwnerDoc())) { + doc->BindingManager()->RemovedFromDocument(tmp, doc); + } + } +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(FragmentOrElement) + nsINode::Trace(tmp, aCallback, aClosure); +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +void +FragmentOrElement::MarkUserData(void* aObject, nsIAtom* aKey, void* aChild, + void* aData) +{ + PRUint32* gen = static_cast(aData); + xpc_MarkInCCGeneration(static_cast(aChild), *gen); +} + +void +FragmentOrElement::MarkUserDataHandler(void* aObject, nsIAtom* aKey, + void* aChild, void* aData) +{ + xpc_TryUnmarkWrappedGrayObject(static_cast(aChild)); +} + +void +FragmentOrElement::MarkNodeChildren(nsINode* aNode) +{ + JSObject* o = GetJSObjectChild(aNode); + xpc_UnmarkGrayObject(o); + + nsEventListenerManager* elm = aNode->GetListenerManager(false); + if (elm) { + elm->UnmarkGrayJSListeners(); + } + + if (aNode->HasProperties()) { + nsIDocument* ownerDoc = aNode->OwnerDoc(); + ownerDoc->PropertyTable(DOM_USER_DATA)-> + Enumerate(aNode, FragmentOrElement::MarkUserData, + &nsCCUncollectableMarker::sGeneration); + ownerDoc->PropertyTable(DOM_USER_DATA_HANDLER)-> + Enumerate(aNode, FragmentOrElement::MarkUserDataHandler, + &nsCCUncollectableMarker::sGeneration); + } +} + +nsINode* +FindOptimizableSubtreeRoot(nsINode* aNode) +{ + nsINode* p; + while ((p = aNode->GetNodeParent())) { + if (aNode->UnoptimizableCCNode()) { + return nullptr; + } + aNode = p; + } + + if (aNode->UnoptimizableCCNode()) { + return nullptr; + } + return aNode; +} + +nsAutoTArray* gCCBlackMarkedNodes = nullptr; + +void +ClearBlackMarkedNodes() +{ + if (!gCCBlackMarkedNodes) { + return; + } + PRUint32 len = gCCBlackMarkedNodes->Length(); + for (PRUint32 i = 0; i < len; ++i) { + nsINode* n = gCCBlackMarkedNodes->ElementAt(i); + n->SetCCMarkedRoot(false); + n->SetInCCBlackTree(false); + } + delete gCCBlackMarkedNodes; + gCCBlackMarkedNodes = nullptr; +} + +// static +bool +FragmentOrElement::CanSkipInCC(nsINode* aNode) +{ + // Don't try to optimize anything during shutdown. + if (nsCCUncollectableMarker::sGeneration == 0) { + return false; + } + + nsIDocument* currentDoc = aNode->GetCurrentDoc(); + if (currentDoc && + nsCCUncollectableMarker::InGeneration(currentDoc->GetMarkedCCGeneration())) { + return !NeedsScriptTraverse(aNode); + } + + // Bail out early if aNode is somewhere in anonymous content, + // or otherwise unusual. + if (aNode->UnoptimizableCCNode()) { + return false; + } + + nsINode* root = + currentDoc ? static_cast(currentDoc) : + FindOptimizableSubtreeRoot(aNode); + if (!root) { + return false; + } + + // Subtree has been traversed already. + if (root->CCMarkedRoot()) { + return root->InCCBlackTree() && !NeedsScriptTraverse(aNode); + } + + if (!gCCBlackMarkedNodes) { + gCCBlackMarkedNodes = new nsAutoTArray; + } + + // nodesToUnpurple contains nodes which will be removed + // from the purple buffer if the DOM tree is black. + nsAutoTArray nodesToUnpurple; + // grayNodes need script traverse, so they aren't removed from + // the purple buffer, but are marked to be in black subtree so that + // traverse is faster. + nsAutoTArray grayNodes; + + bool foundBlack = root->IsBlack(); + if (root != currentDoc) { + currentDoc = nullptr; + if (NeedsScriptTraverse(root)) { + grayNodes.AppendElement(root); + } else if (static_cast(root)->IsPurple()) { + nodesToUnpurple.AppendElement(static_cast(root)); + } + } + + // Traverse the subtree and check if we could know without CC + // that it is black. + // Note, this traverse is non-virtual and inline, so it should be a lot faster + // than CC's generic traverse. + for (nsIContent* node = root->GetFirstChild(); node; + node = node->GetNextNode(root)) { + foundBlack = foundBlack || node->IsBlack(); + if (foundBlack && currentDoc) { + // If we can mark the whole document black, no need to optimize + // so much, since when the next purple node in the document will be + // handled, it is fast to check that currentDoc is in CCGeneration. + break; + } + if (NeedsScriptTraverse(node)) { + // Gray nodes need real CC traverse. + grayNodes.AppendElement(node); + } else if (node->IsPurple()) { + nodesToUnpurple.AppendElement(node); + } + } + + root->SetCCMarkedRoot(true); + root->SetInCCBlackTree(foundBlack); + gCCBlackMarkedNodes->AppendElement(root); + + if (!foundBlack) { + return false; + } + + if (currentDoc) { + // Special case documents. If we know the document is black, + // we can mark the document to be in CCGeneration. + currentDoc-> + MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration); + } else { + for (PRUint32 i = 0; i < grayNodes.Length(); ++i) { + nsINode* node = grayNodes[i]; + node->SetInCCBlackTree(true); + } + gCCBlackMarkedNodes->AppendElements(grayNodes); + } + + // Subtree is black, we can remove non-gray purple nodes from + // purple buffer. + for (PRUint32 i = 0; i < nodesToUnpurple.Length(); ++i) { + nsIContent* purple = nodesToUnpurple[i]; + // Can't remove currently handled purple node. + if (purple != aNode) { + purple->RemovePurple(); + } + } + return !NeedsScriptTraverse(aNode); +} + +nsAutoTArray* gPurpleRoots = nullptr; +nsAutoTArray* gNodesToUnbind = nullptr; + +void ClearCycleCollectorCleanupData() +{ + if (gPurpleRoots) { + PRUint32 len = gPurpleRoots->Length(); + for (PRUint32 i = 0; i < len; ++i) { + nsINode* n = gPurpleRoots->ElementAt(i); + n->SetIsPurpleRoot(false); + } + delete gPurpleRoots; + gPurpleRoots = nullptr; + } + if (gNodesToUnbind) { + PRUint32 len = gNodesToUnbind->Length(); + for (PRUint32 i = 0; i < len; ++i) { + nsIContent* c = gNodesToUnbind->ElementAt(i); + c->SetIsPurpleRoot(false); + ContentUnbinder::Append(c); + } + delete gNodesToUnbind; + gNodesToUnbind = nullptr; + } +} + +static bool +ShouldClearPurple(nsIContent* aContent) +{ + if (aContent && aContent->IsPurple()) { + return true; + } + + JSObject* o = GetJSObjectChild(aContent); + if (o && xpc_IsGrayGCThing(o)) { + return true; + } + + if (aContent->HasListenerManager()) { + return true; + } + + return aContent->HasProperties(); +} + +// If aNode is not optimizable, but is an element +// with a frame in a document which has currently active presshell, +// we can act as if it was optimizable. When the primary frame dies, aNode +// will end up to the purple buffer because of the refcount change. +bool +NodeHasActiveFrame(nsIDocument* aCurrentDoc, nsINode* aNode) +{ + return aCurrentDoc->GetShell() && aNode->IsElement() && + aNode->AsElement()->GetPrimaryFrame(); +} + +bool +OwnedByBindingManager(nsIDocument* aCurrentDoc, nsINode* aNode) +{ + return aNode->IsElement() && + aCurrentDoc->BindingManager()->GetBinding(aNode->AsElement()); +} + +// CanSkip checks if aNode is black, and if it is, returns +// true. If aNode is in a black DOM tree, CanSkip may also remove other objects +// from purple buffer and unmark event listeners and user data. +// If the root of the DOM tree is a document, less optimizations are done +// since checking the blackness of the current document is usually fast and we +// don't want slow down such common cases. +bool +FragmentOrElement::CanSkip(nsINode* aNode, bool aRemovingAllowed) +{ + // Don't try to optimize anything during shutdown. + if (nsCCUncollectableMarker::sGeneration == 0) { + return false; + } + + bool unoptimizable = aNode->UnoptimizableCCNode(); + nsIDocument* currentDoc = aNode->GetCurrentDoc(); + if (currentDoc && + nsCCUncollectableMarker::InGeneration(currentDoc->GetMarkedCCGeneration()) && + (!unoptimizable || NodeHasActiveFrame(currentDoc, aNode) || + OwnedByBindingManager(currentDoc, aNode))) { + MarkNodeChildren(aNode); + return true; + } + + if (unoptimizable) { + return false; + } + + nsINode* root = currentDoc ? static_cast(currentDoc) : + FindOptimizableSubtreeRoot(aNode); + if (!root) { + return false; + } + + // Subtree has been traversed already, and aNode has + // been handled in a way that doesn't require revisiting it. + if (root->IsPurpleRoot()) { + return false; + } + + // nodesToClear contains nodes which are either purple or + // gray. + nsAutoTArray nodesToClear; + + bool foundBlack = root->IsBlack(); + bool domOnlyCycle = false; + if (root != currentDoc) { + currentDoc = nullptr; + if (!foundBlack) { + domOnlyCycle = static_cast(root)->OwnedOnlyByTheDOMTree(); + } + if (ShouldClearPurple(static_cast(root))) { + nodesToClear.AppendElement(static_cast(root)); + } + } + + // Traverse the subtree and check if we could know without CC + // that it is black. + // Note, this traverse is non-virtual and inline, so it should be a lot faster + // than CC's generic traverse. + for (nsIContent* node = root->GetFirstChild(); node; + node = node->GetNextNode(root)) { + foundBlack = foundBlack || node->IsBlack(); + if (foundBlack) { + domOnlyCycle = false; + if (currentDoc) { + // If we can mark the whole document black, no need to optimize + // so much, since when the next purple node in the document will be + // handled, it is fast to check that the currentDoc is in CCGeneration. + break; + } + // No need to put stuff to the nodesToClear array, if we can clear it + // already here. + if (node->IsPurple() && (node != aNode || aRemovingAllowed)) { + node->RemovePurple(); + } + MarkNodeChildren(node); + } else { + domOnlyCycle = domOnlyCycle && node->OwnedOnlyByTheDOMTree(); + if (ShouldClearPurple(node)) { + // Collect interesting nodes which we can clear if we find that + // they are kept alive in a black tree or are in a DOM-only cycle. + nodesToClear.AppendElement(node); + } + } + } + + if (!currentDoc || !foundBlack) { + root->SetIsPurpleRoot(true); + if (domOnlyCycle) { + if (!gNodesToUnbind) { + gNodesToUnbind = new nsAutoTArray(); + } + gNodesToUnbind->AppendElement(static_cast(root)); + for (PRUint32 i = 0; i < nodesToClear.Length(); ++i) { + nsIContent* n = nodesToClear[i]; + if ((n != aNode || aRemovingAllowed) && n->IsPurple()) { + n->RemovePurple(); + } + } + return true; + } else { + if (!gPurpleRoots) { + gPurpleRoots = new nsAutoTArray(); + } + gPurpleRoots->AppendElement(root); + } + } + + if (!foundBlack) { + return false; + } + + if (currentDoc) { + // Special case documents. If we know the document is black, + // we can mark the document to be in CCGeneration. + currentDoc-> + MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration); + MarkNodeChildren(currentDoc); + } + + // Subtree is black, so we can remove purple nodes from + // purple buffer and mark stuff that to be certainly alive. + for (PRUint32 i = 0; i < nodesToClear.Length(); ++i) { + nsIContent* n = nodesToClear[i]; + MarkNodeChildren(n); + // Can't remove currently handled purple node, + // unless aRemovingAllowed is true. + if ((n != aNode || aRemovingAllowed) && n->IsPurple()) { + n->RemovePurple(); + } + } + return true; +} + +bool +FragmentOrElement::CanSkipThis(nsINode* aNode) +{ + if (nsCCUncollectableMarker::sGeneration == 0) { + return false; + } + if (aNode->IsBlack()) { + return true; + } + nsIDocument* c = aNode->GetCurrentDoc(); + return + ((c && nsCCUncollectableMarker::InGeneration(c->GetMarkedCCGeneration())) || + aNode->InCCBlackTree()) && !NeedsScriptTraverse(aNode); +} + +void +FragmentOrElement::InitCCCallbacks() +{ + nsCycleCollector_setForgetSkippableCallback(ClearCycleCollectorCleanupData); + nsCycleCollector_setBeforeUnlinkCallback(ClearBlackMarkedNodes); +} + +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(FragmentOrElement) + return FragmentOrElement::CanSkip(tmp, aRemovingAllowed); +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END + +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(FragmentOrElement) + return FragmentOrElement::CanSkipInCC(tmp); +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END + +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(FragmentOrElement) + return FragmentOrElement::CanSkipThis(tmp); +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END + +static const char* kNSURIs[] = { + " ([none])", + " (xmlns)", + " (xml)", + " (xhtml)", + " (XLink)", + " (XSLT)", + " (XBL)", + " (MathML)", + " (RDF)", + " (XUL)", + " (SVG)", + " (XML Events)" +}; + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(FragmentOrElement) + if (NS_UNLIKELY(cb.WantDebugInfo())) { + char name[512]; + PRUint32 nsid = tmp->GetNameSpaceID(); + nsAtomCString localName(tmp->NodeInfo()->NameAtom()); + nsCAutoString uri; + if (tmp->OwnerDoc()->GetDocumentURI()) { + tmp->OwnerDoc()->GetDocumentURI()->GetSpec(uri); + } + + nsAutoString id; + nsIAtom* idAtom = tmp->GetID(); + if (idAtom) { + id.AppendLiteral(" id='"); + id.Append(nsDependentAtomString(idAtom)); + id.AppendLiteral("'"); + } + + nsAutoString classes; + const nsAttrValue* classAttrValue = tmp->GetClasses(); + if (classAttrValue) { + classes.AppendLiteral(" class='"); + nsAutoString classString; + classAttrValue->ToString(classString); + classString.ReplaceChar(PRUnichar('\n'), PRUnichar(' ')); + classes.Append(classString); + classes.AppendLiteral("'"); + } + + const char* nsuri = nsid < ArrayLength(kNSURIs) ? kNSURIs[nsid] : ""; + PR_snprintf(name, sizeof(name), "FragmentOrElement%s %s%s%s %s", + nsuri, + localName.get(), + NS_ConvertUTF16toUTF8(id).get(), + NS_ConvertUTF16toUTF8(classes).get(), + uri.get()); + cb.DescribeRefCountedNode(tmp->mRefCnt.get(), sizeof(FragmentOrElement), + name); + } + else { + NS_IMPL_CYCLE_COLLECTION_DESCRIBE(FragmentOrElement, tmp->mRefCnt.get()) + } + + // Always need to traverse script objects, so do that before we check + // if we're uncollectable. + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS + + if (!nsINode::Traverse(tmp, cb)) { + return NS_SUCCESS_INTERRUPTED_TRAVERSE; + } + + tmp->OwnerDoc()->BindingManager()->Traverse(tmp, cb); + + if (tmp->HasProperties()) { + if (tmp->IsHTML()) { + nsISupports* property = static_cast + (tmp->GetProperty(nsGkAtoms::microdataProperties)); + cb.NoteXPCOMChild(property); + property = static_cast(tmp->GetProperty(nsGkAtoms::itemref)); + cb.NoteXPCOMChild(property); + property = static_cast(tmp->GetProperty(nsGkAtoms::itemprop)); + cb.NoteXPCOMChild(property); + property = static_cast(tmp->GetProperty(nsGkAtoms::itemtype)); + cb.NoteXPCOMChild(property); + } else if (tmp->IsXUL()) { + nsISupports* property = static_cast + (tmp->GetProperty(nsGkAtoms::contextmenulistener)); + cb.NoteXPCOMChild(property); + property = static_cast + (tmp->GetProperty(nsGkAtoms::popuplistener)); + cb.NoteXPCOMChild(property); + } + } + + // Traverse attribute names and child content. + { + PRUint32 i; + PRUint32 attrs = tmp->mAttrsAndChildren.AttrCount(); + for (i = 0; i < attrs; i++) { + const nsAttrName* name = tmp->mAttrsAndChildren.AttrNameAt(i); + if (!name->IsAtom()) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, + "mAttrsAndChildren[i]->NodeInfo()"); + cb.NoteXPCOMChild(name->NodeInfo()); + } + } + + PRUint32 kids = tmp->mAttrsAndChildren.ChildCount(); + for (i = 0; i < kids; i++) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mAttrsAndChildren[i]"); + cb.NoteXPCOMChild(tmp->mAttrsAndChildren.GetSafeChildAt(i)); + } + } + + // Traverse any DOM slots of interest. + { + nsDOMSlots *slots = tmp->GetExistingDOMSlots(); + if (slots) { + slots->Traverse(cb, tmp->IsXUL()); + } + } +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + + +NS_INTERFACE_MAP_BEGIN(FragmentOrElement) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(FragmentOrElement) + NS_INTERFACE_MAP_ENTRY(Element) + NS_INTERFACE_MAP_ENTRY(nsIContent) + NS_INTERFACE_MAP_ENTRY(nsINode) + NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget) + NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference, + new nsNodeSupportsWeakRefTearoff(this)) + NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMNodeSelector, + new nsNodeSelectorTearoff(this)) + NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMXPathNSResolver, + new nsNode3Tearoff(this)) + NS_INTERFACE_MAP_ENTRY_TEAROFF(nsITouchEventReceiver, + new nsTouchEventReceiverTearoff(this)) + NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIInlineEventHandlers, + new nsInlineEventHandlersTearoff(this)) + // nsNodeSH::PreCreate() depends on the identity pointer being the + // same as nsINode (which nsIContent inherits), so if you change the + // below line, make sure nsNodeSH::PreCreate() still does the right + // thing! + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(FragmentOrElement) +NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(FragmentOrElement, + nsNodeUtils::LastRelease(this)) + +nsresult +FragmentOrElement::PostQueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + return OwnerDoc()->BindingManager()->GetBindingImplementation(this, aIID, + aInstancePtr); +} + +//---------------------------------------------------------------------- +nsresult +FragmentOrElement::LeaveLink(nsPresContext* aPresContext) +{ + nsILinkHandler *handler = aPresContext->GetLinkHandler(); + if (!handler) { + return NS_OK; + } + + return handler->OnLeaveLink(); +} + +nsresult +FragmentOrElement::AddScriptEventListener(nsIAtom* aEventName, + const nsAString& aValue, + bool aDefer) +{ + nsIDocument *ownerDoc = OwnerDoc(); + if (ownerDoc->IsLoadedAsData()) { + // Make this a no-op rather than throwing an error to avoid + // the error causing problems setting the attribute. + return NS_OK; + } + + NS_PRECONDITION(aEventName, "Must have event name!"); + bool defer = true; + nsEventListenerManager* manager = GetEventListenerManagerForAttr(aEventName, + &defer); + if (!manager) { + return NS_OK; + } + + defer = defer && aDefer; // only defer if everyone agrees... + manager->AddScriptEventListener(aEventName, aValue, nsIProgrammingLanguage::JAVASCRIPT, + defer, !nsContentUtils::IsChromeDoc(ownerDoc)); + return NS_OK; +} + + +//---------------------------------------------------------------------- + +const nsAttrName* +FragmentOrElement::InternalGetExistingAttrNameFromQName(const nsAString& aStr) const +{ + return mAttrsAndChildren.GetExistingAttrNameFromQName(aStr); +} + +nsresult +FragmentOrElement::CopyInnerTo(FragmentOrElement* aDst) +{ + PRUint32 i, count = mAttrsAndChildren.AttrCount(); + for (i = 0; i < count; ++i) { + const nsAttrName* name = mAttrsAndChildren.AttrNameAt(i); + const nsAttrValue* value = mAttrsAndChildren.AttrAt(i); + nsAutoString valStr; + value->ToString(valStr); + nsresult rv = aDst->SetAttr(name->NamespaceID(), name->LocalName(), + name->GetPrefix(), valStr, false); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; +} + +bool +FragmentOrElement::MaybeCheckSameAttrVal(PRInt32 aNamespaceID, + nsIAtom* aName, + nsIAtom* aPrefix, + const nsAttrValueOrString& aValue, + bool aNotify, + nsAttrValue& aOldValue, + PRUint8* aModType, + bool* aHasListeners) +{ + bool modification = false; + *aHasListeners = aNotify && + nsContentUtils::HasMutationListeners(this, + NS_EVENT_BITS_MUTATION_ATTRMODIFIED, + this); + + // If we have no listeners and aNotify is false, we are almost certainly + // coming from the content sink and will almost certainly have no previous + // value. Even if we do, setting the value is cheap when we have no + // listeners and don't plan to notify. The check for aNotify here is an + // optimization, the check for *aHasListeners is a correctness issue. + if (*aHasListeners || aNotify) { + nsAttrInfo info(GetAttrInfo(aNamespaceID, aName)); + if (info.mValue) { + // Check whether the old value is the same as the new one. Note that we + // only need to actually _get_ the old value if we have listeners. + if (*aHasListeners) { + // Need to store the old value. + // + // If the current attribute value contains a pointer to some other data + // structure that gets updated in the process of setting the attribute + // we'll no longer have the old value of the attribute. Therefore, we + // should serialize the attribute value now to keep a snapshot. + // + // We have to serialize the value anyway in order to create the + // mutation event so there's no cost in doing it now. + aOldValue.SetToSerialized(*info.mValue); + } + bool valueMatches = aValue.EqualsAsStrings(*info.mValue); + if (valueMatches && aPrefix == info.mName->GetPrefix()) { + if (OwnerDoc()->MayHaveDOMMutationObservers()) { + // For backward compatibility, don't fire mutation events + // when setting an attribute to its old value. + *aHasListeners = false; + } else { + return true; + } + } + modification = true; + } + } + *aModType = modification ? + static_cast(nsIDOMMutationEvent::MODIFICATION) : + static_cast(nsIDOMMutationEvent::ADDITION); + return false; +} + +nsresult +FragmentOrElement::SetAttr(PRInt32 aNamespaceID, nsIAtom* aName, + nsIAtom* aPrefix, const nsAString& aValue, + bool aNotify) +{ + // Keep this in sync with SetParsedAttr below + + NS_ENSURE_ARG_POINTER(aName); + NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown, + "Don't call SetAttr with unknown namespace"); + + if (!mAttrsAndChildren.CanFitMoreAttrs()) { + return NS_ERROR_FAILURE; + } + + PRUint8 modType; + bool hasListeners; + nsAttrValueOrString value(aValue); + nsAttrValue oldValue; + + if (MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, value, aNotify, + oldValue, &modType, &hasListeners)) { + return NS_OK; + } + + nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify); + NS_ENSURE_SUCCESS(rv, rv); + + if (aNotify) { + nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType); + } + + // Hold a script blocker while calling ParseAttribute since that can call + // out to id-observers + nsAutoScriptBlocker scriptBlocker; + + nsAttrValue attrValue; + if (!ParseAttribute(aNamespaceID, aName, aValue, attrValue)) { + attrValue.SetTo(aValue); + } + + return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue, + attrValue, modType, hasListeners, aNotify, + kCallAfterSetAttr); +} + +nsresult +FragmentOrElement::SetParsedAttr(PRInt32 aNamespaceID, nsIAtom* aName, + nsIAtom* aPrefix, nsAttrValue& aParsedValue, + bool aNotify) +{ + // Keep this in sync with SetAttr above + + NS_ENSURE_ARG_POINTER(aName); + NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown, + "Don't call SetAttr with unknown namespace"); + + if (!mAttrsAndChildren.CanFitMoreAttrs()) { + return NS_ERROR_FAILURE; + } + + + PRUint8 modType; + bool hasListeners; + nsAttrValueOrString value(aParsedValue); + nsAttrValue oldValue; + + if (MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, value, aNotify, + oldValue, &modType, &hasListeners)) { + return NS_OK; + } + + nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify); + NS_ENSURE_SUCCESS(rv, rv); + + if (aNotify) { + nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType); + } + + return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue, + aParsedValue, modType, hasListeners, aNotify, + kCallAfterSetAttr); +} + +nsresult +FragmentOrElement::SetAttrAndNotify(PRInt32 aNamespaceID, + nsIAtom* aName, + nsIAtom* aPrefix, + const nsAttrValue& aOldValue, + nsAttrValue& aParsedValue, + PRUint8 aModType, + bool aFireMutation, + bool aNotify, + bool aCallAfterSetAttr) +{ + nsresult rv; + + nsIDocument* document = GetCurrentDoc(); + mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify); + + nsMutationGuard::DidMutate(); + + // Copy aParsedValue for later use since it will be lost when we call + // SetAndTakeMappedAttr below + nsAttrValue aValueForAfterSetAttr; + if (aCallAfterSetAttr) { + aValueForAfterSetAttr.SetTo(aParsedValue); + } + + if (aNamespaceID == kNameSpaceID_None) { + // XXXbz Perhaps we should push up the attribute mapping function + // stuff to FragmentOrElement? + if (!IsAttributeMapped(aName) || + !SetMappedAttribute(document, aName, aParsedValue, &rv)) { + rv = mAttrsAndChildren.SetAndTakeAttr(aName, aParsedValue); + } + } + else { + nsCOMPtr ni; + ni = mNodeInfo->NodeInfoManager()->GetNodeInfo(aName, aPrefix, + aNamespaceID, + nsIDOMNode::ATTRIBUTE_NODE); + NS_ENSURE_TRUE(ni, NS_ERROR_OUT_OF_MEMORY); + + rv = mAttrsAndChildren.SetAndTakeAttr(ni, aParsedValue); + } + NS_ENSURE_SUCCESS(rv, rv); + + if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) { + nsRefPtr binding = + OwnerDoc()->BindingManager()->GetBinding(this); + if (binding) { + binding->AttributeChanged(aName, aNamespaceID, false, aNotify); + } + } + + UpdateState(aNotify); + + if (aNotify) { + nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType); + } + + if (aNamespaceID == kNameSpaceID_XMLEvents && + aName == nsGkAtoms::event && mNodeInfo->GetDocument()) { + mNodeInfo->GetDocument()->AddXMLEventsContent(this); + } + if (aCallAfterSetAttr) { + rv = AfterSetAttr(aNamespaceID, aName, &aValueForAfterSetAttr, aNotify); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (aFireMutation) { + nsMutationEvent mutation(true, NS_MUTATION_ATTRMODIFIED); + + nsCOMPtr attrNode; + nsAutoString ns; + nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns); + GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName), + getter_AddRefs(attrNode)); + mutation.mRelatedNode = attrNode; + + mutation.mAttrName = aName; + nsAutoString newValue; + GetAttr(aNamespaceID, aName, newValue); + if (!newValue.IsEmpty()) { + mutation.mNewAttrValue = do_GetAtom(newValue); + } + if (!aOldValue.IsEmptyString()) { + mutation.mPrevAttrValue = aOldValue.GetAsAtom(); + } + mutation.mAttrChange = aModType; + + mozAutoSubtreeModified subtree(OwnerDoc(), this); + (new nsAsyncDOMEvent(this, mutation))->RunDOMEventWhenSafe(); + } + + return NS_OK; +} + +bool +FragmentOrElement::ParseAttribute(PRInt32 aNamespaceID, + nsIAtom* aAttribute, + const nsAString& aValue, + nsAttrValue& aResult) +{ + return false; +} + +bool +FragmentOrElement::SetMappedAttribute(nsIDocument* aDocument, + nsIAtom* aName, + nsAttrValue& aValue, + nsresult* aRetval) +{ + *aRetval = NS_OK; + return false; +} + +nsEventListenerManager* +FragmentOrElement::GetEventListenerManagerForAttr(nsIAtom* aAttrName, + bool* aDefer) +{ + *aDefer = true; + return GetListenerManager(true); +} + +FragmentOrElement::nsAttrInfo +FragmentOrElement::GetAttrInfo(PRInt32 aNamespaceID, nsIAtom* aName) const +{ + NS_ASSERTION(nullptr != aName, "must have attribute name"); + NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown, + "must have a real namespace ID!"); + + PRInt32 index = mAttrsAndChildren.IndexOfAttr(aName, aNamespaceID); + if (index >= 0) { + return nsAttrInfo(mAttrsAndChildren.AttrNameAt(index), + mAttrsAndChildren.AttrAt(index)); + } + + return nsAttrInfo(nullptr, nullptr); +} + + +bool +FragmentOrElement::GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, + nsAString& aResult) const +{ + NS_ASSERTION(nullptr != aName, "must have attribute name"); + NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, + "must have a real namespace ID!"); + + const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID); + if (!val) { + // Since we are returning a success code we'd better do + // something about the out parameters (someone may have + // given us a non-empty string). + aResult.Truncate(); + + return false; + } + + val->ToString(aResult); + + return true; +} + +bool +FragmentOrElement::HasAttr(PRInt32 aNameSpaceID, nsIAtom* aName) const +{ + NS_ASSERTION(nullptr != aName, "must have attribute name"); + NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, + "must have a real namespace ID!"); + + return mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID) >= 0; +} + +bool +FragmentOrElement::AttrValueIs(PRInt32 aNameSpaceID, + nsIAtom* aName, + const nsAString& aValue, + nsCaseTreatment aCaseSensitive) const +{ + NS_ASSERTION(aName, "Must have attr name"); + NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace"); + + const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID); + return val && val->Equals(aValue, aCaseSensitive); +} + +bool +FragmentOrElement::AttrValueIs(PRInt32 aNameSpaceID, + nsIAtom* aName, + nsIAtom* aValue, + nsCaseTreatment aCaseSensitive) const +{ + NS_ASSERTION(aName, "Must have attr name"); + NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace"); + NS_ASSERTION(aValue, "Null value atom"); + + const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID); + return val && val->Equals(aValue, aCaseSensitive); +} + +PRInt32 +FragmentOrElement::FindAttrValueIn(PRInt32 aNameSpaceID, + nsIAtom* aName, + AttrValuesArray* aValues, + nsCaseTreatment aCaseSensitive) const +{ + NS_ASSERTION(aName, "Must have attr name"); + NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace"); + NS_ASSERTION(aValues, "Null value array"); + + const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID); + if (val) { + for (PRInt32 i = 0; aValues[i]; ++i) { + if (val->Equals(*aValues[i], aCaseSensitive)) { + return i; + } + } + return ATTR_VALUE_NO_MATCH; + } + return ATTR_MISSING; +} + +nsresult +FragmentOrElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, + bool aNotify) +{ + NS_ASSERTION(nullptr != aName, "must have attribute name"); + + PRInt32 index = mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID); + if (index < 0) { + return NS_OK; + } + + nsresult rv = BeforeSetAttr(aNameSpaceID, aName, nullptr, aNotify); + NS_ENSURE_SUCCESS(rv, rv); + + nsIDocument *document = GetCurrentDoc(); + mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify); + + if (aNotify) { + nsNodeUtils::AttributeWillChange(this, aNameSpaceID, aName, + nsIDOMMutationEvent::REMOVAL); + } + + bool hasMutationListeners = aNotify && + nsContentUtils::HasMutationListeners(this, + NS_EVENT_BITS_MUTATION_ATTRMODIFIED, + this); + + // Grab the attr node if needed before we remove it from the attr map + nsCOMPtr attrNode; + if (hasMutationListeners) { + nsAutoString ns; + nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns); + GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName), + getter_AddRefs(attrNode)); + } + + // Clear binding to nsIDOMNamedNodeMap + nsDOMSlots *slots = GetExistingDOMSlots(); + if (slots && slots->mAttributeMap) { + slots->mAttributeMap->DropAttribute(aNameSpaceID, aName); + } + + // The id-handling code, and in the future possibly other code, need to + // react to unexpected attribute changes. + nsMutationGuard::DidMutate(); + + nsAttrValue oldValue; + rv = mAttrsAndChildren.RemoveAttrAt(index, oldValue); + NS_ENSURE_SUCCESS(rv, rv); + + if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) { + nsRefPtr binding = + OwnerDoc()->BindingManager()->GetBinding(this); + if (binding) { + binding->AttributeChanged(aName, aNameSpaceID, true, aNotify); + } + } + + UpdateState(aNotify); + + if (aNotify) { + nsNodeUtils::AttributeChanged(this, aNameSpaceID, aName, + nsIDOMMutationEvent::REMOVAL); + } + + rv = AfterSetAttr(aNameSpaceID, aName, nullptr, aNotify); + NS_ENSURE_SUCCESS(rv, rv); + + if (hasMutationListeners) { + nsCOMPtr node = do_QueryObject(this); + nsMutationEvent mutation(true, NS_MUTATION_ATTRMODIFIED); + + mutation.mRelatedNode = attrNode; + mutation.mAttrName = aName; + + nsAutoString value; + oldValue.ToString(value); + if (!value.IsEmpty()) + mutation.mPrevAttrValue = do_GetAtom(value); + mutation.mAttrChange = nsIDOMMutationEvent::REMOVAL; + + mozAutoSubtreeModified subtree(OwnerDoc(), this); + (new nsAsyncDOMEvent(this, mutation))->RunDOMEventWhenSafe(); + } + + return NS_OK; +} + +const nsAttrName* +FragmentOrElement::GetAttrNameAt(PRUint32 aIndex) const +{ + return mAttrsAndChildren.GetSafeAttrNameAt(aIndex); +} + +PRUint32 +FragmentOrElement::GetAttrCount() const +{ + return mAttrsAndChildren.AttrCount(); +} + +const nsTextFragment* +FragmentOrElement::GetText() +{ + return nullptr; +} + +PRUint32 +FragmentOrElement::TextLength() const +{ + // We can remove this assertion if it turns out to be useful to be able + // to depend on this returning 0 + NS_NOTREACHED("called FragmentOrElement::TextLength"); + + return 0; +} + +nsresult +FragmentOrElement::SetText(const PRUnichar* aBuffer, PRUint32 aLength, + bool aNotify) +{ + NS_ERROR("called FragmentOrElement::SetText"); + + return NS_ERROR_FAILURE; +} + +nsresult +FragmentOrElement::AppendText(const PRUnichar* aBuffer, PRUint32 aLength, + bool aNotify) +{ + NS_ERROR("called FragmentOrElement::AppendText"); + + return NS_ERROR_FAILURE; +} + +bool +FragmentOrElement::TextIsOnlyWhitespace() +{ + return false; +} + +void +FragmentOrElement::AppendTextTo(nsAString& aResult) +{ + // We can remove this assertion if it turns out to be useful to be able + // to depend on this appending nothing. + NS_NOTREACHED("called FragmentOrElement::TextLength"); +} + +#ifdef DEBUG +void +FragmentOrElement::ListAttributes(FILE* out) const +{ + PRUint32 index, count = mAttrsAndChildren.AttrCount(); + for (index = 0; index < count; index++) { + nsAutoString buffer; + + // name + mAttrsAndChildren.AttrNameAt(index)->GetQualifiedName(buffer); + + // value + buffer.AppendLiteral("=\""); + nsAutoString value; + mAttrsAndChildren.AttrAt(index)->ToString(value); + for (int i = value.Length(); i >= 0; --i) { + if (value[i] == PRUnichar('"')) + value.Insert(PRUnichar('\\'), PRUint32(i)); + } + buffer.Append(value); + buffer.AppendLiteral("\""); + + fputs(" ", out); + fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out); + } +} + +void +FragmentOrElement::List(FILE* out, PRInt32 aIndent, + const nsCString& aPrefix) const +{ + PRInt32 indent; + for (indent = aIndent; --indent >= 0; ) fputs(" ", out); + + fputs(aPrefix.get(), out); + + fputs(NS_LossyConvertUTF16toASCII(mNodeInfo->QualifiedName()).get(), out); + + fprintf(out, "@%p", (void *)this); + + ListAttributes(out); + + fprintf(out, " state=[%llx]", State().GetInternalValue()); + fprintf(out, " flags=[%08x]", static_cast(GetFlags())); + if (IsCommonAncestorForRangeInSelection()) { + nsRange::RangeHashTable* ranges = + static_cast(GetProperty(nsGkAtoms::range)); + fprintf(out, " ranges:%d", ranges ? ranges->Count() : 0); + } + fprintf(out, " primaryframe=%p", static_cast(GetPrimaryFrame())); + fprintf(out, " refcount=%d<", mRefCnt.get()); + + nsIContent* child = GetFirstChild(); + if (child) { + fputs("\n", out); + + for (; child; child = child->GetNextSibling()) { + child->List(out, aIndent + 1); + } + + for (indent = aIndent; --indent >= 0; ) fputs(" ", out); + } + + fputs(">\n", out); + + FragmentOrElement* nonConstThis = const_cast(this); + + // XXX sXBL/XBL2 issue! Owner or current document? + nsIDocument *document = OwnerDoc(); + + // Note: not listing nsIAnonymousContentCreator-created content... + + nsBindingManager* bindingManager = document->BindingManager(); + nsCOMPtr anonymousChildren; + bindingManager->GetAnonymousNodesFor(nonConstThis, + getter_AddRefs(anonymousChildren)); + + if (anonymousChildren) { + PRUint32 length; + anonymousChildren->GetLength(&length); + if (length > 0) { + for (indent = aIndent; --indent >= 0; ) fputs(" ", out); + fputs("anonymous-children<\n", out); + + for (PRUint32 i = 0; i < length; ++i) { + nsCOMPtr node; + anonymousChildren->Item(i, getter_AddRefs(node)); + nsCOMPtr child = do_QueryInterface(node); + child->List(out, aIndent + 1); + } + + for (indent = aIndent; --indent >= 0; ) fputs(" ", out); + fputs(">\n", out); + } + } + + if (bindingManager->HasContentListFor(nonConstThis)) { + nsCOMPtr contentList; + bindingManager->GetContentListFor(nonConstThis, + getter_AddRefs(contentList)); + + NS_ASSERTION(contentList != nullptr, "oops, binding manager lied"); + + PRUint32 length; + contentList->GetLength(&length); + if (length > 0) { + for (indent = aIndent; --indent >= 0; ) fputs(" ", out); + fputs("content-list<\n", out); + + for (PRUint32 i = 0; i < length; ++i) { + nsCOMPtr node; + contentList->Item(i, getter_AddRefs(node)); + nsCOMPtr child = do_QueryInterface(node); + child->List(out, aIndent + 1); + } + + for (indent = aIndent; --indent >= 0; ) fputs(" ", out); + fputs(">\n", out); + } + } +} + +void +FragmentOrElement::DumpContent(FILE* out, PRInt32 aIndent, + bool aDumpAll) const +{ + PRInt32 indent; + for (indent = aIndent; --indent >= 0; ) fputs(" ", out); + + const nsString& buf = mNodeInfo->QualifiedName(); + fputs("<", out); + fputs(NS_LossyConvertUTF16toASCII(buf).get(), out); + + if(aDumpAll) ListAttributes(out); + + fputs(">", out); + + if(aIndent) fputs("\n", out); + + for (nsIContent* child = GetFirstChild(); + child; + child = child->GetNextSibling()) { + PRInt32 indent = aIndent ? aIndent + 1 : 0; + child->DumpContent(out, indent, aDumpAll); + } + for (indent = aIndent; --indent >= 0; ) fputs(" ", out); + fputs("", out); + + if(aIndent) fputs("\n", out); +} +#endif + +PRUint32 +FragmentOrElement::GetChildCount() const +{ + return mAttrsAndChildren.ChildCount(); +} + +nsIContent * +FragmentOrElement::GetChildAt(PRUint32 aIndex) const +{ + return mAttrsAndChildren.GetSafeChildAt(aIndex); +} + +nsIContent * const * +FragmentOrElement::GetChildArray(PRUint32* aChildCount) const +{ + return mAttrsAndChildren.GetChildArray(aChildCount); +} + +PRInt32 +FragmentOrElement::IndexOf(nsINode* aPossibleChild) const +{ + return mAttrsAndChildren.IndexOfChild(aPossibleChild); +} + +nsINode::nsSlots* +FragmentOrElement::CreateSlots() +{ + return new nsDOMSlots(); +} + +bool +FragmentOrElement::CheckHandleEventForLinksPrecondition(nsEventChainVisitor& aVisitor, + nsIURI** aURI) const +{ + if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault || + (!NS_IS_TRUSTED_EVENT(aVisitor.mEvent) && + (aVisitor.mEvent->message != NS_MOUSE_CLICK) && + (aVisitor.mEvent->message != NS_KEY_PRESS) && + (aVisitor.mEvent->message != NS_UI_ACTIVATE)) || + !aVisitor.mPresContext || + (aVisitor.mEvent->flags & NS_EVENT_FLAG_PREVENT_MULTIPLE_ACTIONS)) { + return false; + } + + // Make sure we actually are a link + return IsLink(aURI); +} + +nsresult +FragmentOrElement::PreHandleEventForLinks(nsEventChainPreVisitor& aVisitor) +{ + // Optimisation: return early if this event doesn't interest us. + // IMPORTANT: this switch and the switch below it must be kept in sync! + switch (aVisitor.mEvent->message) { + case NS_MOUSE_ENTER_SYNTH: + case NS_FOCUS_CONTENT: + case NS_MOUSE_EXIT_SYNTH: + case NS_BLUR_CONTENT: + break; + default: + return NS_OK; + } + + // Make sure we meet the preconditions before continuing + nsCOMPtr absURI; + if (!CheckHandleEventForLinksPrecondition(aVisitor, getter_AddRefs(absURI))) { + return NS_OK; + } + + nsresult rv = NS_OK; + + // We do the status bar updates in PreHandleEvent so that the status bar gets + // updated even if the event is consumed before we have a chance to set it. + switch (aVisitor.mEvent->message) { + // Set the status bar similarly for mouseover and focus + case NS_MOUSE_ENTER_SYNTH: + aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; + // FALL THROUGH + case NS_FOCUS_CONTENT: + if (aVisitor.mEvent->eventStructType != NS_FOCUS_EVENT || + !static_cast(aVisitor.mEvent)->isRefocus) { + nsAutoString target; + GetLinkTarget(target); + nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target, + false, true, true); + // Make sure any ancestor links don't also TriggerLink + aVisitor.mEvent->flags |= NS_EVENT_FLAG_PREVENT_MULTIPLE_ACTIONS; + } + break; + + case NS_MOUSE_EXIT_SYNTH: + aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; + // FALL THROUGH + case NS_BLUR_CONTENT: + rv = LeaveLink(aVisitor.mPresContext); + if (NS_SUCCEEDED(rv)) { + aVisitor.mEvent->flags |= NS_EVENT_FLAG_PREVENT_MULTIPLE_ACTIONS; + } + break; + + default: + // switch not in sync with the optimization switch earlier in this function + NS_NOTREACHED("switch statements not in sync"); + return NS_ERROR_UNEXPECTED; + } + + return rv; +} + +nsresult +FragmentOrElement::PostHandleEventForLinks(nsEventChainPostVisitor& aVisitor) +{ + // Optimisation: return early if this event doesn't interest us. + // IMPORTANT: this switch and the switch below it must be kept in sync! + switch (aVisitor.mEvent->message) { + case NS_MOUSE_BUTTON_DOWN: + case NS_MOUSE_CLICK: + case NS_UI_ACTIVATE: + case NS_KEY_PRESS: + break; + default: + return NS_OK; + } + + // Make sure we meet the preconditions before continuing + nsCOMPtr absURI; + if (!CheckHandleEventForLinksPrecondition(aVisitor, getter_AddRefs(absURI))) { + return NS_OK; + } + + nsresult rv = NS_OK; + + switch (aVisitor.mEvent->message) { + case NS_MOUSE_BUTTON_DOWN: + { + if (aVisitor.mEvent->eventStructType == NS_MOUSE_EVENT && + static_cast(aVisitor.mEvent)->button == + nsMouseEvent::eLeftButton) { + // don't make the link grab the focus if there is no link handler + nsILinkHandler *handler = aVisitor.mPresContext->GetLinkHandler(); + nsIDocument *document = GetCurrentDoc(); + if (handler && document) { + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); + if (fm) { + aVisitor.mEvent->flags |= NS_EVENT_FLAG_PREVENT_MULTIPLE_ACTIONS; + nsCOMPtr elem = do_QueryInterface(this); + fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOUSE | + nsIFocusManager::FLAG_NOSCROLL); + } + + nsEventStateManager::SetActiveManager( + aVisitor.mPresContext->EventStateManager(), this); + } + } + } + break; + + case NS_MOUSE_CLICK: + if (NS_IS_MOUSE_LEFT_CLICK(aVisitor.mEvent)) { + nsInputEvent* inputEvent = static_cast(aVisitor.mEvent); + if (inputEvent->IsControl() || inputEvent->IsMeta() || + inputEvent->IsAlt() ||inputEvent->IsShift()) { + break; + } + + // The default action is simply to dispatch DOMActivate + nsCOMPtr shell = aVisitor.mPresContext->GetPresShell(); + if (shell) { + // single-click + nsEventStatus status = nsEventStatus_eIgnore; + nsUIEvent actEvent(NS_IS_TRUSTED_EVENT(aVisitor.mEvent), + NS_UI_ACTIVATE, 1); + + rv = shell->HandleDOMEventWithTarget(this, &actEvent, &status); + if (NS_SUCCEEDED(rv)) { + aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; + } + } + } + break; + + case NS_UI_ACTIVATE: + { + if (aVisitor.mEvent->originalTarget == this) { + nsAutoString target; + GetLinkTarget(target); + nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target, + true, true, NS_IS_TRUSTED_EVENT(aVisitor.mEvent)); + aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; + } + } + break; + + case NS_KEY_PRESS: + { + if (aVisitor.mEvent->eventStructType == NS_KEY_EVENT) { + nsKeyEvent* keyEvent = static_cast(aVisitor.mEvent); + if (keyEvent->keyCode == NS_VK_RETURN) { + nsEventStatus status = nsEventStatus_eIgnore; + rv = DispatchClickEvent(aVisitor.mPresContext, keyEvent, this, + false, 0, &status); + if (NS_SUCCEEDED(rv)) { + aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; + } + } + } + } + break; + + default: + // switch not in sync with the optimization switch earlier in this function + NS_NOTREACHED("switch statements not in sync"); + return NS_ERROR_UNEXPECTED; + } + + return rv; +} + +void +FragmentOrElement::FireNodeRemovedForChildren() +{ + nsIDocument* doc = OwnerDoc(); + // Optimize the common case + if (!nsContentUtils:: + HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEREMOVED)) { + return; + } + + nsCOMPtr owningDoc = doc; + + nsCOMPtr child; + for (child = GetFirstChild(); + child && child->GetNodeParent() == this; + child = child->GetNextSibling()) { + nsContentUtils::MaybeFireNodeRemoved(child, this, doc); + } +} + +void +FragmentOrElement::GetLinkTarget(nsAString& aTarget) +{ + aTarget.Truncate(); +} + +// NOTE: The aPresContext pointer is NOT addrefed. +// *aSelectorList might be null even if NS_OK is returned; this +// happens when all the selectors were pseudo-element selectors. +static nsresult +ParseSelectorList(nsINode* aNode, + const nsAString& aSelectorString, + nsCSSSelectorList** aSelectorList) +{ + NS_ENSURE_ARG(aNode); + + nsIDocument* doc = aNode->OwnerDoc(); + nsCSSParser parser(doc->CSSLoader()); + + nsCSSSelectorList* selectorList; + nsresult rv = parser.ParseSelectorString(aSelectorString, + doc->GetDocumentURI(), + 0, // XXXbz get the line number! + &selectorList); + NS_ENSURE_SUCCESS(rv, rv); + + // Filter out pseudo-element selectors from selectorList + nsCSSSelectorList** slot = &selectorList; + do { + nsCSSSelectorList* cur = *slot; + if (cur->mSelectors->IsPseudoElement()) { + *slot = cur->mNext; + cur->mNext = nullptr; + delete cur; + } else { + slot = &cur->mNext; + } + } while (*slot); + *aSelectorList = selectorList; + + return NS_OK; +} + +// Actually find elements matching aSelectorList (which must not be +// null) and which are descendants of aRoot and put them in aList. If +// onlyFirstMatch, then stop once the first one is found. +template +inline static nsresult FindMatchingElements(nsINode* aRoot, + const nsAString& aSelector, + T &aList) +{ + nsAutoPtr selectorList; + nsresult rv = ParseSelectorList(aRoot, aSelector, + getter_Transfers(selectorList)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(selectorList, NS_OK); + + NS_ASSERTION(selectorList->mSelectors, + "How can we not have any selectors?"); + + nsIDocument* doc = aRoot->OwnerDoc(); + TreeMatchContext matchingContext(false, nsRuleWalker::eRelevantLinkUnvisited, + doc, TreeMatchContext::eNeverMatchVisited); + doc->FlushPendingLinkUpdates(); + + // Fast-path selectors involving IDs. We can only do this if aRoot + // is in the document and the document is not in quirks mode, since + // ID selectors are case-insensitive in quirks mode. Also, only do + // this if selectorList only has one selector, because otherwise + // ordering the elements correctly is a pain. + NS_ASSERTION(aRoot->IsElement() || aRoot->IsNodeOfType(nsINode::eDOCUMENT) || + !aRoot->IsInDoc(), + "The optimization below to check ContentIsDescendantOf only for " + "elements depends on aRoot being either an element or a " + "document if it's in the document."); + if (aRoot->IsInDoc() && + doc->GetCompatibilityMode() != eCompatibility_NavQuirks && + !selectorList->mNext && + selectorList->mSelectors->mIDList) { + nsIAtom* id = selectorList->mSelectors->mIDList->mAtom; + const nsSmallVoidArray* elements = + doc->GetAllElementsForId(nsDependentAtomString(id)); + + // XXXbz: Should we fall back to the tree walk if aRoot is not the + // document and |elements| is long, for some value of "long"? + if (elements) { + for (PRInt32 i = 0; i < elements->Count(); ++i) { + Element *element = static_cast(elements->ElementAt(i)); + if (!aRoot->IsElement() || + (element != aRoot && + nsContentUtils::ContentIsDescendantOf(element, aRoot))) { + // We have an element with the right id and it's a strict descendant + // of aRoot. Make sure it really matches the selector. + if (nsCSSRuleProcessor::SelectorListMatches(element, matchingContext, + selectorList)) { + aList.AppendElement(element); + if (onlyFirstMatch) { + return NS_OK; + } + } + } + } + } + + // No elements with this id, or none of them are our descendants, + // or none of them match. We're done here. + return NS_OK; + } + + for (nsIContent* cur = aRoot->GetFirstChild(); + cur; + cur = cur->GetNextNode(aRoot)) { + if (cur->IsElement() && + nsCSSRuleProcessor::SelectorListMatches(cur->AsElement(), + matchingContext, + selectorList)) { + aList.AppendElement(cur->AsElement()); + if (onlyFirstMatch) { + return NS_OK; + } + } + } + + return NS_OK; +} + +struct ElementHolder { + ElementHolder() : mElement(nullptr) {} + void AppendElement(Element* aElement) { + NS_ABORT_IF_FALSE(!mElement, "Should only get one element"); + mElement = aElement; + } + Element* mElement; +}; + +/* static */ +nsIContent* +FragmentOrElement::doQuerySelector(nsINode* aRoot, const nsAString& aSelector, + nsresult *aResult) +{ + NS_PRECONDITION(aResult, "Null out param?"); + + ElementHolder holder; + *aResult = FindMatchingElements(aRoot, aSelector, holder); + + return holder.mElement; +} + +/* static */ +nsresult +FragmentOrElement::doQuerySelectorAll(nsINode* aRoot, + const nsAString& aSelector, + nsIDOMNodeList **aReturn) +{ + NS_PRECONDITION(aReturn, "Null out param?"); + + nsSimpleContentList* contentList = new nsSimpleContentList(aRoot); + NS_ENSURE_TRUE(contentList, NS_ERROR_OUT_OF_MEMORY); + NS_ADDREF(*aReturn = contentList); + + return FindMatchingElements(aRoot, aSelector, *contentList); +} + + +bool +FragmentOrElement::MozMatchesSelector(const nsAString& aSelector, nsresult* aResult) +{ + nsAutoPtr selectorList; + bool matches = false; + + *aResult = ParseSelectorList(this, aSelector, getter_Transfers(selectorList)); + + if (NS_SUCCEEDED(*aResult)) { + OwnerDoc()->FlushPendingLinkUpdates(); + TreeMatchContext matchingContext(false, + nsRuleWalker::eRelevantLinkUnvisited, + OwnerDoc(), + TreeMatchContext::eNeverMatchVisited); + matches = nsCSSRuleProcessor::SelectorListMatches(this, matchingContext, + selectorList); + } + + return matches; +} + +NS_IMETHODIMP +FragmentOrElement::MozMatchesSelector(const nsAString& aSelector, bool* aReturn) +{ + NS_PRECONDITION(aReturn, "Null out param?"); + + nsresult rv; + *aReturn = MozMatchesSelector(aSelector, &rv); + + return rv; +} + +size_t +FragmentOrElement::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const +{ + return Element::SizeOfExcludingThis(aMallocSizeOf) + + mAttrsAndChildren.SizeOfExcludingThis(aMallocSizeOf); +} + +static const nsAttrValue::EnumTable kCORSAttributeTable[] = { + // Order matters here + // See ParseCORSValue + { "anonymous", CORS_ANONYMOUS }, + { "use-credentials", CORS_USE_CREDENTIALS }, + { 0 } +}; + +/* static */ void +FragmentOrElement::ParseCORSValue(const nsAString& aValue, + nsAttrValue& aResult) +{ + DebugOnly success = + aResult.ParseEnumValue(aValue, kCORSAttributeTable, false, + // default value is anonymous if aValue is + // not a value we understand + &kCORSAttributeTable[0]); + MOZ_ASSERT(success); +} + +/* static */ CORSMode +FragmentOrElement::StringToCORSMode(const nsAString& aValue) +{ + if (aValue.IsVoid()) { + return CORS_NONE; + } + + nsAttrValue val; + FragmentOrElement::ParseCORSValue(aValue, val); + return CORSMode(val.GetEnumValue()); +} + +/* static */ CORSMode +FragmentOrElement::AttrValueToCORSMode(const nsAttrValue* aValue) +{ + if (!aValue) { + return CORS_NONE; + } + + return CORSMode(aValue->GetEnumValue()); +} + +NS_IMETHODIMP +FragmentOrElement::GetOnmouseenter(JSContext* cx, JS::Value* vp) +{ + return nsINode::GetOnmouseenter(cx, vp); +} + +NS_IMETHODIMP +FragmentOrElement::SetOnmouseenter(JSContext* cx, const JS::Value& v) +{ + return nsINode::SetOnmouseenter(cx, v); +} + +NS_IMETHODIMP +FragmentOrElement::GetOnmouseleave(JSContext* cx, JS::Value* vp) +{ + return nsINode::GetOnmouseleave(cx, vp); +} + +NS_IMETHODIMP +FragmentOrElement::SetOnmouseleave(JSContext* cx, const JS::Value& v) +{ + return nsINode::SetOnmouseleave(cx, v); +} + +NS_IMETHODIMP +FragmentOrElement::MozRequestPointerLock() +{ + OwnerDoc()->RequestPointerLock(this); + return NS_OK; +} + +static const char* +GetFullScreenError(nsIDocument* aDoc) +{ + nsCOMPtr win = aDoc->GetWindow(); + if (win && win->IsInAppOrigin()) { + // Request is in a web app and in the same origin as the web app. + // Don't enforce as strict security checks for web apps, the user + // is supposed to have trust in them. However documents cross-origin + // to the web app must still confirm to the normal security checks. + return nullptr; + } + + if (!nsContentUtils::IsRequestFullScreenAllowed()) { + return "FullScreenDeniedNotInputDriven"; + } + + if (nsContentUtils::IsSitePermDeny(aDoc->NodePrincipal(), "fullscreen")) { + return "FullScreenDeniedBlocked"; + } + + return nullptr; +} + +nsresult FragmentOrElement::MozRequestFullScreen() +{ + // Only grant full-screen requests if this is called from inside a trusted + // event handler (i.e. inside an event handler for a user initiated event). + // This stops the full-screen from being abused similar to the popups of old, + // and it also makes it harder for bad guys' script to go full-screen and + // spoof the browser chrome/window and phish logins etc. + // Note that requests for fullscreen inside a web app's origin are exempt + // from this restriction. + const char* error = GetFullScreenError(OwnerDoc()); + if (error) { + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, + "DOM", OwnerDoc(), + nsContentUtils::eDOM_PROPERTIES, + error); + nsRefPtr e = + new nsAsyncDOMEvent(OwnerDoc(), + NS_LITERAL_STRING("mozfullscreenerror"), + true, + false); + e->PostDOMEvent(); + return NS_OK; + } + + OwnerDoc()->AsyncRequestFullScreen(this); + + return NS_OK; +} + diff --git a/content/base/src/Makefile.in b/content/base/src/Makefile.in index 28f958e625c3..c64a7ccadbc9 100644 --- a/content/base/src/Makefile.in +++ b/content/base/src/Makefile.in @@ -125,6 +125,7 @@ CPPSRCS = \ nsXMLContentSerializer.cpp \ nsXMLHttpRequest.cpp \ nsXMLNameSpaceMap.cpp \ + FragmentOrElement.cpp \ Link.cpp \ nsBlobProtocolHandler.cpp \ nsFrameMessageManager.cpp \ diff --git a/content/base/src/nsDOMTokenList.cpp b/content/base/src/nsDOMTokenList.cpp index c1689e6806c3..3cda211c173b 100644 --- a/content/base/src/nsDOMTokenList.cpp +++ b/content/base/src/nsDOMTokenList.cpp @@ -14,8 +14,10 @@ #include "nsGenericElement.h" #include "dombindings.h" +using namespace mozilla; +using namespace mozilla::dom; -nsDOMTokenList::nsDOMTokenList(nsGenericElement *aElement, nsIAtom* aAttrAtom) +nsDOMTokenList::nsDOMTokenList(FragmentOrElement *aElement, nsIAtom* aAttrAtom) : mElement(aElement), mAttrAtom(aAttrAtom) { diff --git a/content/base/src/nsDOMTokenList.h b/content/base/src/nsDOMTokenList.h index 16c0cb047976..b1e13f3fcc04 100644 --- a/content/base/src/nsDOMTokenList.h +++ b/content/base/src/nsDOMTokenList.h @@ -24,7 +24,7 @@ public: NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMTokenList) NS_DECL_NSIDOMDOMTOKENLIST - nsDOMTokenList(nsGenericElement* aElement, nsIAtom* aAttrAtom); + nsDOMTokenList(mozilla::dom::FragmentOrElement* aElement, nsIAtom* aAttrAtom); void DropReference(); @@ -50,7 +50,7 @@ protected: void AddInternal(const nsAttrValue* aAttr, const nsAString& aToken); void RemoveInternal(const nsAttrValue* aAttr, const nsAString& aToken); - nsGenericElement* mElement; + mozilla::dom::FragmentOrElement* mElement; nsCOMPtr mAttrAtom; }; diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index d047a4796652..0a854ba31c0a 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -129,6 +129,7 @@ using namespace mozilla; using namespace mozilla::dom; +#if 0 NS_DEFINE_IID(kThisPtrOffsetsSID, NS_THISPTROFFSETS_SID); PRInt32 nsIContent::sTabFocusModel = eTabFocus_any; @@ -1343,20 +1344,14 @@ nsGenericElement::nsDOMSlots::Unlink(bool aIsXUL) mClassList = nullptr; } } +#endif nsGenericElement::nsGenericElement(already_AddRefed aNodeInfo) - : Element(aNodeInfo) + : FragmentOrElement(aNodeInfo) { - NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::ELEMENT_NODE || - (mNodeInfo->NodeType() == - nsIDOMNode::DOCUMENT_FRAGMENT_NODE && - mNodeInfo->Equals(nsGkAtoms::documentFragmentNodeName, - kNameSpaceID_None)), - "Bad NodeType in aNodeInfo"); - - SetIsElement(); } +#if 0 nsGenericElement::~nsGenericElement() { NS_PRECONDITION(!IsInDoc(), @@ -4809,4 +4804,4 @@ nsresult nsGenericElement::MozRequestFullScreen() return NS_OK; } - +#endif diff --git a/content/base/src/nsGenericElement.h b/content/base/src/nsGenericElement.h index 33528f0fafed..32a93a2d8295 100644 --- a/content/base/src/nsGenericElement.h +++ b/content/base/src/nsGenericElement.h @@ -14,6 +14,7 @@ #include "nsCOMPtr.h" #include "nsAutoPtr.h" +#include "mozilla/dom/FragmentOrElement.h" #include "mozilla/dom/Element.h" #include "nsIDOMElement.h" #include "nsIDOMDocumentFragment.h" @@ -57,6 +58,7 @@ struct nsRect; typedef PRUptrdiff PtrBits; +#if 0 /** * Class that implements the nsIDOMNodeList interface (a list of children of * the content), by holding a reference to the content and delegating GetLength @@ -201,15 +203,17 @@ private: // Forward declare to allow being a friend class nsTouchEventReceiverTearoff; class nsInlineEventHandlersTearoff; +#endif /** * A generic base class for DOM elements, implementing many nsIContent, * nsIDOMNode and nsIDOMElement methods. */ -class nsGenericElement : public mozilla::dom::Element +class nsGenericElement : public mozilla::dom::FragmentOrElement { public: nsGenericElement(already_AddRefed aNodeInfo); +#if 0 virtual ~nsGenericElement(); friend class nsTouchEventReceiverTearoff; @@ -365,14 +369,18 @@ public: { return FindAttributeDependence(aAttribute, aMaps, N); } +#endif private: +#if 0 static bool FindAttributeDependence(const nsIAtom* aAttribute, const MappedAttributeEntry* const aMaps[], PRUint32 aMapCount); +#endif public: +#if 0 // nsIDOMNode method implementation NS_IMETHOD GetNodeName(nsAString& aNodeName); NS_IMETHOD GetLocalName(nsAString& aLocalName); @@ -641,8 +649,10 @@ public: * but if not should have been parsed via ParseCORSValue). */ static mozilla::CORSMode AttrValueToCORSMode(const nsAttrValue* aValue); +#endif protected: +#if 0 /* * Named-bools for use with SetAttrAndNotify to make call sites easier to * read. @@ -807,8 +817,10 @@ protected: nsresult GetAttributeNodeNSInternal(const nsAString& aNamespaceURI, const nsAString& aLocalName, nsIDOMAttr** aReturn); +#endif public: +#if 0 // Because of a bug in MS C++ compiler nsDOMSlots must be declared public, // otherwise nsXULElement::nsXULSlots doesn't compile. /** @@ -881,8 +893,10 @@ public: */ nsRefPtr mClassList; }; +#endif protected: +#if 0 // Override from nsINode virtual nsINode::nsSlots* CreateSlots(); @@ -971,8 +985,10 @@ protected: * Array containing all attributes and children for this element */ nsAttrAndChildArray mAttrsAndChildren; +#endif private: +#if 0 /** * Get this element's client area rect in app units. * @return the frame's client area @@ -982,8 +998,10 @@ private: nsIScrollableFrame* GetScrollFrame(nsIFrame **aStyledFrame = nullptr); nsContentList* GetChildrenList(); +#endif }; +#if 0 /** * Macros to implement Clone(). _elementName is the class for which to implement * Clone. @@ -1118,5 +1136,6 @@ private: \ return NS_OK; \ } +#endif #endif /* nsGenericElement_h___ */ diff --git a/content/base/src/nsStyledElement.h b/content/base/src/nsStyledElement.h index 7eb5bf0c05d5..e55325e27881 100644 --- a/content/base/src/nsStyledElement.h +++ b/content/base/src/nsStyledElement.h @@ -68,7 +68,7 @@ protected: virtual bool ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aAttribute, const nsAString& aValue, nsAttrValue& aResult); - friend class nsGenericElement; + friend class mozilla::dom::FragmentOrElement; /** * Create the style struct from the style attr. Used when an element is From ec805a875af4d708630fcf916f466efc11b7d1a8 Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Wed, 27 Jun 2012 16:01:55 +0300 Subject: [PATCH 004/114] Bug 563659 part 3 - Make Element inherit from FragmentOrElement; r=bz --- content/base/public/Element.h | 6 ++-- content/base/public/FragmentOrElement.h | 29 +++++++++++++++++-- content/base/src/FragmentOrElement.cpp | 27 +++++++++++++++-- content/base/src/nsAttrName.h | 2 ++ content/base/src/nsAttrValue.h | 2 +- content/base/src/nsContentList.h | 2 +- content/base/src/nsDOMAttributeMap.h | 2 +- content/base/src/nsDOMTokenList.cpp | 2 +- content/base/src/nsDOMTokenList.h | 4 +-- content/base/src/nsGenericElement.cpp | 28 ++++++++++++++++-- content/base/src/nsGenericElement.h | 26 +++++++++++++++-- content/base/src/nsStyledElement.h | 2 +- content/smil/nsISMILAttr.h | 3 +- content/svg/content/src/SVGAttrValueWrapper.h | 2 +- 14 files changed, 115 insertions(+), 22 deletions(-) diff --git a/content/base/public/Element.h b/content/base/public/Element.h index bff472d4d8c9..ebcfc2f85ba7 100644 --- a/content/base/public/Element.h +++ b/content/base/public/Element.h @@ -7,7 +7,7 @@ #ifndef mozilla_dom_Element_h__ #define mozilla_dom_Element_h__ -#include "nsIContent.h" +#include "mozilla/dom/FragmentOrElement.h" #include "nsEventStates.h" class nsEventStateManager; @@ -60,12 +60,12 @@ class Link; { 0xc6c049a1, 0x96e8, 0x4580, \ { 0xa6, 0x93, 0xb9, 0x5f, 0x53, 0xbe, 0xe8, 0x1c } } -class Element : public nsIContent +class Element : public FragmentOrElement { public: #ifdef MOZILLA_INTERNAL_API Element(already_AddRefed aNodeInfo) : - nsIContent(aNodeInfo), + FragmentOrElement(aNodeInfo), mState(NS_EVENT_STATE_MOZ_READONLY) {} #endif // MOZILLA_INTERNAL_API diff --git a/content/base/public/FragmentOrElement.h b/content/base/public/FragmentOrElement.h index 6f2fbc7af104..d4a679731d43 100644 --- a/content/base/public/FragmentOrElement.h +++ b/content/base/public/FragmentOrElement.h @@ -14,7 +14,7 @@ #include "nsCOMPtr.h" #include "nsAutoPtr.h" -#include "mozilla/dom/Element.h" +#include "nsIContent.h" #include "nsIDOMElement.h" #include "nsIDOMDocumentFragment.h" #include "nsILinkHandler.h" @@ -209,7 +209,7 @@ class nsInlineEventHandlersTearoff; namespace mozilla { namespace dom { -class FragmentOrElement : public mozilla::dom::Element +class FragmentOrElement : public nsIContent { public: FragmentOrElement(already_AddRefed aNodeInfo); @@ -240,6 +240,7 @@ public: NS_IMETHOD SetTextContent(const nsAString& aTextContent); // nsIContent interface methods +#if 0 virtual void UpdateEditableState(bool aNotify); virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, @@ -247,9 +248,11 @@ public: bool aCompileEventHandlers); virtual void UnbindFromTree(bool aDeep = true, bool aNullParent = true); +#endif virtual already_AddRefed GetChildren(PRUint32 aFilter); virtual nsIAtom *GetClassAttributeName() const; virtual already_AddRefed GetExistingAttrNameFromQName(const nsAString& aStr) const; +#if 0 nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, const nsAString& aValue, bool aNotify) { @@ -298,6 +301,7 @@ public: bool aNotify); virtual const nsAttrName* GetAttrNameAt(PRUint32 aIndex) const; virtual PRUint32 GetAttrCount() const; +#endif virtual const nsTextFragment *GetText(); virtual PRUint32 TextLength() const; virtual nsresult SetText(const PRUnichar* aBuffer, PRUint32 aLength, @@ -318,6 +322,7 @@ public: virtual void DestroyContent(); virtual void SaveSubtreeState(); +#if 0 virtual nsISMILAttr* GetAnimatedAttr(PRInt32 /*aNamespaceID*/, nsIAtom* /*aName*/) { return nullptr; @@ -336,14 +341,17 @@ public: virtual void DumpContent(FILE* out, PRInt32 aIndent, bool aDumpAll) const; void List(FILE* out, PRInt32 aIndent, const nsCString& aPrefix) const; void ListAttributes(FILE* out) const; +#endif #endif virtual const nsAttrValue* DoGetClasses() const; NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker); +#if 0 virtual mozilla::css::StyleRule* GetInlineStyleRule(); virtual nsresult SetInlineStyleRule(mozilla::css::StyleRule* aStyleRule, const nsAString* aSerialized, bool aNotify); +#endif NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const; virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, @@ -382,12 +390,16 @@ public: NS_IMETHOD GetNodeValue(nsAString& aNodeValue); NS_IMETHOD SetNodeValue(const nsAString& aNodeValue); NS_IMETHOD GetNodeType(PRUint16* aNodeType); +#if 0 NS_IMETHOD GetAttributes(nsIDOMNamedNodeMap** aAttributes); +#endif NS_IMETHOD GetNamespaceURI(nsAString& aNamespaceURI); NS_IMETHOD GetPrefix(nsAString& aPrefix); NS_IMETHOD IsSupported(const nsAString& aFeature, const nsAString& aVersion, bool* aReturn); +#if 0 NS_IMETHOD HasAttributes(bool* aHasAttributes); +#endif NS_IMETHOD HasChildNodes(bool* aHasChildNodes); nsresult InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild, nsIDOMNode** aReturn) @@ -408,8 +420,10 @@ public: return InsertBefore(aNewChild, nullptr, aReturn); } +#if 0 // nsIDOMElement method implementation NS_DECL_NSIDOMELEMENT +#endif nsresult CloneNode(bool aDeep, PRUint8 aOptionalArgc, nsIDOMNode **aResult) { @@ -546,6 +560,7 @@ public: { } +#if 0 PRInt32 GetScrollTop(); PRInt32 GetScrollLeft(); PRInt32 GetScrollHeight(); @@ -584,6 +599,7 @@ public: * that effectively live in mAttrsAndChildren. */ virtual nsAttrInfo GetAttrInfo(PRInt32 aNamespaceID, nsIAtom* aName) const; +#endif NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(FragmentOrElement) @@ -679,6 +695,7 @@ protected: * @param aNotify should we notify document-observers? * @param aCallAfterSetAttr should we call AfterSetAttr? */ +#if 0 nsresult SetAttrAndNotify(PRInt32 aNamespaceID, nsIAtom* aName, nsIAtom* aPrefix, @@ -722,6 +739,7 @@ protected: nsIAtom* aName, nsAttrValue& aValue, nsresult* aRetval); +#endif /** * Hook that is called by FragmentOrElement::SetAttr to allow subclasses to @@ -791,6 +809,7 @@ protected: * @param aRect offset rectangle * @param aOffsetParent offset parent */ +#if 0 virtual void GetOffsetRect(nsRect& aRect, nsIContent** aOffsetParent); /** @@ -810,6 +829,7 @@ protected: nsresult GetAttributeNodeNSInternal(const nsAString& aNamespaceURI, const nsAString& aLocalName, nsIDOMAttr** aReturn); +#endif public: // Because of a bug in MS C++ compiler nsDOMSlots must be declared public, @@ -906,6 +926,7 @@ protected: OwnerDoc()->UnregisterFreezableElement(this); } +#if 0 /** * Add/remove this element to the documents id cache */ @@ -930,6 +951,7 @@ protected: } } } +#endif /** * Functions to carry out event default actions for links of all types @@ -980,10 +1002,13 @@ private: * Get this element's client area rect in app units. * @return the frame's client area */ +#if 0 nsRect GetClientAreaRect(); nsIScrollableFrame* GetScrollFrame(nsIFrame **aStyledFrame = nullptr); +#endif +protected: nsContentList* GetChildrenList(); }; diff --git a/content/base/src/FragmentOrElement.cpp b/content/base/src/FragmentOrElement.cpp index 21359310857f..0844aec97fe9 100644 --- a/content/base/src/FragmentOrElement.cpp +++ b/content/base/src/FragmentOrElement.cpp @@ -135,6 +135,7 @@ PRInt32 nsIContent::sTabFocusModel = eTabFocus_any; bool nsIContent::sTabFocusModelAppliesToXUL = false; PRUint32 nsMutationGuard::sMutationCount = 0; +#if 0 nsEventStates Element::IntrinsicState() const { @@ -309,6 +310,7 @@ Element::ClearStyleStateLocks() NotifyStyleStateChange(locks); } +#endif nsIContent* nsIContent::FindFirstNonNativeAnonymous() const @@ -628,6 +630,7 @@ nsNode3Tearoff::LookupNamespaceURI(const nsAString& aNamespacePrefix, return mNode->LookupNamespaceURI(aNamespacePrefix, aNamespaceURI); } +#if 0 nsIContent* FragmentOrElement::GetFirstElementChild() { @@ -772,6 +775,7 @@ FragmentOrElement::GetNextElementSibling(nsIDOMElement** aResult) return result ? CallQueryInterface(result, aResult) : NS_OK; } +#endif nsContentList* FragmentOrElement::GetChildrenList() @@ -787,6 +791,7 @@ FragmentOrElement::GetChildrenList() return slots->mChildrenList; } +#if 0 nsDOMTokenList* FragmentOrElement::GetClassList(nsresult *aResult) { @@ -1183,6 +1188,7 @@ FragmentOrElement::GetClientRects(nsIDOMClientRectList** aResult) *aResult = rectList.forget().get(); return NS_OK; } +#endif //---------------------------------------------------------------------- @@ -1345,7 +1351,7 @@ FragmentOrElement::nsDOMSlots::Unlink(bool aIsXUL) } FragmentOrElement::FragmentOrElement(already_AddRefed aNodeInfo) - : Element(aNodeInfo) + : nsIContent(aNodeInfo) { NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::ELEMENT_NODE || (mNodeInfo->NodeType() == @@ -1488,6 +1494,7 @@ FragmentOrElement::IsSupported(const nsAString& aFeature, return InternalIsSupported(this, aFeature, aVersion, aReturn); } +#if 0 NS_IMETHODIMP FragmentOrElement::HasAttributes(bool* aReturn) { @@ -1516,6 +1523,7 @@ FragmentOrElement::GetAttributes(nsIDOMNamedNodeMap** aAttributes) return NS_OK; } +#endif nsresult FragmentOrElement::HasChildNodes(bool* aReturn) @@ -1525,6 +1533,7 @@ FragmentOrElement::HasChildNodes(bool* aReturn) return NS_OK; } +#if 0 NS_IMETHODIMP FragmentOrElement::GetTagName(nsAString& aTagName) { @@ -2225,6 +2234,7 @@ FragmentOrElement::UnbindFromTree(bool aDeep, bool aNullParent) nsNodeUtils::ParentChainChanged(this); } +#endif already_AddRefed FragmentOrElement::GetChildren(PRUint32 aFilter) @@ -2437,6 +2447,7 @@ FragmentOrElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker) return NS_OK; } +#if 0 nsICSSDeclaration* FragmentOrElement::GetSMILOverrideStyle() { @@ -2500,6 +2511,7 @@ FragmentOrElement::SetInlineStyleRule(css::StyleRule* aStyleRule, NS_NOTYETIMPLEMENTED("FragmentOrElement::SetInlineStyleRule"); return NS_ERROR_NOT_IMPLEMENTED; } +#endif NS_IMETHODIMP_(bool) FragmentOrElement::IsAttributeMapped(const nsIAtom* aAttribute) const @@ -3580,6 +3592,7 @@ FragmentOrElement::CopyInnerTo(FragmentOrElement* aDst) return NS_OK; } +#if 0 bool FragmentOrElement::MaybeCheckSameAttrVal(PRInt32 aNamespaceID, nsIAtom* aName, @@ -3834,6 +3847,7 @@ FragmentOrElement::SetMappedAttribute(nsIDocument* aDocument, *aRetval = NS_OK; return false; } +#endif nsEventListenerManager* FragmentOrElement::GetEventListenerManagerForAttr(nsIAtom* aAttrName, @@ -3843,6 +3857,7 @@ FragmentOrElement::GetEventListenerManagerForAttr(nsIAtom* aAttrName, return GetListenerManager(true); } +#if 0 FragmentOrElement::nsAttrInfo FragmentOrElement::GetAttrInfo(PRInt32 aNamespaceID, nsIAtom* aName) const { @@ -4041,6 +4056,7 @@ FragmentOrElement::GetAttrCount() const { return mAttrsAndChildren.AttrCount(); } +#endif const nsTextFragment* FragmentOrElement::GetText() @@ -4090,6 +4106,7 @@ FragmentOrElement::AppendTextTo(nsAString& aResult) NS_NOTREACHED("called FragmentOrElement::TextLength"); } +#if 0 #ifdef DEBUG void FragmentOrElement::ListAttributes(FILE* out) const @@ -4243,6 +4260,7 @@ FragmentOrElement::DumpContent(FILE* out, PRInt32 aIndent, if(aIndent) fputs("\n", out); } #endif +#endif PRUint32 FragmentOrElement::GetChildCount() const @@ -4646,6 +4664,7 @@ FragmentOrElement::doQuerySelectorAll(nsINode* aRoot, } +#if 0 bool FragmentOrElement::MozMatchesSelector(const nsAString& aSelector, nsresult* aResult) { @@ -4677,11 +4696,12 @@ FragmentOrElement::MozMatchesSelector(const nsAString& aSelector, bool* aReturn) return rv; } +#endif size_t FragmentOrElement::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const { - return Element::SizeOfExcludingThis(aMallocSizeOf) + + return nsIContent::SizeOfExcludingThis(aMallocSizeOf) + mAttrsAndChildren.SizeOfExcludingThis(aMallocSizeOf); } @@ -4727,6 +4747,7 @@ FragmentOrElement::AttrValueToCORSMode(const nsAttrValue* aValue) return CORSMode(aValue->GetEnumValue()); } +#if 0 NS_IMETHODIMP FragmentOrElement::GetOnmouseenter(JSContext* cx, JS::Value* vp) { @@ -4809,4 +4830,4 @@ nsresult FragmentOrElement::MozRequestFullScreen() return NS_OK; } - +#endif diff --git a/content/base/src/nsAttrName.h b/content/base/src/nsAttrName.h index b63dde2ebde8..ba59123a91d9 100644 --- a/content/base/src/nsAttrName.h +++ b/content/base/src/nsAttrName.h @@ -158,6 +158,7 @@ public: } } +#ifdef MOZILLA_INTERNAL_API void GetPrefix(nsAString& aStr) const { if (IsAtom()) { @@ -167,6 +168,7 @@ public: NodeInfo()->GetPrefix(aStr); } } +#endif PRUint32 HashValue() const { diff --git a/content/base/src/nsAttrValue.h b/content/base/src/nsAttrValue.h index 018dcaecde44..5384a3f73cdd 100644 --- a/content/base/src/nsAttrValue.h +++ b/content/base/src/nsAttrValue.h @@ -12,7 +12,7 @@ #define nsAttrValue_h___ #include "nscore.h" -#include "nsString.h" +#include "nsStringGlue.h" #include "nsStringBuffer.h" #include "nsColor.h" #include "nsCaseTreatment.h" diff --git a/content/base/src/nsContentList.h b/content/base/src/nsContentList.h index ff17e8dbdd37..10ff514e0c10 100644 --- a/content/base/src/nsContentList.h +++ b/content/base/src/nsContentList.h @@ -14,7 +14,7 @@ #include "nsISupports.h" #include "nsTArray.h" -#include "nsString.h" +#include "nsStringGlue.h" #include "nsIHTMLCollection.h" #include "nsIDOMNodeList.h" #include "nsINodeList.h" diff --git a/content/base/src/nsDOMAttributeMap.h b/content/base/src/nsDOMAttributeMap.h index 713f14e36701..f4cffdb61474 100644 --- a/content/base/src/nsDOMAttributeMap.h +++ b/content/base/src/nsDOMAttributeMap.h @@ -11,7 +11,7 @@ #define nsDOMAttributeMap_h___ #include "nsIDOMNamedNodeMap.h" -#include "nsString.h" +#include "nsStringGlue.h" #include "nsRefPtrHashtable.h" #include "nsCycleCollectionParticipant.h" #include "nsIDOMNode.h" diff --git a/content/base/src/nsDOMTokenList.cpp b/content/base/src/nsDOMTokenList.cpp index 3cda211c173b..9c3af587f1a5 100644 --- a/content/base/src/nsDOMTokenList.cpp +++ b/content/base/src/nsDOMTokenList.cpp @@ -17,7 +17,7 @@ using namespace mozilla; using namespace mozilla::dom; -nsDOMTokenList::nsDOMTokenList(FragmentOrElement *aElement, nsIAtom* aAttrAtom) +nsDOMTokenList::nsDOMTokenList(nsGenericElement* aElement, nsIAtom* aAttrAtom) : mElement(aElement), mAttrAtom(aAttrAtom) { diff --git a/content/base/src/nsDOMTokenList.h b/content/base/src/nsDOMTokenList.h index b1e13f3fcc04..16c0cb047976 100644 --- a/content/base/src/nsDOMTokenList.h +++ b/content/base/src/nsDOMTokenList.h @@ -24,7 +24,7 @@ public: NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMTokenList) NS_DECL_NSIDOMDOMTOKENLIST - nsDOMTokenList(mozilla::dom::FragmentOrElement* aElement, nsIAtom* aAttrAtom); + nsDOMTokenList(nsGenericElement* aElement, nsIAtom* aAttrAtom); void DropReference(); @@ -50,7 +50,7 @@ protected: void AddInternal(const nsAttrValue* aAttr, const nsAString& aToken); void RemoveInternal(const nsAttrValue* aAttr, const nsAString& aToken); - mozilla::dom::FragmentOrElement* mElement; + nsGenericElement* mElement; nsCOMPtr mAttrAtom; }; diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index 0a854ba31c0a..28604976c3cd 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -135,6 +135,7 @@ NS_DEFINE_IID(kThisPtrOffsetsSID, NS_THISPTROFFSETS_SID); PRInt32 nsIContent::sTabFocusModel = eTabFocus_any; bool nsIContent::sTabFocusModelAppliesToXUL = false; PRUint32 nsMutationGuard::sMutationCount = 0; +#endif nsEventStates Element::IntrinsicState() const @@ -311,6 +312,7 @@ Element::ClearStyleStateLocks() NotifyStyleStateChange(locks); } +#if 0 nsIContent* nsIContent::FindFirstNonNativeAnonymous() const { @@ -628,6 +630,7 @@ nsNode3Tearoff::LookupNamespaceURI(const nsAString& aNamespacePrefix, { return mNode->LookupNamespaceURI(aNamespacePrefix, aNamespaceURI); } +#endif nsIContent* nsGenericElement::GetFirstElementChild() @@ -774,6 +777,7 @@ nsGenericElement::GetNextElementSibling(nsIDOMElement** aResult) return result ? CallQueryInterface(result, aResult) : NS_OK; } +#if 0 nsContentList* nsGenericElement::GetChildrenList() { @@ -787,6 +791,7 @@ nsGenericElement::GetChildrenList() return slots->mChildrenList; } +#endif nsDOMTokenList* nsGenericElement::GetClassList(nsresult *aResult) @@ -1189,6 +1194,7 @@ nsGenericElement::GetClientRects(nsIDOMClientRectList** aResult) //---------------------------------------------------------------------- +#if 0 NS_IMPL_ISUPPORTS1(nsNodeWeakReference, nsIWeakReference) @@ -1347,7 +1353,7 @@ nsGenericElement::nsDOMSlots::Unlink(bool aIsXUL) #endif nsGenericElement::nsGenericElement(already_AddRefed aNodeInfo) - : FragmentOrElement(aNodeInfo) + : Element(aNodeInfo) { } @@ -1482,6 +1488,7 @@ nsGenericElement::IsSupported(const nsAString& aFeature, { return InternalIsSupported(this, aFeature, aVersion, aReturn); } +#endif NS_IMETHODIMP nsGenericElement::HasAttributes(bool* aReturn) @@ -1512,6 +1519,7 @@ nsGenericElement::GetAttributes(nsIDOMNamedNodeMap** aAttributes) return NS_OK; } +#if 0 nsresult nsGenericElement::HasChildNodes(bool* aReturn) { @@ -1519,6 +1527,7 @@ nsGenericElement::HasChildNodes(bool* aReturn) return NS_OK; } +#endif NS_IMETHODIMP nsGenericElement::GetTagName(nsAString& aTagName) @@ -2221,6 +2230,7 @@ nsGenericElement::UnbindFromTree(bool aDeep, bool aNullParent) nsNodeUtils::ParentChainChanged(this); } +#if 0 already_AddRefed nsGenericElement::GetChildren(PRUint32 aFilter) { @@ -2431,6 +2441,7 @@ nsGenericElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker) { return NS_OK; } +#endif nsICSSDeclaration* nsGenericElement::GetSMILOverrideStyle() @@ -2496,6 +2507,7 @@ nsGenericElement::SetInlineStyleRule(css::StyleRule* aStyleRule, return NS_ERROR_NOT_IMPLEMENTED; } +#if 0 NS_IMETHODIMP_(bool) nsGenericElement::IsAttributeMapped(const nsIAtom* aAttribute) const { @@ -3512,6 +3524,7 @@ nsGenericElement::PostQueryInterface(REFNSIID aIID, void** aInstancePtr) } //---------------------------------------------------------------------- +#if 0 nsresult nsGenericElement::LeaveLink(nsPresContext* aPresContext) { @@ -3548,6 +3561,7 @@ nsGenericElement::AddScriptEventListener(nsIAtom* aEventName, defer, !nsContentUtils::IsChromeDoc(ownerDoc)); return NS_OK; } +#endif //---------------------------------------------------------------------- @@ -3574,6 +3588,7 @@ nsGenericElement::CopyInnerTo(nsGenericElement* aDst) return NS_OK; } +#endif bool nsGenericElement::MaybeCheckSameAttrVal(PRInt32 aNamespaceID, @@ -3830,6 +3845,7 @@ nsGenericElement::SetMappedAttribute(nsIDocument* aDocument, return false; } +#if 0 nsEventListenerManager* nsGenericElement::GetEventListenerManagerForAttr(nsIAtom* aAttrName, bool* aDefer) @@ -3837,6 +3853,7 @@ nsGenericElement::GetEventListenerManagerForAttr(nsIAtom* aAttrName, *aDefer = true; return GetListenerManager(true); } +#endif nsGenericElement::nsAttrInfo nsGenericElement::GetAttrInfo(PRInt32 aNamespaceID, nsIAtom* aName) const @@ -4037,6 +4054,7 @@ nsGenericElement::GetAttrCount() const return mAttrsAndChildren.AttrCount(); } +#if 0 const nsTextFragment* nsGenericElement::GetText() { @@ -4084,6 +4102,7 @@ nsGenericElement::AppendTextTo(nsAString& aResult) // to depend on this appending nothing. NS_NOTREACHED("called nsGenericElement::TextLength"); } +#endif #ifdef DEBUG void @@ -4239,6 +4258,7 @@ nsGenericElement::DumpContent(FILE* out, PRInt32 aIndent, } #endif +#if 0 PRUint32 nsGenericElement::GetChildCount() const { @@ -4482,6 +4502,7 @@ nsGenericElement::GetLinkTarget(nsAString& aTarget) { aTarget.Truncate(); } +#endif // NOTE: The aPresContext pointer is NOT addrefed. // *aSelectorList might be null even if NS_OK is returned; this @@ -4523,6 +4544,7 @@ ParseSelectorList(nsINode* aNode, // Actually find elements matching aSelectorList (which must not be // null) and which are descendants of aRoot and put them in aList. If // onlyFirstMatch, then stop once the first one is found. +#if 0 template inline static nsresult FindMatchingElements(nsINode* aRoot, const nsAString& aSelector, @@ -4639,6 +4661,7 @@ nsGenericElement::doQuerySelectorAll(nsINode* aRoot, return FindMatchingElements(aRoot, aSelector, *contentList); } +#endif bool @@ -4673,6 +4696,7 @@ nsGenericElement::MozMatchesSelector(const nsAString& aSelector, bool* aReturn) return rv; } +#if 0 size_t nsGenericElement::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const { @@ -4721,6 +4745,7 @@ nsGenericElement::AttrValueToCORSMode(const nsAttrValue* aValue) return CORSMode(aValue->GetEnumValue()); } +#endif NS_IMETHODIMP nsGenericElement::GetOnmouseenter(JSContext* cx, JS::Value* vp) @@ -4804,4 +4829,3 @@ nsresult nsGenericElement::MozRequestFullScreen() return NS_OK; } -#endif diff --git a/content/base/src/nsGenericElement.h b/content/base/src/nsGenericElement.h index 32a93a2d8295..25f82b833494 100644 --- a/content/base/src/nsGenericElement.h +++ b/content/base/src/nsGenericElement.h @@ -209,7 +209,7 @@ class nsInlineEventHandlersTearoff; * A generic base class for DOM elements, implementing many nsIContent, * nsIDOMNode and nsIDOMElement methods. */ -class nsGenericElement : public mozilla::dom::FragmentOrElement +class nsGenericElement : public mozilla::dom::Element { public: nsGenericElement(already_AddRefed aNodeInfo); @@ -241,6 +241,7 @@ public: NS_IMETHOD SetTextContent(const nsAString& aTextContent); // nsIContent interface methods +#endif virtual void UpdateEditableState(bool aNotify); virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, @@ -248,9 +249,11 @@ public: bool aCompileEventHandlers); virtual void UnbindFromTree(bool aDeep = true, bool aNullParent = true); +#if 0 virtual already_AddRefed GetChildren(PRUint32 aFilter); virtual nsIAtom *GetClassAttributeName() const; virtual already_AddRefed GetExistingAttrNameFromQName(const nsAString& aStr) const; +#endif nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, const nsAString& aValue, bool aNotify) { @@ -299,6 +302,7 @@ public: bool aNotify); virtual const nsAttrName* GetAttrNameAt(PRUint32 aIndex) const; virtual PRUint32 GetAttrCount() const; +#if 0 virtual const nsTextFragment *GetText(); virtual PRUint32 TextLength() const; virtual nsresult SetText(const PRUnichar* aBuffer, PRUint32 aLength, @@ -318,6 +322,7 @@ public: virtual void DestroyContent(); virtual void SaveSubtreeState(); +#endif virtual nsISMILAttr* GetAnimatedAttr(PRInt32 /*aNamespaceID*/, nsIAtom* /*aName*/) { @@ -339,12 +344,15 @@ public: void ListAttributes(FILE* out) const; #endif +#if 0 virtual const nsAttrValue* DoGetClasses() const; NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker); +#endif virtual mozilla::css::StyleRule* GetInlineStyleRule(); virtual nsresult SetInlineStyleRule(mozilla::css::StyleRule* aStyleRule, const nsAString* aSerialized, bool aNotify); +#if 0 NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const; virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, @@ -387,12 +395,16 @@ public: NS_IMETHOD GetNodeValue(nsAString& aNodeValue); NS_IMETHOD SetNodeValue(const nsAString& aNodeValue); NS_IMETHOD GetNodeType(PRUint16* aNodeType); +#endif NS_IMETHOD GetAttributes(nsIDOMNamedNodeMap** aAttributes); +#if 0 NS_IMETHOD GetNamespaceURI(nsAString& aNamespaceURI); NS_IMETHOD GetPrefix(nsAString& aPrefix); NS_IMETHOD IsSupported(const nsAString& aFeature, const nsAString& aVersion, bool* aReturn); +#endif NS_IMETHOD HasAttributes(bool* aHasAttributes); +#if 0 NS_IMETHOD HasChildNodes(bool* aHasChildNodes); nsresult InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild, nsIDOMNode** aReturn) @@ -412,10 +424,12 @@ public: { return InsertBefore(aNewChild, nullptr, aReturn); } +#endif // nsIDOMElement method implementation NS_DECL_NSIDOMELEMENT +#if 0 nsresult CloneNode(bool aDeep, PRUint8 aOptionalArgc, nsIDOMNode **aResult) { if (!aOptionalArgc) { @@ -550,6 +564,7 @@ public: virtual void RecompileScriptEventListeners() { } +#endif PRInt32 GetScrollTop(); PRInt32 GetScrollLeft(); @@ -590,6 +605,7 @@ public: */ virtual nsAttrInfo GetAttrInfo(PRInt32 aNamespaceID, nsIAtom* aName) const; +#if 0 NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsGenericElement) virtual void NodeInfoChanged(nsINodeInfo* aOldNodeInfo) @@ -663,6 +679,7 @@ protected: static const bool kDontNotifyDocumentObservers = false; static const bool kCallAfterSetAttr = true; static const bool kDontCallAfterSetAttr = false; +#endif /** * Set attribute and (if needed) notify documentobservers and fire off @@ -746,6 +763,7 @@ protected: */ // Note that this is inlined so that when subclasses call it it gets // inlined. Those calls don't go through a vtable. +#if 0 virtual nsresult BeforeSetAttr(PRInt32 aNamespaceID, nsIAtom* aName, const nsAttrValueOrString* aValue, bool aNotify) @@ -790,6 +808,7 @@ protected: * Internal hook for converting an attribute name-string to an atomized name */ virtual const nsAttrName* InternalGetExistingAttrNameFromQName(const nsAString& aStr) const; +#endif /** * Retrieve the rectangle for the offsetX properties, which @@ -817,7 +836,6 @@ protected: nsresult GetAttributeNodeNSInternal(const nsAString& aNamespaceURI, const nsAString& aLocalName, nsIDOMAttr** aReturn); -#endif public: #if 0 @@ -917,6 +935,7 @@ protected: OwnerDoc()->UnregisterFreezableElement(this); } +#endif /** * Add/remove this element to the documents id cache */ @@ -941,6 +960,7 @@ protected: } } } +#if 0 /** * Functions to carry out event default actions for links of all types @@ -988,7 +1008,6 @@ protected: #endif private: -#if 0 /** * Get this element's client area rect in app units. * @return the frame's client area @@ -997,6 +1016,7 @@ private: nsIScrollableFrame* GetScrollFrame(nsIFrame **aStyledFrame = nullptr); +#if 0 nsContentList* GetChildrenList(); #endif }; diff --git a/content/base/src/nsStyledElement.h b/content/base/src/nsStyledElement.h index e55325e27881..7eb5bf0c05d5 100644 --- a/content/base/src/nsStyledElement.h +++ b/content/base/src/nsStyledElement.h @@ -68,7 +68,7 @@ protected: virtual bool ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aAttribute, const nsAString& aValue, nsAttrValue& aResult); - friend class mozilla::dom::FragmentOrElement; + friend class nsGenericElement; /** * Create the style struct from the style attr. Used when an element is diff --git a/content/smil/nsISMILAttr.h b/content/smil/nsISMILAttr.h index de1cd233d087..6d679660f63a 100644 --- a/content/smil/nsISMILAttr.h +++ b/content/smil/nsISMILAttr.h @@ -6,12 +6,13 @@ #ifndef NS_ISMILATTR_H_ #define NS_ISMILATTR_H_ -#include "nsStringFwd.h" +#include "nscore.h" class nsSMILValue; class nsISMILType; class nsISMILAnimationElement; class nsIContent; +class nsAString; //////////////////////////////////////////////////////////////////////// // nsISMILAttr: A variable targeted by SMIL for animation and can therefore have diff --git a/content/svg/content/src/SVGAttrValueWrapper.h b/content/svg/content/src/SVGAttrValueWrapper.h index 9a890a5bf9d9..8c02b73a5bb0 100644 --- a/content/svg/content/src/SVGAttrValueWrapper.h +++ b/content/svg/content/src/SVGAttrValueWrapper.h @@ -12,7 +12,7 @@ * types don't need to be exported outside the SVG module. */ -#include "nsString.h" +#include "nsStringGlue.h" class nsSVGAngle; class nsSVGIntegerPair; From a5142cc25911c15edecfd96c6c250ec847de47af Mon Sep 17 00:00:00 2001 From: Honza Bambas Date: Tue, 31 Jul 2012 20:59:17 +0200 Subject: [PATCH 005/114] Bug 766210 - Delay updating nsPrefetchNode's reference to redirect channel until we know redirect is approved, r=jduell --- uriloader/prefetch/nsPrefetchService.cpp | 29 +++++++++++++++++++++--- uriloader/prefetch/nsPrefetchService.h | 4 ++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/uriloader/prefetch/nsPrefetchService.cpp b/uriloader/prefetch/nsPrefetchService.cpp index 61a42bab90a6..88aa4e0964ec 100644 --- a/uriloader/prefetch/nsPrefetchService.cpp +++ b/uriloader/prefetch/nsPrefetchService.cpp @@ -220,12 +220,13 @@ nsPrefetchNode::CancelChannel(nsresult error) // nsPrefetchNode::nsISupports //----------------------------------------------------------------------------- -NS_IMPL_ISUPPORTS5(nsPrefetchNode, +NS_IMPL_ISUPPORTS6(nsPrefetchNode, nsIDOMLoadStatus, nsIRequestObserver, nsIStreamListener, nsIInterfaceRequestor, - nsIChannelEventSink) + nsIChannelEventSink, + nsIRedirectResultListener) //----------------------------------------------------------------------------- // nsPrefetchNode::nsIStreamListener @@ -325,6 +326,12 @@ nsPrefetchNode::GetInterface(const nsIID &aIID, void **aResult) return NS_OK; } + if (aIID.Equals(NS_GET_IID(nsIRedirectResultListener))) { + NS_ADDREF_THIS(); + *aResult = static_cast(this); + return NS_OK; + } + return NS_ERROR_NO_INTERFACE; } @@ -361,12 +368,28 @@ nsPrefetchNode::AsyncOnChannelRedirect(nsIChannel *aOldChannel, NS_LITERAL_CSTRING("prefetch"), false); - mChannel = aNewChannel; + // Assign to mChannel after we get notification about success of the + // redirect in OnRedirectResult. + mRedirectChannel = aNewChannel; callback->OnRedirectVerifyCallback(NS_OK); return NS_OK; } +//----------------------------------------------------------------------------- +// nsPrefetchNode::nsIRedirectResultListener +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +nsPrefetchNode::OnRedirectResult(bool proceeding) +{ + if (proceeding && mRedirectChannel) + mChannel = mRedirectChannel; + + mRedirectChannel = nsnull; + + return NS_OK; +} //----------------------------------------------------------------------------- // nsPrefetchService diff --git a/uriloader/prefetch/nsPrefetchService.h b/uriloader/prefetch/nsPrefetchService.h index 79d0882e779e..2a4b0ee9fc31 100644 --- a/uriloader/prefetch/nsPrefetchService.h +++ b/uriloader/prefetch/nsPrefetchService.h @@ -9,6 +9,7 @@ #include "nsIObserver.h" #include "nsIInterfaceRequestor.h" #include "nsIChannelEventSink.h" +#include "nsIRedirectResultListener.h" #include "nsIWebProgressListener.h" #include "nsIStreamListener.h" #include "nsIChannel.h" @@ -85,6 +86,7 @@ class nsPrefetchNode MOZ_FINAL : public nsIDOMLoadStatus , public nsIStreamListener , public nsIInterfaceRequestor , public nsIChannelEventSink + , public nsIRedirectResultListener { public: NS_DECL_ISUPPORTS @@ -93,6 +95,7 @@ public: NS_DECL_NSISTREAMLISTENER NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSICHANNELEVENTSINK + NS_DECL_NSIREDIRECTRESULTLISTENER nsPrefetchNode(nsPrefetchService *aPrefetchService, nsIURI *aURI, @@ -112,6 +115,7 @@ public: private: nsRefPtr mService; nsCOMPtr mChannel; + nsCOMPtr mRedirectChannel; PRUint16 mState; PRInt32 mBytesRead; }; From 66c7e9bfac108856319154cfcaf6a8e91aaa85c3 Mon Sep 17 00:00:00 2001 From: Honza Bambas Date: Tue, 31 Jul 2012 20:59:17 +0200 Subject: [PATCH 006/114] Bug 768568, r=kaie --- browser/base/content/test/browser_alltabslistener.js | 2 ++ security/manager/boot/src/nsSecureBrowserUIImpl.cpp | 5 ++++- security/manager/boot/src/nsSecureBrowserUIImpl.h | 1 + uriloader/base/nsDocLoader.cpp | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/browser/base/content/test/browser_alltabslistener.js b/browser/base/content/test/browser_alltabslistener.js index 07e4d117a839..4d7d11435169 100644 --- a/browser/base/content/test/browser_alltabslistener.js +++ b/browser/base/content/test/browser_alltabslistener.js @@ -131,6 +131,7 @@ function startTest2() { "onStateChange", "onLocationChange", "onSecurityChange", + "onSecurityChange", "onStateChange" ]; gFrontNotifications = gAllNotifications; @@ -155,6 +156,7 @@ function startTest4() { "onStateChange", "onLocationChange", "onSecurityChange", + "onSecurityChange", "onStateChange" ]; gFrontNotifications = []; diff --git a/security/manager/boot/src/nsSecureBrowserUIImpl.cpp b/security/manager/boot/src/nsSecureBrowserUIImpl.cpp index 66bccffd8011..292741f2e450 100644 --- a/security/manager/boot/src/nsSecureBrowserUIImpl.cpp +++ b/security/manager/boot/src/nsSecureBrowserUIImpl.cpp @@ -132,6 +132,7 @@ nsSecureBrowserUIImpl::nsSecureBrowserUIImpl() , mSubRequestsBrokenSecurity(0) , mSubRequestsNoSecurity(0) , mRestoreSubrequests(false) + , mOnLocationChangeSeen(false) #ifdef DEBUG , mOnStateLocationChangeReentranceDetection(0) #endif @@ -1217,9 +1218,10 @@ nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress, // But when the target sink changes between OnLocationChange and // OnStateChange, we have to fire the notification here (again). - if (sinkChanged) + if (sinkChanged || mOnLocationChangeSeen) return EvaluateAndUpdateSecurityState(aRequest, securityInfo, false); } + mOnLocationChangeSeen = false; if (mRestoreSubrequests && !inProgress) { @@ -1610,6 +1612,7 @@ nsSecureBrowserUIImpl::OnLocationChange(nsIWebProgress* aWebProgress, if (windowForProgress.get() == window.get()) { // For toplevel channels, update the security state right away. + mOnLocationChangeSeen = true; return EvaluateAndUpdateSecurityState(aRequest, securityInfo, true); } diff --git a/security/manager/boot/src/nsSecureBrowserUIImpl.h b/security/manager/boot/src/nsSecureBrowserUIImpl.h index 033f29f554b4..a360cfe5e5fe 100644 --- a/security/manager/boot/src/nsSecureBrowserUIImpl.h +++ b/security/manager/boot/src/nsSecureBrowserUIImpl.h @@ -95,6 +95,7 @@ protected: PRInt32 mSubRequestsBrokenSecurity; PRInt32 mSubRequestsNoSecurity; bool mRestoreSubrequests; + bool mOnLocationChangeSeen; #ifdef DEBUG /* related to mReentrantMonitor */ PRInt32 mOnStateLocationChangeReentranceDetection; diff --git a/uriloader/base/nsDocLoader.cpp b/uriloader/base/nsDocLoader.cpp index 1fdb962d3b2b..e1cf224c9628 100644 --- a/uriloader/base/nsDocLoader.cpp +++ b/uriloader/base/nsDocLoader.cpp @@ -1387,6 +1387,7 @@ nsDocLoader::FireOnLocationChange(nsIWebProgress* aWebProgress, continue; } + PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, ("DocLoader [%p] calling %p->OnLocationChange", this, listener.get())); listener->OnLocationChange(aWebProgress, aRequest, aUri, aFlags); } From 9b61c937c8e8386189e296eada0548259267be2b Mon Sep 17 00:00:00 2001 From: Honza Bambas Date: Tue, 31 Jul 2012 20:59:18 +0200 Subject: [PATCH 007/114] Bug 774243 - [Linux] Process name changes to RunProcess, r=benjamin --- xpcom/threads/nsProcess.h | 1 + xpcom/threads/nsProcessCommon.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/xpcom/threads/nsProcess.h b/xpcom/threads/nsProcess.h index 4b5a5b7b6f2f..e3435d2e022f 100644 --- a/xpcom/threads/nsProcess.h +++ b/xpcom/threads/nsProcess.h @@ -59,6 +59,7 @@ private: PRThread* mThread; mozilla::Mutex mLock; bool mShutdown; + bool mBlocking; nsCOMPtr mExecutable; nsString mTargetPath; diff --git a/xpcom/threads/nsProcessCommon.cpp b/xpcom/threads/nsProcessCommon.cpp index a15b2ae8904f..ca893ae02731 100644 --- a/xpcom/threads/nsProcessCommon.cpp +++ b/xpcom/threads/nsProcessCommon.cpp @@ -67,6 +67,7 @@ nsProcess::nsProcess() : mThread(nullptr) , mLock("nsProcess.mLock") , mShutdown(false) + , mBlocking(false) , mPid(-1) , mObserver(nullptr) , mWeakObserver(nullptr) @@ -222,9 +223,11 @@ static int assembleCmdLine(char *const *argv, PRUnichar **wideCmdLine, void PR_CALLBACK nsProcess::Monitor(void *arg) { - PR_SetCurrentThreadName("RunProcess"); - nsRefPtr process = dont_AddRef(static_cast(arg)); + + if (!process->mBlocking) + PR_SetCurrentThreadName("RunProcess"); + #if defined(PROCESSMODEL_WINAPI) DWORD dwRetVal; unsigned long exitCode = -1; @@ -507,6 +510,7 @@ nsProcess::RunProcess(bool blocking, char **my_argv, nsIObserver* observer, #endif NS_ADDREF_THIS(); + mBlocking = blocking; if (blocking) { Monitor(this); if (mExitValue < 0) From 933e8b34d65b25d5db094a60c5e6ccf36e89022f Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Tue, 31 Jul 2012 12:26:14 -0700 Subject: [PATCH 008/114] Bug 779220. Add JS_InternStringN for callers that know the length of the string. r=luke This mirrors the existing JS_InternUCStringN. --- js/src/jsapi.cpp | 8 +++++++- js/src/jsapi.h | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index cdca106e8f29..99703f260ca9 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -5955,10 +5955,16 @@ JS_InternJSString(JSContext *cx, JSString *str) JS_PUBLIC_API(JSString *) JS_InternString(JSContext *cx, const char *s) +{ + return JS_InternStringN(cx, s, strlen(s)); +} + +JS_PUBLIC_API(JSString *) +JS_InternStringN(JSContext *cx, const char *s, size_t length) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); - JSAtom *atom = js_Atomize(cx, s, strlen(s), InternAtom); + JSAtom *atom = js_Atomize(cx, s, length, InternAtom); JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom)); return atom; } diff --git a/js/src/jsapi.h b/js/src/jsapi.h index fc63a8dfe89a..fa2a8a4f11bd 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -5265,6 +5265,9 @@ JS_NewStringCopyZ(JSContext *cx, const char *s); extern JS_PUBLIC_API(JSString *) JS_InternJSString(JSContext *cx, JSString *str); +extern JS_PUBLIC_API(JSString *) +JS_InternStringN(JSContext *cx, const char *s, size_t length); + extern JS_PUBLIC_API(JSString *) JS_InternString(JSContext *cx, const char *s); From 0d2a16823ef7bb7a7663074c05a8ef528b1e9c05 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Tue, 31 Jul 2012 12:28:03 -0700 Subject: [PATCH 009/114] Bug 778307. Don't shadow mFormat in DrawTargetCG. r=bgirard This was causing problems with Azure content. --- gfx/2d/DrawTargetCG.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/gfx/2d/DrawTargetCG.h b/gfx/2d/DrawTargetCG.h index 2a505cefc0db..18d6fb0eec2d 100644 --- a/gfx/2d/DrawTargetCG.h +++ b/gfx/2d/DrawTargetCG.h @@ -163,8 +163,6 @@ private: */ void *mData; - SurfaceFormat mFormat; - RefPtr mSnapshot; }; From fe84423ccffa60bd3ba64d0f4452e438a1317d59 Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Tue, 31 Jul 2012 14:27:02 -0600 Subject: [PATCH 010/114] Bug 775227: disable one more test on Android for OOM; r=jmaher --- testing/mochitest/android.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/mochitest/android.json b/testing/mochitest/android.json index 3fd3e23ca28e..ced51fccf5ce 100644 --- a/testing/mochitest/android.json +++ b/testing/mochitest/android.json @@ -141,7 +141,7 @@ "dom/imptests/webapps/DOMCore/tests/approved/test_Range-mutations.html": "bug 775227", "dom/imptests/webapps/DOMCore/tests/approved/test_Range-set.html": "bug 775227", "dom/imptests/webapps/DOMCore/tests/approved/test_Range-surroundContents.html": "bug 775227", - + "dom/imptests/webapps/WebStorage/tests/submissions/Infraware/test_event_session_key.html": "bug 775227", "dom/indexedDB/test/test_third_party.html": "TIMED_OUT", "dom/network/tests/test_network_basics.html": "", "dom/settings/tests/test_settings_events.html": "", From 216e84af0257e5d79c29492c97a3e8bc90008940 Mon Sep 17 00:00:00 2001 From: Mark Cote Date: Wed, 25 Jul 2012 11:21:51 -0400 Subject: [PATCH 011/114] Bug 778159 Remove SUTAgent network-verification ping. r=wlach --- build/mobile/sutagent/android/RunCmdThread.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/build/mobile/sutagent/android/RunCmdThread.java b/build/mobile/sutagent/android/RunCmdThread.java index 87041b064fa3..807ed8c0236d 100755 --- a/build/mobile/sutagent/android/RunCmdThread.java +++ b/build/mobile/sutagent/android/RunCmdThread.java @@ -47,8 +47,6 @@ public class RunCmdThread extends Thread public void run() { try { - int nIterations = 0; - SvrSocket.setSoTimeout(5000); while (bListening) { @@ -61,16 +59,6 @@ public class RunCmdThread extends Thread } catch (SocketTimeoutException toe) { - if (++nIterations > 60) - { - nIterations = 0; - String sRet = SendPing("www.mozilla.org"); - if (sRet.contains("3 received")) - handler.post(new doCancelNotification()); - else - handler.post(new doSendNotification("SUTAgent - Network Connectivity Error", sRet)); - sRet = null; - } continue; } catch (IOException e) From f8fc648682f434b86487746c8d1688787debdeaf Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Tue, 31 Jul 2012 14:54:21 +1200 Subject: [PATCH 012/114] b=778031 add FinishX to XSync less frequently and use it r=cjones --HG-- extra : transplant_source : %BC%2C%80%F65%1DV%B7YVI%80%B2%FD%FE%F1%18G%06%26 --- dom/plugins/base/nsPluginNativeWindowGtk2.cpp | 3 ++- dom/plugins/ipc/PluginInstanceParent.cpp | 6 +++--- gfx/gl/GLContextProviderEGL.cpp | 2 +- gfx/gl/GLContextProviderGLX.cpp | 2 +- gfx/layers/ipc/ShadowLayerUtilsX11.cpp | 2 +- gfx/src/X11Util.cpp | 12 +++++++++++- gfx/src/X11Util.h | 13 +++++++++++++ widget/shared/nsShmImage.h | 4 ++-- 8 files changed, 34 insertions(+), 10 deletions(-) diff --git a/dom/plugins/base/nsPluginNativeWindowGtk2.cpp b/dom/plugins/base/nsPluginNativeWindowGtk2.cpp index 98a70bd530c1..034961b480c0 100644 --- a/dom/plugins/base/nsPluginNativeWindowGtk2.cpp +++ b/dom/plugins/base/nsPluginNativeWindowGtk2.cpp @@ -18,6 +18,7 @@ #include "gtk2compat.h" #include "gtk2xtbin.h" +#include "mozilla/X11Util.h" class nsPluginNativeWindowGtk2 : public nsPluginNativeWindow { public: @@ -307,6 +308,6 @@ socket_unrealize_cb(GtkWidget *widget, gpointer data) if (children) XFree(children); - XSync(display, False); + mozilla::FinishX(display); gdk_error_trap_pop(); } diff --git a/dom/plugins/ipc/PluginInstanceParent.cpp b/dom/plugins/ipc/PluginInstanceParent.cpp index 177f435232be..7a4b488ab62d 100644 --- a/dom/plugins/ipc/PluginInstanceParent.cpp +++ b/dom/plugins/ipc/PluginInstanceParent.cpp @@ -133,7 +133,7 @@ PluginInstanceParent::ActorDestroy(ActorDestroyReason why) const NPRect rect = {0, 0, 0, 0}; RecvNPN_InvalidateRect(rect); #ifdef MOZ_X11 - XSync(DefaultXDisplay(), False); + FinishX(DefaultXDisplay()); #endif } } @@ -634,7 +634,7 @@ PluginInstanceParent::RecvShow(const NPRect& updatedRect, // referencing it, so we XSync here to let them finish before // the plugin starts scribbling on it again, or worse, // destroys it. - XSync(DefaultXDisplay(), False); + FinishX(DefaultXDisplay()); #endif if (mFrontSurface && gfxSharedImageSurface::IsSharedImage(mFrontSurface)) @@ -1260,7 +1260,7 @@ PluginInstanceParent::NPP_HandleEvent(void* event) // process does not need to wait; the child is the process that needs // to wait. A possibly-slightly-better alternative would be to send // an X event to the child that the child would wait for. - XSync(DefaultXDisplay(), False); + FinishX(DefaultXDisplay()); return CallPaint(npremoteevent, &handled) ? handled : 0; diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp index ce0cde65de90..9d3cf8b4bcee 100644 --- a/gfx/gl/GLContextProviderEGL.cpp +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -1415,7 +1415,7 @@ public: if (mBackingSurface && mUpdateSurface == mBackingSurface) { #ifdef MOZ_X11 if (mBackingSurface->GetType() == gfxASurface::SurfaceTypeXlib) { - XSync(DefaultXDisplay(), False); + FinishX(DefaultXDisplay()); } #endif diff --git a/gfx/gl/GLContextProviderGLX.cpp b/gfx/gl/GLContextProviderGLX.cpp index c1e344fb480f..7ee07bf3d948 100644 --- a/gfx/gl/GLContextProviderGLX.cpp +++ b/gfx/gl/GLContextProviderGLX.cpp @@ -365,7 +365,7 @@ void GLXLibrary::AfterGLXCall() { if (mDebug) { - XSync(DefaultXDisplay(), False); + FinishX(DefaultXDisplay()); if (sErrorEvent.mError.error_code) { char buffer[2048]; XGetErrorText(DefaultXDisplay(), sErrorEvent.mError.error_code, buffer, sizeof(buffer)); diff --git a/gfx/layers/ipc/ShadowLayerUtilsX11.cpp b/gfx/layers/ipc/ShadowLayerUtilsX11.cpp index 1c69b8f2d783..64af660d22a3 100644 --- a/gfx/layers/ipc/ShadowLayerUtilsX11.cpp +++ b/gfx/layers/ipc/ShadowLayerUtilsX11.cpp @@ -187,7 +187,7 @@ ShadowLayerManager::PlatformSyncBeforeReplyUpdate() // the child, even though they will be read operations. // Otherwise, the child might start scribbling on new back buffers // that are still participating in requests as old front buffers. - XSync(DefaultXDisplay(), False); + FinishX(DefaultXDisplay()); } } diff --git a/gfx/src/X11Util.cpp b/gfx/src/X11Util.cpp index 41aed5c428cb..49c8ed085d46 100644 --- a/gfx/src/X11Util.cpp +++ b/gfx/src/X11Util.cpp @@ -37,6 +37,16 @@ XVisualIDToInfo(Display* aDisplay, VisualID aVisualID, return false; } +void +FinishX(Display* aDisplay) +{ + unsigned long lastRequest = NextRequest(aDisplay) - 1; + if (lastRequest == LastKnownRequestProcessed(aDisplay)) + return; + + XSync(aDisplay, False); +} + ScopedXErrorHandler::ErrorEvent* ScopedXErrorHandler::sXErrorPtr; int @@ -67,7 +77,7 @@ ScopedXErrorHandler::~ScopedXErrorHandler() bool ScopedXErrorHandler::SyncAndGetError(Display *dpy, XErrorEvent *ev) { - XSync(dpy, False); + FinishX(dpy); return GetError(ev); } diff --git a/gfx/src/X11Util.h b/gfx/src/X11Util.h index ece742490891..4979b182f5d0 100644 --- a/gfx/src/X11Util.h +++ b/gfx/src/X11Util.h @@ -52,6 +52,19 @@ bool XVisualIDToInfo(Display* aDisplay, VisualID aVisualID, Visual** aVisual, unsigned int* aDepth); + +/** + * Ensure that all X requests have been processed. + * + * This is similar to XSync, but doesn't need a round trip if the previous + * request was synchronous or if events have been received since the last + * request. Subsequent FinishX calls will be noops if there have been no + * intermediate requests. + */ + +void +FinishX(Display* aDisplay); + /** * Invoke XFree() on a pointer to memory allocated by Xlib (if the * pointer is nonnull) when this class goes out of scope. diff --git a/widget/shared/nsShmImage.h b/widget/shared/nsShmImage.h index d975094565b7..5026d568c214 100644 --- a/widget/shared/nsShmImage.h +++ b/widget/shared/nsShmImage.h @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 @@ -49,7 +49,7 @@ public: ~nsShmImage() { if (mImage) { - XSync(DISPLAY(), False); + mozilla::FinishX(DISPLAY()); if (mXAttached) { XShmDetach(DISPLAY(), &mInfo); } From cbf24500d047990104615dbad2e25d60831b294a Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Tue, 31 Jul 2012 14:54:21 +1200 Subject: [PATCH 013/114] b=778031 remove unnecessary ScopedXErrorHandler::GetError interface r=cjones --HG-- extra : transplant_source : %FE%EC%0A%24%1B%8A%B3%D2%94%F6%2B%23%E3%A9R%8Df%90%FF%17 --- gfx/src/X11Util.cpp | 5 ----- gfx/src/X11Util.h | 7 ------- 2 files changed, 12 deletions(-) diff --git a/gfx/src/X11Util.cpp b/gfx/src/X11Util.cpp index 49c8ed085d46..fa12c3f49b99 100644 --- a/gfx/src/X11Util.cpp +++ b/gfx/src/X11Util.cpp @@ -78,12 +78,7 @@ bool ScopedXErrorHandler::SyncAndGetError(Display *dpy, XErrorEvent *ev) { FinishX(dpy); - return GetError(ev); -} -bool -ScopedXErrorHandler::GetError(XErrorEvent *ev) -{ bool retval = mXError.mError.error_code != 0; if (ev) *ev = mXError.mError; diff --git a/gfx/src/X11Util.h b/gfx/src/X11Util.h index 4979b182f5d0..57ff6f2697d3 100644 --- a/gfx/src/X11Util.h +++ b/gfx/src/X11Util.h @@ -137,13 +137,6 @@ public: * the first one will be returned. */ bool SyncAndGetError(Display *dpy, XErrorEvent *ev = nullptr); - - /** Like SyncAndGetError, but does not sync. Faster, but only reliably catches errors in synchronous calls. - * - * \param ev this optional parameter, if set, will be filled with the XErrorEvent object. If multiple errors occurred, - * the first one will be returned. - */ - bool GetError(XErrorEvent *ev = nullptr); }; } // namespace mozilla From 81992e1377eb0ad50d9be0d4bdc30f0ba344fc51 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Tue, 31 Jul 2012 14:54:21 +1200 Subject: [PATCH 014/114] b=707722 select config in CreatePixmap to match Pixmap format r=mattwoodrow --HG-- extra : transplant_source : %EB%B9%B8%E1%F8%19%E8%D9%94%A3GX%DC%EC%AA%23%8Be%13%F5 --- gfx/gl/GLContextProviderGLX.cpp | 73 +++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 16 deletions(-) diff --git a/gfx/gl/GLContextProviderGLX.cpp b/gfx/gl/GLContextProviderGLX.cpp index 7ee07bf3d948..f550cbb95d1e 100644 --- a/gfx/gl/GLContextProviderGLX.cpp +++ b/gfx/gl/GLContextProviderGLX.cpp @@ -270,36 +270,77 @@ GLXPixmap GLXLibrary::CreatePixmap(gfxASurface* aSurface) { if (!SupportsTextureFromPixmap(aSurface)) { - return 0; + return None; } + gfxXlibSurface *xs = static_cast(aSurface); + const XRenderPictFormat *format = xs->XRenderFormat(); + if (!format || format->type != PictTypeDirect) { + return None; + } + + bool withAlpha = + aSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA; + int attribs[] = { GLX_DOUBLEBUFFER, False, GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, - GLX_BIND_TO_TEXTURE_RGBA_EXT, True, + (withAlpha ? GLX_BIND_TO_TEXTURE_RGBA_EXT + : GLX_BIND_TO_TEXTURE_RGB_EXT), True, None }; - int numFormats; - Display *display = DefaultXDisplay(); + int numConfigs = 0; + Display *display = xs->XDisplay(); int xscreen = DefaultScreen(display); - ScopedXFree cfg(xChooseFBConfig(display, - xscreen, - attribs, - &numFormats)); - if (!cfg) { - return 0; - } - NS_ABORT_IF_FALSE(numFormats > 0, - "glXChooseFBConfig() failed to match our requested format and violated its spec (!)"); + ScopedXFree cfgs(xChooseFBConfig(display, + xscreen, + attribs, + &numConfigs)); - gfxXlibSurface *xs = static_cast(aSurface); + int matchIndex = -1; + const XRenderDirectFormat& direct = format->direct; + unsigned long redMask = + static_cast(direct.redMask) << direct.red; + unsigned long greenMask = + static_cast(direct.greenMask) << direct.green; + unsigned long blueMask = + static_cast(direct.blueMask) << direct.blue; + ScopedXFree vinfo; + + for (int i = 0; i < numConfigs; i++) { + int size; + // The visual depth won't necessarily match as it may not include the + // alpha buffer, so check buffer size. + if (sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], + GLX_BUFFER_SIZE, &size) != Success || + size != format->depth) { + continue; + } + + vinfo = sGLXLibrary.xGetVisualFromFBConfig(display, cfgs[i]); + if (!vinfo || + vinfo->c_class != TrueColor || + vinfo->red_mask != redMask || + vinfo->green_mask != greenMask || + vinfo->blue_mask != blueMask ) { + continue; + } + + matchIndex = i; + } + if (matchIndex == -1) { + NS_WARNING("[GLX] Couldn't find a FBConfig matching Pixmap format"); + return None; + } int pixmapAttribs[] = { GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, - GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT, + GLX_TEXTURE_FORMAT_EXT, + (withAlpha ? GLX_TEXTURE_FORMAT_RGBA_EXT + : GLX_TEXTURE_FORMAT_RGB_EXT), None}; GLXPixmap glxpixmap = xCreatePixmap(display, - cfg[0], + cfgs[matchIndex], xs->XDrawable(), pixmapAttribs); From 2d77cb161d73a7a28307a6c13d9fc20687d12277 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Tue, 31 Jul 2012 14:54:21 +1200 Subject: [PATCH 015/114] b=687831 remove unused gIsChromium r=mattwoodrow --HG-- extra : transplant_source : %94nUe%29Y%A1%1B2g%10_%D0%DB%2B%C9%AAE%E1%F8 --- gfx/gl/GLContextProviderGLX.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/gfx/gl/GLContextProviderGLX.cpp b/gfx/gl/GLContextProviderGLX.cpp index f550cbb95d1e..2900024b7edf 100644 --- a/gfx/gl/GLContextProviderGLX.cpp +++ b/gfx/gl/GLContextProviderGLX.cpp @@ -40,7 +40,6 @@ namespace mozilla { namespace gl { static bool gIsATI = false; -static bool gIsChromium = false; static int gGLXMajorVersion = 0, gGLXMinorVersion = 0; // Check that we have at least version aMajor.aMinor . @@ -173,7 +172,6 @@ GLXLibrary::EnsureInitialized() int screen = DefaultScreen(display); const char *serverVendor = NULL; - const char *serverVersionStr = NULL; const char *extensionsStr = NULL; if (!xQueryVersion(display, &gGLXMajorVersion, &gGLXMinorVersion)) { @@ -183,7 +181,6 @@ GLXLibrary::EnsureInitialized() } serverVendor = xQueryServerString(display, screen, GLX_VENDOR); - serverVersionStr = xQueryServerString(display, screen, GLX_VERSION); if (!GLXVersionCheck(1, 1)) // Not possible to query for extensions. @@ -243,10 +240,6 @@ GLXLibrary::EnsureInitialized() } gIsATI = serverVendor && DoesStringMatch(serverVendor, "ATI"); - gIsChromium = (serverVendor && - DoesStringMatch(serverVendor, "Chromium")) || - (serverVersionStr && - DoesStringMatch(serverVersionStr, "Chromium")); mInitialized = true; return true; From bebe9debc8545d639b858b708d45d0f83ad42068 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Tue, 31 Jul 2012 14:54:21 +1200 Subject: [PATCH 016/114] b=687831 use XSync for glXWaitX with Mesa r=mattwoodrow --HG-- extra : transplant_source : I%ADPT%BA%E4%A4%C8V%D64%EF%BF%B1l%C1%D2%FEe%B8 --- gfx/gl/GLContextProviderGLX.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/gfx/gl/GLContextProviderGLX.cpp b/gfx/gl/GLContextProviderGLX.cpp index 2900024b7edf..6ac266070ffb 100644 --- a/gfx/gl/GLContextProviderGLX.cpp +++ b/gfx/gl/GLContextProviderGLX.cpp @@ -40,6 +40,7 @@ namespace mozilla { namespace gl { static bool gIsATI = false; +static bool gClientIsMesa = false; static int gGLXMajorVersion = 0, gGLXMinorVersion = 0; // Check that we have at least version aMajor.aMinor . @@ -169,10 +170,7 @@ GLXLibrary::EnsureInitialized() } Display *display = DefaultXDisplay(); - int screen = DefaultScreen(display); - const char *serverVendor = NULL; - const char *extensionsStr = NULL; if (!xQueryVersion(display, &gGLXMajorVersion, &gGLXMinorVersion)) { gGLXMajorVersion = 0; @@ -180,13 +178,13 @@ GLXLibrary::EnsureInitialized() return false; } - serverVendor = xQueryServerString(display, screen, GLX_VENDOR); - if (!GLXVersionCheck(1, 1)) // Not possible to query for extensions. return false; - extensionsStr = xQueryExtensionsString(display, screen); + const char *clientVendor = xGetClientString(display, GLX_VENDOR); + const char *serverVendor = xQueryServerString(display, screen, GLX_VENDOR); + const char *extensionsStr = xQueryExtensionsString(display, screen); GLLibraryLoader::SymLoadStruct *sym13; if (!GLXVersionCheck(1, 3)) { @@ -240,6 +238,7 @@ GLXLibrary::EnsureInitialized() } gIsATI = serverVendor && DoesStringMatch(serverVendor, "ATI"); + gClientIsMesa = clientVendor && DoesStringMatch(clientVendor, "Mesa"); mInitialized = true; return true; @@ -360,7 +359,14 @@ GLXLibrary::BindTexImage(GLXPixmap aPixmap) Display *display = DefaultXDisplay(); // Make sure all X drawing to the surface has finished before binding to a texture. - xWaitX(); + if (gClientIsMesa) { + // Using XSync instead of Mesa's glXWaitX, because its glxWaitX is a + // noop when direct rendering unless the current drawable is a + // single-buffer window. + FinishX(display); + } else { + xWaitX(); + } xBindTexImage(display, aPixmap, GLX_FRONT_LEFT_EXT, NULL); } From 127de9f9842792e3402b02646fba55aaf8a6037b Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Tue, 31 Jul 2012 14:54:36 +1200 Subject: [PATCH 017/114] b=775848 Initialize BasicShadowLayerManager::mRepeatTransaction appropriately r=BenWa --HG-- extra : transplant_source : %3F%14R%1BD%CCL%AFL4%B2%ACN%1EP%D03%F5%27D --- gfx/layers/basic/BasicLayerManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gfx/layers/basic/BasicLayerManager.cpp b/gfx/layers/basic/BasicLayerManager.cpp index 8f7a30545679..815b50f0df34 100644 --- a/gfx/layers/basic/BasicLayerManager.cpp +++ b/gfx/layers/basic/BasicLayerManager.cpp @@ -924,7 +924,8 @@ BasicLayerManager::CreateReadbackLayer() } BasicShadowLayerManager::BasicShadowLayerManager(nsIWidget* aWidget) : - BasicLayerManager(aWidget), mTargetRotation(ROTATION_0) + BasicLayerManager(aWidget), mTargetRotation(ROTATION_0), + mRepeatTransaction(false) { MOZ_COUNT_CTOR(BasicShadowLayerManager); } From c98db46db22d579ab7e1cb0e3e17e5b42dfa6ac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20=C3=81vila=20de=20Esp=C3=ADndola?= Date: Tue, 31 Jul 2012 16:44:14 -0400 Subject: [PATCH 018/114] Bug 779249 - checkin a script to create the tooltool manifests for clang. r=rail. DONTBUILD. --HG-- extra : rebase_source : db11a13de540c77e6c6317f302b840d00682b2d4 --- build/unix/build-clang/create-manifest.py | 55 +++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 build/unix/build-clang/create-manifest.py diff --git a/build/unix/build-clang/create-manifest.py b/build/unix/build-clang/create-manifest.py new file mode 100644 index 000000000000..5f6c113d632a --- /dev/null +++ b/build/unix/build-clang/create-manifest.py @@ -0,0 +1,55 @@ +#!/bin/python + +import os +import simplejson +import sys +import subprocess +import urllib +import glob + +def check_run(args): + r = subprocess.call(args) + assert r == 0 + +old_files = glob.glob('*.manifest') + ['tooltool.py', 'setup.sh'] +for f in old_files: + try: + os.unlink(f) + except: + pass + +urllib.urlretrieve('https://raw.github.com/jhford/tooltool/master/tooltool.py', + 'tooltool.py') +urllib.urlretrieve('https://hg.mozilla.org/mozilla-central/raw-file/tip/build/unix/build-clang/setup.sh', + 'setup.sh') + +check_run(['python', 'tooltool.py', '-m', 'linux32.manifest', 'add', + 'clang-linux32.tar.bz2', 'setup.sh']) +check_run(['python', 'tooltool.py', '-m', 'linux64.manifest', 'add', + 'clang-linux64.tar.bz2', 'setup.sh']) +check_run(['python', 'tooltool.py', '-m', 'darwin.manifest', 'add', + 'clang-darwin.tar.bz2', 'setup.sh']) + +def key_sort(item): + item = item[0] + if item == 'size': + return 0 + if item == 'digest': + return 1 + if item == 'algorithm': + return 3 + return 4 + +rev = os.path.basename(os.getcwd()).split('-')[1] + +for platform in ['darwin', 'linux32', 'linux64']: + old_name = 'clang-' + platform + '.tar.bz2' + manifest = platform + '.manifest' + data = eval(file(manifest).read()) + new_name = data[1]['digest'] + data[1]['filename'] = 'clang.tar.bz2' + data = [{'clang_version' : 'r%s' % rev }] + data + out = file(manifest,'w') + simplejson.dump(data, out, indent=0, item_sort_key=key_sort) + out.write('\n') + os.rename(old_name, new_name) From 083c6b4275c8141fdd180d3ad0759203ce2b0779 Mon Sep 17 00:00:00 2001 From: David Zbarsky Date: Tue, 31 Jul 2012 14:30:53 -0700 Subject: [PATCH 019/114] Fix virtual destructor warnings in dom/camera, no bug, blanket r=bz --- dom/camera/CameraCapabilities.h | 3 ++- dom/camera/DOMCameraManager.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dom/camera/CameraCapabilities.h b/dom/camera/CameraCapabilities.h index c2e529065e8e..e664a17184e2 100644 --- a/dom/camera/CameraCapabilities.h +++ b/dom/camera/CameraCapabilities.h @@ -7,12 +7,13 @@ #include "CameraControl.h" #include "nsAutoPtr.h" +#include "mozilla/Attributes.h" namespace mozilla { typedef nsresult (*ParseItemAndAddFunc)(JSContext* aCx, JSObject* aArray, PRUint32 aIndex, const char* aStart, char** aEnd); -class nsCameraCapabilities : public nsICameraCapabilities +class nsCameraCapabilities MOZ_FINAL : public nsICameraCapabilities { public: NS_DECL_ISUPPORTS diff --git a/dom/camera/DOMCameraManager.h b/dom/camera/DOMCameraManager.h index 86699c23bc36..26b20704c7c3 100644 --- a/dom/camera/DOMCameraManager.h +++ b/dom/camera/DOMCameraManager.h @@ -12,8 +12,9 @@ #include "nsIThread.h" #include "nsThreadUtils.h" #include "nsIDOMCameraManager.h" +#include "mozilla/Attributes.h" -class nsDOMCameraManager : public nsIDOMCameraManager +class nsDOMCameraManager MOZ_FINAL : public nsIDOMCameraManager { public: NS_DECL_ISUPPORTS From c1e342445bc5fd86430410a7680097f4351daee7 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Tue, 31 Jul 2012 17:34:06 -0400 Subject: [PATCH 020/114] Bug 763166 - Fix race condition that could result in using an uninitialized AndroidBridge. r=snorp --- widget/android/AndroidBridge.cpp | 11 +++++------ widget/android/AndroidBridge.h | 3 +-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index 6d8bfd78aa34..bf7d362fdbfe 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -59,7 +59,7 @@ class AndroidRefable { // This isn't in AndroidBridge.h because including StrongPointer.h there is gross static android::sp (*android_SurfaceTexture_getNativeWindow)(JNIEnv* env, jobject surfaceTexture) = nullptr; -AndroidBridge * +void AndroidBridge::ConstructBridge(JNIEnv *jEnv, jclass jGeckoAppShellClass) { @@ -73,12 +73,11 @@ AndroidBridge::ConstructBridge(JNIEnv *jEnv, PR_NewThreadPrivateIndex(&sJavaEnvThreadIndex, JavaThreadDetachFunc); - sBridge = new AndroidBridge(); - if (!sBridge->Init(jEnv, jGeckoAppShellClass)) { - delete sBridge; - sBridge = 0; + AndroidBridge *bridge = new AndroidBridge(); + if (!bridge->Init(jEnv, jGeckoAppShellClass)) { + delete bridge; } - return sBridge; + sBridge = bridge; } bool diff --git a/widget/android/AndroidBridge.h b/widget/android/AndroidBridge.h index e0bc94ea9239..a92168cdbd04 100644 --- a/widget/android/AndroidBridge.h +++ b/widget/android/AndroidBridge.h @@ -101,8 +101,7 @@ public: LAYER_CLIENT_TYPE_GL = 2 // AndroidGeckoGLLayerClient }; - static AndroidBridge *ConstructBridge(JNIEnv *jEnv, - jclass jGeckoAppShellClass); + static void ConstructBridge(JNIEnv *jEnv, jclass jGeckoAppShellClass); static AndroidBridge *Bridge() { return sBridge; From e93421594b51ec164660f342c99e2dc50c193e3d Mon Sep 17 00:00:00 2001 From: Till Schneidereit Date: Tue, 10 Jul 2012 00:11:39 +0200 Subject: [PATCH 021/114] Bug 462300 - Add support for self-hosting syntax and operations (r=luke) --HG-- extra : rebase_source : 82852ba6bf800e4d87f64b178a963e71323af391 --- js/src/frontend/BytecodeEmitter.cpp | 77 ++++++++++++++++++++++------- js/src/frontend/ParseNode-inl.h | 2 +- js/src/frontend/ParseNode.h | 1 + js/src/frontend/Parser.cpp | 33 ++++++++++++- js/src/frontend/Parser.h | 7 +++ js/src/js.msg | 1 + js/src/jsanalyze.cpp | 2 + js/src/jsapi.cpp | 3 +- js/src/jsapi.h | 4 +- js/src/jsatom.tbl | 1 + js/src/jsinfer.cpp | 6 ++- js/src/jsinterp.cpp | 15 +++++- js/src/jsinterpinlines.h | 12 +++++ js/src/jsopcode.tbl | 12 ++++- js/src/jsopcodeinlines.h | 5 ++ js/src/methodjit/Compiler.cpp | 16 ++++++ js/src/methodjit/Compiler.h | 1 + js/src/vm/GlobalObject-inl.h | 7 +++ js/src/vm/GlobalObject.cpp | 15 +++++- js/src/vm/GlobalObject.h | 19 ++++++- js/src/vm/Xdr.h | 2 +- 21 files changed, 210 insertions(+), 31 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 5435accb1eb1..b36770481124 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -1209,7 +1209,7 @@ TryConvertToGname(BytecodeEmitter *bce, ParseNode *pn, JSOp *op) static bool BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) { - JS_ASSERT(pn->isKind(PNK_NAME)); + JS_ASSERT(pn->isKind(PNK_NAME) || pn->isKind(PNK_INTRINSICNAME)); /* Don't attempt if 'pn' is already bound or deoptimized or a nop. */ JSOp op = pn->getOp(); @@ -1746,6 +1746,9 @@ EmitNameOp(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool callContext) case JSOP_NAME: op = JSOP_CALLNAME; break; + case JSOP_INTRINSICNAME: + op = JSOP_CALLINTRINSIC; + break; case JSOP_GETGNAME: op = JSOP_CALLGNAME; break; @@ -5332,12 +5335,54 @@ EmitCallOrNew(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top) * value required for calls (which non-strict mode functions * will box into the global object). */ + uint32_t argc = pn->pn_count - 1; + bool emitArgs = true; ParseNode *pn2 = pn->pn_head; switch (pn2->getKind()) { case PNK_NAME: if (!EmitNameOp(cx, bce, pn2, callop)) return false; break; + case PNK_INTRINSICNAME: + if (pn2->atom() == cx->runtime->atomState._CallFunctionAtom) + { + /* + * Special-casing of %_CallFunction to emit bytecode that directly + * invokes the callee with the correct |this| object and arguments. + * The call %_CallFunction(receiver, ...args, fun) thus becomes: + * - emit lookup for fun + * - emit lookup for receiver + * - emit lookups for ...args + * + * argc is set to the amount of actually emitted args and the + * emitting of args below is disabled by setting emitArgs to false. + */ + if (pn->pn_count < 3) { + bce->reportError(pn, JSMSG_MORE_ARGS_NEEDED, "%_CallFunction", "1", "s"); + return false; + } + ParseNode *funNode = pn2->pn_next; + while (funNode->pn_next) + funNode = funNode->pn_next; + if (!EmitTree(cx, bce, funNode)) + return false; + ParseNode *receiver = pn2->pn_next; + if (!EmitTree(cx, bce, receiver)) + return false; + bool oldInForInit = bce->inForInit; + bce->inForInit = false; + for (ParseNode *argpn = receiver->pn_next; argpn != funNode; argpn = argpn->pn_next) { + if (!EmitTree(cx, bce, argpn)) + return false; + } + bce->inForInit = oldInForInit; + argc -= 2; + emitArgs = false; + break; + } + if (!EmitNameOp(cx, bce, pn2, callop)) + return false; + break; case PNK_DOT: if (!EmitPropOp(cx, pn2, pn2->getOp(), bce, callop)) return false; @@ -5364,25 +5409,23 @@ EmitCallOrNew(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top) if (!callop && Emit1(cx, bce, JSOP_UNDEFINED) < 0) return false; - /* Remember start of callable-object bytecode for decompilation hint. */ - ptrdiff_t off = top; - - /* - * Emit code for each argument in order, then emit the JSOP_*CALL or - * JSOP_NEW bytecode with a two-byte immediate telling how many args - * were pushed on the operand stack. - */ - bool oldInForInit = bce->inForInit; - bce->inForInit = false; - for (ParseNode *pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) { - if (!EmitTree(cx, bce, pn3)) - return false; + if (emitArgs) { + /* + * Emit code for each argument in order, then emit the JSOP_*CALL or + * JSOP_NEW bytecode with a two-byte immediate telling how many args + * were pushed on the operand stack. + */ + bool oldInForInit = bce->inForInit; + bce->inForInit = false; + for (ParseNode *pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) { + if (!EmitTree(cx, bce, pn3)) + return false; + } + bce->inForInit = oldInForInit; } - bce->inForInit = oldInForInit; - if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - off) < 0) + if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - top) < 0) return false; - uint32_t argc = pn->pn_count - 1; if (Emit3(cx, bce, pn->getOp(), ARGC_HI(argc), ARGC_LO(argc)) < 0) return false; CheckTypeSet(cx, bce, pn->getOp()); diff --git a/js/src/frontend/ParseNode-inl.h b/js/src/frontend/ParseNode-inl.h index dfdd21e13af5..a0276a7cd860 100644 --- a/js/src/frontend/ParseNode-inl.h +++ b/js/src/frontend/ParseNode-inl.h @@ -35,7 +35,7 @@ UpvarCookie::set(JSContext *cx, unsigned newLevel, uint16_t newSlot) inline PropertyName * ParseNode::atom() const { - JS_ASSERT(isKind(PNK_FUNCTION) || isKind(PNK_NAME)); + JS_ASSERT(isKind(PNK_FUNCTION) || isKind(PNK_NAME) || isKind(PNK_INTRINSICNAME)); JSAtom *atom = isKind(PNK_FUNCTION) ? pn_funbox->function()->atom : pn_atom; return atom->asPropertyName(); } diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 1c49f0bca67b..6ba25355da25 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -98,6 +98,7 @@ enum ParseNodeKind { PNK_LP, PNK_RP, PNK_NAME, + PNK_INTRINSICNAME, PNK_NUMBER, PNK_STRING, PNK_REGEXP, diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 376323748ec9..90831d6ba2ee 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -117,7 +117,8 @@ Parser::Parser(JSContext *cx, const CompileOptions &options, sct(NULL), keepAtoms(cx->runtime), foldConstants(foldConstants), - compileAndGo(options.compileAndGo) + compileAndGo(options.compileAndGo), + allowIntrinsicsCalls(options.allowIntrinsicsCalls) { cx->activeCompilations++; } @@ -6497,6 +6498,30 @@ Parser::identifierName(bool afterDoubleDot) return node; } +ParseNode * +Parser::intrinsicName() +{ + JS_ASSERT(tokenStream.isCurrentTokenType(TOK_MOD)); + if (tokenStream.getToken() != TOK_NAME) { + reportError(NULL, JSMSG_SYNTAX_ERROR); + return NULL; + } + + PropertyName *name = tokenStream.currentToken().name(); + if (!(name == context->runtime->atomState._CallFunctionAtom || + context->global()->hasIntrinsicFunction(context, name))) + { + reportError(NULL, JSMSG_INTRINSIC_NOT_DEFINED, JS_EncodeString(context, name)); + return NULL; + } + ParseNode *node = NameNode::create(PNK_INTRINSICNAME, name, this, this->tc); + if (!node) + return NULL; + JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NAME); + node->setOp(JSOP_INTRINSICNAME); + return node; +} + #if JS_HAS_XML_SUPPORT ParseNode * Parser::starOrAtPropertyIdentifier(TokenKind tt) @@ -7054,6 +7079,12 @@ Parser::primaryExpr(TokenKind tt, bool afterDoubleDot) case TOK_NULL: return new_(tokenStream.currentToken().pos); + case TOK_MOD: + if (allowIntrinsicsCalls) + return intrinsicName(); + else + goto syntaxerror; + case TOK_ERROR: /* The scanner or one of its subroutines reported the error. */ return NULL; diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 4a1845f40b80..3778d64f342d 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -54,6 +54,12 @@ struct Parser : private AutoGCRooter /* Script can optimize name references based on scope chain. */ const bool compileAndGo:1; + /* + * Self-hosted scripts can use the special syntax %funName(..args) to call + * internal functions. + */ + const bool allowIntrinsicsCalls:1; + public: Parser(JSContext *cx, const CompileOptions &options, const jschar *chars, size_t length, bool foldConstants); @@ -230,6 +236,7 @@ struct Parser : private AutoGCRooter bool checkForFunctionNode(PropertyName *name, ParseNode *node); ParseNode *identifierName(bool afterDoubleDot); + ParseNode *intrinsicName(); #if JS_HAS_XML_SUPPORT // True if E4X syntax is allowed in the current syntactic context. Note this diff --git a/js/src/js.msg b/js/src/js.msg index 49946d1ace9c..70a1e9368adf 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -352,3 +352,4 @@ MSG_DEF(JSMSG_FUNCTION_ARGUMENTS_AND_REST, 298, 0, JSEXN_ERR, "the 'arguments' p MSG_DEF(JSMSG_REST_WITH_DEFAULT, 299, 0, JSEXN_SYNTAXERR, "rest parameter may not have a default") MSG_DEF(JSMSG_NONDEFAULT_FORMAL_AFTER_DEFAULT, 300, 0, JSEXN_SYNTAXERR, "parameter(s) with default followed by parameter without default") MSG_DEF(JSMSG_YIELD_IN_DEFAULT, 301, 0, JSEXN_SYNTAXERR, "yield in default expression") +MSG_DEF(JSMSG_INTRINSIC_NOT_DEFINED, 302, 1, JSEXN_REFERENCEERR, "no intrinsic function {0}") diff --git a/js/src/jsanalyze.cpp b/js/src/jsanalyze.cpp index 0f38dd8ca104..a3bb7a75e7f7 100644 --- a/js/src/jsanalyze.cpp +++ b/js/src/jsanalyze.cpp @@ -570,6 +570,8 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx) case JSOP_RETRVAL: case JSOP_GETGNAME: case JSOP_CALLGNAME: + case JSOP_INTRINSICNAME: + case JSOP_CALLINTRINSIC: case JSOP_SETGNAME: case JSOP_REGEXP: case JSOP_OBJECT: diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 99703f260ca9..a08e5982cca3 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -5067,7 +5067,8 @@ JS::CompileOptions::CompileOptions(JSContext *cx) filename(NULL), lineno(1), compileAndGo(cx->hasRunOption(JSOPTION_COMPILE_N_GO)), - noScriptRval(cx->hasRunOption(JSOPTION_NO_SCRIPT_RVAL)) + noScriptRval(cx->hasRunOption(JSOPTION_NO_SCRIPT_RVAL)), + allowIntrinsicsCalls(false) { } diff --git a/js/src/jsapi.h b/js/src/jsapi.h index fa2a8a4f11bd..26a97926079b 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -4090,7 +4090,7 @@ struct JSClass { * with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was * prevously allowed, but is now an ES5 violation and thus unsupported. */ -#define JSCLASS_GLOBAL_SLOT_COUNT (JSProto_LIMIT * 3 + 23) +#define JSCLASS_GLOBAL_SLOT_COUNT (JSProto_LIMIT * 3 + 24) #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \ (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n))) #define JSCLASS_GLOBAL_FLAGS \ @@ -4962,6 +4962,7 @@ struct CompileOptions { unsigned lineno; bool compileAndGo; bool noScriptRval; + bool allowIntrinsicsCalls; CompileOptions(JSContext *cx); CompileOptions &setPrincipals(JSPrincipals *p) { principals = p; return *this; } @@ -4973,6 +4974,7 @@ struct CompileOptions { } CompileOptions &setCompileAndGo(bool cng) { compileAndGo = cng; return *this; } CompileOptions &setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; } + CompileOptions &setAllowIntrinsicsCalls(bool aic) { allowIntrinsicsCalls = aic; return *this; } }; extern JS_PUBLIC_API(JSScript *) diff --git a/js/src/jsatom.tbl b/js/src/jsatom.tbl index 92f45d08fffa..4b6c45b5295a 100644 --- a/js/src/jsatom.tbl +++ b/js/src/jsatom.tbl @@ -149,3 +149,4 @@ DEFINE_ATOM(unescape, "unescape") DEFINE_ATOM(uneval, "uneval") DEFINE_ATOM(unwatch, "unwatch") DEFINE_ATOM(watch, "watch") +DEFINE_ATOM(_CallFunction, "_CallFunction") diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 3a0353e2a72f..c00a634f20dd 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -3394,11 +3394,13 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, } case JSOP_NAME: - case JSOP_CALLNAME: { + case JSOP_INTRINSICNAME: + case JSOP_CALLNAME: + case JSOP_CALLINTRINSIC: { TypeSet *seen = bytecodeTypes(pc); addTypeBarrier(cx, pc, seen, Type::UnknownType()); seen->addSubset(cx, &pushed[0]); - if (op == JSOP_CALLNAME) + if (op == JSOP_CALLNAME || op == JSOP_CALLINTRINSIC) pushed[0].addPropagateThis(cx, script, pc, Type::UnknownType()); break; } diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index d788a3d90dc4..3aee00d50f2d 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -1418,8 +1418,6 @@ ADD_EMPTY_CASE(JSOP_NOP) ADD_EMPTY_CASE(JSOP_UNUSED1) ADD_EMPTY_CASE(JSOP_UNUSED2) ADD_EMPTY_CASE(JSOP_UNUSED3) -ADD_EMPTY_CASE(JSOP_UNUSED8) -ADD_EMPTY_CASE(JSOP_UNUSED9) ADD_EMPTY_CASE(JSOP_UNUSED10) ADD_EMPTY_CASE(JSOP_UNUSED11) ADD_EMPTY_CASE(JSOP_UNUSED12) @@ -2524,6 +2522,19 @@ BEGIN_CASE(JSOP_CALLNAME) } END_CASE(JSOP_NAME) +BEGIN_CASE(JSOP_INTRINSICNAME) +BEGIN_CASE(JSOP_CALLINTRINSIC) +{ + RootedValue &rval = rootValue0; + + if (!IntrinsicNameOperation(cx, script, regs.pc, rval.address())) + goto error; + + PUSH_COPY(rval); + TypeScript::Monitor(cx, script, regs.pc, rval); +} +END_CASE(JSOP_INTRINSICNAME) + BEGIN_CASE(JSOP_UINT16) PUSH_INT32((int32_t) GET_UINT16(regs.pc)); END_CASE(JSOP_UINT16) diff --git a/js/src/jsinterpinlines.h b/js/src/jsinterpinlines.h index e0e2a12b6ce5..0183145c8579 100644 --- a/js/src/jsinterpinlines.h +++ b/js/src/jsinterpinlines.h @@ -21,6 +21,7 @@ #include "jsfuninlines.h" #include "jsinferinlines.h" +#include "jsopcodeinlines.h" #include "jspropertycacheinlines.h" #include "jstypedarrayinlines.h" @@ -359,6 +360,17 @@ SetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, const Val return true; } +inline bool +IntrinsicNameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, Value *vp) +{ + JSOp op = JSOp(*pc); + RootedPropertyName name(cx); + name = GetNameFromBytecode(cx, script, pc, op); + JSFunction *fun = cx->global()->getIntrinsicFunction(cx, name); + vp->setObject(*fun); + return true; +} + inline bool NameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, Value *vp) { diff --git a/js/src/jsopcode.tbl b/js/src/jsopcode.tbl index f531bdaa28b6..127e59482959 100644 --- a/js/src/jsopcode.tbl +++ b/js/src/jsopcode.tbl @@ -350,9 +350,17 @@ OPDEF(JSOP_DECALIASEDVAR, 140,"decaliasedvar",NULL, 10, 0, 1, 15, JOF_SCOPEC OPDEF(JSOP_ALIASEDVARINC, 141,"aliasedvarinc",NULL, 10, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) OPDEF(JSOP_ALIASEDVARDEC, 142,"aliasedvardec",NULL, 10, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) +/* + * Intrinsic names have the syntax %name and can only be used when the + * CompileOptions flag "allowIntrinsicsCalls" is set. + * + * They are used to access intrinsic functions the runtime doesn't give + * client JS code access to from self-hosted code. + */ +OPDEF(JSOP_INTRINSICNAME, 143, "intrinsicname", NULL, 5, 0, 1, 19, JOF_ATOM|JOF_NAME|JOF_TYPESET) +OPDEF(JSOP_CALLINTRINSIC, 144, "callintrinsic", NULL, 5, 0, 1, 19, JOF_ATOM|JOF_NAME|JOF_TYPESET) + /* Unused. */ -OPDEF(JSOP_UNUSED8, 143,"unused8", NULL, 1, 0, 0, 0, JOF_BYTE) -OPDEF(JSOP_UNUSED9, 144,"unused9", NULL, 1, 0, 0, 0, JOF_BYTE) OPDEF(JSOP_UNUSED10, 145,"unused10", NULL, 1, 0, 0, 0, JOF_BYTE) OPDEF(JSOP_UNUSED11, 146,"unused11", NULL, 1, 0, 0, 0, JOF_BYTE) OPDEF(JSOP_UNUSED12, 147,"unused12", NULL, 1, 0, 0, 0, JOF_BYTE) diff --git a/js/src/jsopcodeinlines.h b/js/src/jsopcodeinlines.h index 94f8c6b69d44..ae05985d5aa0 100644 --- a/js/src/jsopcodeinlines.h +++ b/js/src/jsopcodeinlines.h @@ -4,6 +4,9 @@ * 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/. */ +#ifndef jsopcodeinlines_h__ +#define jsopcodeinlines_h__ + #include "jsautooplen.h" #include "frontend/BytecodeEmitter.h" @@ -118,3 +121,5 @@ public: }; } + +#endif /* jsopcodeinlines_h__ */ diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp index 2b377f7d62c6..933f1b0fe282 100644 --- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -2645,6 +2645,15 @@ mjit::Compiler::generateMethod() } END_CASE(JSOP_NAME) + BEGIN_CASE(JSOP_INTRINSICNAME) + BEGIN_CASE(JSOP_CALLINTRINSIC) + { + PropertyName *name = script->getName(GET_UINT32_INDEX(PC)); + jsop_intrinsicname(name, knownPushedType(0)); + frame.extra(frame.peek(-1)).name = name; + } + END_CASE(JSOP_INTRINSICNAME) + BEGIN_CASE(JSOP_IMPLICITTHIS) { prepareStubCall(Uses(0)); @@ -5552,6 +5561,13 @@ mjit::Compiler::jsop_setprop(PropertyName *name, bool popGuaranteed) return true; } +void +mjit::Compiler::jsop_intrinsicname(PropertyName *name, JSValueType type) +{ + JSFunction *fun = cx->global().get()->getIntrinsicFunction(cx, name); + frame.push(ObjectValue(*fun)); +} + void mjit::Compiler::jsop_name(PropertyName *name, JSValueType type) { diff --git a/js/src/methodjit/Compiler.h b/js/src/methodjit/Compiler.h index dbe671975ea2..79b3ddc3d44a 100644 --- a/js/src/methodjit/Compiler.h +++ b/js/src/methodjit/Compiler.h @@ -653,6 +653,7 @@ private: bool jsop_setprop(PropertyName *name, bool popGuaranteed); void jsop_setprop_slow(PropertyName *name); bool jsop_instanceof(); + void jsop_intrinsicname(PropertyName *name, JSValueType type); void jsop_name(PropertyName *name, JSValueType type); bool jsop_xname(PropertyName *name); void enterBlock(StaticBlockObject *block); diff --git a/js/src/vm/GlobalObject-inl.h b/js/src/vm/GlobalObject-inl.h index ad350e4b0975..ef014c7a3dea 100644 --- a/js/src/vm/GlobalObject-inl.h +++ b/js/src/vm/GlobalObject-inl.h @@ -213,6 +213,13 @@ GlobalObject::setProtoGetter(JSFunction *protoGetter) setSlot(PROTO_GETTER, ObjectValue(*protoGetter)); } +void +GlobalObject::setIntrinsicsHolder(JSObject *obj) +{ + JS_ASSERT(getSlotRef(INTRINSICS).isUndefined()); + setSlot(INTRINSICS, ObjectValue(*obj)); +} + } // namespace js #endif diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index 411baf6b0c32..f26145ad2d74 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -173,6 +173,10 @@ ProtoSetter(JSContext *cx, unsigned argc, Value *vp) return CallNonGenericMethod(cx, TestProtoSetterThis, ProtoSetterImpl, args); } +JSFunctionSpec intrinsic_functions[] = { + JS_FN("ThrowTypeError", ThrowTypeError, 0,0), + JS_FS_END +}; JSObject * GlobalObject::initFunctionAndObjectClasses(JSContext *cx) { @@ -369,14 +373,20 @@ GlobalObject::initFunctionAndObjectClasses(JSContext *cx) self->setOriginalEval(evalobj); /* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */ - RootedFunction throwTypeError(cx); - throwTypeError = js_NewFunction(cx, NULL, ThrowTypeError, 0, 0, self, NULL); + RootedFunction throwTypeError(cx, js_NewFunction(cx, NULL, ThrowTypeError, 0, 0, self, NULL)); if (!throwTypeError) return NULL; if (!throwTypeError->preventExtensions(cx)) return NULL; self->setThrowTypeError(throwTypeError); + RootedObject intrinsicsHolder(cx, JS_NewObject(cx, NULL, NULL, self)); + if (!intrinsicsHolder) + return NULL; + self->setIntrinsicsHolder(intrinsicsHolder); + if (!JS_DefineFunctions(cx, intrinsicsHolder, intrinsic_functions)) + return NULL; + /* * The global object should have |Object.prototype| as its [[Prototype]]. * Eventually we'd like to have standard classes be there from the start, @@ -482,6 +492,7 @@ GlobalObject::clear(JSContext *cx) setSlot(EVAL, UndefinedValue()); setSlot(CREATE_DATAVIEW_FOR_THIS, UndefinedValue()); setSlot(THROWTYPEERROR, UndefinedValue()); + setSlot(INTRINSICS, UndefinedValue()); setSlot(PROTO_GETTER, UndefinedValue()); /* diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index d2e0b90a4130..ce3f4a952b48 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -100,9 +100,10 @@ class GlobalObject : public JSObject static const unsigned RUNTIME_CODEGEN_ENABLED = FUNCTION_NS + 1; static const unsigned FLAGS = RUNTIME_CODEGEN_ENABLED + 1; static const unsigned DEBUGGERS = FLAGS + 1; + static const unsigned INTRINSICS = DEBUGGERS + 1; /* Total reserved-slot count for global objects. */ - static const unsigned RESERVED_SLOTS = DEBUGGERS + 1; + static const unsigned RESERVED_SLOTS = INTRINSICS + 1; void staticAsserts() { /* @@ -135,6 +136,8 @@ class GlobalObject : public JSObject inline void setOriginalEval(JSObject *evalobj); inline void setProtoGetter(JSFunction *protoGetter); + inline void setIntrinsicsHolder(JSObject *obj); + Value getConstructor(JSProtoKey key) const { JS_ASSERT(key <= JSProto_LIMIT); return getSlot(key); @@ -360,6 +363,20 @@ class GlobalObject : public JSObject return &self->getPrototype(JSProto_DataView).toObject(); } + bool hasIntrinsicFunction(JSContext *cx, PropertyName *name) { + RootedObject holder(cx, &getSlotRef(INTRINSICS).toObject()); + Value fun = NullValue(); + return HasDataProperty(cx, holder, NameToId(name), &fun); + } + + JSFunction *getIntrinsicFunction(JSContext *cx, PropertyName *name) { + RootedObject holder(cx, &getSlotRef(INTRINSICS).toObject()); + Value fun = NullValue(); + DebugOnly ok = HasDataProperty(cx, holder, NameToId(name), &fun); + JS_ASSERT(ok); + return fun.toObject().toFunction(); + } + inline RegExpStatics *getRegExpStatics() const; JSObject *getThrowTypeError() const { diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index 4514bdeb6112..52677f042574 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -25,7 +25,7 @@ namespace js { * and saved versions. If deserialization fails, the data should be * invalidated if possible. */ -static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 124); +static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 125); class XDRBuffer { public: From c40afc7692f5fa69a80c18344c9bcc00b4af2f3d Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Tue, 31 Jul 2012 15:25:41 -0700 Subject: [PATCH 022/114] Bug 779038 - Add an Evaluate variant which can read files. r=jimb --- js/src/jsapi.cpp | 56 +++++++++++++++++++++++++++++++++++---------- js/src/jsapi.h | 4 ++++ js/src/shell/js.cpp | 14 +++++------- 3 files changed, 54 insertions(+), 20 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index a08e5982cca3..b252717572ce 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -5058,6 +5058,28 @@ ReadCompleteFile(JSContext *cx, FILE *fp, FileContents &buffer) return true; } +/* + * Open a source file for reading. Supports "-" and NULL to mean stdin. The + * return value must be fclosed unless it is stdin. + */ +static FILE * +OpenFile(JSContext *cx, const char *filename) +{ + FILE *fp; + if (!filename || strcmp(filename, "-") == 0) { + fp = stdin; + } else { + fp = fopen(filename, "r"); + if (!fp) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN, + filename, "No such file or directory"); + return NULL; + } + } + return fp; +} + + JS::CompileOptions::CompileOptions(JSContext *cx) : principals(NULL), originPrincipals(NULL), @@ -5123,18 +5145,10 @@ JS::Compile(JSContext *cx, HandleObject obj, CompileOptions options, FILE *fp) JSScript * JS::Compile(JSContext *cx, HandleObject obj, CompileOptions options, const char *filename) { - FILE *fp; - if (!filename || strcmp(filename, "-") == 0) { - fp = stdin; - } else { - fp = fopen(filename, "r"); - if (!fp) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN, - filename, "No such file or directory"); - return NULL; - } - } - + FILE *fp = OpenFile(cx, filename); + if (!fp) + return NULL; + options = options.setFileAndLine(filename, 1); JSScript *script = Compile(cx, obj, options, fp); if (fp != stdin) fclose(fp); @@ -5625,6 +5639,24 @@ JS::Evaluate(JSContext *cx, HandleObject obj, CompileOptions options, return ok; } +extern JS_PUBLIC_API(bool) +JS::Evaluate(JSContext *cx, HandleObject obj, CompileOptions options, + const char *filename, jsval *rval) +{ + FILE *fp = OpenFile(cx, filename); + if (!fp) + return NULL; + FileContents buffer(cx); + bool ok = ReadCompleteFile(cx, fp, buffer); + if (fp != stdin) + fclose(fp); + if (!ok) + return NULL; + + options = options.setFileAndLine(filename, 1); + return Evaluate(cx, obj, options, buffer.begin(), buffer.length(), rval); +} + JS_PUBLIC_API(JSBool) JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj_, JSPrincipals *principals, diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 26a97926079b..f6a0d3526001 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -5138,6 +5138,10 @@ extern JS_PUBLIC_API(bool) Evaluate(JSContext *cx, JSHandleObject obj, CompileOptions options, const char *bytes, size_t length, jsval *rval); +extern JS_PUBLIC_API(bool) +Evaluate(JSContext *cx, JSHandleObject obj, CompileOptions options, + const char *filename, jsval *rval); + } /* namespace JS */ JS_BEGIN_EXTERN_C diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index d9370efba8d6..d99030bf7147 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -713,15 +713,13 @@ Load(JSContext *cx, unsigned argc, jsval *vp) if (!filename) return false; errno = 0; - uint32_t oldopts = JS_GetOptions(cx); - JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL); - JSScript *script = JS_CompileUTF8File(cx, thisobj, filename.ptr()); - JS_SetOptions(cx, oldopts); - if (!script) - return false; - - if (!compileOnly && !JS_ExecuteScript(cx, thisobj, script, NULL)) + CompileOptions opts(cx); + opts.setCompileAndGo(true).setNoScriptRval(true); + if ((compileOnly && !Compile(cx, thisobj, opts, filename.ptr())) || + !Evaluate(cx, thisobj, opts, filename.ptr(), NULL)) + { return false; + } } JS_SET_RVAL(cx, vp, JSVAL_VOID); From cd47967cb47cc12362bd9fc0ef03f3f551636e09 Mon Sep 17 00:00:00 2001 From: Michael Comella Date: Tue, 31 Jul 2012 18:26:29 -0400 Subject: [PATCH 023/114] Bug 778491 - Make about:home last tabs text correctly centered. r=sriram --- mobile/android/base/resources/layout/abouthome_last_tabs_row.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/mobile/android/base/resources/layout/abouthome_last_tabs_row.xml b/mobile/android/base/resources/layout/abouthome_last_tabs_row.xml index e904b0d70c27..48ec7182957b 100644 --- a/mobile/android/base/resources/layout/abouthome_last_tabs_row.xml +++ b/mobile/android/base/resources/layout/abouthome_last_tabs_row.xml @@ -21,6 +21,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/last_tab_favicon" + android:layout_marginTop="2dip" android:layout_marginLeft="12dip" android:layout_marginRight="12dip" android:textSize="15sp" From 0f58ba8dce3a4bf5969ad25d750ab24c711b6d3a Mon Sep 17 00:00:00 2001 From: Michael Comella Date: Tue, 31 Jul 2012 18:26:29 -0400 Subject: [PATCH 024/114] Bug 778862 - Change match_parent tags to fill_parent. r=sriram --- mobile/android/base/GeckoApp.java | 4 ++-- .../base/resources/layout/font_size_preference.xml | 12 ++++++------ .../android/base/resources/layout/sync_send_tab.xml | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index 53253c1072aa..2bf8b58e7ec1 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -1382,8 +1382,8 @@ abstract public class GeckoApp mFullScreenPluginContainer = new FullScreenHolder(this); FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.FILL_PARENT, Gravity.CENTER); mFullScreenPluginContainer.addView(view, layoutParams); diff --git a/mobile/android/base/resources/layout/font_size_preference.xml b/mobile/android/base/resources/layout/font_size_preference.xml index d59f00d37ccc..a54ebe24a10a 100644 --- a/mobile/android/base/resources/layout/font_size_preference.xml +++ b/mobile/android/base/resources/layout/font_size_preference.xml @@ -4,12 +4,12 @@ - You can obtain one at http://mozilla.org/MPL/2.0/. -->