2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2009-04-23 00:21:22 -07:00
|
|
|
/* vim: set ts=2 sw=2 et tw=79: */
|
2007-03-22 10:30:00 -07:00
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is Mozilla Communicator client code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
2011-06-23 01:30:48 -07:00
|
|
|
* Ms2ger <ms2ger@gmail.com>
|
2007-03-22 10:30:00 -07:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2011-10-10 22:50:08 -07:00
|
|
|
#include "mozilla/Util.h"
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsGenericElement.h"
|
|
|
|
|
|
|
|
#include "nsDOMAttribute.h"
|
|
|
|
#include "nsDOMAttributeMap.h"
|
|
|
|
#include "nsIAtom.h"
|
2012-03-28 22:43:09 -07:00
|
|
|
#include "nsINodeInfo.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsIDOMNodeList.h"
|
|
|
|
#include "nsIDOMDocument.h"
|
|
|
|
#include "nsIContentIterator.h"
|
2011-06-23 19:18:01 -07:00
|
|
|
#include "nsEventListenerManager.h"
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
#include "nsFocusManager.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsILinkHandler.h"
|
|
|
|
#include "nsIScriptGlobalObject.h"
|
|
|
|
#include "nsIURL.h"
|
|
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "nsIFrame.h"
|
2010-02-11 09:34:01 -08:00
|
|
|
#include "nsIAnonymousContentCreator.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsPresContext.h"
|
|
|
|
#include "nsStyleConsts.h"
|
|
|
|
#include "nsString.h"
|
|
|
|
#include "nsUnicharUtils.h"
|
2011-04-21 10:35:52 -07:00
|
|
|
#include "nsEventStateManager.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIDOMEvent.h"
|
|
|
|
#include "nsIPrivateDOMEvent.h"
|
|
|
|
#include "nsDOMCID.h"
|
|
|
|
#include "nsIServiceManager.h"
|
|
|
|
#include "nsIDOMCSSStyleDeclaration.h"
|
2009-09-02 17:28:37 -07:00
|
|
|
#include "nsDOMCSSAttrDeclaration.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsINameSpaceManager.h"
|
|
|
|
#include "nsContentList.h"
|
2009-08-12 01:55:14 -07:00
|
|
|
#include "nsDOMTokenList.h"
|
2011-02-10 23:47:00 -08:00
|
|
|
#include "nsXBLPrototypeBinding.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsDOMError.h"
|
|
|
|
#include "nsDOMString.h"
|
|
|
|
#include "nsIScriptSecurityManager.h"
|
|
|
|
#include "nsIDOMMutationEvent.h"
|
|
|
|
#include "nsMutationEvent.h"
|
|
|
|
#include "nsNodeUtils.h"
|
|
|
|
#include "nsDocument.h"
|
2012-02-13 18:00:56 -08:00
|
|
|
#include "nsAttrValueOrString.h"
|
2007-07-08 17:58:15 -07:00
|
|
|
#ifdef MOZ_XUL
|
2007-05-15 18:13:47 -07:00
|
|
|
#include "nsXULElement.h"
|
2007-07-08 17:58:15 -07:00
|
|
|
#endif /* MOZ_XUL */
|
2007-09-21 02:15:42 -07:00
|
|
|
#include "nsFrameManager.h"
|
2008-02-19 23:40:04 -08:00
|
|
|
#include "nsFrameSelection.h"
|
2011-12-20 01:15:41 -08:00
|
|
|
#ifdef DEBUG
|
2012-01-10 06:19:54 -08:00
|
|
|
#include "nsRange.h"
|
2011-12-20 01:15:41 -08:00
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#include "nsBindingManager.h"
|
|
|
|
#include "nsXBLBinding.h"
|
|
|
|
#include "nsIXBLService.h"
|
|
|
|
#include "nsPIDOMWindow.h"
|
|
|
|
#include "nsPIBoxObject.h"
|
2008-03-11 17:51:12 -07:00
|
|
|
#include "nsClientRect.h"
|
2007-05-30 15:32:54 -07:00
|
|
|
#include "nsSVGUtils.h"
|
|
|
|
#include "nsLayoutUtils.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsGkAtoms.h"
|
|
|
|
#include "nsContentUtils.h"
|
|
|
|
#include "nsIJSContextStack.h"
|
|
|
|
|
|
|
|
#include "nsIDOMEventListener.h"
|
|
|
|
#include "nsIWebNavigation.h"
|
|
|
|
#include "nsIBaseWindow.h"
|
2011-11-27 03:51:53 -08:00
|
|
|
#include "nsIWidget.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#include "jsapi.h"
|
|
|
|
|
|
|
|
#include "nsNodeInfoManager.h"
|
|
|
|
#include "nsICategoryManager.h"
|
|
|
|
#include "nsIDOMDocumentType.h"
|
|
|
|
#include "nsIDOMUserDataHandler.h"
|
2009-02-10 12:56:51 -08:00
|
|
|
#include "nsGenericHTMLElement.h"
|
2008-02-19 23:40:04 -08:00
|
|
|
#include "nsIEditor.h"
|
2010-05-04 10:40:39 -07:00
|
|
|
#include "nsIEditorIMESupport.h"
|
2008-02-19 23:40:04 -08:00
|
|
|
#include "nsIEditorDocShell.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsEventDispatcher.h"
|
|
|
|
#include "nsContentCreatorFunctions.h"
|
|
|
|
#include "nsIControllers.h"
|
2008-08-15 15:26:37 -07:00
|
|
|
#include "nsIView.h"
|
|
|
|
#include "nsIViewManager.h"
|
|
|
|
#include "nsIScrollableFrame.h"
|
2007-05-21 15:26:48 -07:00
|
|
|
#include "nsXBLInsertionPoint.h"
|
2011-03-10 18:48:57 -08:00
|
|
|
#include "mozilla/css/StyleRule.h" /* For nsCSSSelectorList */
|
2008-07-21 17:55:52 -07:00
|
|
|
#include "nsCSSRuleProcessor.h"
|
2009-08-01 08:53:40 -07:00
|
|
|
#include "nsRuleProcessorData.h"
|
2011-12-16 22:02:05 -08:00
|
|
|
#include "nsAsyncDOMEvent.h"
|
2011-08-15 17:55:20 -07:00
|
|
|
#include "nsTextNode.h"
|
2011-05-23 08:39:52 -07:00
|
|
|
#include "dombindings.h"
|
2008-07-21 17:55:52 -07:00
|
|
|
|
2007-07-08 17:58:15 -07:00
|
|
|
#ifdef MOZ_XUL
|
2007-05-24 17:28:20 -07:00
|
|
|
#include "nsIXULDocument.h"
|
2007-07-08 17:58:15 -07:00
|
|
|
#endif /* MOZ_XUL */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#include "nsCycleCollectionParticipant.h"
|
2007-05-10 13:21:12 -07:00
|
|
|
#include "nsCCUncollectableMarker.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-04-11 10:29:06 -07:00
|
|
|
#include "mozAutoDocUpdate.h"
|
|
|
|
|
2010-03-02 12:59:32 -08:00
|
|
|
#include "nsCSSParser.h"
|
2010-09-14 21:46:40 -07:00
|
|
|
#include "prprf.h"
|
2008-09-05 04:36:04 -07:00
|
|
|
|
2009-05-07 12:37:33 -07:00
|
|
|
#include "nsSVGFeatures.h"
|
2011-05-26 12:58:35 -07:00
|
|
|
#include "nsWrapperCacheInlines.h"
|
2012-01-30 12:08:13 -08:00
|
|
|
#include "nsCycleCollector.h"
|
2011-08-24 12:49:25 -07:00
|
|
|
#include "xpcpublic.h"
|
2012-01-11 00:23:07 -08:00
|
|
|
#include "xpcprivate.h"
|
2012-03-01 05:09:00 -08:00
|
|
|
#include "nsLayoutStatics.h"
|
|
|
|
#include "mozilla/Telemetry.h"
|
2011-08-24 12:49:25 -07:00
|
|
|
|
2012-03-10 08:13:51 -08:00
|
|
|
#include "mozilla/CORSMode.h"
|
|
|
|
|
2012-03-21 21:10:51 -07:00
|
|
|
#include "nsStyledElement.h"
|
|
|
|
|
2011-10-10 22:50:08 -07:00
|
|
|
using namespace mozilla;
|
2010-04-30 06:12:05 -07:00
|
|
|
using namespace mozilla::dom;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-11-03 02:31:47 -08:00
|
|
|
NS_DEFINE_IID(kThisPtrOffsetsSID, NS_THISPTROFFSETS_SID);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
PRInt32 nsIContent::sTabFocusModel = eTabFocus_any;
|
2011-09-28 23:19:26 -07:00
|
|
|
bool nsIContent::sTabFocusModelAppliesToXUL = false;
|
2009-04-09 18:36:41 -07:00
|
|
|
PRUint32 nsMutationGuard::sMutationCount = 0;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult);
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
nsINode::nsSlots::~nsSlots()
|
|
|
|
{
|
|
|
|
if (mChildNodes) {
|
|
|
|
mChildNodes->DropReference();
|
|
|
|
NS_RELEASE(mChildNodes);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mWeakReference) {
|
|
|
|
mWeakReference->NoticeNodeDestruction();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-28 07:07:24 -07:00
|
|
|
void
|
|
|
|
nsINode::nsSlots::Traverse(nsCycleCollectionTraversalCallback &cb)
|
|
|
|
{
|
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildNodes");
|
|
|
|
cb.NoteXPCOMChild(mChildNodes);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsINode::nsSlots::Unlink()
|
|
|
|
{
|
|
|
|
if (mChildNodes) {
|
|
|
|
mChildNodes->DropReference();
|
|
|
|
NS_RELEASE(mChildNodes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
nsINode::~nsINode()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!HasSlots(), "nsNodeUtils::LastRelease was not called?");
|
2012-03-14 13:14:02 -07:00
|
|
|
NS_ASSERTION(mSubtreeRoot == this, "Didn't restore state properly?");
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void*
|
|
|
|
nsINode::GetProperty(PRUint16 aCategory, nsIAtom *aPropertyName,
|
|
|
|
nsresult *aStatus) const
|
|
|
|
{
|
2011-10-18 04:19:44 -07:00
|
|
|
return OwnerDoc()->PropertyTable(aCategory)->GetProperty(this, aPropertyName,
|
|
|
|
aStatus);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsINode::SetProperty(PRUint16 aCategory, nsIAtom *aPropertyName, void *aValue,
|
2011-09-28 23:19:26 -07:00
|
|
|
NSPropertyDtorFunc aDtor, bool aTransfer,
|
2007-03-22 10:30:00 -07:00
|
|
|
void **aOldValue)
|
|
|
|
{
|
2011-10-18 04:19:44 -07:00
|
|
|
nsresult rv = OwnerDoc()->PropertyTable(aCategory)->SetProperty(this,
|
|
|
|
aPropertyName,
|
|
|
|
aValue, aDtor,
|
|
|
|
nsnull,
|
|
|
|
aTransfer,
|
|
|
|
aOldValue);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
SetFlags(NODE_HAS_PROPERTIES);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2010-05-20 07:41:00 -07:00
|
|
|
void
|
2007-03-22 10:30:00 -07:00
|
|
|
nsINode::DeleteProperty(PRUint16 aCategory, nsIAtom *aPropertyName)
|
|
|
|
{
|
2011-10-18 04:19:44 -07:00
|
|
|
OwnerDoc()->PropertyTable(aCategory)->DeleteProperty(this, aPropertyName);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void*
|
|
|
|
nsINode::UnsetProperty(PRUint16 aCategory, nsIAtom *aPropertyName,
|
|
|
|
nsresult *aStatus)
|
|
|
|
{
|
2011-10-18 04:19:44 -07:00
|
|
|
return OwnerDoc()->PropertyTable(aCategory)->UnsetProperty(this,
|
|
|
|
aPropertyName,
|
|
|
|
aStatus);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsINode::nsSlots*
|
|
|
|
nsINode::CreateSlots()
|
|
|
|
{
|
2011-04-07 19:29:49 -07:00
|
|
|
return new nsSlots();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2007-07-11 06:05:05 -07:00
|
|
|
nsINode::IsEditableInternal() const
|
|
|
|
{
|
|
|
|
if (HasFlag(NODE_IS_EDITABLE)) {
|
|
|
|
// The node is in an editable contentEditable subtree.
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2007-07-11 06:05:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsIDocument *doc = GetCurrentDoc();
|
|
|
|
|
|
|
|
// Check if the node is in a document and the document is in designMode.
|
|
|
|
return doc && doc->HasFlag(NODE_IS_EDITABLE);
|
|
|
|
}
|
|
|
|
|
2008-02-19 23:40:04 -08:00
|
|
|
static nsIContent* GetEditorRootContent(nsIEditor* aEditor)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMElement> rootElement;
|
|
|
|
aEditor->GetRootElement(getter_AddRefs(rootElement));
|
|
|
|
nsCOMPtr<nsIContent> rootContent(do_QueryInterface(rootElement));
|
|
|
|
return rootContent;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIContent*
|
|
|
|
nsINode::GetTextEditorRootContent(nsIEditor** aEditor)
|
|
|
|
{
|
|
|
|
if (aEditor)
|
|
|
|
*aEditor = nsnull;
|
|
|
|
for (nsINode* node = this; node; node = node->GetNodeParent()) {
|
2010-04-30 06:12:05 -07:00
|
|
|
if (!node->IsElement() ||
|
|
|
|
!node->AsElement()->IsHTML())
|
2008-02-19 23:40:04 -08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIEditor> editor;
|
2009-02-10 12:56:51 -08:00
|
|
|
static_cast<nsGenericHTMLElement*>(node)->
|
|
|
|
GetEditorInternal(getter_AddRefs(editor));
|
|
|
|
if (!editor)
|
|
|
|
continue;
|
|
|
|
|
2008-02-19 23:40:04 -08:00
|
|
|
nsIContent* rootContent = GetEditorRootContent(editor);
|
|
|
|
if (aEditor)
|
|
|
|
editor.swap(*aEditor);
|
|
|
|
return rootContent;
|
|
|
|
}
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
static nsIEditor* GetHTMLEditor(nsPresContext* aPresContext)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISupports> container = aPresContext->GetContainer();
|
|
|
|
nsCOMPtr<nsIEditorDocShell> editorDocShell(do_QueryInterface(container));
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isEditable;
|
2008-02-19 23:40:04 -08:00
|
|
|
if (!editorDocShell ||
|
|
|
|
NS_FAILED(editorDocShell->GetEditable(&isEditable)) || !isEditable)
|
|
|
|
return nsnull;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIEditor> editor;
|
|
|
|
editorDocShell->GetEditor(getter_AddRefs(editor));
|
|
|
|
return editor;
|
|
|
|
}
|
|
|
|
|
2009-12-11 20:25:21 -08:00
|
|
|
static nsIContent* GetRootForContentSubtree(nsIContent* aContent)
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(aContent, nsnull);
|
|
|
|
nsIContent* stop = aContent->GetBindingParent();
|
|
|
|
while (aContent) {
|
|
|
|
nsIContent* parent = aContent->GetParent();
|
|
|
|
if (parent == stop) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
aContent = parent;
|
|
|
|
}
|
|
|
|
return aContent;
|
|
|
|
}
|
|
|
|
|
2008-02-19 23:40:04 -08:00
|
|
|
nsIContent*
|
|
|
|
nsINode::GetSelectionRootContent(nsIPresShell* aPresShell)
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(aPresShell, nsnull);
|
|
|
|
|
|
|
|
if (IsNodeOfType(eDOCUMENT))
|
2010-04-30 06:12:05 -07:00
|
|
|
return static_cast<nsIDocument*>(this)->GetRootElement();
|
2008-02-19 23:40:04 -08:00
|
|
|
if (!IsNodeOfType(eCONTENT))
|
|
|
|
return nsnull;
|
|
|
|
|
2010-01-20 02:22:09 -08:00
|
|
|
if (GetCurrentDoc() != aPresShell->GetDocument()) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
2010-01-07 20:59:23 -08:00
|
|
|
|
2010-07-22 09:22:44 -07:00
|
|
|
if (static_cast<nsIContent*>(this)->HasIndependentSelection()) {
|
2008-02-19 23:40:04 -08:00
|
|
|
// This node should be a descendant of input/textarea editor.
|
|
|
|
nsIContent* content = GetTextEditorRootContent();
|
|
|
|
if (content)
|
|
|
|
return content;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsPresContext* presContext = aPresShell->GetPresContext();
|
|
|
|
if (presContext) {
|
|
|
|
nsIEditor* editor = GetHTMLEditor(presContext);
|
|
|
|
if (editor) {
|
|
|
|
// This node is in HTML editor.
|
|
|
|
nsIDocument* doc = GetCurrentDoc();
|
2009-12-11 20:25:21 -08:00
|
|
|
if (!doc || doc->HasFlag(NODE_IS_EDITABLE) ||
|
|
|
|
!HasFlag(NODE_IS_EDITABLE)) {
|
|
|
|
nsIContent* editorRoot = GetEditorRootContent(editor);
|
2009-12-16 20:46:30 -08:00
|
|
|
NS_ENSURE_TRUE(editorRoot, nsnull);
|
2009-12-11 20:25:21 -08:00
|
|
|
return nsContentUtils::IsInSameAnonymousTree(this, editorRoot) ?
|
|
|
|
editorRoot :
|
|
|
|
GetRootForContentSubtree(static_cast<nsIContent*>(this));
|
|
|
|
}
|
2010-07-22 09:22:44 -07:00
|
|
|
// If the document isn't editable but this is editable, this is in
|
|
|
|
// contenteditable. Use the editing host element for selection root.
|
|
|
|
return static_cast<nsIContent*>(this)->GetEditingHost();
|
2008-02-19 23:40:04 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-18 20:10:49 -07:00
|
|
|
nsRefPtr<nsFrameSelection> fs = aPresShell->FrameSelection();
|
2008-02-19 23:40:04 -08:00
|
|
|
nsIContent* content = fs->GetLimiter();
|
2009-12-11 20:25:21 -08:00
|
|
|
if (!content) {
|
|
|
|
content = fs->GetAncestorLimiter();
|
|
|
|
if (!content) {
|
|
|
|
nsIDocument* doc = aPresShell->GetDocument();
|
|
|
|
NS_ENSURE_TRUE(doc, nsnull);
|
2010-04-30 06:12:05 -07:00
|
|
|
content = doc->GetRootElement();
|
2009-12-11 20:25:21 -08:00
|
|
|
if (!content)
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This node might be in another subtree, if so, we should find this subtree's
|
|
|
|
// root. Otherwise, we can return the content simply.
|
2009-12-16 20:46:30 -08:00
|
|
|
NS_ENSURE_TRUE(content, nsnull);
|
2009-12-11 20:25:21 -08:00
|
|
|
return nsContentUtils::IsInSameAnonymousTree(this, content) ?
|
|
|
|
content : GetRootForContentSubtree(static_cast<nsIContent*>(this));
|
2008-02-19 23:40:04 -08:00
|
|
|
}
|
|
|
|
|
2009-01-29 11:46:18 -08:00
|
|
|
nsINodeList*
|
2009-01-02 09:00:18 -08:00
|
|
|
nsINode::GetChildNodesList()
|
|
|
|
{
|
|
|
|
nsSlots *slots = GetSlots();
|
|
|
|
if (!slots) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!slots->mChildNodes) {
|
|
|
|
slots->mChildNodes = new nsChildContentList(this);
|
|
|
|
if (slots->mChildNodes) {
|
|
|
|
NS_ADDREF(slots->mChildNodes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return slots->mChildNodes;
|
|
|
|
}
|
|
|
|
|
2009-04-23 00:21:22 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
|
|
|
nsINode::CheckNotNativeAnonymous() const
|
|
|
|
{
|
|
|
|
if (!IsNodeOfType(eCONTENT))
|
|
|
|
return;
|
|
|
|
nsIContent* content = static_cast<const nsIContent *>(this)->GetBindingParent();
|
|
|
|
while (content) {
|
|
|
|
if (content->IsRootOfNativeAnonymousSubtree()) {
|
|
|
|
NS_ERROR("Element not marked to be in native anonymous subtree!");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
content = content->GetBindingParent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-01-02 09:00:18 -08:00
|
|
|
nsresult
|
|
|
|
nsINode::GetParentNode(nsIDOMNode** aParentNode)
|
|
|
|
{
|
|
|
|
*aParentNode = nsnull;
|
|
|
|
|
|
|
|
nsINode *parent = GetNodeParent();
|
|
|
|
|
|
|
|
return parent ? CallQueryInterface(parent, aParentNode) : NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-09-11 15:45:39 -07:00
|
|
|
nsresult
|
|
|
|
nsINode::GetParentElement(nsIDOMElement** aParentElement)
|
|
|
|
{
|
|
|
|
*aParentElement = nsnull;
|
|
|
|
nsINode* parent = GetElementParent();
|
|
|
|
return parent ? CallQueryInterface(parent, aParentElement) : NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-01-02 09:00:18 -08:00
|
|
|
nsresult
|
|
|
|
nsINode::GetChildNodes(nsIDOMNodeList** aChildNodes)
|
|
|
|
{
|
|
|
|
*aChildNodes = GetChildNodesList();
|
|
|
|
if (!*aChildNodes) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ADDREF(*aChildNodes);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsINode::GetFirstChild(nsIDOMNode** aNode)
|
|
|
|
{
|
2011-09-27 00:54:58 -07:00
|
|
|
nsIContent* child = GetFirstChild();
|
2009-01-02 09:00:18 -08:00
|
|
|
if (child) {
|
|
|
|
return CallQueryInterface(child, aNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
*aNode = nsnull;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsINode::GetLastChild(nsIDOMNode** aNode)
|
|
|
|
{
|
|
|
|
nsIContent* child = GetLastChild();
|
|
|
|
if (child) {
|
|
|
|
return CallQueryInterface(child, aNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
*aNode = nsnull;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsINode::GetPreviousSibling(nsIDOMNode** aPrevSibling)
|
|
|
|
{
|
|
|
|
*aPrevSibling = nsnull;
|
|
|
|
|
2010-05-17 11:18:25 -07:00
|
|
|
nsIContent *sibling = GetPreviousSibling();
|
2009-01-02 09:00:18 -08:00
|
|
|
|
|
|
|
return sibling ? CallQueryInterface(sibling, aPrevSibling) : NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsINode::GetNextSibling(nsIDOMNode** aNextSibling)
|
|
|
|
{
|
|
|
|
*aNextSibling = nsnull;
|
|
|
|
|
2010-05-17 11:18:25 -07:00
|
|
|
nsIContent *sibling = GetNextSibling();
|
2009-01-02 09:00:18 -08:00
|
|
|
|
|
|
|
return sibling ? CallQueryInterface(sibling, aNextSibling) : NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsINode::GetOwnerDocument(nsIDOMDocument** aOwnerDocument)
|
|
|
|
{
|
|
|
|
*aOwnerDocument = nsnull;
|
|
|
|
|
|
|
|
nsIDocument *ownerDoc = GetOwnerDocument();
|
|
|
|
|
|
|
|
return ownerDoc ? CallQueryInterface(ownerDoc, aOwnerDocument) : NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-05-09 12:33:03 -07:00
|
|
|
nsresult
|
|
|
|
nsINode::RemoveChild(nsINode *aOldChild)
|
|
|
|
{
|
|
|
|
if (!aOldChild) {
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IsNodeOfType(eDATA_NODE)) {
|
|
|
|
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aOldChild && aOldChild->GetNodeParent() == this) {
|
2011-10-18 03:53:36 -07:00
|
|
|
nsContentUtils::MaybeFireNodeRemoved(aOldChild, this, OwnerDoc());
|
2011-05-09 12:33:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32 index = IndexOf(aOldChild);
|
|
|
|
if (index == -1) {
|
|
|
|
// aOldChild isn't one of our children.
|
|
|
|
return NS_ERROR_DOM_NOT_FOUND_ERR;
|
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return RemoveChildAt(index, true);
|
2011-05-09 12:33:03 -07:00
|
|
|
}
|
|
|
|
|
2010-03-17 08:06:19 -07:00
|
|
|
nsresult
|
2011-09-28 23:19:26 -07:00
|
|
|
nsINode::ReplaceOrInsertBefore(bool aReplace, nsIDOMNode* aNewChild,
|
2010-03-17 08:06:19 -07:00
|
|
|
nsIDOMNode* aRefChild, nsIDOMNode** aReturn)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsINode> newChild = do_QueryInterface(aNewChild);
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsINode> refChild;
|
|
|
|
if (aRefChild) {
|
|
|
|
refChild = do_QueryInterface(aRefChild, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = ReplaceOrInsertBefore(aReplace, newChild, refChild);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
NS_ADDREF(*aReturn = aReplace ? aRefChild : aNewChild);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsINode::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContent> oldChild = do_QueryInterface(aOldChild);
|
|
|
|
nsresult rv = RemoveChild(oldChild);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
NS_ADDREF(*aReturn = aOldChild);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2011-06-24 12:55:14 -07:00
|
|
|
nsresult
|
|
|
|
nsINode::Normalize()
|
|
|
|
{
|
|
|
|
// First collect list of nodes to be removed
|
|
|
|
nsAutoTArray<nsCOMPtr<nsIContent>, 50> nodes;
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool canMerge = false;
|
2011-06-24 12:55:14 -07:00
|
|
|
for (nsIContent* node = this->GetFirstChild();
|
|
|
|
node;
|
|
|
|
node = node->GetNextNode(this)) {
|
|
|
|
if (node->NodeType() != nsIDOMNode::TEXT_NODE) {
|
2011-10-17 07:59:28 -07:00
|
|
|
canMerge = false;
|
2011-06-24 12:55:14 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (canMerge || node->TextLength() == 0) {
|
|
|
|
// No need to touch canMerge. That way we can merge across empty
|
|
|
|
// textnodes if and only if the node before is a textnode
|
|
|
|
nodes.AppendElement(node);
|
|
|
|
}
|
|
|
|
else {
|
2011-10-17 07:59:28 -07:00
|
|
|
canMerge = true;
|
2011-06-24 12:55:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// If there's no following sibling, then we need to ensure that we don't
|
|
|
|
// collect following siblings of our (grand)parent as to-be-removed
|
|
|
|
canMerge = canMerge && !!node->GetNextSibling();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nodes.IsEmpty()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We're relying on mozAutoSubtreeModified to keep the doc alive here.
|
2011-10-18 03:53:36 -07:00
|
|
|
nsIDocument* doc = OwnerDoc();
|
2011-06-24 12:55:14 -07:00
|
|
|
|
|
|
|
// Batch possible DOMSubtreeModified events.
|
|
|
|
mozAutoSubtreeModified subtree(doc, nsnull);
|
|
|
|
|
|
|
|
// Fire all DOMNodeRemoved events. Optimize the common case of there being
|
|
|
|
// no listeners
|
2011-09-28 23:19:26 -07:00
|
|
|
bool hasRemoveListeners = nsContentUtils::
|
2011-06-24 12:55:14 -07:00
|
|
|
HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEREMOVED);
|
|
|
|
if (hasRemoveListeners) {
|
|
|
|
for (PRUint32 i = 0; i < nodes.Length(); ++i) {
|
|
|
|
nsContentUtils::MaybeFireNodeRemoved(nodes[i], nodes[i]->GetNodeParent(),
|
|
|
|
doc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
mozAutoDocUpdate batch(doc, UPDATE_CONTENT_MODEL, true);
|
2011-06-24 12:55:14 -07:00
|
|
|
|
|
|
|
// Merge and remove all nodes
|
|
|
|
nsAutoString tmpStr;
|
|
|
|
for (PRUint32 i = 0; i < nodes.Length(); ++i) {
|
|
|
|
nsIContent* node = nodes[i];
|
|
|
|
// Merge with previous node unless empty
|
|
|
|
const nsTextFragment* text = node->GetText();
|
|
|
|
if (text->GetLength()) {
|
|
|
|
nsIContent* target = node->GetPreviousSibling();
|
|
|
|
NS_ASSERTION((target && target->NodeType() == nsIDOMNode::TEXT_NODE) ||
|
|
|
|
hasRemoveListeners,
|
|
|
|
"Should always have a previous text sibling unless "
|
|
|
|
"mutation events messed us up");
|
|
|
|
if (!hasRemoveListeners ||
|
|
|
|
(target && target->NodeType() == nsIDOMNode::TEXT_NODE)) {
|
2011-08-15 17:55:20 -07:00
|
|
|
nsTextNode* t = static_cast<nsTextNode*>(target);
|
2011-06-24 12:55:14 -07:00
|
|
|
if (text->Is2b()) {
|
2011-10-17 07:59:28 -07:00
|
|
|
t->AppendTextForNormalize(text->Get2b(), text->GetLength(), true, node);
|
2011-06-24 12:55:14 -07:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
tmpStr.Truncate();
|
|
|
|
text->AppendTo(tmpStr);
|
2011-10-17 07:59:28 -07:00
|
|
|
t->AppendTextForNormalize(tmpStr.get(), tmpStr.Length(), true, node);
|
2011-06-24 12:55:14 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove node
|
2011-08-23 05:57:29 -07:00
|
|
|
nsCOMPtr<nsINode> parent = node->GetNodeParent();
|
2011-06-24 12:55:14 -07:00
|
|
|
NS_ASSERTION(parent || hasRemoveListeners,
|
|
|
|
"Should always have a parent unless "
|
|
|
|
"mutation events messed us up");
|
|
|
|
if (parent) {
|
2011-10-17 07:59:28 -07:00
|
|
|
parent->RemoveChildAt(parent->IndexOf(node), true);
|
2011-06-24 12:55:14 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-06-14 00:56:48 -07:00
|
|
|
nsresult
|
|
|
|
nsINode::GetDOMBaseURI(nsAString &aURI) const
|
2010-04-19 08:40:15 -07:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIURI> baseURI = GetBaseURI();
|
|
|
|
|
|
|
|
nsCAutoString spec;
|
|
|
|
if (baseURI) {
|
|
|
|
baseURI->GetSpec(spec);
|
|
|
|
}
|
|
|
|
|
|
|
|
CopyUTF8toUTF16(spec, aURI);
|
2011-06-14 00:56:48 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
2010-04-19 08:40:15 -07:00
|
|
|
}
|
|
|
|
|
2011-06-14 00:56:48 -07:00
|
|
|
nsresult
|
2010-04-19 08:40:16 -07:00
|
|
|
nsINode::LookupPrefix(const nsAString& aNamespaceURI, nsAString& aPrefix)
|
|
|
|
{
|
|
|
|
Element *element = GetNameSpaceElement();
|
2011-06-14 00:56:48 -07:00
|
|
|
if (element) {
|
|
|
|
// XXX Waiting for DOM spec to list error codes.
|
|
|
|
|
|
|
|
// Trace up the content parent chain looking for the namespace
|
|
|
|
// declaration that defines the aNamespaceURI namespace. Once found,
|
|
|
|
// return the prefix (i.e. the attribute localName).
|
|
|
|
for (nsIContent* content = element; content;
|
|
|
|
content = content->GetParent()) {
|
|
|
|
PRUint32 attrCount = content->GetAttrCount();
|
|
|
|
|
|
|
|
for (PRUint32 i = 0; i < attrCount; ++i) {
|
|
|
|
const nsAttrName* name = content->GetAttrNameAt(i);
|
|
|
|
|
|
|
|
if (name->NamespaceEquals(kNameSpaceID_XMLNS) &&
|
|
|
|
content->AttrValueIs(kNameSpaceID_XMLNS, name->LocalName(),
|
|
|
|
aNamespaceURI, eCaseMatters)) {
|
|
|
|
// If the localName is "xmlns", the prefix we output should be
|
|
|
|
// null.
|
|
|
|
nsIAtom *localName = name->LocalName();
|
|
|
|
|
|
|
|
if (localName != nsGkAtoms::xmlns) {
|
|
|
|
localName->ToString(aPrefix);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
SetDOMStringToNull(aPrefix);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-04-19 08:40:16 -07:00
|
|
|
}
|
2011-06-14 00:56:48 -07:00
|
|
|
|
|
|
|
SetDOMStringToNull(aPrefix);
|
|
|
|
|
|
|
|
return NS_OK;
|
2010-04-19 08:40:16 -07:00
|
|
|
}
|
|
|
|
|
2010-04-19 08:40:15 -07:00
|
|
|
static nsresult
|
|
|
|
SetUserDataProperty(PRUint16 aCategory, nsINode *aNode, nsIAtom *aKey,
|
|
|
|
nsISupports* aValue, void** aOldValue)
|
|
|
|
{
|
|
|
|
nsresult rv = aNode->SetProperty(aCategory, aKey, aValue,
|
2011-10-17 07:59:28 -07:00
|
|
|
nsPropertyTable::SupportsDtorFunc, true,
|
2010-04-19 08:40:15 -07:00
|
|
|
aOldValue);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// Property table owns it now.
|
|
|
|
NS_ADDREF(aValue);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2010-04-19 08:40:15 -07:00
|
|
|
nsINode::SetUserData(const nsAString &aKey, nsIVariant *aData,
|
|
|
|
nsIDOMUserDataHandler *aHandler, nsIVariant **aResult)
|
2010-04-19 08:40:15 -07:00
|
|
|
{
|
|
|
|
*aResult = nsnull;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAtom> key = do_GetAtom(aKey);
|
|
|
|
if (!key) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
void *data;
|
|
|
|
if (aData) {
|
2010-04-19 08:40:15 -07:00
|
|
|
rv = SetUserDataProperty(DOM_USER_DATA, this, key, aData, &data);
|
2010-04-19 08:40:15 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
else {
|
2010-04-19 08:40:15 -07:00
|
|
|
data = UnsetProperty(DOM_USER_DATA, key);
|
2010-04-19 08:40:15 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Take over ownership of the old data from the property table.
|
|
|
|
nsCOMPtr<nsIVariant> oldData = dont_AddRef(static_cast<nsIVariant*>(data));
|
|
|
|
|
|
|
|
if (aData && aHandler) {
|
|
|
|
nsCOMPtr<nsIDOMUserDataHandler> oldHandler;
|
2010-04-19 08:40:15 -07:00
|
|
|
rv = SetUserDataProperty(DOM_USER_DATA_HANDLER, this, key, aHandler,
|
2010-04-19 08:40:15 -07:00
|
|
|
getter_AddRefs(oldHandler));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
// We failed to set the handler, remove the data.
|
2010-04-19 08:40:15 -07:00
|
|
|
DeleteProperty(DOM_USER_DATA, key);
|
2010-04-19 08:40:15 -07:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2010-04-19 08:40:15 -07:00
|
|
|
DeleteProperty(DOM_USER_DATA_HANDLER, key);
|
2010-04-19 08:40:15 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
oldData.swap(*aResult);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint16
|
2011-06-14 00:56:48 -07:00
|
|
|
nsINode::CompareDocPosition(nsINode* aOtherNode)
|
2010-04-19 08:40:15 -07:00
|
|
|
{
|
2010-04-19 08:40:17 -07:00
|
|
|
NS_PRECONDITION(aOtherNode, "don't pass null");
|
2010-04-19 08:40:15 -07:00
|
|
|
|
2010-04-19 08:40:17 -07:00
|
|
|
if (this == aOtherNode) {
|
2010-04-19 08:40:15 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-08-09 22:36:00 -07:00
|
|
|
nsAutoTArray<nsINode*, 32> parents1, parents2;
|
2010-04-19 08:40:15 -07:00
|
|
|
|
2010-04-19 08:40:17 -07:00
|
|
|
nsINode *node1 = aOtherNode, *node2 = this;
|
|
|
|
|
2010-04-19 08:40:15 -07:00
|
|
|
// Check if either node is an attribute
|
|
|
|
nsIAttribute* attr1 = nsnull;
|
2010-04-19 08:40:17 -07:00
|
|
|
if (node1->IsNodeOfType(nsINode::eATTRIBUTE)) {
|
|
|
|
attr1 = static_cast<nsIAttribute*>(node1);
|
2010-04-19 08:40:15 -07:00
|
|
|
nsIContent* elem = attr1->GetContent();
|
|
|
|
// If there is an owner element add the attribute
|
|
|
|
// to the chain and walk up to the element
|
|
|
|
if (elem) {
|
2010-04-19 08:40:17 -07:00
|
|
|
node1 = elem;
|
2010-04-19 08:40:15 -07:00
|
|
|
parents1.AppendElement(static_cast<nsINode*>(attr1));
|
|
|
|
}
|
|
|
|
}
|
2010-04-19 08:40:17 -07:00
|
|
|
if (node2->IsNodeOfType(nsINode::eATTRIBUTE)) {
|
|
|
|
nsIAttribute* attr2 = static_cast<nsIAttribute*>(node2);
|
2010-04-19 08:40:15 -07:00
|
|
|
nsIContent* elem = attr2->GetContent();
|
2010-04-19 08:40:17 -07:00
|
|
|
if (elem == node1 && attr1) {
|
2010-04-19 08:40:15 -07:00
|
|
|
// Both nodes are attributes on the same element.
|
|
|
|
// Compare position between the attributes.
|
|
|
|
|
|
|
|
PRUint32 i;
|
|
|
|
const nsAttrName* attrName;
|
|
|
|
for (i = 0; (attrName = elem->GetAttrNameAt(i)); ++i) {
|
|
|
|
if (attrName->Equals(attr1->NodeInfo())) {
|
|
|
|
NS_ASSERTION(!attrName->Equals(attr2->NodeInfo()),
|
|
|
|
"Different attrs at same position");
|
2011-06-14 00:56:48 -07:00
|
|
|
return nsIDOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
|
|
|
|
nsIDOMNode::DOCUMENT_POSITION_PRECEDING;
|
2010-04-19 08:40:15 -07:00
|
|
|
}
|
|
|
|
if (attrName->Equals(attr2->NodeInfo())) {
|
2011-06-14 00:56:48 -07:00
|
|
|
return nsIDOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
|
|
|
|
nsIDOMNode::DOCUMENT_POSITION_FOLLOWING;
|
2010-04-19 08:40:15 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
NS_NOTREACHED("neither attribute in the element");
|
2011-06-14 00:56:48 -07:00
|
|
|
return nsIDOMNode::DOCUMENT_POSITION_DISCONNECTED;
|
2010-04-19 08:40:15 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (elem) {
|
2010-04-19 08:40:17 -07:00
|
|
|
node2 = elem;
|
2010-04-19 08:40:15 -07:00
|
|
|
parents2.AppendElement(static_cast<nsINode*>(attr2));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We now know that both nodes are either nsIContents or nsIDocuments.
|
|
|
|
// If either node started out as an attribute, that attribute will have
|
|
|
|
// the same relative position as its ownerElement, except if the
|
|
|
|
// ownerElement ends up being the container for the other node
|
|
|
|
|
|
|
|
// Build the chain of parents
|
|
|
|
do {
|
2010-04-19 08:40:17 -07:00
|
|
|
parents1.AppendElement(node1);
|
|
|
|
node1 = node1->GetNodeParent();
|
|
|
|
} while (node1);
|
2010-04-19 08:40:15 -07:00
|
|
|
do {
|
2010-04-19 08:40:17 -07:00
|
|
|
parents2.AppendElement(node2);
|
|
|
|
node2 = node2->GetNodeParent();
|
|
|
|
} while (node2);
|
2010-04-19 08:40:15 -07:00
|
|
|
|
|
|
|
// Check if the nodes are disconnected.
|
|
|
|
PRUint32 pos1 = parents1.Length();
|
|
|
|
PRUint32 pos2 = parents2.Length();
|
|
|
|
nsINode* top1 = parents1.ElementAt(--pos1);
|
|
|
|
nsINode* top2 = parents2.ElementAt(--pos2);
|
|
|
|
if (top1 != top2) {
|
|
|
|
return top1 < top2 ?
|
2011-06-14 00:56:48 -07:00
|
|
|
(nsIDOMNode::DOCUMENT_POSITION_PRECEDING |
|
|
|
|
nsIDOMNode::DOCUMENT_POSITION_DISCONNECTED |
|
|
|
|
nsIDOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC) :
|
|
|
|
(nsIDOMNode::DOCUMENT_POSITION_FOLLOWING |
|
|
|
|
nsIDOMNode::DOCUMENT_POSITION_DISCONNECTED |
|
|
|
|
nsIDOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
|
2010-04-19 08:40:15 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Find where the parent chain differs and check indices in the parent.
|
|
|
|
nsINode* parent = top1;
|
|
|
|
PRUint32 len;
|
|
|
|
for (len = NS_MIN(pos1, pos2); len > 0; --len) {
|
|
|
|
nsINode* child1 = parents1.ElementAt(--pos1);
|
|
|
|
nsINode* child2 = parents2.ElementAt(--pos2);
|
|
|
|
if (child1 != child2) {
|
|
|
|
// child1 or child2 can be an attribute here. This will work fine since
|
|
|
|
// IndexOf will return -1 for the attribute making the attribute be
|
|
|
|
// considered before any child.
|
|
|
|
return parent->IndexOf(child1) < parent->IndexOf(child2) ?
|
2011-06-14 00:56:48 -07:00
|
|
|
static_cast<PRUint16>(nsIDOMNode::DOCUMENT_POSITION_PRECEDING) :
|
|
|
|
static_cast<PRUint16>(nsIDOMNode::DOCUMENT_POSITION_FOLLOWING);
|
2010-04-19 08:40:15 -07:00
|
|
|
}
|
|
|
|
parent = child1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We hit the end of one of the parent chains without finding a difference
|
|
|
|
// between the chains. That must mean that one node is an ancestor of the
|
|
|
|
// other. The one with the shortest chain must be the ancestor.
|
|
|
|
return pos1 < pos2 ?
|
2011-06-14 00:56:48 -07:00
|
|
|
(nsIDOMNode::DOCUMENT_POSITION_PRECEDING |
|
|
|
|
nsIDOMNode::DOCUMENT_POSITION_CONTAINS) :
|
|
|
|
(nsIDOMNode::DOCUMENT_POSITION_FOLLOWING |
|
|
|
|
nsIDOMNode::DOCUMENT_POSITION_CONTAINED_BY);
|
2011-06-14 00:56:48 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2011-06-14 00:56:48 -07:00
|
|
|
nsINode::IsEqualTo(nsINode* aOther)
|
|
|
|
{
|
|
|
|
if (!aOther) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-06-14 00:56:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoString string1, string2;
|
|
|
|
|
|
|
|
nsINode* node1 = this;
|
|
|
|
nsINode* node2 = aOther;
|
|
|
|
do {
|
|
|
|
PRUint16 nodeType = node1->NodeType();
|
|
|
|
if (nodeType != node2->NodeType()) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-06-14 00:56:48 -07:00
|
|
|
}
|
2011-06-14 00:56:49 -07:00
|
|
|
|
2012-03-28 22:43:09 -07:00
|
|
|
nsINodeInfo* nodeInfo1 = node1->mNodeInfo;
|
|
|
|
nsINodeInfo* nodeInfo2 = node2->mNodeInfo;
|
2011-06-14 00:56:49 -07:00
|
|
|
if (!nodeInfo1->Equals(nodeInfo2) ||
|
|
|
|
nodeInfo1->GetExtraName() != nodeInfo2->GetExtraName()) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-06-14 00:56:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
switch(nodeType) {
|
|
|
|
case nsIDOMNode::ELEMENT_NODE:
|
|
|
|
{
|
|
|
|
// Both are elements (we checked that their nodeinfos are equal). Do the
|
|
|
|
// check on attributes.
|
|
|
|
Element* element1 = node1->AsElement();
|
|
|
|
Element* element2 = node2->AsElement();
|
|
|
|
PRUint32 attrCount = element1->GetAttrCount();
|
|
|
|
if (attrCount != element2->GetAttrCount()) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-06-14 00:56:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Iterate over attributes.
|
|
|
|
for (PRUint32 i = 0; i < attrCount; ++i) {
|
|
|
|
const nsAttrName* attrName = element1->GetAttrNameAt(i);
|
|
|
|
#ifdef DEBUG
|
2011-09-28 23:19:26 -07:00
|
|
|
bool hasAttr =
|
2011-06-14 00:56:48 -07:00
|
|
|
#endif
|
|
|
|
element1->GetAttr(attrName->NamespaceID(), attrName->LocalName(),
|
|
|
|
string1);
|
|
|
|
NS_ASSERTION(hasAttr, "Why don't we have an attr?");
|
|
|
|
|
|
|
|
if (!element2->AttrValueIs(attrName->NamespaceID(),
|
|
|
|
attrName->LocalName(),
|
|
|
|
string1,
|
|
|
|
eCaseMatters)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-06-14 00:56:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case nsIDOMNode::TEXT_NODE:
|
|
|
|
case nsIDOMNode::COMMENT_NODE:
|
|
|
|
case nsIDOMNode::CDATA_SECTION_NODE:
|
|
|
|
case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
|
|
|
|
{
|
|
|
|
string1.Truncate();
|
|
|
|
static_cast<nsIContent*>(node1)->AppendTextTo(string1);
|
|
|
|
string2.Truncate();
|
|
|
|
static_cast<nsIContent*>(node2)->AppendTextTo(string2);
|
|
|
|
|
|
|
|
if (!string1.Equals(string2)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-06-14 00:56:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case nsIDOMNode::DOCUMENT_NODE:
|
|
|
|
case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
|
|
|
|
break;
|
|
|
|
case nsIDOMNode::ATTRIBUTE_NODE:
|
|
|
|
{
|
|
|
|
NS_ASSERTION(node1 == this && node2 == aOther,
|
|
|
|
"Did we come upon an attribute node while walking a "
|
|
|
|
"subtree?");
|
|
|
|
nsCOMPtr<nsIDOMNode> domNode1 = do_QueryInterface(node1);
|
|
|
|
nsCOMPtr<nsIDOMNode> domNode2 = do_QueryInterface(node2);
|
|
|
|
domNode1->GetNodeValue(string1);
|
|
|
|
domNode2->GetNodeValue(string2);
|
|
|
|
|
|
|
|
// Returning here as to not bother walking subtree. And there is no
|
|
|
|
// risk that we're half way through walking some other subtree since
|
|
|
|
// attribute nodes doesn't appear in subtrees.
|
|
|
|
return string1.Equals(string2);
|
|
|
|
}
|
|
|
|
case nsIDOMNode::DOCUMENT_TYPE_NODE:
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMDocumentType> docType1 = do_QueryInterface(node1);
|
|
|
|
nsCOMPtr<nsIDOMDocumentType> docType2 = do_QueryInterface(node2);
|
|
|
|
|
|
|
|
NS_ASSERTION(docType1 && docType2, "Why don't we have a document type node?");
|
|
|
|
|
|
|
|
// Public ID
|
|
|
|
docType1->GetPublicId(string1);
|
|
|
|
docType2->GetPublicId(string2);
|
|
|
|
if (!string1.Equals(string2)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-06-14 00:56:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// System ID
|
|
|
|
docType1->GetSystemId(string1);
|
|
|
|
docType2->GetSystemId(string2);
|
|
|
|
if (!string1.Equals(string2)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-06-14 00:56:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Internal subset
|
|
|
|
docType1->GetInternalSubset(string1);
|
|
|
|
docType2->GetInternalSubset(string2);
|
|
|
|
if (!string1.Equals(string2)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-06-14 00:56:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
2011-10-17 07:59:28 -07:00
|
|
|
NS_ABORT_IF_FALSE(false, "Unknown node type");
|
2011-06-14 00:56:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsINode* nextNode = node1->GetFirstChild();
|
|
|
|
if (nextNode) {
|
|
|
|
node1 = nextNode;
|
|
|
|
node2 = node2->GetFirstChild();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (node2->GetFirstChild()) {
|
|
|
|
// node2 has a firstChild, but node1 doesn't
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-06-14 00:56:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Find next sibling, possibly walking parent chain.
|
|
|
|
while (1) {
|
|
|
|
if (node1 == this) {
|
|
|
|
NS_ASSERTION(node2 == aOther, "Should have reached the start node "
|
|
|
|
"for both trees at the same time");
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2011-06-14 00:56:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nextNode = node1->GetNextSibling();
|
|
|
|
if (nextNode) {
|
|
|
|
node1 = nextNode;
|
|
|
|
node2 = node2->GetNextSibling();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node2->GetNextSibling()) {
|
|
|
|
// node2 has a nextSibling, but node1 doesn't
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-06-14 00:56:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
node1 = node1->GetNodeParent();
|
|
|
|
node2 = node2->GetNodeParent();
|
|
|
|
NS_ASSERTION(node1 && node2, "no parent while walking subtree");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while(node2);
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-06-14 00:56:48 -07:00
|
|
|
}
|
|
|
|
|
2011-06-14 00:56:48 -07:00
|
|
|
nsresult
|
2010-04-19 08:40:16 -07:00
|
|
|
nsINode::LookupNamespaceURI(const nsAString& aNamespacePrefix,
|
|
|
|
nsAString& aNamespaceURI)
|
|
|
|
{
|
|
|
|
Element *element = GetNameSpaceElement();
|
2011-12-20 06:54:14 -08:00
|
|
|
if (!element ||
|
|
|
|
NS_FAILED(element->LookupNamespaceURIInternal(aNamespacePrefix,
|
|
|
|
aNamespaceURI))) {
|
2010-04-19 08:40:16 -07:00
|
|
|
SetDOMStringToNull(aNamespaceURI);
|
|
|
|
}
|
2011-06-14 00:56:48 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
2010-04-19 08:40:16 -07:00
|
|
|
}
|
|
|
|
|
2011-06-23 19:17:59 -07:00
|
|
|
NS_IMPL_DOMTARGET_DEFAULTS(nsINode)
|
|
|
|
|
2011-06-23 19:17:58 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsINode::AddEventListener(const nsAString& aType,
|
|
|
|
nsIDOMEventListener *aListener,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aUseCapture,
|
|
|
|
bool aWantsUntrusted,
|
2011-06-23 19:17:59 -07:00
|
|
|
PRUint8 aOptionalArgc)
|
2011-06-23 19:17:58 -07:00
|
|
|
{
|
2011-06-23 19:17:59 -07:00
|
|
|
NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
|
2011-06-23 19:17:58 -07:00
|
|
|
"Won't check if this is chrome, you want to set "
|
2011-10-17 07:59:28 -07:00
|
|
|
"aWantsUntrusted to false or make the aWantsUntrusted "
|
2011-06-23 19:17:59 -07:00
|
|
|
"explicit by making aOptionalArgc non-zero.");
|
2011-06-23 19:17:58 -07:00
|
|
|
|
2011-06-23 19:18:02 -07:00
|
|
|
if (!aWantsUntrusted &&
|
2011-06-23 19:17:59 -07:00
|
|
|
(aOptionalArgc < 2 &&
|
2011-10-18 03:53:36 -07:00
|
|
|
!nsContentUtils::IsChromeDoc(OwnerDoc()))) {
|
2011-10-17 07:59:28 -07:00
|
|
|
aWantsUntrusted = true;
|
2011-06-23 19:17:58 -07:00
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
nsEventListenerManager* listener_manager = GetListenerManager(true);
|
2011-06-23 19:18:02 -07:00
|
|
|
NS_ENSURE_STATE(listener_manager);
|
2011-08-18 02:45:00 -07:00
|
|
|
listener_manager->AddEventListener(aType, aListener, aUseCapture,
|
|
|
|
aWantsUntrusted);
|
|
|
|
return NS_OK;
|
2011-06-23 19:17:58 -07:00
|
|
|
}
|
|
|
|
|
2011-11-24 17:09:58 -08:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsINode::AddSystemEventListener(const nsAString& aType,
|
|
|
|
nsIDOMEventListener *aListener,
|
|
|
|
bool aUseCapture,
|
|
|
|
bool aWantsUntrusted,
|
|
|
|
PRUint8 aOptionalArgc)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
|
|
|
|
"Won't check if this is chrome, you want to set "
|
|
|
|
"aWantsUntrusted to false or make the aWantsUntrusted "
|
|
|
|
"explicit by making aOptionalArgc non-zero.");
|
|
|
|
|
|
|
|
if (!aWantsUntrusted &&
|
|
|
|
(aOptionalArgc < 2 &&
|
|
|
|
!nsContentUtils::IsChromeDoc(OwnerDoc()))) {
|
|
|
|
aWantsUntrusted = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
|
|
|
|
aWantsUntrusted);
|
|
|
|
}
|
|
|
|
|
2011-06-23 19:17:59 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsINode::RemoveEventListener(const nsAString& aType,
|
|
|
|
nsIDOMEventListener* aListener,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aUseCapture)
|
2011-06-23 19:17:59 -07:00
|
|
|
{
|
2011-10-17 07:59:28 -07:00
|
|
|
nsEventListenerManager* elm = GetListenerManager(false);
|
2011-06-23 19:18:02 -07:00
|
|
|
if (elm) {
|
|
|
|
elm->RemoveEventListener(aType, aListener, aUseCapture);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
2011-06-23 19:17:59 -07:00
|
|
|
}
|
|
|
|
|
2011-11-24 17:09:58 -08:00
|
|
|
NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsINode)
|
|
|
|
|
2011-06-23 19:17:59 -07:00
|
|
|
nsresult
|
|
|
|
nsINode::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
|
|
|
|
{
|
|
|
|
// This is only here so that we can use the NS_DECL_NSIDOMTARGET macro
|
|
|
|
NS_ABORT();
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2011-09-28 23:19:26 -07:00
|
|
|
nsINode::DispatchEvent(nsIDOMEvent *aEvent, bool* aRetVal)
|
2011-06-23 19:17:59 -07:00
|
|
|
{
|
2011-06-23 19:18:02 -07:00
|
|
|
// XXX sXBL/XBL2 issue -- do we really want the owner here? What
|
|
|
|
// if that's the XBL document? Would we want its presshell? Or what?
|
2011-10-18 03:53:36 -07:00
|
|
|
nsCOMPtr<nsIDocument> document = OwnerDoc();
|
2011-06-23 19:18:02 -07:00
|
|
|
|
|
|
|
// Do nothing if the element does not belong to a document
|
|
|
|
if (!document) {
|
2011-10-17 07:59:28 -07:00
|
|
|
*aRetVal = true;
|
2011-06-23 19:18:02 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Obtain a presentation shell
|
|
|
|
nsIPresShell *shell = document->GetShell();
|
|
|
|
nsRefPtr<nsPresContext> context;
|
|
|
|
if (shell) {
|
|
|
|
context = shell->GetPresContext();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
|
|
nsresult rv =
|
|
|
|
nsEventDispatcher::DispatchDOMEvent(this, nsnull, aEvent, context,
|
|
|
|
&status);
|
|
|
|
*aRetVal = (status != nsEventStatus_eConsumeNoDefault);
|
|
|
|
return rv;
|
2011-06-23 19:17:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsINode::PostHandleEvent(nsEventChainPostVisitor& /*aVisitor*/)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsINode::DispatchDOMEvent(nsEvent* aEvent,
|
|
|
|
nsIDOMEvent* aDOMEvent,
|
|
|
|
nsPresContext* aPresContext,
|
|
|
|
nsEventStatus* aEventStatus)
|
|
|
|
{
|
|
|
|
return nsEventDispatcher::DispatchDOMEvent(this, aEvent, aDOMEvent,
|
|
|
|
aPresContext, aEventStatus);
|
|
|
|
}
|
|
|
|
|
2011-06-23 19:18:01 -07:00
|
|
|
nsEventListenerManager*
|
2011-09-28 23:19:26 -07:00
|
|
|
nsINode::GetListenerManager(bool aCreateIfNotFound)
|
2011-06-23 19:17:59 -07:00
|
|
|
{
|
|
|
|
return nsContentUtils::GetListenerManager(this, aCreateIfNotFound);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIScriptContext*
|
|
|
|
nsINode::GetContextForEventHandlers(nsresult* aRv)
|
|
|
|
{
|
|
|
|
return nsContentUtils::GetContextForEventHandlers(this, aRv);
|
|
|
|
}
|
|
|
|
|
2011-08-28 07:07:24 -07:00
|
|
|
/* static */
|
|
|
|
void
|
|
|
|
nsINode::Trace(nsINode *tmp, TraceCallback cb, void *closure)
|
|
|
|
{
|
|
|
|
nsContentUtils::TraceWrapper(tmp, cb, closure);
|
|
|
|
}
|
|
|
|
|
2012-01-30 12:08:13 -08:00
|
|
|
|
|
|
|
static
|
|
|
|
bool UnoptimizableCCNode(nsINode* aNode)
|
2011-12-23 14:28:58 -08:00
|
|
|
{
|
2012-01-30 12:08:13 -08:00
|
|
|
const PtrBits problematicFlags = (NODE_IS_ANONYMOUS |
|
|
|
|
NODE_IS_IN_ANONYMOUS_SUBTREE |
|
|
|
|
NODE_IS_NATIVE_ANONYMOUS_ROOT |
|
|
|
|
NODE_MAY_BE_IN_BINDING_MNGR |
|
|
|
|
NODE_IS_INSERTION_PARENT);
|
|
|
|
return aNode->HasFlag(problematicFlags) ||
|
|
|
|
aNode->NodeType() == nsIDOMNode::ATTRIBUTE_NODE ||
|
|
|
|
// For strange cases like xbl:content/xbl:children
|
|
|
|
(aNode->IsElement() &&
|
|
|
|
aNode->AsElement()->IsInNamespace(kNameSpaceID_XBL));
|
2011-12-23 14:28:58 -08:00
|
|
|
}
|
|
|
|
|
2011-08-28 07:07:24 -07:00
|
|
|
/* static */
|
|
|
|
bool
|
|
|
|
nsINode::Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb)
|
|
|
|
{
|
2012-03-22 08:37:54 -07:00
|
|
|
if (NS_LIKELY(!cb.WantAllTraces())) {
|
|
|
|
nsIDocument *currentDoc = tmp->GetCurrentDoc();
|
|
|
|
if (currentDoc &&
|
|
|
|
nsCCUncollectableMarker::InGeneration(currentDoc->GetMarkedCCGeneration())) {
|
2011-12-23 14:28:58 -08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-03-22 08:37:54 -07:00
|
|
|
if (nsCCUncollectableMarker::sGeneration) {
|
|
|
|
// If we're black no need to traverse.
|
|
|
|
if (tmp->IsBlack() || tmp->InCCBlackTree()) {
|
2011-12-23 14:28:58 -08:00
|
|
|
return false;
|
|
|
|
}
|
2012-03-22 08:37:54 -07:00
|
|
|
|
|
|
|
if (!UnoptimizableCCNode(tmp)) {
|
|
|
|
// If we're in a black document, return early.
|
|
|
|
if ((currentDoc && currentDoc->IsBlack())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// If we're not in anonymous content and we have a black parent,
|
|
|
|
// return early.
|
|
|
|
nsIContent* parent = tmp->GetParent();
|
|
|
|
if (parent && !UnoptimizableCCNode(parent) && parent->IsBlack()) {
|
|
|
|
NS_ABORT_IF_FALSE(parent->IndexOf(tmp) >= 0, "Parent doesn't own us?");
|
|
|
|
return false;
|
|
|
|
}
|
2011-12-23 14:28:58 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-28 22:43:09 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNodeInfo)
|
2011-08-28 07:07:24 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(GetParent())
|
|
|
|
|
|
|
|
nsSlots *slots = tmp->GetExistingSlots();
|
|
|
|
if (slots) {
|
|
|
|
slots->Traverse(cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmp->HasProperties()) {
|
|
|
|
nsNodeUtils::TraverseUserData(tmp, cb);
|
|
|
|
}
|
|
|
|
|
2012-02-27 06:03:15 -08:00
|
|
|
if (tmp->NodeType() != nsIDOMNode::DOCUMENT_NODE &&
|
|
|
|
tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) {
|
2011-08-28 07:07:24 -07:00
|
|
|
nsContentUtils::TraverseListenerManager(tmp, cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
void
|
|
|
|
nsINode::Unlink(nsINode *tmp)
|
|
|
|
{
|
|
|
|
nsContentUtils::ReleaseWrapper(tmp, tmp);
|
|
|
|
|
|
|
|
nsSlots *slots = tmp->GetExistingSlots();
|
|
|
|
if (slots) {
|
|
|
|
slots->Unlink();
|
|
|
|
}
|
|
|
|
|
2012-02-27 06:03:15 -08:00
|
|
|
if (tmp->NodeType() != nsIDOMNode::DOCUMENT_NODE &&
|
|
|
|
tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) {
|
2011-08-28 07:07:24 -07:00
|
|
|
nsContentUtils::RemoveListenerManager(tmp);
|
|
|
|
tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmp->HasProperties()) {
|
|
|
|
nsNodeUtils::UnlinkUserData(tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
2010-10-20 04:26:32 -07:00
|
|
|
nsEventStates
|
2011-05-31 18:46:56 -07:00
|
|
|
Element::IntrinsicState() const
|
2007-06-27 19:48:16 -07:00
|
|
|
{
|
2007-07-11 06:05:05 -07:00
|
|
|
return IsEditable() ? NS_EVENT_STATE_MOZ_READWRITE :
|
|
|
|
NS_EVENT_STATE_MOZ_READONLY;
|
2007-06-27 19:48:16 -07:00
|
|
|
}
|
|
|
|
|
2011-05-31 18:46:56 -07:00
|
|
|
void
|
|
|
|
Element::NotifyStateChange(nsEventStates aStates)
|
|
|
|
{
|
|
|
|
nsIDocument* doc = GetCurrentDoc();
|
|
|
|
if (doc) {
|
|
|
|
nsAutoScriptBlocker scriptBlocker;
|
|
|
|
doc->ContentStateChanged(this, aStates);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-31 18:46:57 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-06-27 19:48:16 -07:00
|
|
|
void
|
2011-05-31 18:46:57 -07:00
|
|
|
Element::UpdateState(bool aNotify)
|
2007-06-27 19:48:16 -07:00
|
|
|
{
|
2011-05-31 18:46:57 -07:00
|
|
|
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
|
2011-09-28 23:19:26 -07:00
|
|
|
nsIContent::UpdateEditableState(bool aNotify)
|
2011-05-31 18:46:57 -07:00
|
|
|
{
|
|
|
|
// Guaranteed to be non-element content
|
|
|
|
NS_ASSERTION(!IsElement(), "What happened here?");
|
2007-06-27 19:48:16 -07:00
|
|
|
nsIContent *parent = GetParent();
|
|
|
|
|
|
|
|
SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
|
|
|
|
}
|
|
|
|
|
2011-05-31 18:46:57 -07:00
|
|
|
void
|
2011-09-28 23:19:26 -07:00
|
|
|
nsGenericElement::UpdateEditableState(bool aNotify)
|
2011-05-31 18:46:57 -07:00
|
|
|
{
|
|
|
|
nsIContent *parent = GetParent();
|
|
|
|
|
|
|
|
SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
|
2011-07-20 12:58:25 -07:00
|
|
|
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);
|
2011-05-31 18:46:57 -07:00
|
|
|
} else {
|
2011-07-20 12:58:25 -07:00
|
|
|
RemoveStatesSilently(NS_EVENT_STATE_MOZ_READWRITE);
|
|
|
|
AddStatesSilently(NS_EVENT_STATE_MOZ_READONLY);
|
2011-05-31 18:46:57 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-08 10:42:38 -08:00
|
|
|
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<nsEventStates*> (GetProperty(nsGkAtoms::lockedStyleStates));
|
|
|
|
if (locks) {
|
|
|
|
return *locks;
|
|
|
|
}
|
|
|
|
return nsEventStates();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nsEventStatesPropertyDtor(void *aObject, nsIAtom *aProperty,
|
|
|
|
void *aPropertyValue, void *aData)
|
|
|
|
{
|
|
|
|
nsEventStates *states = static_cast<nsEventStates*>(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);
|
|
|
|
}
|
|
|
|
|
2008-02-26 04:40:18 -08:00
|
|
|
nsIContent*
|
|
|
|
nsIContent::FindFirstNonNativeAnonymous() const
|
|
|
|
{
|
|
|
|
// This handles also nested native anonymous content.
|
2008-07-22 21:50:20 -07:00
|
|
|
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<nsIContent*>(content);
|
2008-02-26 04:40:18 -08:00
|
|
|
}
|
|
|
|
}
|
2008-07-22 21:50:20 -07:00
|
|
|
return nsnull;
|
2008-02-26 04:40:18 -08:00
|
|
|
}
|
|
|
|
|
2010-04-16 11:15:28 -07:00
|
|
|
nsIContent*
|
|
|
|
nsIContent::GetFlattenedTreeParent() const
|
|
|
|
{
|
|
|
|
nsIContent *parent = GetParent();
|
|
|
|
if (parent && parent->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
|
2011-10-18 03:53:36 -07:00
|
|
|
nsIDocument *doc = parent->OwnerDoc();
|
2011-10-18 04:19:44 -07:00
|
|
|
nsIContent* insertionElement =
|
|
|
|
doc->BindingManager()->GetNestedInsertionPoint(parent, this);
|
|
|
|
if (insertionElement) {
|
|
|
|
parent = insertionElement;
|
2010-04-16 11:15:28 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return parent;
|
|
|
|
}
|
|
|
|
|
2011-11-27 03:51:53 -08:00
|
|
|
nsIContent::IMEState
|
2010-05-04 10:40:39 -07:00
|
|
|
nsIContent::GetDesiredIMEState()
|
|
|
|
{
|
|
|
|
if (!IsEditableInternal()) {
|
2011-11-27 03:51:53 -08:00
|
|
|
return IMEState(IMEState::DISABLED);
|
2010-05-04 10:40:39 -07:00
|
|
|
}
|
2010-07-22 09:22:44 -07:00
|
|
|
// 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();
|
|
|
|
|
2010-05-04 10:40:39 -07:00
|
|
|
// This is in another editable content, use the result of it.
|
2010-07-22 09:22:44 -07:00
|
|
|
if (editableAncestor && editableAncestor != this) {
|
2010-05-04 10:40:39 -07:00
|
|
|
return editableAncestor->GetDesiredIMEState();
|
|
|
|
}
|
|
|
|
nsIDocument* doc = GetCurrentDoc();
|
|
|
|
if (!doc) {
|
2011-11-27 03:51:53 -08:00
|
|
|
return IMEState(IMEState::DISABLED);
|
2010-05-04 10:40:39 -07:00
|
|
|
}
|
2010-06-25 06:59:57 -07:00
|
|
|
nsIPresShell* ps = doc->GetShell();
|
2010-05-04 10:40:39 -07:00
|
|
|
if (!ps) {
|
2011-11-27 03:51:53 -08:00
|
|
|
return IMEState(IMEState::DISABLED);
|
2010-05-04 10:40:39 -07:00
|
|
|
}
|
|
|
|
nsPresContext* pc = ps->GetPresContext();
|
|
|
|
if (!pc) {
|
2011-11-27 03:51:53 -08:00
|
|
|
return IMEState(IMEState::DISABLED);
|
2010-05-04 10:40:39 -07:00
|
|
|
}
|
|
|
|
nsIEditor* editor = GetHTMLEditor(pc);
|
|
|
|
nsCOMPtr<nsIEditorIMESupport> imeEditor = do_QueryInterface(editor);
|
|
|
|
if (!imeEditor) {
|
2011-11-27 03:51:53 -08:00
|
|
|
return IMEState(IMEState::DISABLED);
|
2010-05-04 10:40:39 -07:00
|
|
|
}
|
2011-11-27 03:51:53 -08:00
|
|
|
IMEState state;
|
|
|
|
imeEditor->GetPreferredIMEState(&state);
|
2010-05-04 10:40:39 -07:00
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2010-07-22 09:22:44 -07:00
|
|
|
nsIContent::HasIndependentSelection()
|
|
|
|
{
|
|
|
|
nsIFrame* frame = GetPrimaryFrame();
|
|
|
|
return (frame && frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIContent*
|
|
|
|
nsIContent::GetEditingHost()
|
|
|
|
{
|
|
|
|
// If this isn't editable, return NULL.
|
2011-07-14 08:25:07 -07:00
|
|
|
NS_ENSURE_TRUE(IsEditableInternal(), nsnull);
|
2010-07-22 09:22:44 -07:00
|
|
|
|
|
|
|
nsIDocument* doc = GetCurrentDoc();
|
|
|
|
NS_ENSURE_TRUE(doc, nsnull);
|
|
|
|
// If this is in designMode, we should return <body>
|
|
|
|
if (doc->HasFlag(NODE_IS_EDITABLE)) {
|
|
|
|
return doc->GetBodyElement();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIContent* content = this;
|
|
|
|
for (nsIContent* parent = GetParent();
|
|
|
|
parent && parent->HasFlag(NODE_IS_EDITABLE);
|
|
|
|
parent = content->GetParent()) {
|
|
|
|
content = parent;
|
|
|
|
}
|
|
|
|
return content;
|
|
|
|
}
|
|
|
|
|
2010-04-19 08:40:15 -07:00
|
|
|
nsresult
|
2011-12-20 06:54:14 -08:00
|
|
|
nsIContent::LookupNamespaceURIInternal(const nsAString& aNamespacePrefix,
|
|
|
|
nsAString& aNamespaceURI) const
|
2010-04-19 08:40:15 -07:00
|
|
|
{
|
|
|
|
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<nsIAtom> 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.
|
2010-04-19 08:40:16 -07:00
|
|
|
const nsIContent* content = this;
|
|
|
|
do {
|
2010-04-19 08:40:15 -07:00
|
|
|
if (content->GetAttr(kNameSpaceID_XMLNS, name, aNamespaceURI))
|
|
|
|
return NS_OK;
|
2010-04-19 08:40:16 -07:00
|
|
|
} while ((content = content->GetParent()));
|
2010-04-19 08:40:15 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2011-02-10 23:47:00 -08:00
|
|
|
already_AddRefed<nsIURI>
|
|
|
|
nsIContent::GetBaseURI() const
|
|
|
|
{
|
2011-10-18 03:53:36 -07:00
|
|
|
nsIDocument* doc = OwnerDoc();
|
2011-02-10 23:47:00 -08:00
|
|
|
// Start with document base
|
|
|
|
nsCOMPtr<nsIURI> 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<nsString, 5> 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) {
|
2011-10-18 04:19:44 -07:00
|
|
|
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;
|
2011-02-10 23:47:00 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-02-02 12:50:50 -08:00
|
|
|
|
|
|
|
nsIURI* explicitBaseURI = elem->GetExplicitBaseURI();
|
|
|
|
if (explicitBaseURI) {
|
|
|
|
base = explicitBaseURI;
|
|
|
|
break;
|
|
|
|
}
|
2011-02-10 23:47:00 -08:00
|
|
|
|
|
|
|
// 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<nsIURI> 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();
|
|
|
|
}
|
|
|
|
|
2012-02-02 12:50:50 -08:00
|
|
|
static void
|
|
|
|
ReleaseURI(void*, /* aObject*/
|
|
|
|
nsIAtom*, /* aPropertyName */
|
|
|
|
void* aPropertyValue,
|
|
|
|
void* /* aData */)
|
|
|
|
{
|
|
|
|
nsIURI* uri = static_cast<nsIURI*>(aPropertyValue);
|
|
|
|
NS_RELEASE(uri);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsINode::SetExplicitBaseURI(nsIURI* aURI)
|
|
|
|
{
|
|
|
|
nsresult rv = SetProperty(nsGkAtoms::baseURIProperty, aURI, ReleaseURI);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
SetHasExplicitBaseURI();
|
|
|
|
NS_ADDREF(aURI);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
2012-03-14 07:22:10 -07:00
|
|
|
static inline JSObject*
|
2012-02-16 08:45:19 -08:00
|
|
|
GetJSObjectChild(nsWrapperCache* aCache)
|
|
|
|
{
|
2012-03-14 07:22:10 -07:00
|
|
|
return aCache->PreservingWrapper() ? aCache->GetWrapperPreserveColor() : NULL;
|
2012-02-16 08:45:19 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
NeedsScriptTraverse(nsWrapperCache* aCache)
|
|
|
|
{
|
|
|
|
JSObject* o = GetJSObjectChild(aCache);
|
|
|
|
return o && xpc_IsGrayGCThing(o);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
2011-05-26 12:58:35 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsChildContentList)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsChildContentList)
|
|
|
|
|
2012-02-16 08:45:19 -08:00
|
|
|
// If nsChildContentList is changed so that any additional fields are
|
|
|
|
// traversed by the cycle collector, then CAN_SKIP must be updated.
|
2011-05-26 12:58:35 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsChildContentList)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsChildContentList)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsChildContentList)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsChildContentList)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
2008-10-22 07:31:14 -07:00
|
|
|
|
2012-02-16 08:45:19 -08:00
|
|
|
// 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
|
|
|
|
|
2008-11-03 02:31:47 -08:00
|
|
|
NS_INTERFACE_TABLE_HEAD(nsChildContentList)
|
2008-11-13 08:54:52 -08:00
|
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
2008-11-03 02:31:47 -08:00
|
|
|
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
|
2011-05-26 12:58:35 -07:00
|
|
|
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsChildContentList)
|
2010-03-17 08:09:05 -07:00
|
|
|
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(NodeList)
|
2008-10-22 07:31:14 -07:00
|
|
|
NS_INTERFACE_MAP_END
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-05-23 08:39:52 -07:00
|
|
|
JSObject*
|
2012-03-14 08:25:40 -07:00
|
|
|
nsChildContentList::WrapObject(JSContext *cx, JSObject *scope,
|
2011-06-29 10:17:37 -07:00
|
|
|
bool *triedToWrap)
|
2011-05-23 08:39:52 -07:00
|
|
|
{
|
2011-08-20 06:53:33 -07:00
|
|
|
return mozilla::dom::binding::NodeList::create(cx, scope, this, triedToWrap);
|
2011-05-23 08:39:52 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsChildContentList::GetLength(PRUint32* aLength)
|
|
|
|
{
|
|
|
|
*aLength = mNode ? mNode->GetChildCount() : 0;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-10-22 07:31:14 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsChildContentList::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
|
|
|
|
{
|
|
|
|
nsINode* node = GetNodeAt(aIndex);
|
|
|
|
if (!node) {
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CallQueryInterface(node, aReturn);
|
|
|
|
}
|
|
|
|
|
2009-01-29 11:46:18 -08:00
|
|
|
nsIContent*
|
2008-09-10 20:15:29 -07:00
|
|
|
nsChildContentList::GetNodeAt(PRUint32 aIndex)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (mNode) {
|
2008-09-10 20:15:29 -07:00
|
|
|
return mNode->GetChildAt(aIndex);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-09-10 20:15:29 -07:00
|
|
|
return nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-01-29 11:46:18 -08:00
|
|
|
PRInt32
|
|
|
|
nsChildContentList::IndexOf(nsIContent* aContent)
|
|
|
|
{
|
|
|
|
if (mNode) {
|
|
|
|
return mNode->IndexOf(aContent);
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_1(nsNode3Tearoff, mNode)
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-04-25 09:35:27 -07:00
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNode3Tearoff)
|
2009-06-14 11:06:22 -07:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMXPathNSResolver)
|
2010-04-19 08:41:37 -07:00
|
|
|
NS_INTERFACE_MAP_END_AGGREGATED(mNode)
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNode3Tearoff)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsNode3Tearoff)
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsNode3Tearoff::LookupNamespaceURI(const nsAString& aNamespacePrefix,
|
|
|
|
nsAString& aNamespaceURI)
|
|
|
|
{
|
2011-06-14 00:56:48 -07:00
|
|
|
return mNode->LookupNamespaceURI(aNamespacePrefix, aNamespaceURI);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
nsIContent*
|
|
|
|
nsGenericElement::GetFirstElementChild()
|
2008-08-04 17:58:16 -07:00
|
|
|
{
|
2010-04-19 08:41:37 -07:00
|
|
|
nsAttrAndChildArray& children = mAttrsAndChildren;
|
2008-08-04 17:58:16 -07:00
|
|
|
PRUint32 i, count = children.ChildCount();
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
nsIContent* child = children.ChildAt(i);
|
2010-04-30 06:12:05 -07:00
|
|
|
if (child->IsElement()) {
|
2010-04-19 08:41:37 -07:00
|
|
|
return child;
|
2008-08-04 17:58:16 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
return nsnull;
|
2008-08-04 17:58:16 -07:00
|
|
|
}
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
nsIContent*
|
|
|
|
nsGenericElement::GetLastElementChild()
|
2008-08-04 17:58:16 -07:00
|
|
|
{
|
2010-04-19 08:41:37 -07:00
|
|
|
nsAttrAndChildArray& children = mAttrsAndChildren;
|
2008-08-04 17:58:16 -07:00
|
|
|
PRUint32 i = children.ChildCount();
|
|
|
|
while (i > 0) {
|
|
|
|
nsIContent* child = children.ChildAt(--i);
|
2010-04-30 06:12:05 -07:00
|
|
|
if (child->IsElement()) {
|
2010-04-19 08:41:37 -07:00
|
|
|
return child;
|
2008-08-04 17:58:16 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
return nsnull;
|
2008-08-04 17:58:16 -07:00
|
|
|
}
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
nsIContent*
|
|
|
|
nsGenericElement::GetPreviousElementSibling()
|
2008-08-04 17:58:16 -07:00
|
|
|
{
|
2010-04-19 08:41:37 -07:00
|
|
|
nsIContent* parent = GetParent();
|
2008-08-04 17:58:16 -07:00
|
|
|
if (!parent) {
|
2010-04-19 08:41:37 -07:00
|
|
|
return nsnull;
|
2008-08-04 17:58:16 -07:00
|
|
|
}
|
|
|
|
|
2010-04-30 06:12:05 -07:00
|
|
|
NS_ASSERTION(parent->IsElement() ||
|
2008-08-04 17:58:16 -07:00
|
|
|
parent->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT),
|
|
|
|
"Parent content must be an element or a doc fragment");
|
|
|
|
|
|
|
|
nsAttrAndChildArray& children =
|
|
|
|
static_cast<nsGenericElement*>(parent)->mAttrsAndChildren;
|
2010-04-19 08:41:37 -07:00
|
|
|
PRInt32 index = children.IndexOfChild(this);
|
2008-08-04 17:58:16 -07:00
|
|
|
if (index < 0) {
|
2010-04-19 08:41:37 -07:00
|
|
|
return nsnull;
|
2008-08-04 17:58:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32 i = index;
|
|
|
|
while (i > 0) {
|
|
|
|
nsIContent* child = children.ChildAt((PRUint32)--i);
|
2010-04-30 06:12:05 -07:00
|
|
|
if (child->IsElement()) {
|
2010-04-19 08:41:37 -07:00
|
|
|
return child;
|
2008-08-04 17:58:16 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
return nsnull;
|
2008-08-04 17:58:16 -07:00
|
|
|
}
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
nsIContent*
|
|
|
|
nsGenericElement::GetNextElementSibling()
|
2008-08-04 17:58:16 -07:00
|
|
|
{
|
2010-04-19 08:41:37 -07:00
|
|
|
nsIContent* parent = GetParent();
|
2008-08-04 17:58:16 -07:00
|
|
|
if (!parent) {
|
2010-04-19 08:41:37 -07:00
|
|
|
return nsnull;
|
2008-08-04 17:58:16 -07:00
|
|
|
}
|
|
|
|
|
2010-04-30 06:12:05 -07:00
|
|
|
NS_ASSERTION(parent->IsElement() ||
|
2008-08-04 17:58:16 -07:00
|
|
|
parent->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT),
|
|
|
|
"Parent content must be an element or a doc fragment");
|
|
|
|
|
|
|
|
nsAttrAndChildArray& children =
|
|
|
|
static_cast<nsGenericElement*>(parent)->mAttrsAndChildren;
|
2010-04-19 08:41:37 -07:00
|
|
|
PRInt32 index = children.IndexOfChild(this);
|
2008-08-04 17:58:16 -07:00
|
|
|
if (index < 0) {
|
2010-04-19 08:41:37 -07:00
|
|
|
return nsnull;
|
2008-08-04 17:58:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32 i, count = children.ChildCount();
|
|
|
|
for (i = (PRUint32)index + 1; i < count; ++i) {
|
|
|
|
nsIContent* child = children.ChildAt(i);
|
2010-04-30 06:12:05 -07:00
|
|
|
if (child->IsElement()) {
|
2010-04-19 08:41:37 -07:00
|
|
|
return child;
|
2008-08-04 17:58:16 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2011-12-18 02:06:23 -08:00
|
|
|
nsGenericElement::GetChildElementCount(PRUint32* aResult)
|
|
|
|
{
|
|
|
|
*aResult = GetChildrenList()->Length(true);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// readonly attribute nsIDOMNodeList children
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsGenericElement::GetChildElements(nsIDOMNodeList** aResult)
|
|
|
|
{
|
|
|
|
NS_ADDREF(*aResult = GetChildrenList());
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsGenericElement::GetFirstElementChild(nsIDOMElement** aResult)
|
2010-04-19 08:41:37 -07:00
|
|
|
{
|
|
|
|
*aResult = nsnull;
|
|
|
|
|
2011-12-18 02:06:23 -08:00
|
|
|
nsIContent *result = GetFirstElementChild();
|
2010-04-19 08:41:37 -07:00
|
|
|
|
|
|
|
return result ? CallQueryInterface(result, aResult) : NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2011-12-18 02:06:23 -08:00
|
|
|
nsGenericElement::GetLastElementChild(nsIDOMElement** aResult)
|
2010-04-19 08:41:37 -07:00
|
|
|
{
|
|
|
|
*aResult = nsnull;
|
|
|
|
|
2011-12-18 02:06:23 -08:00
|
|
|
nsIContent *result = GetLastElementChild();
|
2010-04-19 08:41:37 -07:00
|
|
|
|
|
|
|
return result ? CallQueryInterface(result, aResult) : NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2011-12-18 02:06:23 -08:00
|
|
|
nsGenericElement::GetPreviousElementSibling(nsIDOMElement** aResult)
|
2010-04-19 08:41:37 -07:00
|
|
|
{
|
|
|
|
*aResult = nsnull;
|
|
|
|
|
2011-12-18 02:06:23 -08:00
|
|
|
nsIContent *result = GetPreviousElementSibling();
|
2010-04-19 08:41:37 -07:00
|
|
|
|
|
|
|
return result ? CallQueryInterface(result, aResult) : NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2011-12-18 02:06:23 -08:00
|
|
|
nsGenericElement::GetNextElementSibling(nsIDOMElement** aResult)
|
2010-04-19 08:41:37 -07:00
|
|
|
{
|
|
|
|
*aResult = nsnull;
|
|
|
|
|
2011-12-18 02:06:23 -08:00
|
|
|
nsIContent *result = GetNextElementSibling();
|
2010-04-19 08:41:37 -07:00
|
|
|
|
|
|
|
return result ? CallQueryInterface(result, aResult) : NS_OK;
|
2008-08-04 17:58:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsContentList*
|
2010-04-19 08:41:37 -07:00
|
|
|
nsGenericElement::GetChildrenList()
|
2008-08-04 17:58:16 -07:00
|
|
|
{
|
2010-12-21 17:04:00 -08:00
|
|
|
nsGenericElement::nsDOMSlots *slots = DOMSlots();
|
2008-08-04 17:58:16 -07:00
|
|
|
|
|
|
|
if (!slots->mChildrenList) {
|
2010-08-31 19:47:00 -07:00
|
|
|
slots->mChildrenList = new nsContentList(this, kNameSpaceID_Wildcard,
|
|
|
|
nsGkAtoms::_asterix, nsGkAtoms::_asterix,
|
2011-10-17 07:59:28 -07:00
|
|
|
false);
|
2008-08-04 17:58:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return slots->mChildrenList;
|
|
|
|
}
|
|
|
|
|
2011-08-22 02:14:13 -07:00
|
|
|
nsDOMTokenList*
|
2010-04-19 08:41:37 -07:00
|
|
|
nsGenericElement::GetClassList(nsresult *aResult)
|
|
|
|
{
|
|
|
|
*aResult = NS_ERROR_OUT_OF_MEMORY;
|
2008-08-04 17:58:16 -07:00
|
|
|
|
2010-12-21 17:04:00 -08:00
|
|
|
nsGenericElement::nsDOMSlots *slots = DOMSlots();
|
2008-08-04 17:58:16 -07:00
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
if (!slots->mClassList) {
|
|
|
|
nsCOMPtr<nsIAtom> classAttr = GetClassAttributeName();
|
|
|
|
if (!classAttr) {
|
|
|
|
*aResult = NS_OK;
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
slots->mClassList = new nsDOMTokenList(this, classAttr);
|
|
|
|
}
|
|
|
|
|
|
|
|
*aResult = NS_OK;
|
|
|
|
|
|
|
|
return slots->mClassList;
|
2008-08-04 17:58:16 -07:00
|
|
|
}
|
|
|
|
|
2009-08-12 01:55:14 -07:00
|
|
|
NS_IMETHODIMP
|
2011-12-18 02:06:23 -08:00
|
|
|
nsGenericElement::GetClassList(nsIDOMDOMTokenList** aResult)
|
2009-08-12 01:55:14 -07:00
|
|
|
{
|
2010-04-19 08:41:37 -07:00
|
|
|
*aResult = nsnull;
|
2009-08-12 01:55:14 -07:00
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
nsresult rv;
|
2011-12-18 02:06:23 -08:00
|
|
|
nsIDOMDOMTokenList* list = GetClassList(&rv);
|
2010-04-19 08:41:37 -07:00
|
|
|
NS_ENSURE_TRUE(list, rv);
|
2009-08-12 01:55:14 -07:00
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
NS_ADDREF(*aResult = list);
|
2009-08-12 01:55:14 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-12-18 02:06:23 -08:00
|
|
|
NS_IMETHODIMP
|
2011-09-28 23:19:26 -07:00
|
|
|
nsGenericElement::SetCapture(bool aRetargetToElement)
|
2009-09-13 06:13:16 -07:00
|
|
|
{
|
|
|
|
// 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.
|
2010-05-06 05:32:14 -07:00
|
|
|
if (nsIPresShell::GetCapturingContent())
|
2011-12-18 02:06:23 -08:00
|
|
|
return NS_OK;
|
2009-09-13 06:13:16 -07:00
|
|
|
|
2010-05-06 05:32:14 -07:00
|
|
|
nsIPresShell::SetCapturingContent(this, CAPTURE_PREVENTDRAG |
|
2010-02-02 18:07:08 -08:00
|
|
|
(aRetargetToElement ? CAPTURE_RETARGETTOELEMENT : 0));
|
2010-05-06 05:32:14 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-12-18 02:06:23 -08:00
|
|
|
NS_IMETHODIMP
|
2010-05-06 05:32:14 -07:00
|
|
|
nsGenericElement::ReleaseCapture()
|
2009-09-13 06:13:16 -07:00
|
|
|
{
|
2010-05-06 05:32:14 -07:00
|
|
|
if (nsIPresShell::GetCapturingContent() == this) {
|
2009-09-13 06:13:16 -07:00
|
|
|
nsIPresShell::SetCapturingContent(nsnull, 0);
|
|
|
|
}
|
2010-05-06 05:32:14 -07:00
|
|
|
|
2009-09-13 06:13:16 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-08-15 15:26:37 -07:00
|
|
|
nsIFrame*
|
|
|
|
nsGenericElement::GetStyledFrame()
|
|
|
|
{
|
|
|
|
nsIFrame *frame = GetPrimaryFrame(Flush_Layout);
|
2009-12-01 09:21:00 -08:00
|
|
|
return frame ? nsLayoutUtils::GetStyleFrame(frame) : nsnull;
|
2008-08-15 15:26:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsGenericElement::GetOffsetRect(nsRect& aRect, nsIContent** aOffsetParent)
|
|
|
|
{
|
|
|
|
*aOffsetParent = nsnull;
|
|
|
|
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.
|
2008-09-06 01:52:56 -07:00
|
|
|
nsIFrame* parent = frame->GetParent() ? frame->GetParent() : frame;
|
|
|
|
nsRect rcFrame = nsLayoutUtils::GetAllInFlowRectsUnion(frame, parent);
|
2008-08-15 15:26:37 -07:00
|
|
|
aRect.width = nsPresContext::AppUnitsToIntCSSPixels(rcFrame.width);
|
|
|
|
aRect.height = nsPresContext::AppUnitsToIntCSSPixels(rcFrame.height);
|
|
|
|
}
|
|
|
|
|
2009-09-02 20:57:36 -07:00
|
|
|
nsIScrollableFrame*
|
2010-04-19 08:41:37 -07:00
|
|
|
nsGenericElement::GetScrollFrame(nsIFrame **aStyledFrame)
|
2008-08-15 15:26:37 -07:00
|
|
|
{
|
|
|
|
// it isn't clear what to return for SVG nodes, so just return nothing
|
2010-04-19 08:41:37 -07:00
|
|
|
if (IsSVG()) {
|
2009-09-02 20:57:36 -07:00
|
|
|
if (aStyledFrame) {
|
|
|
|
*aStyledFrame = nsnull;
|
|
|
|
}
|
|
|
|
return nsnull;
|
2008-08-15 15:26:37 -07:00
|
|
|
}
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
nsIFrame* frame = GetStyledFrame();
|
2008-08-15 15:26:37 -07:00
|
|
|
|
2009-09-02 20:57:36 -07:00
|
|
|
if (aStyledFrame) {
|
|
|
|
*aStyledFrame = frame;
|
2008-08-15 15:26:37 -07:00
|
|
|
}
|
|
|
|
if (!frame) {
|
2009-09-02 20:57:36 -07:00
|
|
|
return nsnull;
|
2008-08-15 15:26:37 -07:00
|
|
|
}
|
|
|
|
|
2009-09-02 20:57:36 -07:00
|
|
|
// menu frames implement GetScrollTargetFrame but we don't want
|
2011-10-18 13:17:45 -07:00
|
|
|
// to use it here. Similar for comboboxes.
|
|
|
|
if (frame->GetType() != nsGkAtoms::menuFrame &&
|
|
|
|
frame->GetType() != nsGkAtoms::comboboxControlFrame) {
|
2009-09-02 20:57:36 -07:00
|
|
|
nsIScrollableFrame *scrollFrame = frame->GetScrollTargetFrame();
|
|
|
|
if (scrollFrame)
|
|
|
|
return scrollFrame;
|
|
|
|
}
|
2008-08-15 15:26:37 -07:00
|
|
|
|
2011-10-18 03:53:36 -07:00
|
|
|
nsIDocument* doc = OwnerDoc();
|
2011-09-28 23:19:26 -07:00
|
|
|
bool quirksMode = doc->GetCompatibilityMode() == eCompatibility_NavQuirks;
|
2010-04-30 06:12:05 -07:00
|
|
|
Element* elementWithRootScrollInfo =
|
|
|
|
quirksMode ? doc->GetBodyElement() : doc->GetRootElement();
|
2010-04-19 08:41:37 -07:00
|
|
|
if (this == elementWithRootScrollInfo) {
|
2009-09-02 20:57:36 -07:00
|
|
|
// 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();
|
2008-08-15 15:26:37 -07:00
|
|
|
}
|
|
|
|
|
2009-09-02 20:57:36 -07:00
|
|
|
return nsnull;
|
2008-08-15 15:26:37 -07:00
|
|
|
}
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
PRInt32
|
|
|
|
nsGenericElement::GetScrollTop()
|
2008-08-15 15:26:37 -07:00
|
|
|
{
|
2009-09-02 20:57:36 -07:00
|
|
|
nsIScrollableFrame* sf = GetScrollFrame();
|
2010-04-19 08:41:37 -07:00
|
|
|
|
|
|
|
return sf ?
|
|
|
|
nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollPosition().y) :
|
|
|
|
0;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2011-12-18 02:06:23 -08:00
|
|
|
nsGenericElement::GetScrollTop(PRInt32* aScrollTop)
|
2010-04-19 08:41:37 -07:00
|
|
|
{
|
2011-12-18 02:06:23 -08:00
|
|
|
*aScrollTop = GetScrollTop();
|
2008-08-15 15:26:37 -07:00
|
|
|
|
2009-09-02 20:57:36 -07:00
|
|
|
return NS_OK;
|
2008-08-15 15:26:37 -07:00
|
|
|
}
|
|
|
|
|
2011-12-18 02:06:23 -08:00
|
|
|
NS_IMETHODIMP
|
2010-04-19 08:41:37 -07:00
|
|
|
nsGenericElement::SetScrollTop(PRInt32 aScrollTop)
|
2008-08-15 15:26:37 -07:00
|
|
|
{
|
2009-09-02 20:57:36 -07:00
|
|
|
nsIScrollableFrame* sf = GetScrollFrame();
|
|
|
|
if (sf) {
|
|
|
|
nsPoint pt = sf->GetScrollPosition();
|
|
|
|
pt.y = nsPresContext::CSSPixelsToAppUnits(aScrollTop);
|
|
|
|
sf->ScrollTo(pt, nsIScrollableFrame::INSTANT);
|
2008-08-15 15:26:37 -07:00
|
|
|
}
|
2009-09-02 20:57:36 -07:00
|
|
|
return NS_OK;
|
2008-08-15 15:26:37 -07:00
|
|
|
}
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
PRInt32
|
|
|
|
nsGenericElement::GetScrollLeft()
|
2008-08-15 15:26:37 -07:00
|
|
|
{
|
2009-09-02 20:57:36 -07:00
|
|
|
nsIScrollableFrame* sf = GetScrollFrame();
|
2010-04-19 08:41:37 -07:00
|
|
|
|
|
|
|
return sf ?
|
|
|
|
nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollPosition().x) :
|
|
|
|
0;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2011-12-18 02:06:23 -08:00
|
|
|
nsGenericElement::GetScrollLeft(PRInt32* aScrollLeft)
|
2010-04-19 08:41:37 -07:00
|
|
|
{
|
2011-12-18 02:06:23 -08:00
|
|
|
*aScrollLeft = GetScrollLeft();
|
2008-08-15 15:26:37 -07:00
|
|
|
|
2009-09-02 20:57:36 -07:00
|
|
|
return NS_OK;
|
2008-08-15 15:26:37 -07:00
|
|
|
}
|
|
|
|
|
2011-12-18 02:06:23 -08:00
|
|
|
NS_IMETHODIMP
|
2010-04-19 08:41:37 -07:00
|
|
|
nsGenericElement::SetScrollLeft(PRInt32 aScrollLeft)
|
2008-08-15 15:26:37 -07:00
|
|
|
{
|
2009-09-02 20:57:36 -07:00
|
|
|
nsIScrollableFrame* sf = GetScrollFrame();
|
|
|
|
if (sf) {
|
|
|
|
nsPoint pt = sf->GetScrollPosition();
|
|
|
|
pt.x = nsPresContext::CSSPixelsToAppUnits(aScrollLeft);
|
|
|
|
sf->ScrollTo(pt, nsIScrollableFrame::INSTANT);
|
2008-08-15 15:26:37 -07:00
|
|
|
}
|
2009-09-02 20:57:36 -07:00
|
|
|
return NS_OK;
|
2008-08-15 15:26:37 -07:00
|
|
|
}
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
PRInt32
|
|
|
|
nsGenericElement::GetScrollHeight()
|
2008-08-15 15:26:37 -07:00
|
|
|
{
|
2010-04-19 08:41:37 -07:00
|
|
|
if (IsSVG())
|
|
|
|
return 0;
|
2008-08-15 15:26:37 -07:00
|
|
|
|
2009-09-02 20:57:36 -07:00
|
|
|
nsIScrollableFrame* sf = GetScrollFrame();
|
|
|
|
if (!sf) {
|
2008-08-15 15:26:37 -07:00
|
|
|
nsRect rcFrame;
|
|
|
|
nsCOMPtr<nsIContent> parent;
|
2010-04-19 08:41:37 -07:00
|
|
|
GetOffsetRect(rcFrame, getter_AddRefs(parent));
|
|
|
|
return rcFrame.height;
|
2008-08-15 15:26:37 -07:00
|
|
|
}
|
|
|
|
|
2009-09-02 20:57:36 -07:00
|
|
|
nscoord height = sf->GetScrollRange().height + sf->GetScrollPortRect().height;
|
2010-04-19 08:41:37 -07:00
|
|
|
return nsPresContext::AppUnitsToIntCSSPixels(height);
|
2008-08-15 15:26:37 -07:00
|
|
|
}
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
NS_IMETHODIMP
|
2011-12-18 02:06:23 -08:00
|
|
|
nsGenericElement::GetScrollHeight(PRInt32* aScrollHeight)
|
2008-08-15 15:26:37 -07:00
|
|
|
{
|
2011-12-18 02:06:23 -08:00
|
|
|
*aScrollHeight = GetScrollHeight();
|
2008-08-15 15:26:37 -07:00
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
nsGenericElement::GetScrollWidth()
|
|
|
|
{
|
|
|
|
if (IsSVG())
|
|
|
|
return 0;
|
2008-08-15 15:26:37 -07:00
|
|
|
|
2009-09-02 20:57:36 -07:00
|
|
|
nsIScrollableFrame* sf = GetScrollFrame();
|
|
|
|
if (!sf) {
|
2008-08-15 15:26:37 -07:00
|
|
|
nsRect rcFrame;
|
|
|
|
nsCOMPtr<nsIContent> parent;
|
2010-04-19 08:41:37 -07:00
|
|
|
GetOffsetRect(rcFrame, getter_AddRefs(parent));
|
|
|
|
return rcFrame.width;
|
2008-08-15 15:26:37 -07:00
|
|
|
}
|
|
|
|
|
2009-09-02 20:57:36 -07:00
|
|
|
nscoord width = sf->GetScrollRange().width + sf->GetScrollPortRect().width;
|
2010-04-19 08:41:37 -07:00
|
|
|
return nsPresContext::AppUnitsToIntCSSPixels(width);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2011-12-18 02:06:23 -08:00
|
|
|
nsGenericElement::GetScrollWidth(PRInt32 *aScrollWidth)
|
2010-04-19 08:41:37 -07:00
|
|
|
{
|
2011-12-18 02:06:23 -08:00
|
|
|
*aScrollWidth = GetScrollWidth();
|
2010-04-19 08:41:37 -07:00
|
|
|
|
2009-09-02 20:57:36 -07:00
|
|
|
return NS_OK;
|
2008-08-15 15:26:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsRect
|
2010-04-19 08:41:37 -07:00
|
|
|
nsGenericElement::GetClientAreaRect()
|
2008-08-15 15:26:37 -07:00
|
|
|
{
|
2009-09-02 20:57:36 -07:00
|
|
|
nsIFrame* styledFrame;
|
|
|
|
nsIScrollableFrame* sf = GetScrollFrame(&styledFrame);
|
2008-08-15 15:26:37 -07:00
|
|
|
|
2009-09-02 20:57:36 -07:00
|
|
|
if (sf) {
|
|
|
|
return sf->GetScrollPortRect();
|
2008-08-15 15:26:37 -07:00
|
|
|
}
|
|
|
|
|
2009-09-02 20:57:36 -07:00
|
|
|
if (styledFrame &&
|
|
|
|
(styledFrame->GetStyleDisplay()->mDisplay != NS_STYLE_DISPLAY_INLINE ||
|
|
|
|
styledFrame->IsFrameOfType(nsIFrame::eReplaced))) {
|
2008-08-15 15:26:37 -07:00
|
|
|
// Special case code to make client area work even when there isn't
|
|
|
|
// a scroll view, see bug 180552, bug 227567.
|
2009-09-02 20:57:36 -07:00
|
|
|
return styledFrame->GetPaddingRect() - styledFrame->GetPositionIgnoringScrolling();
|
2008-08-15 15:26:37 -07:00
|
|
|
}
|
|
|
|
|
2009-09-02 20:57:36 -07:00
|
|
|
// SVG nodes reach here and just return 0
|
2008-08-15 15:26:37 -07:00
|
|
|
return nsRect(0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
NS_IMETHODIMP
|
2011-12-18 02:06:23 -08:00
|
|
|
nsGenericElement::GetClientTop(PRInt32 *aClientTop)
|
2008-08-15 15:26:37 -07:00
|
|
|
{
|
2011-12-18 02:06:23 -08:00
|
|
|
*aClientTop = GetClientTop();
|
2008-08-15 15:26:37 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
NS_IMETHODIMP
|
2011-12-18 02:06:23 -08:00
|
|
|
nsGenericElement::GetClientLeft(PRInt32 *aClientLeft)
|
2008-08-15 15:26:37 -07:00
|
|
|
{
|
2011-12-18 02:06:23 -08:00
|
|
|
*aClientLeft = GetClientLeft();
|
2008-08-15 15:26:37 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
NS_IMETHODIMP
|
2011-12-18 02:06:23 -08:00
|
|
|
nsGenericElement::GetClientHeight(PRInt32 *aClientHeight)
|
2008-08-15 15:26:37 -07:00
|
|
|
{
|
2011-12-18 02:06:23 -08:00
|
|
|
*aClientHeight = GetClientHeight();
|
2008-08-15 15:26:37 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
NS_IMETHODIMP
|
2011-12-18 02:06:23 -08:00
|
|
|
nsGenericElement::GetClientWidth(PRInt32 *aClientWidth)
|
2008-08-15 15:26:37 -07:00
|
|
|
{
|
2011-12-18 02:06:23 -08:00
|
|
|
*aClientWidth = GetClientWidth();
|
2008-08-15 15:26:37 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-12-18 02:06:23 -08:00
|
|
|
NS_IMETHODIMP
|
2010-04-19 08:41:37 -07:00
|
|
|
nsGenericElement::GetBoundingClientRect(nsIDOMClientRect** aResult)
|
2007-05-30 15:32:54 -07:00
|
|
|
{
|
|
|
|
// Weak ref, since we addref it below
|
2008-03-11 17:51:12 -07:00
|
|
|
nsClientRect* rect = new nsClientRect();
|
2007-05-30 15:32:54 -07:00
|
|
|
NS_ADDREF(*aResult = rect);
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
|
2007-05-30 15:32:54 -07:00
|
|
|
if (!frame) {
|
|
|
|
// display:none, perhaps? Return the empty rect
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2008-02-27 01:26:15 -08:00
|
|
|
|
|
|
|
nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion(frame,
|
2011-12-27 19:26:46 -08:00
|
|
|
nsLayoutUtils::GetContainingBlockForClientRect(frame),
|
|
|
|
nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
|
2009-09-03 21:49:18 -07:00
|
|
|
rect->SetLayoutRect(r);
|
2007-05-30 15:32:54 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-01-28 09:42:52 -08:00
|
|
|
NS_IMETHODIMP
|
2011-08-11 06:29:50 -07:00
|
|
|
nsGenericElement::GetElementsByClassName(const nsAString& aClasses,
|
|
|
|
nsIDOMNodeList** aReturn)
|
|
|
|
{
|
|
|
|
return nsContentUtils::GetElementsByClassName(this, aClasses, aReturn);
|
|
|
|
}
|
|
|
|
|
2011-12-18 02:06:23 -08:00
|
|
|
NS_IMETHODIMP
|
2010-04-19 08:41:37 -07:00
|
|
|
nsGenericElement::GetClientRects(nsIDOMClientRectList** aResult)
|
2008-01-28 09:42:52 -08:00
|
|
|
{
|
|
|
|
*aResult = nsnull;
|
|
|
|
|
2011-08-22 02:14:13 -07:00
|
|
|
nsRefPtr<nsClientRectList> rectList = new nsClientRectList(this);
|
2008-02-27 01:26:15 -08:00
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
|
2008-01-28 09:42:52 -08:00
|
|
|
if (!frame) {
|
|
|
|
// display:none, perhaps? Return an empty list
|
|
|
|
*aResult = rectList.forget().get();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-09-24 14:01:48 -07:00
|
|
|
nsLayoutUtils::RectListBuilder builder(rectList);
|
2008-02-27 01:26:15 -08:00
|
|
|
nsLayoutUtils::GetAllInFlowRects(frame,
|
2011-12-27 19:26:46 -08:00
|
|
|
nsLayoutUtils::GetContainingBlockForClientRect(frame), &builder,
|
|
|
|
nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
|
2008-02-27 01:26:15 -08:00
|
|
|
if (NS_FAILED(builder.mRV))
|
|
|
|
return builder.mRV;
|
2008-01-28 09:42:52 -08:00
|
|
|
*aResult = rectList.forget().get();
|
2007-05-30 15:32:54 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
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 = nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
2007-04-25 09:35:27 -07:00
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNodeSupportsWeakRefTearoff)
|
2007-03-22 10:30:00 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
2010-04-19 08:41:37 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_1(nsNodeSelectorTearoff, mNode)
|
2008-07-21 17:55:52 -07:00
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNodeSelectorTearoff)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMNodeSelector)
|
2010-04-19 08:41:37 -07:00
|
|
|
NS_INTERFACE_MAP_END_AGGREGATED(mNode)
|
2008-07-21 17:55:52 -07:00
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNodeSelectorTearoff)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsNodeSelectorTearoff)
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsNodeSelectorTearoff::QuerySelector(const nsAString& aSelector,
|
|
|
|
nsIDOMElement **aReturn)
|
|
|
|
{
|
2010-04-19 08:41:37 -07:00
|
|
|
nsresult rv;
|
|
|
|
nsIContent* result = nsGenericElement::doQuerySelector(mNode, aSelector, &rv);
|
|
|
|
return result ? CallQueryInterface(result, aReturn) : rv;
|
2008-07-21 17:55:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsNodeSelectorTearoff::QuerySelectorAll(const nsAString& aSelector,
|
|
|
|
nsIDOMNodeList **aReturn)
|
|
|
|
{
|
2010-04-19 08:41:37 -07:00
|
|
|
return nsGenericElement::doQuerySelectorAll(mNode, aSelector, aReturn);
|
2008-07-21 17:55:52 -07:00
|
|
|
}
|
|
|
|
|
2011-08-24 12:49:25 -07:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
2011-08-24 12:49:25 -07:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
2008-07-21 17:55:52 -07:00
|
|
|
//----------------------------------------------------------------------
|
2011-04-07 19:29:49 -07:00
|
|
|
nsGenericElement::nsDOMSlots::nsDOMSlots()
|
|
|
|
: nsINode::nsSlots(),
|
2011-05-20 10:23:49 -07:00
|
|
|
mDataset(nsnull),
|
2007-03-22 10:30:00 -07:00
|
|
|
mBindingParent(nsnull)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsGenericElement::nsDOMSlots::~nsDOMSlots()
|
|
|
|
{
|
|
|
|
if (mAttributeMap) {
|
|
|
|
mAttributeMap->DropReference();
|
|
|
|
}
|
2009-08-12 01:55:14 -07:00
|
|
|
|
|
|
|
if (mClassList) {
|
|
|
|
mClassList->DropReference();
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-08-28 07:07:24 -07:00
|
|
|
void
|
|
|
|
nsGenericElement::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));
|
2011-08-22 02:14:13 -07:00
|
|
|
|
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mClassList");
|
|
|
|
cb.NoteXPCOMChild(mClassList.get());
|
2011-08-28 07:07:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsGenericElement::nsDOMSlots::Unlink(bool aIsXUL)
|
|
|
|
{
|
|
|
|
mStyle = nsnull;
|
|
|
|
mSMILOverrideStyle = nsnull;
|
|
|
|
if (mAttributeMap) {
|
|
|
|
mAttributeMap->DropReference();
|
|
|
|
mAttributeMap = nsnull;
|
|
|
|
}
|
|
|
|
if (aIsXUL)
|
|
|
|
NS_IF_RELEASE(mControllers);
|
|
|
|
mChildrenList = nsnull;
|
2011-08-22 02:14:13 -07:00
|
|
|
if (mClassList) {
|
|
|
|
mClassList->DropReference();
|
|
|
|
mClassList = nsnull;
|
|
|
|
}
|
2011-08-28 07:07:24 -07:00
|
|
|
}
|
|
|
|
|
2012-03-28 22:43:09 -07:00
|
|
|
nsGenericElement::nsGenericElement(already_AddRefed<nsINodeInfo> aNodeInfo)
|
2010-04-30 06:12:05 -07:00
|
|
|
: Element(aNodeInfo)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-06-14 00:56:49 -07:00
|
|
|
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");
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Set the default scriptID to JS - but skip SetScriptTypeID as it
|
|
|
|
// does extra work we know isn't necessary here...
|
2011-04-07 19:29:49 -07:00
|
|
|
SetFlags((nsIProgrammingLanguage::JAVASCRIPT << NODE_SCRIPT_TYPE_OFFSET));
|
|
|
|
SetIsElement();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsGenericElement::~nsGenericElement()
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(!IsInDoc(),
|
|
|
|
"Please remove this from the document properly");
|
2011-07-26 04:11:14 -07:00
|
|
|
if (GetParent()) {
|
|
|
|
NS_RELEASE(mParent);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsGenericElement::GetNodeName(nsAString& aNodeName)
|
|
|
|
{
|
2011-06-14 00:56:49 -07:00
|
|
|
aNodeName = NodeName();
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsGenericElement::GetLocalName(nsAString& aLocalName)
|
|
|
|
{
|
2011-06-14 00:56:49 -07:00
|
|
|
aLocalName = LocalName();
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsGenericElement::GetNodeValue(nsAString& aNodeValue)
|
|
|
|
{
|
|
|
|
SetDOMStringToNull(aNodeValue);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsGenericElement::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
|
|
|
|
nsGenericElement::GetNodeType(PRUint16* aNodeType)
|
|
|
|
{
|
2011-06-14 00:56:48 -07:00
|
|
|
*aNodeType = NodeType();
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsGenericElement::GetNamespaceURI(nsAString& aNamespaceURI)
|
|
|
|
{
|
|
|
|
return mNodeInfo->GetNamespaceURI(aNamespaceURI);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsGenericElement::GetPrefix(nsAString& aPrefix)
|
|
|
|
{
|
|
|
|
mNodeInfo->GetPrefix(aPrefix);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::InternalIsSupported(nsISupports* aObject,
|
|
|
|
const nsAString& aFeature,
|
|
|
|
const nsAString& aVersion,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool* aReturn)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aReturn);
|
2011-10-17 07:59:28 -07:00
|
|
|
*aReturn = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// 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) {
|
2011-10-17 07:59:28 -07:00
|
|
|
*aReturn = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
} 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) {
|
2011-10-17 07:59:28 -07:00
|
|
|
*aReturn = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
} else if (PL_strcasecmp(f, "XPath") == 0) {
|
|
|
|
if (aVersion.IsEmpty() ||
|
|
|
|
PL_strcmp(v, "3.0") == 0) {
|
2011-10-17 07:59:28 -07:00
|
|
|
*aReturn = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2011-04-30 06:56:16 -07:00
|
|
|
} else if (PL_strcasecmp(f, "SVGEvents") == 0 ||
|
|
|
|
PL_strcasecmp(f, "SVGZoomEvents") == 0 ||
|
2011-12-31 01:44:03 -08:00
|
|
|
nsSVGFeatures::HasFeature(aObject, aFeature)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aVersion.IsEmpty() ||
|
|
|
|
PL_strcmp(v, "1.0") == 0 ||
|
|
|
|
PL_strcmp(v, "1.1") == 0) {
|
2011-10-17 07:59:28 -07:00
|
|
|
*aReturn = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
2009-03-09 18:20:17 -07:00
|
|
|
else if (NS_SMILEnabled() && PL_strcasecmp(f, "TimeControl") == 0) {
|
2009-01-14 20:38:07 -08:00
|
|
|
if (aVersion.IsEmpty() || PL_strcmp(v, "1.0") == 0) {
|
2011-10-17 07:59:28 -07:00
|
|
|
*aReturn = true;
|
2009-01-14 20:38:07 -08:00
|
|
|
}
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsGenericElement::IsSupported(const nsAString& aFeature,
|
|
|
|
const nsAString& aVersion,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool* aReturn)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
return InternalIsSupported(this, aFeature, aVersion, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2011-09-28 23:19:26 -07:00
|
|
|
nsGenericElement::HasAttributes(bool* aReturn)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aReturn);
|
|
|
|
|
|
|
|
*aReturn = GetAttrCount() > 0;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsGenericElement::GetAttributes(nsIDOMNamedNodeMap** aAttributes)
|
|
|
|
{
|
2011-06-14 00:56:49 -07:00
|
|
|
if (!IsElement()) {
|
|
|
|
*aAttributes = nsnull;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-12-21 17:04:00 -08:00
|
|
|
nsDOMSlots *slots = DOMSlots();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (!slots->mAttributeMap) {
|
|
|
|
slots->mAttributeMap = new nsDOMAttributeMap(this);
|
|
|
|
if (!slots->mAttributeMap->Init()) {
|
|
|
|
slots->mAttributeMap = nsnull;
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ADDREF(*aAttributes = slots->mAttributeMap);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2011-09-28 23:19:26 -07:00
|
|
|
nsGenericElement::HasChildNodes(bool* aReturn)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
*aReturn = mAttrsAndChildren.ChildCount() > 0;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsGenericElement::GetTagName(nsAString& aTagName)
|
|
|
|
{
|
2011-06-14 00:56:49 -07:00
|
|
|
aTagName = NodeName();
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::GetAttribute(const nsAString& aName,
|
|
|
|
nsAString& aReturn)
|
|
|
|
{
|
|
|
|
const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
|
|
|
|
|
|
|
|
if (!name) {
|
|
|
|
if (mNodeInfo->NamespaceID() == kNameSpaceID_XUL) {
|
|
|
|
// XXX should be SetDOMStringToNull(aReturn);
|
|
|
|
// See bug 232598
|
|
|
|
aReturn.Truncate();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
SetDOMStringToNull(aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
GetAttr(name->NamespaceID(), name->LocalName(), aReturn);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::SetAttribute(const nsAString& aName,
|
|
|
|
const nsAString& aValue)
|
|
|
|
{
|
|
|
|
const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
|
|
|
|
|
|
|
|
if (!name) {
|
2011-10-17 07:59:28 -07:00
|
|
|
nsresult rv = nsContentUtils::CheckQName(aName, false);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aName);
|
|
|
|
NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return SetAttr(kNameSpaceID_None, nameAtom, aValue, true);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return SetAttr(name->NamespaceID(), name->LocalName(), name->GetPrefix(),
|
2011-10-17 07:59:28 -07:00
|
|
|
aValue, true);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::RemoveAttribute(const nsAString& aName)
|
|
|
|
{
|
|
|
|
const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
|
|
|
|
|
|
|
|
if (!name) {
|
2012-03-04 15:38:03 -08:00
|
|
|
// 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.
|
2007-03-22 10:30:00 -07:00
|
|
|
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);
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return UnsetAttr(name->NamespaceID(), name->LocalName(), true);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::GetAttributeNode(const nsAString& aName,
|
|
|
|
nsIDOMAttr** aReturn)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aReturn);
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
2011-10-18 03:53:36 -07:00
|
|
|
nsIDocument* document = OwnerDoc();
|
2011-06-23 01:30:48 -07:00
|
|
|
if (document) {
|
|
|
|
document->WarnOnceAbout(nsIDocument::eGetAttributeNode);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDOMNamedNodeMap> map;
|
|
|
|
nsresult rv = GetAttributes(getter_AddRefs(map));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
rv = map->GetNamedItem(aName, getter_AddRefs(node));
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && node) {
|
|
|
|
rv = CallQueryInterface(node, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::SetAttributeNode(nsIDOMAttr* aAttribute,
|
|
|
|
nsIDOMAttr** aReturn)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aReturn);
|
|
|
|
NS_ENSURE_ARG_POINTER(aAttribute);
|
|
|
|
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
2011-10-18 04:19:44 -07:00
|
|
|
OwnerDoc()->WarnOnceAbout(nsIDocument::eSetAttributeNode);
|
2011-06-23 01:30:48 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDOMNamedNodeMap> map;
|
|
|
|
nsresult rv = GetAttributes(getter_AddRefs(map));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> returnNode;
|
|
|
|
rv = map->SetNamedItem(aAttribute, getter_AddRefs(returnNode));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (returnNode) {
|
|
|
|
rv = CallQueryInterface(returnNode, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::RemoveAttributeNode(nsIDOMAttr* aAttribute,
|
|
|
|
nsIDOMAttr** aReturn)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aReturn);
|
|
|
|
NS_ENSURE_ARG_POINTER(aAttribute);
|
|
|
|
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
2011-10-18 04:19:44 -07:00
|
|
|
OwnerDoc()->WarnOnceAbout(nsIDocument::eRemoveAttributeNode);
|
2011-06-23 01:30:48 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDOMNamedNodeMap> map;
|
|
|
|
nsresult rv = GetAttributes(getter_AddRefs(map));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsAutoString name;
|
|
|
|
|
|
|
|
rv = aAttribute->GetName(name);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
rv = map->RemoveNamedItem(name, getter_AddRefs(node));
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && node) {
|
|
|
|
rv = CallQueryInterface(node, aReturn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::GetElementsByTagName(const nsAString& aTagname,
|
|
|
|
nsIDOMNodeList** aReturn)
|
|
|
|
{
|
2010-08-31 19:47:00 -07:00
|
|
|
nsContentList *list = NS_GetContentList(this, kNameSpaceID_Unknown,
|
2010-11-23 11:10:56 -08:00
|
|
|
aTagname).get();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// transfer ref to aReturn
|
|
|
|
*aReturn = list;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::GetAttributeNS(const nsAString& aNamespaceURI,
|
|
|
|
const nsAString& aLocalName,
|
|
|
|
nsAString& aReturn)
|
|
|
|
{
|
|
|
|
PRInt32 nsid =
|
|
|
|
nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
|
|
|
|
|
|
|
|
if (nsid == kNameSpaceID_Unknown) {
|
2012-03-11 00:48:16 -08:00
|
|
|
// Unknown namespace means no attribute.
|
|
|
|
SetDOMStringToNull(aReturn);
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAtom> name = do_GetAtom(aLocalName);
|
2012-03-11 00:48:16 -08:00
|
|
|
bool hasAttr = GetAttr(nsid, name, aReturn);
|
|
|
|
if (!hasAttr) {
|
|
|
|
SetDOMStringToNull(aReturn);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::SetAttributeNS(const nsAString& aNamespaceURI,
|
|
|
|
const nsAString& aQualifiedName,
|
|
|
|
const nsAString& aValue)
|
|
|
|
{
|
2012-03-28 22:43:09 -07:00
|
|
|
nsCOMPtr<nsINodeInfo> ni;
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult rv =
|
|
|
|
nsContentUtils::GetNodeInfoFromQName(aNamespaceURI, aQualifiedName,
|
|
|
|
mNodeInfo->NodeInfoManager(),
|
2011-06-14 00:56:49 -07:00
|
|
|
nsIDOMNode::ATTRIBUTE_NODE,
|
2007-03-22 10:30:00 -07:00
|
|
|
getter_AddRefs(ni));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
return SetAttr(ni->NamespaceID(), ni->NameAtom(), ni->GetPrefixAtom(),
|
2011-10-17 07:59:28 -07:00
|
|
|
aValue, true);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::RemoveAttributeNS(const nsAString& aNamespaceURI,
|
|
|
|
const nsAString& aLocalName)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIAtom> name = do_GetAtom(aLocalName);
|
|
|
|
PRInt32 nsid =
|
|
|
|
nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
|
|
|
|
|
|
|
|
if (nsid == kNameSpaceID_Unknown) {
|
2012-03-04 15:38:03 -08:00
|
|
|
// 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.
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
UnsetAttr(nsid, name, true);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::GetAttributeNodeNS(const nsAString& aNamespaceURI,
|
|
|
|
const nsAString& aLocalName,
|
|
|
|
nsIDOMAttr** aReturn)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aReturn);
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
2011-10-18 04:19:44 -07:00
|
|
|
OwnerDoc()->WarnOnceAbout(nsIDocument::eGetAttributeNodeNS);
|
2011-06-23 01:30:48 -07:00
|
|
|
|
2012-02-27 15:57:28 -08:00
|
|
|
return GetAttributeNodeNSInternal(aNamespaceURI, aLocalName, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::GetAttributeNodeNSInternal(const nsAString& aNamespaceURI,
|
|
|
|
const nsAString& aLocalName,
|
|
|
|
nsIDOMAttr** aReturn)
|
|
|
|
{
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDOMNamedNodeMap> map;
|
|
|
|
nsresult rv = GetAttributes(getter_AddRefs(map));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
rv = map->GetNamedItemNS(aNamespaceURI, aLocalName, getter_AddRefs(node));
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && node) {
|
|
|
|
rv = CallQueryInterface(node, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::SetAttributeNodeNS(nsIDOMAttr* aNewAttr,
|
|
|
|
nsIDOMAttr** aReturn)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aReturn);
|
|
|
|
NS_ENSURE_ARG_POINTER(aNewAttr);
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
2011-10-18 04:19:44 -07:00
|
|
|
OwnerDoc()->WarnOnceAbout(nsIDocument::eSetAttributeNodeNS);
|
2011-06-23 01:30:48 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDOMNamedNodeMap> map;
|
|
|
|
nsresult rv = GetAttributes(getter_AddRefs(map));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> returnNode;
|
|
|
|
rv = map->SetNamedItemNS(aNewAttr, getter_AddRefs(returnNode));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (returnNode) {
|
|
|
|
rv = CallQueryInterface(returnNode, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::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);
|
|
|
|
}
|
|
|
|
|
2010-11-23 11:10:56 -08:00
|
|
|
NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-11-23 11:10:56 -08:00
|
|
|
nsContentList *list = NS_GetContentList(this, nameSpaceId, aLocalName).get();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// transfer ref to aReturn
|
|
|
|
*aReturn = list;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2011-09-28 23:19:26 -07:00
|
|
|
nsGenericElement::HasAttribute(const nsAString& aName, bool* aReturn)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aReturn);
|
|
|
|
|
|
|
|
const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
|
|
|
|
*aReturn = (name != nsnull);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::HasAttributeNS(const nsAString& aNamespaceURI,
|
|
|
|
const nsAString& aLocalName,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool* aReturn)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aReturn);
|
|
|
|
|
|
|
|
PRInt32 nsid =
|
|
|
|
nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
|
|
|
|
|
|
|
|
if (nsid == kNameSpaceID_Unknown) {
|
|
|
|
// Unknown namespace means no attr...
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
*aReturn = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAtom> name = do_GetAtom(aLocalName);
|
|
|
|
*aReturn = HasAttr(nsid, name);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-05-21 15:26:48 -07:00
|
|
|
static nsXBLBinding*
|
|
|
|
GetFirstBindingWithContent(nsBindingManager* aBmgr, nsIContent* aBoundElem)
|
|
|
|
{
|
|
|
|
nsXBLBinding* binding = aBmgr->GetBinding(aBoundElem);
|
|
|
|
while (binding) {
|
|
|
|
if (binding->GetAnonymousContent()) {
|
|
|
|
return binding;
|
|
|
|
}
|
|
|
|
binding = binding->GetBaseBinding();
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2007-05-22 15:41:32 -07:00
|
|
|
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) {
|
2011-09-28 23:19:26 -07:00
|
|
|
bool allowScripts = aBinding->AllowScripts();
|
2007-07-08 17:58:15 -07:00
|
|
|
#ifdef MOZ_XUL
|
2007-05-24 17:28:20 -07:00
|
|
|
nsCOMPtr<nsIXULDocument> xulDoc = do_QueryInterface(aDocument);
|
2007-07-08 17:58:15 -07:00
|
|
|
#endif
|
2007-05-22 15:41:32 -07:00
|
|
|
PRUint32 i;
|
|
|
|
for (i = 0; i < inserts->Length(); ++i) {
|
|
|
|
nsCOMPtr<nsIContent> insertRoot =
|
|
|
|
inserts->ElementAt(i)->GetDefaultContent();
|
|
|
|
if (insertRoot) {
|
2011-09-27 00:54:58 -07:00
|
|
|
for (nsCOMPtr<nsIContent> child = insertRoot->GetFirstChild();
|
|
|
|
child;
|
|
|
|
child = child->GetNextSibling()) {
|
2007-05-22 15:41:32 -07:00
|
|
|
rv = child->BindToTree(aDocument, aInsertParent,
|
|
|
|
aBinding->GetBoundElement(), allowScripts);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-05-24 17:28:20 -07:00
|
|
|
|
2007-07-08 17:58:15 -07:00
|
|
|
#ifdef MOZ_XUL
|
2007-05-24 17:28:20 -07:00
|
|
|
if (xulDoc) {
|
|
|
|
xulDoc->AddSubtreeToDocument(child);
|
|
|
|
}
|
2007-07-08 17:58:15 -07:00
|
|
|
#endif
|
2007-05-22 15:41:32 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult
|
|
|
|
nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|
|
|
nsIContent* aBindingParent,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aCompileEventHandlers)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
|
|
|
|
NS_PRECONDITION(HasSameOwnerDoc(NODE_FROM(aParent, aDocument)),
|
|
|
|
"Must have the same owner document");
|
2007-05-15 18:13:47 -07:00
|
|
|
NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(),
|
2007-03-22 10:30:00 -07:00
|
|
|
"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!");
|
2007-05-21 15:26:48 -07:00
|
|
|
NS_PRECONDITION(!aParent || !aDocument ||
|
|
|
|
!aParent->HasFlag(NODE_FORCE_XBL_BINDINGS),
|
|
|
|
"Parent in document but flagged as forcing XBL");
|
2008-07-22 21:50:20 -07:00
|
|
|
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 "
|
2008-02-26 04:40:18 -08:00
|
|
|
"own binding parent");
|
2012-03-21 21:10:51 -07:00
|
|
|
NS_PRECONDITION(aBindingParent || !aParent ||
|
|
|
|
aBindingParent == aParent->GetBindingParent(),
|
|
|
|
"We should be passed the right binding parent");
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-08 17:58:15 -07:00
|
|
|
#ifdef MOZ_XUL
|
2007-03-22 10:30:00 -07:00
|
|
|
// First set the binding parent
|
2007-05-15 18:13:47 -07:00
|
|
|
nsXULElement* xulElem = nsXULElement::FromContent(this);
|
|
|
|
if (xulElem) {
|
|
|
|
xulElem->SetXULBindingParent(aBindingParent);
|
|
|
|
}
|
2007-07-08 17:58:15 -07:00
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2007-05-15 18:13:47 -07:00
|
|
|
if (aBindingParent) {
|
2010-12-21 17:04:00 -08:00
|
|
|
nsDOMSlots *slots = DOMSlots();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-05-15 18:13:47 -07:00
|
|
|
slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2008-07-22 21:50:20 -07:00
|
|
|
NS_ASSERTION(!aBindingParent || IsRootOfNativeAnonymousSubtree() ||
|
2008-04-11 15:44:48 -07:00
|
|
|
!HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE) ||
|
2008-12-03 02:18:57 -08:00
|
|
|
(aParent && aParent->IsInNativeAnonymousSubtree()),
|
2008-10-22 17:55:04 -07:00
|
|
|
"Trying to re-bind content from native anonymous subtree to "
|
2008-04-11 15:44:48 -07:00
|
|
|
"non-native anonymous parent!");
|
2009-02-24 10:39:09 -08:00
|
|
|
if (aParent && aParent->IsInNativeAnonymousSubtree()) {
|
2008-04-11 15:44:48 -07:00
|
|
|
SetFlags(NODE_IS_IN_ANONYMOUS_SUBTREE);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool hadForceXBL = HasFlag(NODE_FORCE_XBL_BINDINGS);
|
2007-05-21 15:26:48 -07:00
|
|
|
|
2007-05-15 18:13:47 -07:00
|
|
|
// Now set the parent and set the "Force attach xbl" flag if needed.
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aParent) {
|
2011-07-26 04:11:14 -07:00
|
|
|
if (!GetParent()) {
|
|
|
|
NS_ADDREF(aParent);
|
|
|
|
}
|
2011-04-07 19:29:49 -07:00
|
|
|
mParent = aParent;
|
2007-05-15 18:13:47 -07:00
|
|
|
|
|
|
|
if (aParent->HasFlag(NODE_FORCE_XBL_BINDINGS)) {
|
|
|
|
SetFlags(NODE_FORCE_XBL_BINDINGS);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
else {
|
2011-04-07 19:29:49 -07:00
|
|
|
mParent = aDocument;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2011-04-07 19:29:49 -07:00
|
|
|
SetParentIsContent(aParent);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// 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, nsnull,
|
|
|
|
// aDocument);
|
|
|
|
|
2012-03-14 13:14:02 -07:00
|
|
|
// We no longer need to track the subtree pointer (and in fact we'll assert
|
|
|
|
// if we do this any later).
|
|
|
|
ClearSubtreeRootPointer();
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Being added to a document.
|
2011-04-07 19:29:49 -07:00
|
|
|
SetInDocument();
|
2007-05-15 18:13:47 -07:00
|
|
|
|
|
|
|
// Unset this flag since we now really are in a document.
|
2010-01-18 01:26:40 -08:00
|
|
|
UnsetFlags(NODE_FORCE_XBL_BINDINGS |
|
|
|
|
// And clear the lazy frame construction bits.
|
2010-06-18 09:23:04 -07:00
|
|
|
NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES |
|
|
|
|
// And the restyle bits
|
|
|
|
ELEMENT_ALL_RESTYLE_FLAGS);
|
2012-03-14 13:14:02 -07:00
|
|
|
} else {
|
|
|
|
// If we're not in the doc, update our subtree pointer.
|
|
|
|
SetSubtreeRootPointer(aParent->SubtreeRoot());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-05-21 15:26:48 -07:00
|
|
|
// If NODE_FORCE_XBL_BINDINGS was set we might have anonymous children
|
|
|
|
// that also need to be told that they are moving.
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult rv;
|
2007-05-21 15:26:48 -07:00
|
|
|
if (hadForceXBL) {
|
2011-10-18 04:19:44 -07:00
|
|
|
nsBindingManager* bmgr = OwnerDoc()->BindingManager();
|
|
|
|
|
|
|
|
// First check if we have a binding...
|
|
|
|
nsXBLBinding* contBinding =
|
|
|
|
GetFirstBindingWithContent(bmgr, this);
|
|
|
|
if (contBinding) {
|
|
|
|
nsCOMPtr<nsIContent> anonRoot = contBinding->GetAnonymousContent();
|
|
|
|
bool allowScripts = contBinding->AllowScripts();
|
|
|
|
for (nsCOMPtr<nsIContent> child = anonRoot->GetFirstChild();
|
|
|
|
child;
|
|
|
|
child = child->GetNextSibling()) {
|
|
|
|
rv = child->BindToTree(aDocument, this, this, allowScripts);
|
2007-05-22 15:41:32 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-05-21 15:26:48 -07:00
|
|
|
}
|
|
|
|
|
2011-10-18 04:19:44 -07:00
|
|
|
// ...then check if we have content in insertion points that are
|
|
|
|
// direct children of the <content>
|
|
|
|
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);
|
2007-05-21 15:26:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
UpdateEditableState(false);
|
2007-06-27 19:48:16 -07:00
|
|
|
|
2007-05-21 15:26:48 -07:00
|
|
|
// Now recurse into our kids
|
2010-07-27 11:39:13 -07:00
|
|
|
for (nsIContent* child = GetFirstChild(); child;
|
|
|
|
child = child->GetNextSibling()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
rv = child->BindToTree(aDocument, this, aBindingParent,
|
|
|
|
aCompileEventHandlers);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsNodeUtils::ParentChainChanged(this);
|
|
|
|
|
2012-03-21 21:10:51 -07:00
|
|
|
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<nsStyledElement*>(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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-28 23:19:26 -07:00
|
|
|
nsGenericElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(aDeep || (!GetCurrentDoc() && !GetBindingParent()),
|
|
|
|
"Shallow unbind won't clear document and binding parent on "
|
|
|
|
"kids!");
|
2012-03-21 21:10:51 -07:00
|
|
|
|
|
|
|
RemoveFromIdTable();
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Make sure to unbind this node before doing the kids
|
2007-09-20 19:05:43 -07:00
|
|
|
nsIDocument *document =
|
2011-10-18 03:53:36 -07:00
|
|
|
HasFlag(NODE_FORCE_XBL_BINDINGS) ? OwnerDoc() : GetCurrentDoc();
|
2009-02-05 01:42:55 -08:00
|
|
|
|
2011-04-07 19:29:49 -07:00
|
|
|
if (aNullParent) {
|
2011-12-06 13:59:39 -08:00
|
|
|
if (IsFullScreenAncestor()) {
|
2011-10-31 22:11:09 -07:00
|
|
|
// The element being removed is an ancestor of the full-screen element,
|
|
|
|
// exit full-screen state.
|
2011-12-15 06:47:03 -08:00
|
|
|
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
|
|
|
"DOM", OwnerDoc(),
|
|
|
|
nsContentUtils::eDOM_PROPERTIES,
|
|
|
|
"RemovedFullScreenElement");
|
2011-12-06 13:59:39 -08:00
|
|
|
// Fully exit full-screen.
|
|
|
|
nsIDocument::ExitFullScreen(false);
|
2011-10-31 22:11:09 -07:00
|
|
|
}
|
2011-07-26 04:11:14 -07:00
|
|
|
if (GetParent()) {
|
|
|
|
NS_RELEASE(mParent);
|
|
|
|
} else {
|
|
|
|
mParent = nsnull;
|
|
|
|
}
|
2011-04-07 19:29:49 -07:00
|
|
|
SetParentIsContent(false);
|
|
|
|
}
|
|
|
|
ClearInDocument();
|
2009-02-05 01:42:55 -08:00
|
|
|
|
2012-03-14 13:14:02 -07:00
|
|
|
// Begin keeping track of our subtree root.
|
|
|
|
SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot());
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (document) {
|
|
|
|
// Notify XBL- & nsIAnonymousContentCreator-generated
|
|
|
|
// anonymous content that the document is changing.
|
2010-06-03 18:09:08 -07:00
|
|
|
document->BindingManager()->RemovedFromDocument(this, document);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-02-18 14:52:19 -08:00
|
|
|
document->ClearBoxObjectFor(this);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-10-07 20:22:42 -07:00
|
|
|
// Ensure that CSS transitions don't continue on an element at a
|
|
|
|
// different place in the tree (even if reinserted before next
|
|
|
|
// animation refresh).
|
2009-10-15 17:23:19 -07:00
|
|
|
// FIXME (Bug 522599): Need a test for this.
|
2009-10-07 20:22:42 -07:00
|
|
|
if (HasFlag(NODE_HAS_PROPERTIES)) {
|
|
|
|
DeleteProperty(nsGkAtoms::transitionsOfBeforeProperty);
|
|
|
|
DeleteProperty(nsGkAtoms::transitionsOfAfterProperty);
|
|
|
|
DeleteProperty(nsGkAtoms::transitionsProperty);
|
2011-04-11 23:18:44 -07:00
|
|
|
DeleteProperty(nsGkAtoms::animationsOfBeforeProperty);
|
|
|
|
DeleteProperty(nsGkAtoms::animationsOfAfterProperty);
|
|
|
|
DeleteProperty(nsGkAtoms::animationsProperty);
|
2009-10-07 20:22:42 -07:00
|
|
|
}
|
|
|
|
|
2007-05-15 18:13:47 -07:00
|
|
|
// Unset this since that's what the old code effectively did.
|
|
|
|
UnsetFlags(NODE_FORCE_XBL_BINDINGS);
|
2012-02-20 04:54:45 -08:00
|
|
|
|
2007-07-08 17:58:15 -07:00
|
|
|
#ifdef MOZ_XUL
|
2007-05-15 18:13:47 -07:00
|
|
|
nsXULElement* xulElem = nsXULElement::FromContent(this);
|
|
|
|
if (xulElem) {
|
|
|
|
xulElem->SetXULBindingParent(nsnull);
|
|
|
|
}
|
2007-07-08 17:58:15 -07:00
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2007-05-15 18:13:47 -07:00
|
|
|
nsDOMSlots *slots = GetExistingDOMSlots();
|
|
|
|
if (slots) {
|
|
|
|
slots->mBindingParent = nsnull;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (aDeep) {
|
2007-05-15 18:13:47 -07:00
|
|
|
// 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();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
for (i = 0; i < n; ++i) {
|
2011-10-17 07:59:28 -07:00
|
|
|
// Note that we pass false for aNullParent here, since we don't want
|
2007-03-22 10:30:00 -07:00
|
|
|
// the kids to forget us. We _do_ want them to forget their binding
|
|
|
|
// parent, though, since this only walks non-anonymous kids.
|
2011-10-17 07:59:28 -07:00
|
|
|
mAttrsAndChildren.ChildAt(i)->UnbindFromTree(true, false);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsNodeUtils::ParentChainChanged(this);
|
|
|
|
}
|
|
|
|
|
2010-02-11 09:34:01 -08:00
|
|
|
already_AddRefed<nsINodeList>
|
2010-10-15 08:34:35 -07:00
|
|
|
nsGenericElement::GetChildren(PRUint32 aFilter)
|
2010-02-11 09:34:01 -08:00
|
|
|
{
|
2009-06-15 23:32:10 -07:00
|
|
|
nsRefPtr<nsSimpleContentList> list = new nsSimpleContentList(this);
|
2010-02-11 09:34:01 -08:00
|
|
|
if (!list) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIFrame *frame = GetPrimaryFrame();
|
|
|
|
|
|
|
|
// Append :before generated content.
|
|
|
|
if (frame) {
|
|
|
|
nsIFrame *beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
|
|
|
|
if (beforeFrame) {
|
2010-02-20 16:52:50 -08:00
|
|
|
list->AppendElement(beforeFrame->GetContent());
|
2010-02-11 09:34:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 = nsnull;
|
|
|
|
|
2011-10-18 03:53:36 -07:00
|
|
|
nsIDocument* document = OwnerDoc();
|
2011-10-18 04:19:44 -07:00
|
|
|
if (!(aFilter & eAllButXBL)) {
|
|
|
|
childList = document->BindingManager()->GetXBLChildNodesFor(this);
|
|
|
|
if (!childList) {
|
|
|
|
childList = GetChildNodesList();
|
2010-02-11 09:34:01 -08:00
|
|
|
}
|
2011-10-18 04:19:44 -07:00
|
|
|
|
2010-02-11 09:34:01 -08:00
|
|
|
} else {
|
2011-10-18 04:19:44 -07:00
|
|
|
childList = document->BindingManager()->GetContentListFor(this);
|
2010-02-11 09:34:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2010-10-15 08:34:35 -07:00
|
|
|
creator->AppendAnonymousContentTo(*list, aFilter);
|
2010-02-11 09:34:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Append :after generated content.
|
|
|
|
nsIFrame *afterFrame = nsLayoutUtils::GetAfterFrame(frame);
|
|
|
|
if (afterFrame) {
|
2010-02-20 16:52:50 -08:00
|
|
|
list->AppendElement(afterFrame->GetContent());
|
2010-02-11 09:34:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsINodeList* returnList = nsnull;
|
|
|
|
list.forget(&returnList);
|
|
|
|
return returnList;
|
|
|
|
}
|
|
|
|
|
2008-03-12 03:26:12 -07:00
|
|
|
static nsIContent*
|
2008-06-23 01:07:06 -07:00
|
|
|
FindNativeAnonymousSubtreeOwner(nsIContent* aContent)
|
2008-03-12 03:26:12 -07:00
|
|
|
{
|
2008-06-23 01:07:06 -07:00
|
|
|
if (aContent->IsInNativeAnonymousSubtree()) {
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isNativeAnon = false;
|
2008-06-23 01:07:06 -07:00
|
|
|
while (aContent && !isNativeAnon) {
|
2008-07-22 21:50:20 -07:00
|
|
|
isNativeAnon = aContent->IsRootOfNativeAnonymousSubtree();
|
2008-06-23 01:07:06 -07:00
|
|
|
aContent = aContent->GetParent();
|
|
|
|
}
|
2008-03-12 03:26:12 -07:00
|
|
|
}
|
|
|
|
return aContent;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult
|
2011-06-23 19:17:59 -07:00
|
|
|
nsIContent::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
//FIXME! Document how this event retargeting works, Bug 329124.
|
2011-10-17 07:59:28 -07:00
|
|
|
aVisitor.mCanHandle = true;
|
2012-02-27 06:03:15 -08:00
|
|
|
aVisitor.mMayHaveListenerManager = HasListenerManager();
|
2007-05-13 06:59:00 -07:00
|
|
|
|
|
|
|
// Don't propagate mouseover and mouseout events when mouse is moving
|
|
|
|
// inside native anonymous content.
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isAnonForEvents = IsRootOfNativeAnonymousSubtree();
|
2008-06-23 01:07:06 -07:00
|
|
|
if ((aVisitor.mEvent->message == NS_MOUSE_ENTER_SYNTH ||
|
|
|
|
aVisitor.mEvent->message == NS_MOUSE_EXIT_SYNTH) &&
|
2008-08-27 04:11:12 -07:00
|
|
|
// Check if we should stop event propagation when event has just been
|
|
|
|
// dispatched or when we're about to propagate from
|
|
|
|
// native anonymous subtree.
|
2011-06-23 19:17:59 -07:00
|
|
|
((this == aVisitor.mEvent->originalTarget &&
|
|
|
|
!IsInNativeAnonymousSubtree()) || isAnonForEvents)) {
|
2007-05-13 06:59:00 -07:00
|
|
|
nsCOMPtr<nsIContent> relatedTarget =
|
2007-07-08 00:08:04 -07:00
|
|
|
do_QueryInterface(static_cast<nsMouseEvent*>
|
|
|
|
(aVisitor.mEvent)->relatedTarget);
|
2007-05-13 06:59:00 -07:00
|
|
|
if (relatedTarget &&
|
2011-10-18 03:53:36 -07:00
|
|
|
relatedTarget->OwnerDoc() == OwnerDoc()) {
|
2007-05-13 06:59:00 -07:00
|
|
|
|
|
|
|
// 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.
|
2011-06-23 19:17:59 -07:00
|
|
|
// If this is the original target, aVisitor.mRelatedTargetIsInAnon
|
2007-05-13 06:59:00 -07:00
|
|
|
// must be updated.
|
|
|
|
if (isAnonForEvents || aVisitor.mRelatedTargetIsInAnon ||
|
2011-06-23 19:17:59 -07:00
|
|
|
(aVisitor.mEvent->originalTarget == this &&
|
2008-02-26 04:40:18 -08:00
|
|
|
(aVisitor.mRelatedTargetIsInAnon =
|
|
|
|
relatedTarget->IsInNativeAnonymousSubtree()))) {
|
2011-06-23 19:17:59 -07:00
|
|
|
nsIContent* anonOwner = FindNativeAnonymousSubtreeOwner(this);
|
2008-06-23 01:07:06 -07:00
|
|
|
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) {
|
2008-08-27 04:11:12 -07:00
|
|
|
#ifdef DEBUG_smaug
|
|
|
|
nsCOMPtr<nsIContent> originalTarget =
|
2008-06-23 01:07:06 -07:00
|
|
|
do_QueryInterface(aVisitor.mEvent->originalTarget);
|
2008-08-27 04:11:12 -07:00
|
|
|
nsAutoString ot, ct, rt;
|
|
|
|
if (originalTarget) {
|
|
|
|
originalTarget->Tag()->ToString(ot);
|
2008-06-23 01:07:06 -07:00
|
|
|
}
|
2011-06-23 19:17:59 -07:00
|
|
|
Tag()->ToString(ct);
|
2008-08-27 04:11:12 -07:00
|
|
|
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)"
|
2011-06-23 19:17:59 -07:00
|
|
|
: (IsInNativeAnonymousSubtree()
|
2008-08-27 04:11:12 -07:00
|
|
|
? "(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 = nsnull;
|
|
|
|
// Event should not propagate to non-anon content.
|
|
|
|
aVisitor.mCanHandle = isAnonForEvents;
|
|
|
|
return NS_OK;
|
2007-05-18 03:23:45 -07:00
|
|
|
}
|
|
|
|
}
|
2007-05-13 06:59:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-23 19:17:59 -07:00
|
|
|
nsIContent* parent = GetParent();
|
|
|
|
// Event may need to be retargeted if this is the root of a native
|
2008-12-03 01:26:38 -08:00
|
|
|
// anonymous content subtree or event is dispatched somewhere inside XBL.
|
2007-05-13 06:59:00 -07:00
|
|
|
if (isAnonForEvents) {
|
2008-04-11 15:44:48 -07:00
|
|
|
// 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!?!");
|
2007-03-22 10:30:00 -07:00
|
|
|
aVisitor.mEventTargetAtParent = parent;
|
2008-12-03 01:26:38 -08:00
|
|
|
} else if (parent && aVisitor.mOriginalTargetIsInAnon) {
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->target));
|
|
|
|
if (content && content->GetBindingParent() == parent) {
|
|
|
|
aVisitor.mEventTargetAtParent = parent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for an anonymous parent
|
|
|
|
// XXX XBL2/sXBL issue
|
2011-06-23 19:17:59 -07:00
|
|
|
if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
|
2011-10-18 04:19:44 -07:00
|
|
|
nsIContent* insertionParent = OwnerDoc()->BindingManager()->
|
|
|
|
GetInsertionParent(this);
|
|
|
|
NS_ASSERTION(!(aVisitor.mEventTargetAtParent && insertionParent &&
|
|
|
|
aVisitor.mEventTargetAtParent != insertionParent),
|
|
|
|
"Retargeting and having insertion parent!");
|
|
|
|
if (insertionParent) {
|
|
|
|
parent = insertionParent;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parent) {
|
|
|
|
aVisitor.mParentTarget = parent;
|
|
|
|
} else {
|
2011-06-23 19:17:59 -07:00
|
|
|
aVisitor.mParentTarget = GetCurrentDoc();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
const nsAttrValue*
|
2008-09-10 20:22:20 -07:00
|
|
|
nsGenericElement::DoGetClasses() const
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-09-10 20:22:20 -07:00
|
|
|
NS_NOTREACHED("Shouldn't ever be called");
|
2007-03-22 10:30:00 -07:00
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsGenericElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-03-28 20:32:11 -07:00
|
|
|
nsIDOMCSSStyleDeclaration*
|
|
|
|
nsGenericElement::GetSMILOverrideStyle()
|
2009-09-02 17:28:37 -07:00
|
|
|
{
|
2010-12-21 17:04:00 -08:00
|
|
|
nsGenericElement::nsDOMSlots *slots = DOMSlots();
|
2009-09-02 17:28:37 -07:00
|
|
|
|
|
|
|
if (!slots->mSMILOverrideStyle) {
|
2011-10-17 07:59:28 -07:00
|
|
|
slots->mSMILOverrideStyle = new nsDOMCSSAttributeDeclaration(this, true);
|
2009-09-02 17:28:37 -07:00
|
|
|
}
|
|
|
|
|
2011-03-28 20:32:11 -07:00
|
|
|
return slots->mSMILOverrideStyle;
|
2009-09-02 17:28:37 -07:00
|
|
|
}
|
|
|
|
|
2011-03-10 18:48:57 -08:00
|
|
|
css::StyleRule*
|
2009-09-02 17:28:37 -07:00
|
|
|
nsGenericElement::GetSMILOverrideStyleRule()
|
|
|
|
{
|
|
|
|
nsGenericElement::nsDOMSlots *slots = GetExistingDOMSlots();
|
2009-09-24 10:58:04 -07:00
|
|
|
return slots ? slots->mSMILOverrideStyleRule.get() : nsnull;
|
2009-09-02 17:28:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2011-03-10 18:48:57 -08:00
|
|
|
nsGenericElement::SetSMILOverrideStyleRule(css::StyleRule* aStyleRule,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aNotify)
|
2009-09-02 17:28:37 -07:00
|
|
|
{
|
2010-12-21 17:04:00 -08:00
|
|
|
nsGenericElement::nsDOMSlots *slots = DOMSlots();
|
2009-09-02 17:28:37 -07:00
|
|
|
|
|
|
|
slots->mSMILOverrideStyleRule = aStyleRule;
|
|
|
|
|
|
|
|
if (aNotify) {
|
|
|
|
nsIDocument* doc = GetCurrentDoc();
|
2010-03-11 22:03:49 -08:00
|
|
|
// Only need to request a restyle if we're in a document. (We might not
|
2009-10-20 09:54:47 -07:00
|
|
|
// 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) {
|
2010-06-25 06:59:57 -07:00
|
|
|
nsCOMPtr<nsIPresShell> shell = doc->GetShell();
|
2010-01-07 02:36:11 -08:00
|
|
|
if (shell) {
|
2010-06-30 18:54:29 -07:00
|
|
|
shell->RestyleForAnimation(this, eRestyle_Self);
|
2009-10-20 09:54:47 -07:00
|
|
|
}
|
2009-09-02 17:28:37 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-03-10 18:48:57 -08:00
|
|
|
css::StyleRule*
|
2007-03-22 10:30:00 -07:00
|
|
|
nsGenericElement::GetInlineStyleRule()
|
|
|
|
{
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2011-03-10 18:48:57 -08:00
|
|
|
nsGenericElement::SetInlineStyleRule(css::StyleRule* aStyleRule,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
NS_NOTYETIMPLEMENTED("nsGenericElement::SetInlineStyleRule");
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
NS_IMETHODIMP_(bool)
|
2007-03-22 10:30:00 -07:00
|
|
|
nsGenericElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
|
|
|
{
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsChangeHint
|
|
|
|
nsGenericElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
|
|
|
|
PRInt32 aModType) const
|
|
|
|
{
|
|
|
|
return nsChangeHint(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIAtom *
|
|
|
|
nsGenericElement::GetClassAttributeName() const
|
|
|
|
{
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2007-03-22 10:30:00 -07:00
|
|
|
nsGenericElement::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) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-03-28 22:43:09 -07:00
|
|
|
already_AddRefed<nsINodeInfo>
|
2007-03-22 10:30:00 -07:00
|
|
|
nsGenericElement::GetExistingAttrNameFromQName(const nsAString& aStr) const
|
|
|
|
{
|
|
|
|
const nsAttrName* name = InternalGetExistingAttrNameFromQName(aStr);
|
|
|
|
if (!name) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2012-03-28 22:43:09 -07:00
|
|
|
nsINodeInfo* nodeInfo;
|
2007-03-22 10:30:00 -07:00
|
|
|
if (name->IsAtom()) {
|
2011-06-14 00:56:49 -07:00
|
|
|
nodeInfo = mNodeInfo->NodeInfoManager()->
|
|
|
|
GetNodeInfo(name->Atom(), nsnull, kNameSpaceID_None,
|
|
|
|
nsIDOMNode::ATTRIBUTE_NODE).get();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
NS_ADDREF(nodeInfo = name->NodeInfo());
|
|
|
|
}
|
|
|
|
|
|
|
|
return nodeInfo;
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2007-03-22 10:30:00 -07:00
|
|
|
nsGenericElement::IsLink(nsIURI** aURI) const
|
|
|
|
{
|
|
|
|
*aURI = nsnull;
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2007-03-22 10:30:00 -07:00
|
|
|
nsGenericElement::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();
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
if (!document)
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(document->GetWindow());
|
|
|
|
if (!window)
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
|
|
|
|
nsCOMPtr<nsPIDOMWindow> focusedFrame;
|
|
|
|
nsIContent* contentToBlur =
|
2011-10-17 07:59:28 -07:00
|
|
|
nsFocusManager::GetFocusedDescendant(window, false, getter_AddRefs(focusedFrame));
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
if (contentToBlur == aContent)
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
// if focus on this element would get redirected, then check the redirected
|
|
|
|
// content as well when blurring.
|
|
|
|
return (contentToBlur && nsFocusManager::GetRedirectedFocus(aContent) == contentToBlur);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsIContent*
|
|
|
|
nsGenericElement::GetBindingParent() const
|
|
|
|
{
|
|
|
|
nsDOMSlots *slots = GetExistingDOMSlots();
|
|
|
|
|
|
|
|
if (slots) {
|
|
|
|
return slots->mBindingParent;
|
|
|
|
}
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2007-03-22 10:30:00 -07:00
|
|
|
nsGenericElement::IsNodeOfType(PRUint32 aFlags) const
|
|
|
|
{
|
2010-04-30 06:12:06 -07:00
|
|
|
return !(aFlags & ~eCONTENT);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
PRUint32
|
|
|
|
nsGenericElement::GetScriptTypeID() const
|
|
|
|
{
|
|
|
|
PtrBits flags = GetFlags();
|
|
|
|
|
2010-06-18 09:23:04 -07:00
|
|
|
return (flags >> NODE_SCRIPT_TYPE_OFFSET) & NODE_SCRIPT_TYPE_MASK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-05-07 06:59:51 -07:00
|
|
|
NS_IMETHODIMP
|
2007-03-22 10:30:00 -07:00
|
|
|
nsGenericElement::SetScriptTypeID(PRUint32 aLang)
|
|
|
|
{
|
2010-06-18 09:23:04 -07:00
|
|
|
if ((aLang & NODE_SCRIPT_TYPE_MASK) != aLang) {
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ERROR("script ID too large!");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
/* SetFlags will just mask in the specific flags set, leaving existing
|
|
|
|
ones alone. So we must clear all the bits first */
|
2010-08-31 13:46:41 -07:00
|
|
|
UnsetFlags(NODE_SCRIPT_TYPE_MASK << NODE_SCRIPT_TYPE_OFFSET);
|
2007-03-22 10:30:00 -07:00
|
|
|
SetFlags(aLang << NODE_SCRIPT_TYPE_OFFSET);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::InsertChildAt(nsIContent* aKid,
|
|
|
|
PRUint32 aIndex,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(aKid, "null ptr");
|
|
|
|
|
2010-05-10 18:12:34 -07:00
|
|
|
return doInsertChildAt(aKid, aIndex, aNotify, mAttrsAndChildren);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-02-07 06:36:16 -08:00
|
|
|
static nsresult
|
|
|
|
AdoptNodeIntoOwnerDoc(nsINode *aParent, nsINode *aNode)
|
|
|
|
{
|
2011-05-09 12:33:03 -07:00
|
|
|
NS_ASSERTION(!aNode->GetNodeParent(),
|
|
|
|
"Should have removed from parent already");
|
|
|
|
|
2011-10-18 03:53:36 -07:00
|
|
|
nsIDocument *doc = aParent->OwnerDoc();
|
2011-02-07 06:36:16 -08:00
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> adoptedNode;
|
|
|
|
rv = domDoc->AdoptNode(node, getter_AddRefs(adoptedNode));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2011-10-18 03:53:36 -07:00
|
|
|
NS_ASSERTION(aParent->OwnerDoc() == doc,
|
2011-05-09 12:33:03 -07:00
|
|
|
"ownerDoc chainged while adopting");
|
2011-02-07 06:36:16 -08:00
|
|
|
NS_ASSERTION(adoptedNode == node, "Uh, adopt node changed nodes?");
|
|
|
|
NS_ASSERTION(aParent->HasSameOwnerDoc(aNode),
|
|
|
|
"ownerDocument changed again after adopting!");
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsresult
|
2010-05-10 18:12:34 -07:00
|
|
|
nsINode::doInsertChildAt(nsIContent* aKid, PRUint32 aIndex,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aNotify, nsAttrAndChildArray& aChildArray)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-05-09 12:33:03 -07:00
|
|
|
NS_PRECONDITION(!aKid->GetNodeParent(),
|
|
|
|
"Inserting node that already has parent");
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult rv;
|
|
|
|
|
2011-05-09 12:33:03 -07:00
|
|
|
// The id-handling code, and in the future possibly other code, need to
|
|
|
|
// react to unexpected attribute changes.
|
|
|
|
nsMutationGuard::DidMutate();
|
|
|
|
|
|
|
|
// Do this before checking the child-count since this could cause mutations
|
|
|
|
nsIDocument* doc = GetCurrentDoc();
|
|
|
|
mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, aNotify);
|
|
|
|
|
2010-05-10 18:12:34 -07:00
|
|
|
if (!HasSameOwnerDoc(aKid)) {
|
2011-09-17 06:32:32 -07:00
|
|
|
rv = AdoptNodeIntoOwnerDoc(this, aKid);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-10-26 18:55:06 -07:00
|
|
|
PRUint32 childCount = aChildArray.ChildCount();
|
|
|
|
NS_ENSURE_TRUE(aIndex <= childCount, NS_ERROR_ILLEGAL_VALUE);
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isAppend = (aIndex == childCount);
|
2010-10-26 18:55:06 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
rv = aChildArray.InsertChildAt(aKid, aIndex);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2010-05-10 18:12:34 -07:00
|
|
|
if (aIndex == 0) {
|
|
|
|
mFirstChild = aKid;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIContent* parent =
|
|
|
|
IsNodeOfType(eDOCUMENT) ? nsnull : static_cast<nsIContent*>(this);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-03-21 21:10:51 -07:00
|
|
|
rv = aKid->BindToTree(doc, parent,
|
|
|
|
parent ? parent->GetBindingParent() : nsnull,
|
|
|
|
true);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (NS_FAILED(rv)) {
|
2010-05-10 18:12:34 -07:00
|
|
|
if (GetFirstChild() == aKid) {
|
|
|
|
mFirstChild = aKid->GetNextSibling();
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
aChildArray.RemoveChildAt(aIndex);
|
|
|
|
aKid->UnbindFromTree();
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2010-05-10 18:12:34 -07:00
|
|
|
NS_ASSERTION(aKid->GetNodeParent() == this,
|
2009-07-30 02:27:24 -07:00
|
|
|
"Did we run script inappropriately?");
|
|
|
|
|
|
|
|
if (aNotify) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// Note that we always want to call ContentInserted when things are added
|
|
|
|
// as kids to documents
|
2010-05-10 18:12:34 -07:00
|
|
|
if (parent && isAppend) {
|
2010-05-10 18:12:34 -07:00
|
|
|
nsNodeUtils::ContentAppended(parent, aKid, aIndex);
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
2010-05-10 18:12:34 -07:00
|
|
|
nsNodeUtils::ContentInserted(this, aKid, aIndex);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (nsContentUtils::HasMutationListeners(aKid,
|
2010-05-10 18:12:34 -07:00
|
|
|
NS_EVENT_BITS_MUTATION_NODEINSERTED, this)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
nsMutationEvent mutation(true, NS_MUTATION_NODEINSERTED);
|
2010-05-10 18:12:34 -07:00
|
|
|
mutation.mRelatedNode = do_QueryInterface(this);
|
2008-04-04 18:11:50 -07:00
|
|
|
|
2011-10-18 03:53:36 -07:00
|
|
|
mozAutoSubtreeModified subtree(OwnerDoc(), this);
|
2011-12-16 22:02:05 -08:00
|
|
|
(new nsAsyncDOMEvent(aKid, mutation))->RunDOMEventWhenSafe();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2011-09-28 23:19:26 -07:00
|
|
|
nsGenericElement::RemoveChildAt(PRUint32 aIndex, bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContent> oldKid = mAttrsAndChildren.GetSafeChildAt(aIndex);
|
|
|
|
NS_ASSERTION(oldKid == GetChildAt(aIndex), "Unexpected child in RemoveChildAt");
|
|
|
|
|
|
|
|
if (oldKid) {
|
2012-03-29 14:09:06 -07:00
|
|
|
doRemoveChildAt(aIndex, aNotify, oldKid, mAttrsAndChildren);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-03-29 14:09:06 -07:00
|
|
|
void
|
2011-09-28 23:19:26 -07:00
|
|
|
nsINode::doRemoveChildAt(PRUint32 aIndex, bool aNotify,
|
2011-05-25 10:58:23 -07:00
|
|
|
nsIContent* aKid, nsAttrAndChildArray& aChildArray)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2010-05-10 18:12:34 -07:00
|
|
|
NS_PRECONDITION(aKid && aKid->GetNodeParent() == this &&
|
|
|
|
aKid == GetChildAt(aIndex) &&
|
|
|
|
IndexOf(aKid) == (PRInt32)aIndex, "Bogus aKid");
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-05-09 12:33:03 -07:00
|
|
|
nsMutationGuard::DidMutate();
|
2008-03-14 16:08:57 -07:00
|
|
|
|
2011-05-09 12:33:03 -07:00
|
|
|
nsIDocument* doc = GetCurrentDoc();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-05-09 12:33:03 -07:00
|
|
|
mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-07-21 15:05:17 -07:00
|
|
|
nsIContent* previousSibling = aKid->GetPreviousSibling();
|
|
|
|
|
2010-05-10 18:12:34 -07:00
|
|
|
if (GetFirstChild() == aKid) {
|
|
|
|
mFirstChild = aKid->GetNextSibling();
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
aChildArray.RemoveChildAt(aIndex);
|
|
|
|
|
|
|
|
if (aNotify) {
|
2010-07-21 15:05:17 -07:00
|
|
|
nsNodeUtils::ContentRemoved(this, aKid, aIndex, previousSibling);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
aKid->UnbindFromTree();
|
|
|
|
}
|
|
|
|
|
2011-08-11 06:29:50 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsGenericElement::GetTextContent(nsAString &aTextContent)
|
|
|
|
{
|
2011-10-17 07:59:28 -07:00
|
|
|
nsContentUtils::GetNodeTextContent(this, true, aTextContent);
|
2011-08-11 06:29:50 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsGenericElement::SetTextContent(const nsAString& aTextContent)
|
|
|
|
{
|
2011-10-17 07:59:28 -07:00
|
|
|
return nsContentUtils::SetNodeTextContent(this, aTextContent, false);
|
2011-08-11 06:29:50 -07:00
|
|
|
}
|
|
|
|
|
2012-02-20 04:54:45 -08:00
|
|
|
/* static */
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult
|
|
|
|
nsGenericElement::DispatchEvent(nsPresContext* aPresContext,
|
|
|
|
nsEvent* aEvent,
|
|
|
|
nsIContent* aTarget,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aFullDispatch,
|
2007-03-22 10:30:00 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-03-25 22:38:22 -07:00
|
|
|
nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!shell) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aFullDispatch) {
|
|
|
|
return shell->HandleEventWithTarget(aEvent, nsnull, aTarget, aStatus);
|
|
|
|
}
|
|
|
|
|
|
|
|
return shell->HandleDOMEventWithTarget(aTarget, aEvent, aStatus);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::DispatchClickEvent(nsPresContext* aPresContext,
|
|
|
|
nsInputEvent* aSourceEvent,
|
|
|
|
nsIContent* aTarget,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aFullDispatch,
|
2011-07-19 09:19:32 -07:00
|
|
|
PRUint32 aFlags,
|
2007-03-22 10:30:00 -07:00
|
|
|
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;
|
2008-12-11 15:55:15 -08:00
|
|
|
float pressure = 0;
|
2010-04-06 05:59:24 -07:00
|
|
|
PRUint16 inputSource = 0;
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aSourceEvent->eventStructType == NS_MOUSE_EVENT) {
|
2007-07-08 00:08:04 -07:00
|
|
|
clickCount = static_cast<nsMouseEvent*>(aSourceEvent)->clickCount;
|
2008-12-11 15:55:15 -08:00
|
|
|
pressure = static_cast<nsMouseEvent*>(aSourceEvent)->pressure;
|
2010-04-06 05:59:24 -07:00
|
|
|
inputSource = static_cast<nsMouseEvent*>(aSourceEvent)->inputSource;
|
|
|
|
} else if (aSourceEvent->eventStructType == NS_KEY_EVENT) {
|
2011-08-26 00:43:56 -07:00
|
|
|
inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2008-12-11 15:55:15 -08:00
|
|
|
event.pressure = pressure;
|
2007-03-22 10:30:00 -07:00
|
|
|
event.clickCount = clickCount;
|
2010-04-06 05:59:24 -07:00
|
|
|
event.inputSource = inputSource;
|
2007-03-22 10:30:00 -07:00
|
|
|
event.isShift = aSourceEvent->isShift;
|
|
|
|
event.isControl = aSourceEvent->isControl;
|
|
|
|
event.isAlt = aSourceEvent->isAlt;
|
|
|
|
event.isMeta = aSourceEvent->isMeta;
|
2011-07-25 10:35:25 -07:00
|
|
|
event.flags |= aFlags; // Be careful not to overwrite existing flags!
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return DispatchEvent(aPresContext, &event, aTarget, aFullDispatch, aStatus);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIFrame*
|
|
|
|
nsGenericElement::GetPrimaryFrame(mozFlushType aType)
|
|
|
|
{
|
|
|
|
nsIDocument* doc = GetCurrentDoc();
|
|
|
|
if (!doc) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cause a flush, so we get up-to-date frame
|
|
|
|
// information
|
|
|
|
doc->FlushPendingNotifications(aType);
|
|
|
|
|
2009-12-24 13:20:05 -08:00
|
|
|
return GetPrimaryFrame();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-11-30 09:57:03 -08:00
|
|
|
void
|
|
|
|
nsGenericElement::DestroyContent()
|
|
|
|
{
|
2011-10-18 03:53:36 -07:00
|
|
|
nsIDocument *document = OwnerDoc();
|
2011-10-18 04:19:44 -07:00
|
|
|
document->BindingManager()->RemovedFromDocument(this, document);
|
|
|
|
document->ClearBoxObjectFor(this);
|
2007-11-30 09:57:03 -08:00
|
|
|
|
2008-11-13 08:54:52 -08:00
|
|
|
// XXX We really should let cycle collection do this, but that currently still
|
|
|
|
// leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684).
|
2009-05-12 13:20:42 -07:00
|
|
|
nsContentUtils::ReleaseWrapper(this, this);
|
2008-11-13 08:54:52 -08:00
|
|
|
|
2007-11-30 09:57:03 -08:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-10 15:47:01 -07:00
|
|
|
void
|
|
|
|
nsGenericElement::SaveSubtreeState()
|
|
|
|
{
|
|
|
|
PRUint32 i, count = mAttrsAndChildren.ChildCount();
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
mAttrsAndChildren.ChildAt(i)->SaveSubtreeState();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
// Generic DOMNode implementations
|
|
|
|
|
2011-06-29 23:16:09 -07:00
|
|
|
// When replacing, aRefChild is the content being replaced; when
|
2007-03-22 10:30:00 -07:00
|
|
|
// inserting it's the content before which we're inserting. In the
|
|
|
|
// latter case it may be null.
|
|
|
|
static
|
2011-09-28 23:19:26 -07:00
|
|
|
bool IsAllowedAsChild(nsIContent* aNewChild, nsINode* aParent,
|
|
|
|
bool aIsReplace, nsINode* aRefChild)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(aNewChild, "Must have new child");
|
2011-06-29 23:16:09 -07:00
|
|
|
NS_PRECONDITION(!aIsReplace || aRefChild,
|
2007-03-22 10:30:00 -07:00
|
|
|
"Must have ref content for replace");
|
2010-03-17 08:06:19 -07:00
|
|
|
NS_PRECONDITION(aParent->IsNodeOfType(nsINode::eDOCUMENT) ||
|
|
|
|
aParent->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT) ||
|
2010-04-30 06:12:05 -07:00
|
|
|
aParent->IsElement(),
|
2010-03-17 08:06:19 -07:00
|
|
|
"Nodes that are not documents, document fragments or "
|
|
|
|
"elements can't be parents!");
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-03-21 21:10:51 -07:00
|
|
|
// A common case is that aNewChild has no kids, in which case
|
|
|
|
// aParent can't be a descendant of aNewChild unless they're
|
|
|
|
// actually equal to each other. Fast-path that case, since aParent
|
|
|
|
// could be pretty deep in the DOM tree.
|
|
|
|
if (aParent &&
|
|
|
|
(aNewChild == aParent ||
|
|
|
|
(aNewChild->GetFirstChild() &&
|
|
|
|
nsContentUtils::ContentIsDescendantOf(aParent, aNewChild)))) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// The allowed child nodes differ for documents and elements
|
2011-06-14 00:56:50 -07:00
|
|
|
switch (aNewChild->NodeType()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
case nsIDOMNode::COMMENT_NODE :
|
|
|
|
case nsIDOMNode::PROCESSING_INSTRUCTION_NODE :
|
|
|
|
// OK in both cases
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
case nsIDOMNode::TEXT_NODE :
|
|
|
|
case nsIDOMNode::CDATA_SECTION_NODE :
|
|
|
|
case nsIDOMNode::ENTITY_REFERENCE_NODE :
|
|
|
|
// Only allowed under elements
|
|
|
|
return aParent != nsnull;
|
|
|
|
case nsIDOMNode::ELEMENT_NODE :
|
|
|
|
{
|
2010-03-17 08:06:19 -07:00
|
|
|
if (!aParent->IsNodeOfType(nsINode::eDOCUMENT)) {
|
|
|
|
// Always ok to have elements under other elements or document fragments
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-04-30 06:12:05 -07:00
|
|
|
Element* rootElement =
|
|
|
|
static_cast<nsIDocument*>(aParent)->GetRootElement();
|
|
|
|
if (rootElement) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// Already have a documentElement, so this is only OK if we're
|
|
|
|
// replacing it.
|
2011-06-29 23:16:09 -07:00
|
|
|
return aIsReplace && rootElement == aRefChild;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// We don't have a documentElement yet. Our one remaining constraint is
|
|
|
|
// that the documentElement must come after the doctype.
|
2011-06-29 23:16:09 -07:00
|
|
|
if (!aRefChild) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// Appending is just fine.
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now grovel for a doctype
|
2010-03-17 08:06:19 -07:00
|
|
|
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aParent);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(doc, "Shouldn't happen");
|
|
|
|
nsCOMPtr<nsIDOMDocumentType> docType;
|
|
|
|
doc->GetDoctype(getter_AddRefs(docType));
|
|
|
|
nsCOMPtr<nsIContent> docTypeContent = do_QueryInterface(docType);
|
|
|
|
|
|
|
|
if (!docTypeContent) {
|
|
|
|
// It's all good.
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-03-17 08:06:19 -07:00
|
|
|
PRInt32 doctypeIndex = aParent->IndexOf(docTypeContent);
|
2011-06-29 23:16:09 -07:00
|
|
|
PRInt32 insertIndex = aParent->IndexOf(aRefChild);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Now we're OK in the following two cases only:
|
|
|
|
// 1) We're replacing something that's not before the doctype
|
|
|
|
// 2) We're inserting before something that comes after the doctype
|
|
|
|
return aIsReplace ? (insertIndex >= doctypeIndex) :
|
|
|
|
insertIndex > doctypeIndex;
|
|
|
|
}
|
|
|
|
case nsIDOMNode::DOCUMENT_TYPE_NODE :
|
|
|
|
{
|
2010-03-17 08:06:19 -07:00
|
|
|
if (!aParent->IsNodeOfType(nsINode::eDOCUMENT)) {
|
|
|
|
// doctypes only allowed under documents
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-03-17 08:06:19 -07:00
|
|
|
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aParent);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(doc, "Shouldn't happen");
|
|
|
|
nsCOMPtr<nsIDOMDocumentType> docType;
|
|
|
|
doc->GetDoctype(getter_AddRefs(docType));
|
|
|
|
nsCOMPtr<nsIContent> docTypeContent = do_QueryInterface(docType);
|
|
|
|
if (docTypeContent) {
|
|
|
|
// Already have a doctype, so this is only OK if we're replacing it
|
2011-06-29 23:16:09 -07:00
|
|
|
return aIsReplace && docTypeContent == aRefChild;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// We don't have a doctype yet. Our one remaining constraint is
|
|
|
|
// that the doctype must come before the documentElement.
|
2010-04-30 06:12:05 -07:00
|
|
|
Element* rootElement =
|
|
|
|
static_cast<nsIDocument*>(aParent)->GetRootElement();
|
|
|
|
if (!rootElement) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// It's all good
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-06-29 23:16:09 -07:00
|
|
|
if (!aRefChild) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// Trying to append a doctype, but have a documentElement
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-04-30 06:12:05 -07:00
|
|
|
PRInt32 rootIndex = aParent->IndexOf(rootElement);
|
2011-06-29 23:16:09 -07:00
|
|
|
PRInt32 insertIndex = aParent->IndexOf(aRefChild);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Now we're OK if and only if insertIndex <= rootIndex. Indeed, either
|
2011-06-29 23:16:09 -07:00
|
|
|
// we end up replacing aRefChild or we end up before it. Either one is
|
|
|
|
// ok as long as aRefChild is not after rootElement.
|
2007-03-22 10:30:00 -07:00
|
|
|
return insertIndex <= rootIndex;
|
|
|
|
}
|
|
|
|
case nsIDOMNode::DOCUMENT_FRAGMENT_NODE :
|
|
|
|
{
|
|
|
|
// Note that for now we only allow nodes inside document fragments if
|
|
|
|
// they're allowed inside elements. If we ever change this to allow
|
|
|
|
// doctype nodes in document fragments, we'll need to update this code
|
2010-03-17 08:06:19 -07:00
|
|
|
if (!aParent->IsNodeOfType(nsINode::eDOCUMENT)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// All good here
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool sawElement = false;
|
2011-09-27 00:54:58 -07:00
|
|
|
for (nsIContent* child = aNewChild->GetFirstChild();
|
|
|
|
child;
|
|
|
|
child = child->GetNextSibling()) {
|
|
|
|
if (child->IsElement()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
if (sawElement) {
|
|
|
|
// Can't put two elements into a document
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2011-10-17 07:59:28 -07:00
|
|
|
sawElement = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
// If we can put this content at the the right place, we might be ok;
|
|
|
|
// if not, we bail out.
|
2011-09-27 00:54:58 -07:00
|
|
|
if (!IsAllowedAsChild(child, aParent, aIsReplace, aRefChild)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Everything in the fragment checked out ok, so we can stick it in here
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
/*
|
|
|
|
* aNewChild is of invalid type.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-04-30 04:01:25 -07:00
|
|
|
void
|
|
|
|
nsGenericElement::FireNodeInserted(nsIDocument* aDoc,
|
|
|
|
nsINode* aParent,
|
2011-05-25 10:58:23 -07:00
|
|
|
nsTArray<nsCOMPtr<nsIContent> >& aNodes)
|
2010-04-30 04:01:25 -07:00
|
|
|
{
|
2011-05-25 10:58:23 -07:00
|
|
|
PRUint32 count = aNodes.Length();
|
|
|
|
for (PRUint32 i = 0; i < count; ++i) {
|
2010-04-30 04:01:25 -07:00
|
|
|
nsIContent* childContent = aNodes[i];
|
|
|
|
|
|
|
|
if (nsContentUtils::HasMutationListeners(childContent,
|
|
|
|
NS_EVENT_BITS_MUTATION_NODEINSERTED, aParent)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
nsMutationEvent mutation(true, NS_MUTATION_NODEINSERTED);
|
2010-04-30 04:01:25 -07:00
|
|
|
mutation.mRelatedNode = do_QueryInterface(aParent);
|
|
|
|
|
|
|
|
mozAutoSubtreeModified subtree(aDoc, aParent);
|
2011-12-16 22:02:05 -08:00
|
|
|
(new nsAsyncDOMEvent(childContent, mutation))->RunDOMEventWhenSafe();
|
2010-04-30 04:01:25 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult
|
2011-09-28 23:19:26 -07:00
|
|
|
nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
|
2010-03-17 08:06:19 -07:00
|
|
|
nsINode* aRefChild)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (!aNewChild || (aReplace && !aRefChild)) {
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
|
|
|
|
2011-05-09 12:33:03 -07:00
|
|
|
if ((!IsNodeOfType(eDOCUMENT) &&
|
|
|
|
!IsNodeOfType(eDOCUMENT_FRAGMENT) &&
|
|
|
|
!IsElement()) ||
|
|
|
|
!aNewChild->IsNodeOfType(eCONTENT)){
|
2010-04-15 01:28:57 -07:00
|
|
|
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
|
|
|
}
|
|
|
|
|
2011-06-14 00:56:48 -07:00
|
|
|
PRUint16 nodeType = aNewChild->NodeType();
|
2011-05-09 12:33:03 -07:00
|
|
|
|
|
|
|
// Before we do anything else, fire all DOMNodeRemoved mutation events
|
|
|
|
// We do this up front as to avoid having to deal with script running
|
|
|
|
// at random places further down.
|
|
|
|
// Scope firing mutation events so that we don't carry any state that
|
|
|
|
// might be stale
|
|
|
|
{
|
|
|
|
// This check happens again further down (though then using IndexOf).
|
|
|
|
// We're only checking this here to avoid firing mutation events when
|
|
|
|
// none should be fired.
|
|
|
|
// It's ok that we do the check twice in the case when firing mutation
|
|
|
|
// events as we need to recheck after running script anyway.
|
|
|
|
if (aRefChild && aRefChild->GetNodeParent() != this) {
|
|
|
|
return NS_ERROR_DOM_NOT_FOUND_ERR;
|
|
|
|
}
|
|
|
|
|
2011-06-29 23:16:09 -07:00
|
|
|
// If we're replacing, fire for node-to-be-replaced.
|
|
|
|
// If aRefChild == aNewChild then we'll fire for it in check below
|
|
|
|
if (aReplace && aRefChild != aNewChild) {
|
2011-10-18 03:53:36 -07:00
|
|
|
nsContentUtils::MaybeFireNodeRemoved(aRefChild, this, OwnerDoc());
|
2011-05-09 12:33:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the new node already has a parent, fire for removing from old
|
|
|
|
// parent
|
|
|
|
nsINode* oldParent = aNewChild->GetNodeParent();
|
|
|
|
if (oldParent) {
|
|
|
|
nsContentUtils::MaybeFireNodeRemoved(aNewChild, oldParent,
|
2011-10-18 03:53:36 -07:00
|
|
|
aNewChild->OwnerDoc());
|
2011-05-09 12:33:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we're inserting a fragment, fire for all the children of the
|
|
|
|
// fragment
|
|
|
|
if (nodeType == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
|
|
|
|
static_cast<nsGenericElement*>(aNewChild)->FireNodeRemovedForChildren();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-18 03:53:36 -07:00
|
|
|
nsIDocument* doc = OwnerDoc();
|
2011-05-09 12:33:03 -07:00
|
|
|
nsIContent* newContent = static_cast<nsIContent*>(aNewChild);
|
2007-03-22 10:30:00 -07:00
|
|
|
PRInt32 insPos;
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
mozAutoDocUpdate batch(GetCurrentDoc(), UPDATE_CONTENT_MODEL, true);
|
2010-10-26 18:55:06 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Figure out which index to insert at
|
|
|
|
if (aRefChild) {
|
2010-03-17 08:06:19 -07:00
|
|
|
insPos = IndexOf(aRefChild);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (insPos < 0) {
|
|
|
|
return NS_ERROR_DOM_NOT_FOUND_ERR;
|
|
|
|
}
|
2010-03-17 08:06:19 -07:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
insPos = GetChildCount();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure that the inserted node is allowed as a child of its new parent.
|
2011-06-29 23:16:09 -07:00
|
|
|
if (!IsAllowedAsChild(newContent, this, aReplace, aRefChild)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
|
|
|
}
|
|
|
|
|
2011-06-14 00:56:48 -07:00
|
|
|
nsresult res;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// If we're replacing
|
|
|
|
if (aReplace) {
|
2011-10-17 07:59:28 -07:00
|
|
|
res = RemoveChildAt(insPos, true);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
2011-05-09 12:33:03 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-05-09 12:33:03 -07:00
|
|
|
if (newContent->IsRootOfAnonymousSubtree()) {
|
|
|
|
// This is anonymous content. Don't allow its insertion
|
|
|
|
// anywhere, since it might have UnbindFromTree calls coming
|
|
|
|
// its way.
|
|
|
|
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-05-09 12:33:03 -07:00
|
|
|
// Remove the new child from the old parent if one exists
|
2011-08-23 05:57:29 -07:00
|
|
|
nsCOMPtr<nsINode> oldParent = newContent->GetNodeParent();
|
2011-05-09 12:33:03 -07:00
|
|
|
if (oldParent) {
|
|
|
|
PRInt32 removeIndex = oldParent->IndexOf(newContent);
|
|
|
|
if (removeIndex < 0) {
|
|
|
|
// newContent is anonymous. We can't deal with this, so just bail
|
|
|
|
NS_ERROR("How come our flags didn't catch this?");
|
|
|
|
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
res = oldParent->RemoveChildAt(removeIndex, true);
|
2011-05-09 12:33:03 -07:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
|
|
|
|
|
|
|
// Adjust insert index if the node we ripped out was a sibling
|
|
|
|
// of the node we're inserting before
|
|
|
|
if (oldParent == this && removeIndex < insPos) {
|
|
|
|
--insPos;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-09 12:33:03 -07:00
|
|
|
// Move new child over to our document if needed. Do this after removing
|
|
|
|
// it from its parent so that AdoptNode doesn't fire DOMNodeRemoved
|
|
|
|
// DocumentType nodes are the only nodes that can have a null
|
|
|
|
// ownerDocument according to the DOM spec, and we need to allow
|
|
|
|
// inserting them w/o calling AdoptNode().
|
2011-09-17 06:32:32 -07:00
|
|
|
if (!HasSameOwnerDoc(newContent)) {
|
2011-05-09 12:33:03 -07:00
|
|
|
res = AdoptNodeIntoOwnerDoc(this, aNewChild);
|
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
|
|
|
}
|
2011-02-07 06:36:16 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/*
|
|
|
|
* Check if we're inserting a document fragment. If we are, we need
|
|
|
|
* to remove the children of the document fragment and add them
|
|
|
|
* individually (i.e. we don't add the actual document fragment).
|
|
|
|
*/
|
|
|
|
if (nodeType == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
|
|
|
|
PRUint32 count = newContent->GetChildCount();
|
|
|
|
|
2009-07-30 02:27:24 -07:00
|
|
|
if (!count) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Copy the children into a separate array to avoid having to deal with
|
|
|
|
// mutations to the fragment while we're inserting.
|
2011-05-25 10:58:23 -07:00
|
|
|
nsAutoTArray<nsCOMPtr<nsIContent>, 50> fragChildren;
|
|
|
|
fragChildren.SetCapacity(count);
|
2011-09-27 00:54:58 -07:00
|
|
|
for (nsIContent* child = newContent->GetFirstChild();
|
|
|
|
child;
|
|
|
|
child = child->GetNextSibling()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(child->GetCurrentDoc() == nsnull,
|
|
|
|
"How did we get a child with a current doc?");
|
2011-05-25 10:58:23 -07:00
|
|
|
fragChildren.AppendElement(child);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-05-25 10:58:23 -07:00
|
|
|
// Remove the children from the fragment.
|
|
|
|
for (PRUint32 i = count; i > 0;) {
|
2011-10-17 07:59:28 -07:00
|
|
|
newContent->RemoveChildAt(--i, true);
|
2009-07-30 02:27:24 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool appending =
|
2010-04-30 06:12:05 -07:00
|
|
|
!IsNodeOfType(eDOCUMENT) && PRUint32(insPos) == GetChildCount();
|
2011-07-26 23:43:37 -07:00
|
|
|
PRInt32 firstInsPos = insPos;
|
2010-05-10 18:12:34 -07:00
|
|
|
nsIContent* firstInsertedContent = fragChildren[0];
|
2009-07-30 02:27:24 -07:00
|
|
|
|
|
|
|
// Iterate through the fragment's children, and insert them in the new
|
|
|
|
// parent
|
2011-05-25 10:58:23 -07:00
|
|
|
for (PRUint32 i = 0; i < count; ++i, ++insPos) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// XXXbz how come no reparenting here? That seems odd...
|
|
|
|
// Insert the child.
|
2011-05-25 10:58:23 -07:00
|
|
|
res = InsertChildAt(fragChildren[i], insPos, !appending);
|
2009-07-30 02:27:24 -07:00
|
|
|
if (NS_FAILED(res)) {
|
|
|
|
// Make sure to notify on any children that we did succeed to insert
|
|
|
|
if (appending && i != 0) {
|
2010-03-17 08:06:19 -07:00
|
|
|
nsNodeUtils::ContentAppended(static_cast<nsIContent*>(this),
|
2010-05-10 18:12:34 -07:00
|
|
|
firstInsertedContent,
|
2010-03-17 08:06:19 -07:00
|
|
|
firstInsPos);
|
2009-07-30 02:27:24 -07:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-25 10:58:23 -07:00
|
|
|
// Notify and fire mutation events when appending
|
2009-07-30 02:27:24 -07:00
|
|
|
if (appending) {
|
2010-05-10 18:12:34 -07:00
|
|
|
nsNodeUtils::ContentAppended(static_cast<nsIContent*>(this),
|
|
|
|
firstInsertedContent, firstInsPos);
|
2011-05-25 10:58:23 -07:00
|
|
|
// Optimize for the case when there are no listeners
|
|
|
|
if (nsContentUtils::
|
|
|
|
HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEINSERTED)) {
|
|
|
|
nsGenericElement::FireNodeInserted(doc, this, fragChildren);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Not inserting a fragment but rather a single node.
|
|
|
|
|
2010-01-16 06:27:51 -08:00
|
|
|
// FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=544654
|
|
|
|
// We need to reparent here for nodes for which the parent of their
|
|
|
|
// wrapper is not the wrapper for their ownerDocument (XUL elements,
|
2011-05-09 12:33:03 -07:00
|
|
|
// form controls, ...). Also applies in the fragment code above.
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
res = InsertChildAt(newContent, insPos, true);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
|
|
|
}
|
|
|
|
|
2011-06-14 00:56:48 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsINode::CompareDocumentPosition(nsIDOMNode* aOther, PRUint16* aReturn)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsINode> other = do_QueryInterface(aOther);
|
|
|
|
if (!other) {
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
|
|
|
*aReturn = CompareDocPosition(other);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-06-14 00:56:48 -07:00
|
|
|
nsresult
|
2011-09-28 23:19:26 -07:00
|
|
|
nsINode::IsEqualNode(nsIDOMNode* aOther, bool* aReturn)
|
2011-06-14 00:56:48 -07:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsINode> other = do_QueryInterface(aOther);
|
|
|
|
*aReturn = IsEqualTo(other);
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
// nsISupports implementation
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericElement)
|
|
|
|
|
2012-03-01 05:09:00 -08:00
|
|
|
#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;
|
|
|
|
}
|
|
|
|
nsGenericElement* container = static_cast<nsGenericElement*>(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<nsIContent> child =
|
|
|
|
container->mAttrsAndChildren.TakeChildAt(childCount);
|
|
|
|
if (childCount == 0) {
|
|
|
|
container->mFirstChild = nsnull;
|
|
|
|
}
|
|
|
|
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 = nsnull;
|
|
|
|
if (mNext) {
|
|
|
|
nsRefPtr<ContentUnbinder> next;
|
|
|
|
next.swap(mNext);
|
|
|
|
sContentUnbinder = next;
|
|
|
|
next->mLast = mLast;
|
|
|
|
mLast = nsnull;
|
|
|
|
NS_DispatchToMainThread(next);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Append(nsIContent* aSubtreeRoot)
|
|
|
|
{
|
|
|
|
if (!sContentUnbinder) {
|
|
|
|
sContentUnbinder = new ContentUnbinder();
|
|
|
|
nsCOMPtr<nsIRunnable> 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<nsCOMPtr<nsIContent>,
|
|
|
|
SUBTREE_UNBINDINGS_PER_RUNNABLE> mSubtreeRoots;
|
|
|
|
nsRefPtr<ContentUnbinder> mNext;
|
|
|
|
ContentUnbinder* mLast;
|
|
|
|
static ContentUnbinder* sContentUnbinder;
|
|
|
|
};
|
|
|
|
|
|
|
|
ContentUnbinder* ContentUnbinder::sContentUnbinder = nsnull;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericElement)
|
2011-08-28 07:07:24 -07:00
|
|
|
nsINode::Unlink(tmp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-08-24 13:02:07 -07:00
|
|
|
if (tmp->HasProperties() && tmp->IsXUL()) {
|
2007-12-15 14:18:05 -08:00
|
|
|
tmp->DeleteProperty(nsGkAtoms::contextmenulistener);
|
|
|
|
tmp->DeleteProperty(nsGkAtoms::popuplistener);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Unlink child content (and unbind our subtree).
|
2012-03-01 05:09:00 -08:00
|
|
|
if (UnoptimizableCCNode(tmp) || !nsCCUncollectableMarker::sGeneration) {
|
2008-04-11 10:29:06 -07:00
|
|
|
PRUint32 childCount = tmp->mAttrsAndChildren.ChildCount();
|
|
|
|
if (childCount) {
|
|
|
|
// Don't allow script to run while we're unbinding everything.
|
|
|
|
nsAutoScriptBlocker scriptBlocker;
|
|
|
|
while (childCount-- > 0) {
|
2011-11-02 20:36:16 -07:00
|
|
|
// 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<nsIContent> child = tmp->mAttrsAndChildren.TakeChildAt(childCount);
|
|
|
|
if (childCount == 0) {
|
|
|
|
tmp->mFirstChild = nsnull;
|
|
|
|
}
|
|
|
|
child->UnbindFromTree();
|
2008-04-11 10:29:06 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2012-03-01 05:09:00 -08:00
|
|
|
} 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.
|
|
|
|
} */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Unlink any DOM slots of interest.
|
|
|
|
{
|
|
|
|
nsDOMSlots *slots = tmp->GetExistingDOMSlots();
|
2007-11-30 09:57:03 -08:00
|
|
|
if (slots) {
|
2011-08-28 07:07:24 -07:00
|
|
|
slots->Unlink(tmp->IsXUL());
|
2007-11-30 09:57:03 -08:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2009-07-02 05:05:32 -07:00
|
|
|
|
|
|
|
{
|
|
|
|
nsIDocument *doc;
|
2011-10-18 03:53:36 -07:00
|
|
|
if (!tmp->GetNodeParent() && (doc = tmp->OwnerDoc())) {
|
2010-06-03 18:09:08 -07:00
|
|
|
doc->BindingManager()->RemovedFromDocument(tmp, doc);
|
2009-07-02 05:05:32 -07:00
|
|
|
}
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
|
2009-05-12 13:20:42 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGenericElement)
|
2011-08-28 07:07:24 -07:00
|
|
|
nsINode::Trace(tmp, aCallback, aClosure);
|
2009-05-12 13:20:42 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
|
|
|
|
2012-01-30 12:08:13 -08:00
|
|
|
void
|
|
|
|
nsGenericElement::MarkUserData(void* aObject, nsIAtom* aKey, void* aChild,
|
|
|
|
void* aData)
|
|
|
|
{
|
|
|
|
PRUint32* gen = static_cast<PRUint32*>(aData);
|
|
|
|
xpc_MarkInCCGeneration(static_cast<nsISupports*>(aChild), *gen);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsGenericElement::MarkUserDataHandler(void* aObject, nsIAtom* aKey,
|
|
|
|
void* aChild, void* aData)
|
|
|
|
{
|
2012-03-28 21:51:46 -07:00
|
|
|
xpc_TryUnmarkWrappedGrayObject(static_cast<nsISupports*>(aChild));
|
2012-01-30 12:08:13 -08:00
|
|
|
}
|
|
|
|
|
2012-02-10 12:47:29 -08:00
|
|
|
void
|
|
|
|
nsGenericElement::MarkNodeChildren(nsINode* aNode)
|
2012-01-30 12:08:13 -08:00
|
|
|
{
|
|
|
|
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, nsGenericElement::MarkUserData,
|
|
|
|
&nsCCUncollectableMarker::sGeneration);
|
|
|
|
ownerDoc->PropertyTable(DOM_USER_DATA_HANDLER)->
|
|
|
|
Enumerate(aNode, nsGenericElement::MarkUserDataHandler,
|
|
|
|
&nsCCUncollectableMarker::sGeneration);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsINode*
|
|
|
|
FindOptimizableSubtreeRoot(nsINode* aNode)
|
|
|
|
{
|
|
|
|
nsINode* p;
|
|
|
|
while ((p = aNode->GetNodeParent())) {
|
|
|
|
if (UnoptimizableCCNode(aNode)) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
aNode = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (UnoptimizableCCNode(aNode)) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
return aNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoTArray<nsINode*, 1020>* gCCBlackMarkedNodes = nsnull;
|
|
|
|
|
|
|
|
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 = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool
|
|
|
|
nsGenericElement::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);
|
|
|
|
}
|
|
|
|
|
2012-03-18 07:17:05 -07:00
|
|
|
// Bail out early if aNode is somewhere in anonymous content,
|
|
|
|
// or otherwise unusual.
|
|
|
|
if (UnoptimizableCCNode(aNode)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-01-30 12:08:13 -08:00
|
|
|
nsINode* root =
|
|
|
|
currentDoc ? static_cast<nsINode*>(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<nsINode*, 1020>;
|
|
|
|
}
|
|
|
|
|
|
|
|
// nodesToUnpurple contains nodes which will be removed
|
|
|
|
// from the purple buffer if the DOM tree is black.
|
|
|
|
nsAutoTArray<nsIContent*, 1020> 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<nsINode*, 1020> grayNodes;
|
|
|
|
|
|
|
|
bool foundBlack = root->IsBlack();
|
|
|
|
if (root != currentDoc) {
|
|
|
|
currentDoc = nsnull;
|
|
|
|
if (NeedsScriptTraverse(root)) {
|
|
|
|
grayNodes.AppendElement(root);
|
|
|
|
} else if (static_cast<nsIContent*>(root)->IsPurple()) {
|
|
|
|
nodesToUnpurple.AppendElement(static_cast<nsIContent*>(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<nsINode*, 1020>* gPurpleRoots = nsnull;
|
|
|
|
|
|
|
|
void ClearPurpleRoots()
|
|
|
|
{
|
|
|
|
if (!gPurpleRoots) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
PRUint32 len = gPurpleRoots->Length();
|
|
|
|
for (PRUint32 i = 0; i < len; ++i) {
|
|
|
|
nsINode* n = gPurpleRoots->ElementAt(i);
|
|
|
|
n->SetIsPurpleRoot(false);
|
|
|
|
}
|
|
|
|
delete gPurpleRoots;
|
|
|
|
gPurpleRoots = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
ShouldClearPurple(nsIContent* aContent)
|
|
|
|
{
|
|
|
|
if (aContent && aContent->IsPurple()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSObject* o = GetJSObjectChild(aContent);
|
|
|
|
if (o && xpc_IsGrayGCThing(o)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-02-27 06:03:15 -08:00
|
|
|
if (aContent->HasListenerManager()) {
|
2012-01-30 12:08:13 -08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return aContent->HasProperties();
|
|
|
|
}
|
|
|
|
|
2012-02-10 11:42:46 -08:00
|
|
|
// 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();
|
|
|
|
}
|
|
|
|
|
2012-03-18 07:17:05 -07:00
|
|
|
bool
|
|
|
|
OwnedByBindingManager(nsIDocument* aCurrentDoc, nsINode* aNode)
|
|
|
|
{
|
|
|
|
return aNode->IsElement() &&
|
|
|
|
aCurrentDoc->BindingManager()->GetBinding(aNode->AsElement());
|
|
|
|
}
|
|
|
|
|
2012-01-30 12:08:13 -08:00
|
|
|
// 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
|
2012-02-13 12:59:14 -08:00
|
|
|
nsGenericElement::CanSkip(nsINode* aNode, bool aRemovingAllowed)
|
2012-01-30 12:08:13 -08:00
|
|
|
{
|
|
|
|
// Don't try to optimize anything during shutdown.
|
|
|
|
if (nsCCUncollectableMarker::sGeneration == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-02-10 11:42:46 -08:00
|
|
|
bool unoptimizable = UnoptimizableCCNode(aNode);
|
2012-01-30 12:08:13 -08:00
|
|
|
nsIDocument* currentDoc = aNode->GetCurrentDoc();
|
|
|
|
if (currentDoc &&
|
2012-02-10 11:42:46 -08:00
|
|
|
nsCCUncollectableMarker::InGeneration(currentDoc->GetMarkedCCGeneration()) &&
|
2012-03-18 07:17:05 -07:00
|
|
|
(!unoptimizable || NodeHasActiveFrame(currentDoc, aNode) ||
|
|
|
|
OwnedByBindingManager(currentDoc, aNode))) {
|
2012-01-30 12:08:13 -08:00
|
|
|
MarkNodeChildren(aNode);
|
|
|
|
return true;
|
|
|
|
}
|
2012-03-18 07:17:05 -07:00
|
|
|
|
2012-02-10 11:42:46 -08:00
|
|
|
if (unoptimizable) {
|
|
|
|
return false;
|
|
|
|
}
|
2012-01-30 12:08:13 -08:00
|
|
|
|
|
|
|
nsINode* root = currentDoc ? static_cast<nsINode*>(currentDoc) :
|
|
|
|
FindOptimizableSubtreeRoot(aNode);
|
|
|
|
if (!root) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Subtree has been traversed already, and aNode
|
|
|
|
// wasn't removed from purple buffer. No need to do more here.
|
|
|
|
if (root->IsPurpleRoot()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// nodesToClear contains nodes which are either purple or
|
|
|
|
// gray.
|
|
|
|
nsAutoTArray<nsIContent*, 1020> nodesToClear;
|
|
|
|
|
|
|
|
bool foundBlack = root->IsBlack();
|
|
|
|
if (root != currentDoc) {
|
|
|
|
currentDoc = nsnull;
|
|
|
|
if (ShouldClearPurple(static_cast<nsIContent*>(root))) {
|
|
|
|
nodesToClear.AppendElement(static_cast<nsIContent*>(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) {
|
|
|
|
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.
|
2012-02-13 12:59:14 -08:00
|
|
|
if (node->IsPurple() && (node != aNode || aRemovingAllowed)) {
|
2012-01-30 12:08:13 -08:00
|
|
|
node->RemovePurple();
|
|
|
|
}
|
|
|
|
MarkNodeChildren(node);
|
|
|
|
} else if (ShouldClearPurple(node)) {
|
|
|
|
// Collect interesting nodes which we can clear if we find that
|
|
|
|
// they are kept alive in a black tree.
|
|
|
|
nodesToClear.AppendElement(node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-10 17:21:26 -08:00
|
|
|
if (!currentDoc || !foundBlack) {
|
2012-01-30 12:08:13 -08:00
|
|
|
if (!gPurpleRoots) {
|
|
|
|
gPurpleRoots = new nsAutoTArray<nsINode*, 1020>();
|
|
|
|
}
|
|
|
|
root->SetIsPurpleRoot(true);
|
|
|
|
gPurpleRoots->AppendElement(root);
|
2012-02-10 17:21:26 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!foundBlack) {
|
2012-01-30 12:08:13 -08:00
|
|
|
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);
|
2012-02-13 12:59:14 -08:00
|
|
|
// Can't remove currently handled purple node,
|
|
|
|
// unless aRemovingAllowed is true.
|
|
|
|
if ((n != aNode || aRemovingAllowed) && n->IsPurple()) {
|
2012-01-30 12:08:13 -08:00
|
|
|
n->RemovePurple();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
nsGenericElement::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
|
|
|
|
nsGenericElement::InitCCCallbacks()
|
|
|
|
{
|
|
|
|
nsCycleCollector_setForgetSkippableCallback(ClearPurpleRoots);
|
|
|
|
nsCycleCollector_setBeforeUnlinkCallback(ClearBlackMarkedNodes);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGenericElement)
|
2012-02-13 12:59:14 -08:00
|
|
|
return nsGenericElement::CanSkip(tmp, aRemovingAllowed);
|
2012-01-30 12:08:13 -08:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGenericElement)
|
|
|
|
return nsGenericElement::CanSkipInCC(tmp);
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGenericElement)
|
|
|
|
return nsGenericElement::CanSkipThis(tmp);
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
|
|
|
|
|
2009-02-27 06:48:26 -08:00
|
|
|
static const char* kNSURIs[] = {
|
|
|
|
" ([none])",
|
|
|
|
" (xmlns)",
|
|
|
|
" (xml)",
|
|
|
|
" (xhtml)",
|
|
|
|
" (XLink)",
|
|
|
|
" (XSLT)",
|
|
|
|
" (XBL)",
|
|
|
|
" (MathML)",
|
|
|
|
" (RDF)",
|
|
|
|
" (XUL)",
|
|
|
|
" (SVG)",
|
|
|
|
" (XML Events)"
|
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGenericElement)
|
|
|
|
if (NS_UNLIKELY(cb.WantDebugInfo())) {
|
2012-01-16 05:06:19 -08:00
|
|
|
char name[512];
|
2009-02-27 06:48:26 -08:00
|
|
|
PRUint32 nsid = tmp->GetNameSpaceID();
|
|
|
|
nsAtomCString localName(tmp->NodeInfo()->NameAtom());
|
2012-01-16 05:06:19 -08:00
|
|
|
nsCAutoString uri;
|
|
|
|
if (tmp->OwnerDoc()->GetDocumentURI()) {
|
|
|
|
tmp->OwnerDoc()->GetDocumentURI()->GetSpec(uri);
|
|
|
|
}
|
|
|
|
|
2012-02-11 03:03:54 -08:00
|
|
|
nsAutoString id;
|
|
|
|
nsIAtom* idAtom = tmp->GetID();
|
|
|
|
if (idAtom) {
|
|
|
|
id.AppendLiteral(" id='");
|
|
|
|
id.Append(nsDependentAtomString(idAtom));
|
|
|
|
id.AppendLiteral("'");
|
2009-02-27 06:48:26 -08:00
|
|
|
}
|
2012-02-11 03:03:54 -08:00
|
|
|
|
|
|
|
nsAutoString classes;
|
|
|
|
const nsAttrValue* classAttrValue = tmp->GetClasses();
|
|
|
|
if (classAttrValue) {
|
|
|
|
classes.AppendLiteral(" class='");
|
|
|
|
nsAutoString classString;
|
|
|
|
classAttrValue->ToString(classString);
|
|
|
|
classes.Append(classString);
|
|
|
|
classes.AppendLiteral("'");
|
2009-02-27 06:48:26 -08:00
|
|
|
}
|
2012-02-11 03:03:54 -08:00
|
|
|
|
|
|
|
const char* nsuri = nsid < ArrayLength(kNSURIs) ? kNSURIs[nsid] : "";
|
|
|
|
PR_snprintf(name, sizeof(name), "nsGenericElement%s %s%s%s %s",
|
|
|
|
nsuri,
|
|
|
|
localName.get(),
|
|
|
|
NS_ConvertUTF16toUTF8(id).get(),
|
|
|
|
NS_ConvertUTF16toUTF8(classes).get(),
|
|
|
|
uri.get());
|
2011-06-23 14:10:52 -07:00
|
|
|
cb.DescribeRefCountedNode(tmp->mRefCnt.get(), sizeof(nsGenericElement),
|
|
|
|
name);
|
2009-02-27 06:48:26 -08:00
|
|
|
}
|
|
|
|
else {
|
2011-06-23 14:10:52 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGenericElement, tmp->mRefCnt.get())
|
2009-02-27 06:48:26 -08:00
|
|
|
}
|
|
|
|
|
2009-05-12 13:20:42 -07:00
|
|
|
// Always need to traverse script objects, so do that before we check
|
|
|
|
// if we're uncollectable.
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
|
|
|
|
2011-08-28 07:07:24 -07:00
|
|
|
if (!nsINode::Traverse(tmp, cb)) {
|
2009-03-03 04:14:13 -08:00
|
|
|
return NS_SUCCESS_INTERRUPTED_TRAVERSE;
|
2007-05-10 13:21:12 -07:00
|
|
|
}
|
|
|
|
|
2011-10-18 04:19:44 -07:00
|
|
|
tmp->OwnerDoc()->BindingManager()->Traverse(tmp, cb);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-08-24 13:02:07 -07:00
|
|
|
if (tmp->HasProperties() && tmp->IsXUL()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
nsISupports* property =
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsISupports*>
|
|
|
|
(tmp->GetProperty(nsGkAtoms::contextmenulistener));
|
2007-03-22 10:30:00 -07:00
|
|
|
cb.NoteXPCOMChild(property);
|
2007-07-08 00:08:04 -07:00
|
|
|
property = static_cast<nsISupports*>
|
|
|
|
(tmp->GetProperty(nsGkAtoms::popuplistener));
|
2007-03-22 10:30:00 -07:00
|
|
|
cb.NoteXPCOMChild(property);
|
|
|
|
}
|
|
|
|
|
2008-03-28 07:09:00 -07:00
|
|
|
// Traverse attribute names and child content.
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
PRUint32 i;
|
2008-03-28 07:09:00 -07:00
|
|
|
PRUint32 attrs = tmp->mAttrsAndChildren.AttrCount();
|
|
|
|
for (i = 0; i < attrs; i++) {
|
|
|
|
const nsAttrName* name = tmp->mAttrsAndChildren.AttrNameAt(i);
|
2008-11-27 09:45:25 -08:00
|
|
|
if (!name->IsAtom()) {
|
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
|
|
|
|
"mAttrsAndChildren[i]->NodeInfo()");
|
2012-03-28 22:43:09 -07:00
|
|
|
cb.NoteXPCOMChild(name->NodeInfo());
|
2008-11-27 09:45:25 -08:00
|
|
|
}
|
2008-03-28 07:09:00 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
PRUint32 kids = tmp->mAttrsAndChildren.ChildCount();
|
2008-03-17 16:11:08 -07:00
|
|
|
for (i = 0; i < kids; i++) {
|
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mAttrsAndChildren[i]");
|
2007-03-22 10:30:00 -07:00
|
|
|
cb.NoteXPCOMChild(tmp->mAttrsAndChildren.GetSafeChildAt(i));
|
2008-03-17 16:11:08 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Traverse any DOM slots of interest.
|
|
|
|
{
|
|
|
|
nsDOMSlots *slots = tmp->GetExistingDOMSlots();
|
|
|
|
if (slots) {
|
2011-08-28 07:07:24 -07:00
|
|
|
slots->Traverse(cb, tmp->IsXUL());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
2008-02-21 12:39:20 -08:00
|
|
|
|
2008-11-13 08:54:52 -08:00
|
|
|
NS_INTERFACE_MAP_BEGIN(nsGenericElement)
|
|
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
|
|
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsGenericElement)
|
2011-11-21 07:32:14 -08:00
|
|
|
NS_INTERFACE_MAP_ENTRY(Element)
|
2008-02-21 12:39:20 -08:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIContent)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsINode)
|
2011-06-23 19:17:58 -07:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
|
2008-02-21 12:39:20 -08:00
|
|
|
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
|
|
|
|
new nsNodeSupportsWeakRefTearoff(this))
|
2008-07-21 17:55:52 -07:00
|
|
|
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMNodeSelector,
|
|
|
|
new nsNodeSelectorTearoff(this))
|
2009-06-14 11:06:22 -07:00
|
|
|
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMXPathNSResolver,
|
|
|
|
new nsNode3Tearoff(this))
|
2011-08-24 12:49:25 -07:00
|
|
|
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsITouchEventReceiver,
|
|
|
|
new nsTouchEventReceiverTearoff(this))
|
2011-08-24 12:49:25 -07:00
|
|
|
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIInlineEventHandlers,
|
|
|
|
new nsInlineEventHandlersTearoff(this))
|
2008-02-21 12:39:20 -08:00
|
|
|
// 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
|
|
|
|
|
2011-03-06 03:11:31 -08:00
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGenericElement)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(nsGenericElement,
|
|
|
|
nsNodeUtils::LastRelease(this))
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::PostQueryInterface(REFNSIID aIID, void** aInstancePtr)
|
|
|
|
{
|
2011-10-18 04:19:44 -07:00
|
|
|
return OwnerDoc()->BindingManager()->GetBindingImplementation(this, aIID,
|
2007-03-22 10:30:00 -07:00
|
|
|
aInstancePtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::LeaveLink(nsPresContext* aPresContext)
|
|
|
|
{
|
|
|
|
nsILinkHandler *handler = aPresContext->GetLinkHandler();
|
|
|
|
if (!handler) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return handler->OnLeaveLink();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::AddScriptEventListener(nsIAtom* aEventName,
|
|
|
|
const nsAString& aValue,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aDefer)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-10-18 03:53:36 -07:00
|
|
|
nsIDocument *ownerDoc = OwnerDoc();
|
2011-10-18 04:19:44 -07:00
|
|
|
if (ownerDoc->IsLoadedAsData()) {
|
2007-07-26 19:49:18 -07:00
|
|
|
// Make this a no-op rather than throwing an error to avoid
|
|
|
|
// the error causing problems setting the attribute.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_PRECONDITION(aEventName, "Must have event name!");
|
2011-09-28 23:19:26 -07:00
|
|
|
bool defer = true;
|
2011-09-28 08:54:50 -07:00
|
|
|
nsEventListenerManager* manager = GetEventListenerManagerForAttr(aEventName,
|
|
|
|
&defer);
|
2009-09-16 02:09:12 -07:00
|
|
|
if (!manager) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-06-23 04:23:52 -07:00
|
|
|
defer = defer && aDefer; // only defer if everyone agrees...
|
|
|
|
PRUint32 lang = GetScriptTypeID();
|
2011-07-29 12:37:17 -07:00
|
|
|
manager->AddScriptEventListener(aEventName, aValue, lang, defer,
|
2011-06-23 19:18:02 -07:00
|
|
|
!nsContentUtils::IsChromeDoc(ownerDoc));
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
const nsAttrName*
|
|
|
|
nsGenericElement::InternalGetExistingAttrNameFromQName(const nsAString& aStr) const
|
|
|
|
{
|
2010-03-08 07:45:00 -08:00
|
|
|
return mAttrsAndChildren.GetExistingAttrNameFromQName(aStr);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::CopyInnerTo(nsGenericElement* aDst) const
|
|
|
|
{
|
|
|
|
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(),
|
2011-10-17 07:59:28 -07:00
|
|
|
name->GetPrefix(), valStr, false);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2012-02-13 18:00:56 -08:00
|
|
|
nsGenericElement::MaybeCheckSameAttrVal(PRInt32 aNamespaceID,
|
|
|
|
nsIAtom* aName,
|
|
|
|
nsIAtom* aPrefix,
|
|
|
|
const nsAttrValueOrString& aValue,
|
|
|
|
bool aNotify,
|
|
|
|
nsAttrValue& aOldValue,
|
|
|
|
PRUint8* aModType,
|
|
|
|
bool* aHasListeners)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-28 23:19:26 -07:00
|
|
|
bool modification = false;
|
2011-02-01 11:41:50 -08:00
|
|
|
*aHasListeners = aNotify &&
|
2007-03-22 10:30:00 -07:00
|
|
|
nsContentUtils::HasMutationListeners(this,
|
2007-07-04 13:39:10 -07:00
|
|
|
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
|
|
|
|
this);
|
2011-02-01 11:41:50 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// 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
|
2011-02-01 11:41:50 -08:00
|
|
|
// optimization, the check for *aHasListeners is a correctness issue.
|
|
|
|
if (*aHasListeners || aNotify) {
|
2007-03-22 10:30:00 -07:00
|
|
|
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.
|
2011-02-01 11:41:50 -08:00
|
|
|
if (*aHasListeners) {
|
2012-02-13 18:00:56 -08:00
|
|
|
// 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);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2012-02-13 18:00:56 -08:00
|
|
|
bool valueMatches = aValue.EqualsAsStrings(*info.mValue);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (valueMatches && aPrefix == info.mName->GetPrefix()) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2011-10-17 07:59:28 -07:00
|
|
|
modification = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
2011-02-01 11:41:50 -08:00
|
|
|
*aModType = modification ?
|
|
|
|
static_cast<PRUint8>(nsIDOMMutationEvent::MODIFICATION) :
|
|
|
|
static_cast<PRUint8>(nsIDOMMutationEvent::ADDITION);
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-02-01 11:41:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::SetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
|
|
|
|
nsIAtom* aPrefix, const nsAString& aValue,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aNotify)
|
2011-02-01 11:41:50 -08:00
|
|
|
{
|
|
|
|
// Keep this in sync with SetParsedAttr below
|
|
|
|
|
|
|
|
NS_ENSURE_ARG_POINTER(aName);
|
|
|
|
NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
|
|
|
|
"Don't call SetAttr with unknown namespace");
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-02-01 11:41:50 -08:00
|
|
|
if (!mAttrsAndChildren.CanFitMoreAttrs()) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint8 modType;
|
2011-09-28 23:19:26 -07:00
|
|
|
bool hasListeners;
|
2012-02-13 18:00:56 -08:00
|
|
|
nsAttrValueOrString value(aValue);
|
|
|
|
nsAttrValue oldValue;
|
2011-02-01 11:41:50 -08:00
|
|
|
|
2012-02-13 18:00:56 -08:00
|
|
|
if (MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, value, aNotify,
|
|
|
|
oldValue, &modType, &hasListeners)) {
|
2011-02-01 11:41:50 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2010-02-23 20:37:47 -08:00
|
|
|
|
2012-02-13 18:00:56 -08:00
|
|
|
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2011-02-01 11:41:50 -08:00
|
|
|
|
2010-02-23 20:37:47 -08:00
|
|
|
if (aNotify) {
|
|
|
|
nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType);
|
|
|
|
}
|
|
|
|
|
2011-03-01 21:33:56 -08:00
|
|
|
// Hold a script blocker while calling ParseAttribute since that can call
|
|
|
|
// out to id-observers
|
2011-05-25 10:58:23 -07:00
|
|
|
nsAutoScriptBlocker scriptBlocker;
|
2011-03-01 21:33:56 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsAttrValue attrValue;
|
|
|
|
if (!ParseAttribute(aNamespaceID, aName, aValue, attrValue)) {
|
|
|
|
attrValue.SetTo(aValue);
|
|
|
|
}
|
|
|
|
|
2011-03-02 06:36:19 -08:00
|
|
|
return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
|
|
|
|
attrValue, modType, hasListeners, aNotify,
|
2012-02-13 18:00:56 -08:00
|
|
|
kCallAfterSetAttr);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2011-02-01 11:41:50 -08:00
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::SetParsedAttr(PRInt32 aNamespaceID, nsIAtom* aName,
|
|
|
|
nsIAtom* aPrefix, nsAttrValue& aParsedValue,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aNotify)
|
2011-02-01 11:41:50 -08:00
|
|
|
{
|
|
|
|
// 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;
|
2011-09-28 23:19:26 -07:00
|
|
|
bool hasListeners;
|
2012-02-13 18:00:56 -08:00
|
|
|
nsAttrValueOrString value(aParsedValue);
|
|
|
|
nsAttrValue oldValue;
|
2011-02-01 11:41:50 -08:00
|
|
|
|
|
|
|
if (MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, value, aNotify,
|
2012-02-13 18:00:56 -08:00
|
|
|
oldValue, &modType, &hasListeners)) {
|
2011-02-01 11:41:50 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-02-13 18:00:56 -08:00
|
|
|
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
|
2011-02-01 11:41:50 -08:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (aNotify) {
|
|
|
|
nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
|
|
|
|
aParsedValue, modType, hasListeners, aNotify,
|
2012-02-13 18:00:56 -08:00
|
|
|
kCallAfterSetAttr);
|
2011-02-01 11:41:50 -08:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult
|
|
|
|
nsGenericElement::SetAttrAndNotify(PRInt32 aNamespaceID,
|
|
|
|
nsIAtom* aName,
|
|
|
|
nsIAtom* aPrefix,
|
2012-02-13 18:00:56 -08:00
|
|
|
const nsAttrValue& aOldValue,
|
2007-03-22 10:30:00 -07:00
|
|
|
nsAttrValue& aParsedValue,
|
2010-02-23 20:37:47 -08:00
|
|
|
PRUint8 aModType,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aFireMutation,
|
|
|
|
bool aNotify,
|
2012-02-13 18:00:56 -08:00
|
|
|
bool aCallAfterSetAttr)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
nsIDocument* document = GetCurrentDoc();
|
|
|
|
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
|
2007-07-12 13:05:45 -07:00
|
|
|
|
2010-09-01 15:48:24 -07:00
|
|
|
nsMutationGuard::DidMutate();
|
|
|
|
|
2012-02-13 18:00:56 -08:00
|
|
|
// Copy aParsedValue for later use since it will be lost when we call
|
|
|
|
// SetAndTakeMappedAttr below
|
|
|
|
nsAttrValue aValueForAfterSetAttr;
|
|
|
|
if (aCallAfterSetAttr) {
|
|
|
|
aValueForAfterSetAttr.SetTo(aParsedValue);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aNamespaceID == kNameSpaceID_None) {
|
|
|
|
// XXXbz Perhaps we should push up the attribute mapping function
|
|
|
|
// stuff to nsGenericElement?
|
|
|
|
if (!IsAttributeMapped(aName) ||
|
|
|
|
!SetMappedAttribute(document, aName, aParsedValue, &rv)) {
|
|
|
|
rv = mAttrsAndChildren.SetAndTakeAttr(aName, aParsedValue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2012-03-28 22:43:09 -07:00
|
|
|
nsCOMPtr<nsINodeInfo> ni;
|
2008-09-12 15:32:18 -07:00
|
|
|
ni = mNodeInfo->NodeInfoManager()->GetNodeInfo(aName, aPrefix,
|
2011-06-14 00:56:49 -07:00
|
|
|
aNamespaceID,
|
|
|
|
nsIDOMNode::ATTRIBUTE_NODE);
|
2008-09-25 15:46:52 -07:00
|
|
|
NS_ENSURE_TRUE(ni, NS_ERROR_OUT_OF_MEMORY);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
rv = mAttrsAndChildren.SetAndTakeAttr(ni, aParsedValue);
|
|
|
|
}
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2008-03-03 17:25:06 -08:00
|
|
|
if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
|
2011-10-18 04:19:44 -07:00
|
|
|
nsRefPtr<nsXBLBinding> binding =
|
|
|
|
OwnerDoc()->BindingManager()->GetBinding(this);
|
|
|
|
if (binding) {
|
|
|
|
binding->AttributeChanged(aName, aNamespaceID, false, aNotify);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-31 18:46:57 -07:00
|
|
|
UpdateState(aNotify);
|
|
|
|
|
2007-07-10 18:14:55 -07:00
|
|
|
if (aNotify) {
|
2010-02-23 20:37:47 -08:00
|
|
|
nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType);
|
2007-07-10 18:14:55 -07:00
|
|
|
}
|
2008-12-03 02:39:21 -08:00
|
|
|
|
|
|
|
if (aNamespaceID == kNameSpaceID_XMLEvents &&
|
|
|
|
aName == nsGkAtoms::event && mNodeInfo->GetDocument()) {
|
|
|
|
mNodeInfo->GetDocument()->AddXMLEventsContent(this);
|
|
|
|
}
|
2012-02-13 18:00:56 -08:00
|
|
|
if (aCallAfterSetAttr) {
|
|
|
|
rv = AfterSetAttr(aNamespaceID, aName, &aValueForAfterSetAttr, aNotify);
|
2008-12-03 02:39:21 -08:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aFireMutation) {
|
2011-10-17 07:59:28 -07:00
|
|
|
nsMutationEvent mutation(true, NS_MUTATION_ATTRMODIFIED);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-04-18 10:20:11 -07:00
|
|
|
nsCOMPtr<nsIDOMAttr> attrNode;
|
|
|
|
nsAutoString ns;
|
|
|
|
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
|
2012-02-27 15:57:28 -08:00
|
|
|
GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName),
|
|
|
|
getter_AddRefs(attrNode));
|
2008-04-18 10:20:11 -07:00
|
|
|
mutation.mRelatedNode = attrNode;
|
|
|
|
|
|
|
|
mutation.mAttrName = aName;
|
|
|
|
nsAutoString newValue;
|
|
|
|
GetAttr(aNamespaceID, aName, newValue);
|
|
|
|
if (!newValue.IsEmpty()) {
|
|
|
|
mutation.mNewAttrValue = do_GetAtom(newValue);
|
|
|
|
}
|
2012-02-13 18:00:56 -08:00
|
|
|
if (!aOldValue.IsEmptyString()) {
|
|
|
|
mutation.mPrevAttrValue = aOldValue.GetAsAtom();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2010-02-23 20:37:47 -08:00
|
|
|
mutation.mAttrChange = aModType;
|
2008-04-18 10:20:11 -07:00
|
|
|
|
2011-10-18 03:53:36 -07:00
|
|
|
mozAutoSubtreeModified subtree(OwnerDoc(), this);
|
2011-12-16 22:02:05 -08:00
|
|
|
(new nsAsyncDOMEvent(this, mutation))->RunDOMEventWhenSafe();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2007-03-22 10:30:00 -07:00
|
|
|
nsGenericElement::ParseAttribute(PRInt32 aNamespaceID,
|
|
|
|
nsIAtom* aAttribute,
|
|
|
|
const nsAString& aValue,
|
|
|
|
nsAttrValue& aResult)
|
|
|
|
{
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2007-03-22 10:30:00 -07:00
|
|
|
nsGenericElement::SetMappedAttribute(nsIDocument* aDocument,
|
|
|
|
nsIAtom* aName,
|
|
|
|
nsAttrValue& aValue,
|
|
|
|
nsresult* aRetval)
|
|
|
|
{
|
|
|
|
*aRetval = NS_OK;
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-07-29 12:37:17 -07:00
|
|
|
nsEventListenerManager*
|
2011-09-28 08:54:50 -07:00
|
|
|
nsGenericElement::GetEventListenerManagerForAttr(nsIAtom* aAttrName,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool* aDefer)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-10-17 07:59:28 -07:00
|
|
|
*aDefer = true;
|
|
|
|
return GetListenerManager(true);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsGenericElement::nsAttrInfo
|
|
|
|
nsGenericElement::GetAttrInfo(PRInt32 aNamespaceID, nsIAtom* aName) const
|
|
|
|
{
|
|
|
|
NS_ASSERTION(nsnull != 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(nsnull, nsnull);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2007-03-22 10:30:00 -07:00
|
|
|
nsGenericElement::GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
|
|
|
nsAString& aResult) const
|
|
|
|
{
|
|
|
|
NS_ASSERTION(nsnull != 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();
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
val->ToString(aResult);
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2007-03-22 10:30:00 -07:00
|
|
|
nsGenericElement::HasAttr(PRInt32 aNameSpaceID, nsIAtom* aName) const
|
|
|
|
{
|
|
|
|
NS_ASSERTION(nsnull != aName, "must have attribute name");
|
|
|
|
NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown,
|
|
|
|
"must have a real namespace ID!");
|
|
|
|
|
|
|
|
return mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID) >= 0;
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2007-03-22 10:30:00 -07:00
|
|
|
nsGenericElement::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);
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2007-03-22 10:30:00 -07:00
|
|
|
nsGenericElement::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
|
|
|
|
nsGenericElement::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
|
|
|
|
nsGenericElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
NS_ASSERTION(nsnull != aName, "must have attribute name");
|
|
|
|
|
|
|
|
PRInt32 index = mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID);
|
|
|
|
if (index < 0) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-12-04 08:50:32 -08:00
|
|
|
nsresult rv = BeforeSetAttr(aNameSpaceID, aName, nsnull, aNotify);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2012-02-13 18:00:56 -08:00
|
|
|
|
|
|
|
nsIDocument *document = GetCurrentDoc();
|
2007-03-22 10:30:00 -07:00
|
|
|
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
|
|
|
|
|
2009-06-29 11:36:25 -07:00
|
|
|
if (aNotify) {
|
|
|
|
nsNodeUtils::AttributeWillChange(this, aNameSpaceID, aName,
|
|
|
|
nsIDOMMutationEvent::REMOVAL);
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool hasMutationListeners = aNotify &&
|
2007-03-22 10:30:00 -07:00
|
|
|
nsContentUtils::HasMutationListeners(this,
|
2007-07-04 13:39:10 -07:00
|
|
|
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
|
|
|
|
this);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Grab the attr node if needed before we remove it from the attr map
|
|
|
|
nsCOMPtr<nsIDOMAttr> attrNode;
|
|
|
|
if (hasMutationListeners) {
|
|
|
|
nsAutoString ns;
|
|
|
|
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns);
|
2012-02-27 15:57:28 -08:00
|
|
|
GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName),
|
|
|
|
getter_AddRefs(attrNode));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Clear binding to nsIDOMNamedNodeMap
|
|
|
|
nsDOMSlots *slots = GetExistingDOMSlots();
|
|
|
|
if (slots && slots->mAttributeMap) {
|
|
|
|
slots->mAttributeMap->DropAttribute(aNameSpaceID, aName);
|
|
|
|
}
|
|
|
|
|
2010-09-01 15:48:24 -07:00
|
|
|
// The id-handling code, and in the future possibly other code, need to
|
|
|
|
// react to unexpected attribute changes.
|
|
|
|
nsMutationGuard::DidMutate();
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsAttrValue oldValue;
|
2007-12-04 08:50:32 -08:00
|
|
|
rv = mAttrsAndChildren.RemoveAttrAt(index, oldValue);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2008-03-03 17:25:06 -08:00
|
|
|
if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
|
2011-10-18 04:19:44 -07:00
|
|
|
nsRefPtr<nsXBLBinding> binding =
|
|
|
|
OwnerDoc()->BindingManager()->GetBinding(this);
|
|
|
|
if (binding) {
|
|
|
|
binding->AttributeChanged(aName, aNameSpaceID, true, aNotify);
|
2008-03-03 17:25:06 -08:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-05-31 18:46:57 -07:00
|
|
|
UpdateState(aNotify);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aNotify) {
|
|
|
|
nsNodeUtils::AttributeChanged(this, aNameSpaceID, aName,
|
2009-12-10 14:36:04 -08:00
|
|
|
nsIDOMMutationEvent::REMOVAL);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-12-03 02:39:21 -08:00
|
|
|
rv = AfterSetAttr(aNameSpaceID, aName, nsnull, aNotify);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (hasMutationListeners) {
|
2011-08-30 14:45:31 -07:00
|
|
|
nsCOMPtr<nsIDOMEventTarget> node = do_QueryObject(this);
|
2011-10-17 07:59:28 -07:00
|
|
|
nsMutationEvent mutation(true, NS_MUTATION_ATTRMODIFIED);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-04-18 10:20:11 -07:00
|
|
|
mutation.mRelatedNode = attrNode;
|
|
|
|
mutation.mAttrName = aName;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-04-18 10:20:11 -07:00
|
|
|
nsAutoString value;
|
|
|
|
oldValue.ToString(value);
|
|
|
|
if (!value.IsEmpty())
|
|
|
|
mutation.mPrevAttrValue = do_GetAtom(value);
|
|
|
|
mutation.mAttrChange = nsIDOMMutationEvent::REMOVAL;
|
2008-03-14 16:08:57 -07:00
|
|
|
|
2011-10-18 03:53:36 -07:00
|
|
|
mozAutoSubtreeModified subtree(OwnerDoc(), this);
|
2011-12-16 22:02:05 -08:00
|
|
|
(new nsAsyncDOMEvent(this, mutation))->RunDOMEventWhenSafe();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-12-03 02:39:21 -08:00
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
const nsAttrName*
|
|
|
|
nsGenericElement::GetAttrNameAt(PRUint32 aIndex) const
|
|
|
|
{
|
|
|
|
return mAttrsAndChildren.GetSafeAttrNameAt(aIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32
|
|
|
|
nsGenericElement::GetAttrCount() const
|
|
|
|
{
|
|
|
|
return mAttrsAndChildren.AttrCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
const nsTextFragment*
|
|
|
|
nsGenericElement::GetText()
|
|
|
|
{
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32
|
2012-03-29 14:09:04 -07:00
|
|
|
nsGenericElement::TextLength() const
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
// We can remove this assertion if it turns out to be useful to be able
|
|
|
|
// to depend on this returning 0
|
|
|
|
NS_NOTREACHED("called nsGenericElement::TextLength");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::SetText(const PRUnichar* aBuffer, PRUint32 aLength,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
NS_ERROR("called nsGenericElement::SetText");
|
|
|
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::AppendText(const PRUnichar* aBuffer, PRUint32 aLength,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
NS_ERROR("called nsGenericElement::AppendText");
|
|
|
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2011-11-14 10:10:22 -08:00
|
|
|
nsGenericElement::TextIsOnlyWhitespace()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsGenericElement::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 nsGenericElement::TextLength");
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
|
|
|
nsGenericElement::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
|
|
|
|
nsGenericElement::List(FILE* out, PRInt32 aIndent,
|
|
|
|
const nsCString& aPrefix) const
|
|
|
|
{
|
|
|
|
PRInt32 indent;
|
|
|
|
for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
|
|
|
|
|
|
|
|
fputs(aPrefix.get(), out);
|
|
|
|
|
2011-05-05 09:26:33 -07:00
|
|
|
fputs(NS_LossyConvertUTF16toASCII(mNodeInfo->QualifiedName()).get(), out);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
fprintf(out, "@%p", (void *)this);
|
|
|
|
|
|
|
|
ListAttributes(out);
|
|
|
|
|
2011-05-31 18:46:57 -07:00
|
|
|
fprintf(out, " state=[%llx]", State().GetInternalValue());
|
2010-05-11 17:30:42 -07:00
|
|
|
fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
|
2011-12-20 01:15:41 -08:00
|
|
|
if (IsCommonAncestorForRangeInSelection()) {
|
2012-01-10 06:19:54 -08:00
|
|
|
nsRange::RangeHashTable* ranges =
|
|
|
|
static_cast<nsRange::RangeHashTable*>(GetProperty(nsGkAtoms::range));
|
2011-12-20 01:15:41 -08:00
|
|
|
fprintf(out, " ranges:%d", ranges ? ranges->Count() : 0);
|
|
|
|
}
|
2010-05-01 11:42:47 -07:00
|
|
|
fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
|
2007-03-22 10:30:00 -07:00
|
|
|
fprintf(out, " refcount=%d<", mRefCnt.get());
|
|
|
|
|
2011-09-27 00:54:58 -07:00
|
|
|
nsIContent* child = GetFirstChild();
|
|
|
|
if (child) {
|
2007-03-22 10:30:00 -07:00
|
|
|
fputs("\n", out);
|
2011-09-27 00:54:58 -07:00
|
|
|
|
|
|
|
for (; child; child = child->GetNextSibling()) {
|
|
|
|
child->List(out, aIndent + 1);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
|
|
|
|
}
|
|
|
|
|
|
|
|
fputs(">\n", out);
|
|
|
|
|
2007-07-08 00:08:04 -07:00
|
|
|
nsGenericElement* nonConstThis = const_cast<nsGenericElement*>(this);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// XXX sXBL/XBL2 issue! Owner or current document?
|
2011-10-18 03:53:36 -07:00
|
|
|
nsIDocument *document = OwnerDoc();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-10-18 04:19:44 -07:00
|
|
|
// Note: not listing nsIAnonymousContentCreator-created content...
|
|
|
|
|
|
|
|
nsBindingManager* bindingManager = document->BindingManager();
|
|
|
|
nsCOMPtr<nsIDOMNodeList> 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<nsIDOMNode> node;
|
|
|
|
anonymousChildren->Item(i, getter_AddRefs(node));
|
|
|
|
nsCOMPtr<nsIContent> child = do_QueryInterface(node);
|
|
|
|
child->List(out, aIndent + 1);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2011-10-18 04:19:44 -07:00
|
|
|
|
|
|
|
for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
|
|
|
|
fputs(">\n", out);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2011-10-18 04:19:44 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-10-18 04:19:44 -07:00
|
|
|
if (bindingManager->HasContentListFor(nonConstThis)) {
|
|
|
|
nsCOMPtr<nsIDOMNodeList> contentList;
|
|
|
|
bindingManager->GetContentListFor(nonConstThis,
|
|
|
|
getter_AddRefs(contentList));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-10-18 04:19:44 -07:00
|
|
|
NS_ASSERTION(contentList != nsnull, "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<nsIDOMNode> node;
|
|
|
|
contentList->Item(i, getter_AddRefs(node));
|
|
|
|
nsCOMPtr<nsIContent> child = do_QueryInterface(node);
|
|
|
|
child->List(out, aIndent + 1);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2011-10-18 04:19:44 -07:00
|
|
|
|
|
|
|
for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
|
|
|
|
fputs(">\n", out);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsGenericElement::DumpContent(FILE* out, PRInt32 aIndent,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aDumpAll) const
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
PRInt32 indent;
|
|
|
|
for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
|
|
|
|
|
2011-05-05 09:26:33 -07:00
|
|
|
const nsString& buf = mNodeInfo->QualifiedName();
|
2007-03-22 10:30:00 -07:00
|
|
|
fputs("<", out);
|
|
|
|
fputs(NS_LossyConvertUTF16toASCII(buf).get(), out);
|
|
|
|
|
|
|
|
if(aDumpAll) ListAttributes(out);
|
|
|
|
|
|
|
|
fputs(">", out);
|
|
|
|
|
|
|
|
if(aIndent) fputs("\n", out);
|
|
|
|
|
2011-09-27 00:54:58 -07:00
|
|
|
for (nsIContent* child = GetFirstChild();
|
|
|
|
child;
|
|
|
|
child = child->GetNextSibling()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
PRInt32 indent = aIndent ? aIndent + 1 : 0;
|
2011-09-27 00:54:58 -07:00
|
|
|
child->DumpContent(out, indent, aDumpAll);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
for (indent = aIndent; --indent >= 0; ) fputs(" ", out);
|
|
|
|
fputs("</", out);
|
|
|
|
fputs(NS_LossyConvertUTF16toASCII(buf).get(), out);
|
|
|
|
fputs(">", out);
|
|
|
|
|
|
|
|
if(aIndent) fputs("\n", out);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
PRUint32
|
|
|
|
nsGenericElement::GetChildCount() const
|
|
|
|
{
|
|
|
|
return mAttrsAndChildren.ChildCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIContent *
|
|
|
|
nsGenericElement::GetChildAt(PRUint32 aIndex) const
|
|
|
|
{
|
|
|
|
return mAttrsAndChildren.GetSafeChildAt(aIndex);
|
|
|
|
}
|
|
|
|
|
2008-07-11 13:42:19 -07:00
|
|
|
nsIContent * const *
|
2008-12-03 06:02:03 -08:00
|
|
|
nsGenericElement::GetChildArray(PRUint32* aChildCount) const
|
2008-07-11 13:42:19 -07:00
|
|
|
{
|
2008-12-03 06:02:03 -08:00
|
|
|
return mAttrsAndChildren.GetChildArray(aChildCount);
|
2008-07-11 13:42:19 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
PRInt32
|
|
|
|
nsGenericElement::IndexOf(nsINode* aPossibleChild) const
|
|
|
|
{
|
|
|
|
return mAttrsAndChildren.IndexOfChild(aPossibleChild);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsINode::nsSlots*
|
|
|
|
nsGenericElement::CreateSlots()
|
|
|
|
{
|
2011-04-07 19:29:49 -07:00
|
|
|
return new nsDOMSlots();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2007-04-23 00:31:21 -07:00
|
|
|
nsGenericElement::CheckHandleEventForLinksPrecondition(nsEventChainVisitor& aVisitor,
|
|
|
|
nsIURI** aURI) const
|
|
|
|
{
|
|
|
|
if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault ||
|
2011-06-30 04:52:11 -07:00
|
|
|
(!NS_IS_TRUSTED_EVENT(aVisitor.mEvent) &&
|
|
|
|
(aVisitor.mEvent->message != NS_MOUSE_CLICK) &&
|
|
|
|
(aVisitor.mEvent->message != NS_KEY_PRESS) &&
|
|
|
|
(aVisitor.mEvent->message != NS_UI_ACTIVATE)) ||
|
2010-12-27 12:42:10 -08:00
|
|
|
!aVisitor.mPresContext ||
|
2011-07-19 09:19:32 -07:00
|
|
|
(aVisitor.mEvent->flags & NS_EVENT_FLAG_PREVENT_MULTIPLE_ACTIONS)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-04-23 00:31:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure we actually are a link
|
|
|
|
return IsLink(aURI);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult
|
2007-04-23 00:31:21 -07:00
|
|
|
nsGenericElement::PreHandleEventForLinks(nsEventChainPreVisitor& aVisitor)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2007-04-23 00:31:21 -07:00
|
|
|
// Make sure we meet the preconditions before continuing
|
|
|
|
nsCOMPtr<nsIURI> 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) {
|
2010-10-18 11:12:18 -07:00
|
|
|
// Set the status bar similarly for mouseover and focus
|
2007-04-23 00:31:21 -07:00
|
|
|
case NS_MOUSE_ENTER_SYNTH:
|
|
|
|
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
|
|
|
// FALL THROUGH
|
|
|
|
case NS_FOCUS_CONTENT:
|
2010-10-18 11:12:18 -07:00
|
|
|
if (aVisitor.mEvent->eventStructType != NS_FOCUS_EVENT ||
|
|
|
|
!static_cast<nsFocusEvent*>(aVisitor.mEvent)->isRefocus) {
|
2007-04-23 00:31:21 -07:00
|
|
|
nsAutoString target;
|
|
|
|
GetLinkTarget(target);
|
2007-07-11 06:05:05 -07:00
|
|
|
nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target,
|
2011-10-17 07:59:28 -07:00
|
|
|
false, true, true);
|
2010-12-27 12:42:10 -08:00
|
|
|
// Make sure any ancestor links don't also TriggerLink
|
2011-07-19 09:19:32 -07:00
|
|
|
aVisitor.mEvent->flags |= NS_EVENT_FLAG_PREVENT_MULTIPLE_ACTIONS;
|
2007-04-23 00:31:21 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_MOUSE_EXIT_SYNTH:
|
|
|
|
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
|
|
|
// FALL THROUGH
|
|
|
|
case NS_BLUR_CONTENT:
|
|
|
|
rv = LeaveLink(aVisitor.mPresContext);
|
2010-12-27 12:42:10 -08:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2011-07-19 09:19:32 -07:00
|
|
|
aVisitor.mEvent->flags |= NS_EVENT_FLAG_PREVENT_MULTIPLE_ACTIONS;
|
2010-12-27 12:42:10 -08:00
|
|
|
}
|
2007-04-23 00:31:21 -07:00
|
|
|
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
|
|
|
|
nsGenericElement::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:
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-04-23 00:31:21 -07:00
|
|
|
// Make sure we meet the preconditions before continuing
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIURI> absURI;
|
2007-04-23 00:31:21 -07:00
|
|
|
if (!CheckHandleEventForLinksPrecondition(aVisitor, getter_AddRefs(absURI))) {
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
|
|
|
switch (aVisitor.mEvent->message) {
|
|
|
|
case NS_MOUSE_BUTTON_DOWN:
|
|
|
|
{
|
|
|
|
if (aVisitor.mEvent->eventStructType == NS_MOUSE_EVENT &&
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsMouseEvent*>(aVisitor.mEvent)->button ==
|
2007-03-22 10:30:00 -07:00
|
|
|
nsMouseEvent::eLeftButton) {
|
|
|
|
// don't make the link grab the focus if there is no link handler
|
|
|
|
nsILinkHandler *handler = aVisitor.mPresContext->GetLinkHandler();
|
|
|
|
nsIDocument *document = GetCurrentDoc();
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
if (handler && document) {
|
|
|
|
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
|
|
if (fm) {
|
2011-07-19 09:19:32 -07:00
|
|
|
aVisitor.mEvent->flags |= NS_EVENT_FLAG_PREVENT_MULTIPLE_ACTIONS;
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(this);
|
2009-09-21 08:58:16 -07:00
|
|
|
fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOUSE |
|
|
|
|
nsIFocusManager::FLAG_NOSCROLL);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
|
2010-10-28 07:11:15 -07:00
|
|
|
nsEventStateManager::SetActiveManager(
|
2011-04-21 10:35:52 -07:00
|
|
|
aVisitor.mPresContext->EventStateManager(), this);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_MOUSE_CLICK:
|
|
|
|
if (NS_IS_MOUSE_LEFT_CLICK(aVisitor.mEvent)) {
|
2009-10-13 10:23:48 -07:00
|
|
|
nsInputEvent* inputEvent = static_cast<nsInputEvent*>(aVisitor.mEvent);
|
|
|
|
if (inputEvent->isControl || inputEvent->isMeta ||
|
|
|
|
inputEvent->isAlt ||inputEvent->isShift) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// The default action is simply to dispatch DOMActivate
|
2007-03-25 22:38:22 -07:00
|
|
|
nsCOMPtr<nsIPresShell> shell = aVisitor.mPresContext->GetPresShell();
|
2007-03-22 10:30:00 -07:00
|
|
|
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);
|
2010-12-27 12:42:10 -08:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_UI_ACTIVATE:
|
|
|
|
{
|
2011-01-03 18:46:19 -08:00
|
|
|
if (aVisitor.mEvent->originalTarget == this) {
|
2010-12-27 12:42:10 -08:00
|
|
|
nsAutoString target;
|
|
|
|
GetLinkTarget(target);
|
|
|
|
nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target,
|
2011-10-17 07:59:28 -07:00
|
|
|
true, true, NS_IS_TRUSTED_EVENT(aVisitor.mEvent));
|
2010-12-27 12:42:10 -08:00
|
|
|
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_KEY_PRESS:
|
|
|
|
{
|
|
|
|
if (aVisitor.mEvent->eventStructType == NS_KEY_EVENT) {
|
2007-07-08 00:08:04 -07:00
|
|
|
nsKeyEvent* keyEvent = static_cast<nsKeyEvent*>(aVisitor.mEvent);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (keyEvent->keyCode == NS_VK_RETURN) {
|
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
|
|
rv = DispatchClickEvent(aVisitor.mPresContext, keyEvent, this,
|
2011-10-17 07:59:28 -07:00
|
|
|
false, 0, &status);
|
2007-03-22 10:30:00 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2011-05-09 12:33:03 -07:00
|
|
|
void
|
|
|
|
nsGenericElement::FireNodeRemovedForChildren()
|
|
|
|
{
|
2011-10-18 03:53:36 -07:00
|
|
|
nsIDocument* doc = OwnerDoc();
|
2011-05-09 12:33:03 -07:00
|
|
|
// Optimize the common case
|
|
|
|
if (!nsContentUtils::
|
|
|
|
HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEREMOVED)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocument> owningDoc = doc;
|
|
|
|
|
|
|
|
nsCOMPtr<nsINode> child;
|
|
|
|
for (child = GetFirstChild();
|
|
|
|
child && child->GetNodeParent() == this;
|
|
|
|
child = child->GetNextSibling()) {
|
|
|
|
nsContentUtils::MaybeFireNodeRemoved(child, this, doc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
|
|
|
nsGenericElement::GetLinkTarget(nsAString& aTarget)
|
|
|
|
{
|
|
|
|
aTarget.Truncate();
|
|
|
|
}
|
|
|
|
|
2008-07-21 17:55:52 -07:00
|
|
|
// NOTE: The aPresContext pointer is NOT addrefed.
|
2009-12-10 23:37:41 -08:00
|
|
|
// *aSelectorList might be null even if NS_OK is returned; this
|
|
|
|
// happens when all the selectors were pseudo-element selectors.
|
2008-07-21 17:55:52 -07:00
|
|
|
static nsresult
|
|
|
|
ParseSelectorList(nsINode* aNode,
|
|
|
|
const nsAString& aSelectorString,
|
2011-03-29 10:29:21 -07:00
|
|
|
nsCSSSelectorList** aSelectorList)
|
2008-07-21 17:55:52 -07:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aNode);
|
|
|
|
|
2011-10-18 03:53:36 -07:00
|
|
|
nsIDocument* doc = aNode->OwnerDoc();
|
2010-03-02 12:59:32 -08:00
|
|
|
nsCSSParser parser(doc->CSSLoader());
|
2008-07-21 17:55:52 -07:00
|
|
|
|
2009-12-10 23:37:41 -08:00
|
|
|
nsCSSSelectorList* selectorList;
|
2010-03-02 12:59:32 -08:00
|
|
|
nsresult rv = parser.ParseSelectorString(aSelectorString,
|
|
|
|
doc->GetDocumentURI(),
|
|
|
|
0, // XXXbz get the line number!
|
|
|
|
&selectorList);
|
2008-07-21 17:55:52 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2009-12-10 23:37:41 -08:00
|
|
|
// Filter out pseudo-element selectors from selectorList
|
|
|
|
nsCSSSelectorList** slot = &selectorList;
|
|
|
|
do {
|
|
|
|
nsCSSSelectorList* cur = *slot;
|
|
|
|
if (cur->mSelectors->IsPseudoElement()) {
|
|
|
|
*slot = cur->mNext;
|
|
|
|
cur->mNext = nsnull;
|
|
|
|
delete cur;
|
|
|
|
} else {
|
|
|
|
slot = &cur->mNext;
|
|
|
|
}
|
|
|
|
} while (*slot);
|
|
|
|
*aSelectorList = selectorList;
|
|
|
|
|
2008-07-21 17:55:52 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-10-31 19:50:50 -07:00
|
|
|
// Actually find elements matching aSelectorList (which must not be
|
2012-03-22 00:09:18 -07:00
|
|
|
// null) and which are descendants of aRoot and put them in aList. If
|
2011-10-31 19:50:50 -07:00
|
|
|
// onlyFirstMatch, then stop once the first one is found.
|
2011-10-31 19:49:10 -07:00
|
|
|
template<bool onlyFirstMatch, class T>
|
|
|
|
inline static nsresult FindMatchingElements(nsINode* aRoot,
|
|
|
|
const nsAString& aSelector,
|
|
|
|
T &aList)
|
2008-07-21 17:55:52 -07:00
|
|
|
{
|
|
|
|
nsAutoPtr<nsCSSSelectorList> selectorList;
|
2011-10-31 19:49:10 -07:00
|
|
|
nsresult rv = ParseSelectorList(aRoot, aSelector,
|
|
|
|
getter_Transfers(selectorList));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2011-10-31 19:50:50 -07:00
|
|
|
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);
|
2011-11-13 19:24:41 -08:00
|
|
|
doc->FlushPendingLinkUpdates();
|
2011-10-31 19:50:50 -07:00
|
|
|
|
|
|
|
// 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.
|
2011-11-03 22:32:09 -07:00
|
|
|
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.");
|
2011-10-31 19:50:50 -07:00
|
|
|
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) {
|
2011-11-03 22:32:09 -07:00
|
|
|
for (PRInt32 i = 0; i < elements->Count(); ++i) {
|
2011-10-31 19:50:50 -07:00
|
|
|
Element *element = static_cast<Element*>(elements->ElementAt(i));
|
|
|
|
if (!aRoot->IsElement() ||
|
2012-03-22 00:09:18 -07:00
|
|
|
(element != aRoot &&
|
|
|
|
nsContentUtils::ContentIsDescendantOf(element, aRoot))) {
|
|
|
|
// We have an element with the right id and it's a strict descendant
|
2011-10-31 19:50:50 -07:00
|
|
|
// 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;
|
|
|
|
}
|
2008-07-21 17:55:52 -07:00
|
|
|
|
2011-03-29 10:29:22 -07:00
|
|
|
for (nsIContent* cur = aRoot->GetFirstChild();
|
|
|
|
cur;
|
|
|
|
cur = cur->GetNextNode(aRoot)) {
|
|
|
|
if (cur->IsElement() &&
|
|
|
|
nsCSSRuleProcessor::SelectorListMatches(cur->AsElement(),
|
|
|
|
matchingContext,
|
|
|
|
selectorList)) {
|
2011-10-31 19:49:10 -07:00
|
|
|
aList.AppendElement(cur->AsElement());
|
|
|
|
if (onlyFirstMatch) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2011-03-29 10:29:22 -07:00
|
|
|
}
|
|
|
|
}
|
2008-07-21 17:55:52 -07:00
|
|
|
|
2011-10-31 19:49:10 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ElementHolder {
|
|
|
|
ElementHolder() : mElement(nsnull) {}
|
|
|
|
void AppendElement(Element* aElement) {
|
|
|
|
NS_ABORT_IF_FALSE(!mElement, "Should only get one element");
|
|
|
|
mElement = aElement;
|
|
|
|
}
|
|
|
|
Element* mElement;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
nsIContent*
|
|
|
|
nsGenericElement::doQuerySelector(nsINode* aRoot, const nsAString& aSelector,
|
|
|
|
nsresult *aResult)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aResult, "Null out param?");
|
|
|
|
|
|
|
|
ElementHolder holder;
|
|
|
|
*aResult = FindMatchingElements<true>(aRoot, aSelector, holder);
|
|
|
|
|
|
|
|
return holder.mElement;
|
2008-07-21 17:55:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
nsresult
|
|
|
|
nsGenericElement::doQuerySelectorAll(nsINode* aRoot,
|
|
|
|
const nsAString& aSelector,
|
|
|
|
nsIDOMNodeList **aReturn)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aReturn, "Null out param?");
|
|
|
|
|
2009-06-15 23:32:10 -07:00
|
|
|
nsSimpleContentList* contentList = new nsSimpleContentList(aRoot);
|
2008-07-21 17:55:52 -07:00
|
|
|
NS_ENSURE_TRUE(contentList, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
NS_ADDREF(*aReturn = contentList);
|
|
|
|
|
2011-10-31 19:49:10 -07:00
|
|
|
return FindMatchingElements<false>(aRoot, aSelector, *contentList);
|
2008-07-21 17:55:52 -07:00
|
|
|
}
|
2009-09-30 15:17:14 -07:00
|
|
|
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2010-10-21 07:09:00 -07:00
|
|
|
nsGenericElement::MozMatchesSelector(const nsAString& aSelector, nsresult* aResult)
|
2009-09-30 15:17:14 -07:00
|
|
|
{
|
|
|
|
nsAutoPtr<nsCSSSelectorList> selectorList;
|
2011-09-28 23:19:26 -07:00
|
|
|
bool matches = false;
|
2009-09-30 15:17:14 -07:00
|
|
|
|
2011-03-29 10:29:21 -07:00
|
|
|
*aResult = ParseSelectorList(this, aSelector, getter_Transfers(selectorList));
|
2010-10-21 07:09:00 -07:00
|
|
|
|
|
|
|
if (NS_SUCCEEDED(*aResult)) {
|
2011-11-13 19:24:41 -08:00
|
|
|
OwnerDoc()->FlushPendingLinkUpdates();
|
2011-10-17 07:59:28 -07:00
|
|
|
TreeMatchContext matchingContext(false,
|
2011-03-29 10:29:21 -07:00
|
|
|
nsRuleWalker::eRelevantLinkUnvisited,
|
2011-10-18 03:53:36 -07:00
|
|
|
OwnerDoc());
|
2011-03-29 10:29:21 -07:00
|
|
|
matches = nsCSSRuleProcessor::SelectorListMatches(this, matchingContext,
|
|
|
|
selectorList);
|
2009-09-30 15:17:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return matches;
|
|
|
|
}
|
2010-04-19 08:41:37 -07:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2011-12-18 02:06:23 -08:00
|
|
|
nsGenericElement::MozMatchesSelector(const nsAString& aSelector, bool* aReturn)
|
2010-04-19 08:41:37 -07:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(aReturn, "Null out param?");
|
2010-10-21 07:09:00 -07:00
|
|
|
|
|
|
|
nsresult rv;
|
2011-12-18 02:06:23 -08:00
|
|
|
*aReturn = MozMatchesSelector(aSelector, &rv);
|
2010-10-21 07:09:00 -07:00
|
|
|
|
|
|
|
return rv;
|
2010-04-19 08:41:37 -07:00
|
|
|
}
|
2011-08-26 15:39:00 -07:00
|
|
|
|
2012-02-01 13:58:01 -08:00
|
|
|
size_t
|
|
|
|
nsINode::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
|
2011-08-26 15:39:00 -07:00
|
|
|
{
|
2012-02-01 13:58:01 -08:00
|
|
|
size_t n = 0;
|
2011-08-26 15:39:00 -07:00
|
|
|
nsEventListenerManager* elm =
|
2011-10-17 07:59:28 -07:00
|
|
|
const_cast<nsINode*>(this)->GetListenerManager(false);
|
2011-08-26 15:39:00 -07:00
|
|
|
if (elm) {
|
2012-02-01 13:58:01 -08:00
|
|
|
n += elm->SizeOfIncludingThis(aMallocSizeOf);
|
2011-08-26 15:39:00 -07:00
|
|
|
}
|
|
|
|
|
2012-02-01 13:58:01 -08:00
|
|
|
// Measurement of the following members may be added later if DMD finds it is
|
|
|
|
// worthwhile:
|
|
|
|
// - mNodeInfo (Nb: allocated in nsNodeInfo.cpp with a nsFixedSizeAllocator)
|
|
|
|
// - mSlots
|
|
|
|
//
|
|
|
|
// The following members are not measured:
|
|
|
|
// - mParent, mNextSibling, mPreviousSibling, mFirstChild: because they're
|
|
|
|
// non-owning
|
|
|
|
return n;
|
2011-08-26 15:39:00 -07:00
|
|
|
}
|
2011-07-12 07:56:01 -07:00
|
|
|
|
2012-02-01 13:58:01 -08:00
|
|
|
size_t
|
|
|
|
nsGenericElement::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
|
2011-07-12 07:56:01 -07:00
|
|
|
{
|
2012-02-01 13:58:01 -08:00
|
|
|
return Element::SizeOfExcludingThis(aMallocSizeOf) +
|
|
|
|
mAttrsAndChildren.SizeOfExcludingThis(aMallocSizeOf);
|
2011-07-12 07:56:01 -07:00
|
|
|
}
|
|
|
|
|
2012-03-10 08:13:51 -08:00
|
|
|
static const nsAttrValue::EnumTable kCORSAttributeTable[] = {
|
|
|
|
// Order matters here
|
|
|
|
// See ParseCORSValue
|
|
|
|
{ "anonymous", CORS_ANONYMOUS },
|
|
|
|
{ "use-credentials", CORS_USE_CREDENTIALS },
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
/* static */ void
|
|
|
|
nsGenericElement::ParseCORSValue(const nsAString& aValue,
|
|
|
|
nsAttrValue& aResult)
|
|
|
|
{
|
|
|
|
DebugOnly<bool> success =
|
|
|
|
aResult.ParseEnumValue(aValue, kCORSAttributeTable, false,
|
|
|
|
// default value is anonymous if aValue is
|
|
|
|
// not a value we understand
|
|
|
|
&kCORSAttributeTable[0]);
|
|
|
|
MOZ_ASSERT(success);
|
|
|
|
}
|
|
|
|
|
2012-03-10 08:13:52 -08:00
|
|
|
/* static */ CORSMode
|
|
|
|
nsGenericElement::StringToCORSMode(const nsAString& aValue)
|
|
|
|
{
|
|
|
|
if (aValue.IsVoid()) {
|
|
|
|
return CORS_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAttrValue val;
|
|
|
|
nsGenericElement::ParseCORSValue(aValue, val);
|
|
|
|
return CORSMode(val.GetEnumValue());
|
|
|
|
}
|
|
|
|
|
2012-03-10 08:13:52 -08:00
|
|
|
/* static */ CORSMode
|
|
|
|
nsGenericElement::AttrValueToCORSMode(const nsAttrValue* aValue)
|
|
|
|
{
|
|
|
|
if (!aValue) {
|
|
|
|
return CORS_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CORSMode(aValue->GetEnumValue());
|
|
|
|
}
|
|
|
|
|
2011-08-24 12:49:25 -07:00
|
|
|
#define EVENT(name_, id_, type_, struct_) \
|
|
|
|
NS_IMETHODIMP nsINode::GetOn##name_(JSContext *cx, jsval *vp) { \
|
2011-10-17 07:59:28 -07:00
|
|
|
nsEventListenerManager *elm = GetListenerManager(false); \
|
2011-08-24 12:49:25 -07:00
|
|
|
if (elm) { \
|
|
|
|
elm->GetJSEventListener(nsGkAtoms::on##name_, vp); \
|
|
|
|
} else { \
|
|
|
|
*vp = JSVAL_NULL; \
|
|
|
|
} \
|
|
|
|
return NS_OK; \
|
|
|
|
} \
|
|
|
|
NS_IMETHODIMP nsINode::SetOn##name_(JSContext *cx, const jsval &v) { \
|
2011-10-17 07:59:28 -07:00
|
|
|
nsEventListenerManager *elm = GetListenerManager(true); \
|
2011-08-24 12:49:25 -07:00
|
|
|
if (!elm) { \
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
JSObject *obj = GetWrapper(); \
|
|
|
|
if (!obj) { \
|
|
|
|
/* Just silently do nothing */ \
|
|
|
|
return NS_OK; \
|
|
|
|
} \
|
|
|
|
return elm->SetJSEventListenerToJsval(nsGkAtoms::on##name_, cx, obj, v); \
|
|
|
|
}
|
|
|
|
#define TOUCH_EVENT EVENT
|
2011-09-19 19:56:45 -07:00
|
|
|
#define DOCUMENT_ONLY_EVENT EVENT
|
2011-08-24 12:49:25 -07:00
|
|
|
#include "nsEventNameList.h"
|
2011-09-19 19:56:45 -07:00
|
|
|
#undef DOCUMENT_ONLY_EVENT
|
2011-08-24 12:49:25 -07:00
|
|
|
#undef TOUCH_EVENT
|
|
|
|
#undef EVENT
|
2011-09-02 13:15:53 -07:00
|
|
|
|
2011-12-18 02:06:23 -08:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsGenericElement::GetOnmouseenter(JSContext* cx, JS::Value* vp)
|
|
|
|
{
|
|
|
|
return nsINode::GetOnmouseenter(cx, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsGenericElement::SetOnmouseenter(JSContext* cx, const JS::Value& v)
|
|
|
|
{
|
|
|
|
return nsINode::SetOnmouseenter(cx, v);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsGenericElement::GetOnmouseleave(JSContext* cx, JS::Value* vp)
|
|
|
|
{
|
|
|
|
return nsINode::GetOnmouseleave(cx, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsGenericElement::SetOnmouseleave(JSContext* cx, const JS::Value& v)
|
|
|
|
{
|
|
|
|
return nsINode::SetOnmouseleave(cx, v);
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2011-09-02 13:15:53 -07:00
|
|
|
nsINode::Contains(const nsINode* aOther) const
|
|
|
|
{
|
2011-09-07 08:04:04 -07:00
|
|
|
if (aOther == this) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2011-09-07 08:04:04 -07:00
|
|
|
}
|
2011-09-02 13:15:53 -07:00
|
|
|
if (!aOther ||
|
2011-10-18 03:53:36 -07:00
|
|
|
OwnerDoc() != aOther->OwnerDoc() ||
|
2011-09-02 13:15:53 -07:00
|
|
|
IsInDoc() != aOther->IsInDoc() ||
|
|
|
|
!(aOther->IsElement() ||
|
|
|
|
aOther->IsNodeOfType(nsINode::eCONTENT)) ||
|
|
|
|
!GetFirstChild()) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-09-02 13:15:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
const nsIContent* other = static_cast<const nsIContent*>(aOther);
|
2011-10-18 03:53:36 -07:00
|
|
|
if (this == OwnerDoc()) {
|
2011-09-02 13:15:53 -07:00
|
|
|
// document.contains(aOther) returns true if aOther is in the document,
|
|
|
|
// but is not in any anonymous subtree.
|
|
|
|
// IsInDoc() check is done already before this.
|
|
|
|
return !other->IsInAnonymousSubtree();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IsElement() && !IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-09-02 13:15:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
const nsIContent* thisContent = static_cast<const nsIContent*>(this);
|
|
|
|
if (thisContent->GetBindingParent() != other->GetBindingParent()) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-09-02 13:15:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nsContentUtils::ContentIsDescendantOf(other, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2011-09-28 23:19:26 -07:00
|
|
|
nsINode::Contains(nsIDOMNode* aOther, bool* aReturn)
|
2011-09-02 13:15:53 -07:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsINode> node = do_QueryInterface(aOther);
|
|
|
|
*aReturn = Contains(node);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-03-23 21:37:04 -07:00
|
|
|
|
2012-03-29 14:09:04 -07:00
|
|
|
PRUint32
|
|
|
|
nsINode::Length() const
|
|
|
|
{
|
|
|
|
switch (NodeType()) {
|
|
|
|
case nsIDOMNode::DOCUMENT_TYPE_NODE:
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case nsIDOMNode::TEXT_NODE:
|
|
|
|
case nsIDOMNode::CDATA_SECTION_NODE:
|
|
|
|
case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
|
|
|
|
case nsIDOMNode::COMMENT_NODE:
|
|
|
|
MOZ_ASSERT(IsNodeOfType(eCONTENT));
|
|
|
|
return static_cast<const nsIContent*>(this)->TextLength();
|
|
|
|
|
|
|
|
default:
|
|
|
|
return GetChildCount();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-28 22:37:46 -07:00
|
|
|
nsresult nsGenericElement::MozRequestFullScreen()
|
2012-03-23 21:37:04 -07:00
|
|
|
{
|
|
|
|
// 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.
|
|
|
|
if (!nsContentUtils::IsRequestFullScreenAllowed()) {
|
|
|
|
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
|
|
|
"DOM", OwnerDoc(),
|
|
|
|
nsContentUtils::eDOM_PROPERTIES,
|
|
|
|
"FullScreenDeniedNotInputDriven");
|
|
|
|
nsRefPtr<nsAsyncDOMEvent> e =
|
|
|
|
new nsAsyncDOMEvent(OwnerDoc(),
|
|
|
|
NS_LITERAL_STRING("mozfullscreenerror"),
|
|
|
|
true,
|
|
|
|
false);
|
|
|
|
e->PostDOMEvent();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
OwnerDoc()->AsyncRequestFullScreen(this);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|