Mozilla Cross-Reference mozilla
mozilla/ content/ xtf/ src/ nsXTFElementWrapper.cpp
CVS Log
CVS Blame
CVS Graph
Diff file
Raw file
changes to
this file in
the last:
day
week
month
view using tree:
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  * http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  *
15  * The Original Code is the Mozilla XTF project.
16  *
17  * The Initial Developer of the Original Code is
18  * Alex Fritze.
19  * Portions created by the Initial Developer are Copyright (C) 2004
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  *   Alex Fritze <alex@croczilla.com> (original author)
24  *
25  * Alternatively, the contents of this file may be used under the terms of
26  * either the GNU General Public License Version 2 or later (the "GPL"), or
27  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28  * in which case the provisions of the GPL or the LGPL are applicable instead
29  * of those above. If you wish to allow use of your version of this file only
30  * under the terms of either the GPL or the LGPL, and not to allow others to
31  * use your version of this file under the terms of the MPL, indicate your
32  * decision by deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL or the LGPL. If you do not delete
34  * the provisions above, a recipient may use your version of this file under
35  * the terms of any one of the MPL, the GPL or the LGPL.
36  *
37  * ***** END LICENSE BLOCK ***** */
38 
39 #include "nsXTFElementWrapper.h"
40 #include "nsIXTFElement.h"
41 #include "nsCOMPtr.h"
42 #include "nsString.h"
43 #include "nsXTFInterfaceAggregator.h"
44 #include "nsIClassInfo.h"
45 #include "nsPIDOMWindow.h"
46 #include "nsIInterfaceRequestorUtils.h"
47 #include "nsIDocument.h"
48 #include "nsGkAtoms.h"
49 #include "nsIPresShell.h"
50 #include "nsPresContext.h"
51 #include "nsIEventStateManager.h"
52 #include "nsIEventListenerManager.h"
53 #include "nsIDOMEvent.h"
54 #include "nsGUIEvent.h"
55 #include "nsContentUtils.h"
56 #include "nsIXTFService.h"
57 #include "nsIDOMAttr.h"
58 #include "nsIAttribute.h"
59 #include "nsDOMAttributeMap.h"
60 #include "nsUnicharUtils.h"
61 #include "nsEventDispatcher.h"
62 #include "nsIProgrammingLanguage.h"
63 #include "nsIXPConnect.h"
64 #include "nsXTFWeakTearoff.h"
65 #include "mozAutoDocUpdate.h"
66 
67 nsXTFElementWrapper::nsXTFElementWrapper(nsINodeInfo* aNodeInfo,
68                                          nsIXTFElement* aXTFElement)
69     : nsXTFElementWrapperBase(aNodeInfo),
70       mXTFElement(aXTFElement),
71       mNotificationMask(0),
72       mIntrinsicState(0),
73       mTmpAttrName(nsGkAtoms::_asterix) // XXX this is a hack, but names
74                                             // have to have a value
75 {
76 }
77 
78 nsXTFElementWrapper::~nsXTFElementWrapper()
79 {
80   mXTFElement->OnDestroyed();
81   mXTFElement = nsnull;
82 }
83 
84 nsresult
85 nsXTFElementWrapper::Init()
86 {
87   // pass a weak wrapper (non base object ref-counted), so that
88   // our mXTFElement can safely addref/release.
89   nsISupports* weakWrapper = nsnull;
90   nsresult rv = NS_NewXTFWeakTearoff(NS_GET_IID(nsIXTFElementWrapper),
91                                      (nsIXTFElementWrapper*)this,
92                                      &weakWrapper);
93   NS_ENSURE_SUCCESS(rv, rv);
94 
95   mXTFElement->OnCreated(static_cast<nsIXTFElementWrapper*>(weakWrapper));
96   weakWrapper->Release();
97 
98   PRBool innerHandlesAttribs = PR_FALSE;
99   GetXTFElement()->GetIsAttributeHandler(&innerHandlesAttribs);
100   if (innerHandlesAttribs)
101     mAttributeHandler = do_QueryInterface(GetXTFElement());
102   return NS_OK;
103 }
104 
105 //----------------------------------------------------------------------
106 // nsISupports implementation
107 
108 NS_IMPL_ADDREF_INHERITED(nsXTFElementWrapper, nsXTFElementWrapperBase)
109 NS_IMPL_RELEASE_INHERITED(nsXTFElementWrapper, nsXTFElementWrapperBase)
110 
111 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXTFElementWrapper)
112 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXTFElementWrapper,
113                                                   nsXTFElementWrapperBase)
114   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mXTFElement)
115   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mAttributeHandler)
116 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
117 
118 NS_IMETHODIMP
119 nsXTFElementWrapper::QueryInterface(REFNSIID aIID, void** aInstancePtr)
120 {
121   NS_PRECONDITION(aInstancePtr, "null out param");
122 
123   if (aIID.Equals(NS_GET_IID(nsIClassInfo))) {
124     *aInstancePtr = static_cast<nsIClassInfo*>(this);
125     NS_ADDREF_THIS();
126     return NS_OK;
127   }
128   if (aIID.Equals(NS_GET_IID(nsIXTFElementWrapper))) {
129     *aInstancePtr = static_cast<nsIXTFElementWrapper*>(this);
130     NS_ADDREF_THIS();
131     return NS_OK;
132   }
133 
134   nsresult rv = nsXTFElementWrapperBase::QueryInterface(aIID, aInstancePtr);
135   if (NS_SUCCEEDED(rv)) {
136     return rv;
137   }
138 
139   // try to get get the interface from our wrapped element:
140   nsCOMPtr<nsISupports> inner;
141   QueryInterfaceInner(aIID, getter_AddRefs(inner));
142 
143   if (inner) {
144     rv = NS_NewXTFInterfaceAggregator(aIID, inner,
145                                       static_cast<nsIContent*>(this),
146                                       aInstancePtr);
147 
148     return rv;
149   }
150 
151   return NS_ERROR_NO_INTERFACE;
152 }
153 
154 //----------------------------------------------------------------------
155 // nsIContent methods:
156 
157 nsresult
158 nsXTFElementWrapper::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
159                                 nsIContent* aBindingParent,
160                                 PRBool aCompileEventHandlers)
161 {
162   // XXXbz making up random order for the notifications... Perhaps
163   // this api should more closely match BindToTree/UnbindFromTree?
164   nsCOMPtr<nsIDOMElement> domParent;
165   if (aParent != GetParent()) {
166     domParent = do_QueryInterface(aParent);
167   }
168 
169   nsCOMPtr<nsIDOMDocument> domDocument;
170   if (aDocument &&
171       (mNotificationMask & (nsIXTFElement::NOTIFY_WILL_CHANGE_DOCUMENT |
172                             nsIXTFElement::NOTIFY_DOCUMENT_CHANGED))) {
173     domDocument = do_QueryInterface(aDocument);
174   }
175 
176   if (domDocument &&
177       (mNotificationMask & (nsIXTFElement::NOTIFY_WILL_CHANGE_DOCUMENT))) {
178     GetXTFElement()->WillChangeDocument(domDocument);
179   }
180 
181   if (domParent &&
182       (mNotificationMask & (nsIXTFElement::NOTIFY_WILL_CHANGE_PARENT))) {
183     GetXTFElement()->WillChangeParent(domParent);
184   }
185 
186   nsresult rv = nsXTFElementWrapperBase::BindToTree(aDocument, aParent,
187                                                     aBindingParent,
188                                                     aCompileEventHandlers);
189 
190   NS_ENSURE_SUCCESS(rv, rv);
191 
192   if (mNotificationMask & nsIXTFElement::NOTIFY_PERFORM_ACCESSKEY)
193     RegUnregAccessKey(PR_TRUE);
194 
195   if (domDocument &&
196       (mNotificationMask & (nsIXTFElement::NOTIFY_DOCUMENT_CHANGED))) {
197     GetXTFElement()->DocumentChanged(domDocument);
198   }
199 
200   if (domParent &&
201       (mNotificationMask & (nsIXTFElement::NOTIFY_PARENT_CHANGED))) {
202     GetXTFElement()->ParentChanged(domParent);
203   }
204 
205   return rv;  
206 }
207 
208 void
209 nsXTFElementWrapper::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
210 {
211   // XXXbz making up random order for the notifications... Perhaps
212   // this api should more closely match BindToTree/UnbindFromTree?
213 
214   PRBool inDoc = IsInDoc();
215   if (inDoc &&
216       (mNotificationMask & nsIXTFElement::NOTIFY_WILL_CHANGE_DOCUMENT)) {
217     GetXTFElement()->WillChangeDocument(nsnull);
218   }
219 
220   PRBool parentChanged = aNullParent && GetParent();
221 
222   if (parentChanged &&
223       (mNotificationMask & nsIXTFElement::NOTIFY_WILL_CHANGE_PARENT)) {
224     GetXTFElement()->WillChangeParent(nsnull);
225   }
226 
227   if (mNotificationMask & nsIXTFElement::NOTIFY_PERFORM_ACCESSKEY)
228     RegUnregAccessKey(PR_FALSE);
229 
230   nsXTFElementWrapperBase::UnbindFromTree(aDeep, aNullParent);
231 
232   if (parentChanged &&
233       (mNotificationMask & nsIXTFElement::NOTIFY_PARENT_CHANGED)) {
234     GetXTFElement()->ParentChanged(nsnull);
235   }
236 
237   if (inDoc &&
238       (mNotificationMask & nsIXTFElement::NOTIFY_DOCUMENT_CHANGED)) {
239     GetXTFElement()->DocumentChanged(nsnull);
240   }
241 }
242 
243 nsresult
244 nsXTFElementWrapper::InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
245                                    PRBool aNotify)
246 {
247   nsresult rv;
248 
249   nsCOMPtr<nsIDOMNode> domKid;
250   if (mNotificationMask & (nsIXTFElement::NOTIFY_WILL_INSERT_CHILD |
251                            nsIXTFElement::NOTIFY_CHILD_INSERTED))
252     domKid = do_QueryInterface(aKid);
253   
254   if (mNotificationMask & nsIXTFElement::NOTIFY_WILL_INSERT_CHILD)
255     GetXTFElement()->WillInsertChild(domKid, aIndex);
256   rv = nsXTFElementWrapperBase::InsertChildAt(aKid, aIndex, aNotify);
257   if (mNotificationMask & nsIXTFElement::NOTIFY_CHILD_INSERTED)
258     GetXTFElement()->ChildInserted(domKid, aIndex);
259   
260   return rv;
261 }
262 
263 nsresult
264 nsXTFElementWrapper::RemoveChildAt(PRUint32 aIndex, PRBool aNotify)
265 {
266   nsresult rv;
267   if (mNotificationMask & nsIXTFElement::NOTIFY_WILL_REMOVE_CHILD)
268     GetXTFElement()->WillRemoveChild(aIndex);
269   rv = nsXTFElementWrapperBase::RemoveChildAt(aIndex, aNotify);
270   if (mNotificationMask & nsIXTFElement::NOTIFY_CHILD_REMOVED)
271     GetXTFElement()->ChildRemoved(aIndex);
272   return rv;
273 }
274 
275 nsIAtom *
276 nsXTFElementWrapper::GetIDAttributeName() const
277 {
278   // XXX:
279   return nsGkAtoms::id;
280 }
281 
282 nsresult
283 nsXTFElementWrapper::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
284                              nsIAtom* aPrefix, const nsAString& aValue,
285                              PRBool aNotify)
286 {
287   nsresult rv;
288 
289   if (aNameSpaceID == kNameSpaceID_None &&
290       (mNotificationMask & nsIXTFElement::NOTIFY_WILL_SET_ATTRIBUTE))
291     GetXTFElement()->WillSetAttribute(aName, aValue);
292 
293   if (aNameSpaceID==kNameSpaceID_None && HandledByInner(aName)) {
294     rv = mAttributeHandler->SetAttribute(aName, aValue);
295     // XXX mutation events?
296   }
297   else { // let wrapper handle it
298     rv = nsXTFElementWrapperBase::SetAttr(aNameSpaceID, aName, aPrefix, aValue, aNotify);
299   }
300   
301   if (aNameSpaceID == kNameSpaceID_None &&
302       (mNotificationMask & nsIXTFElement::NOTIFY_ATTRIBUTE_SET))
303     GetXTFElement()->AttributeSet(aName, aValue);
304 
305   if (mNotificationMask & nsIXTFElement::NOTIFY_PERFORM_ACCESSKEY) {
306     nsCOMPtr<nsIDOMAttr> accesskey;
307     GetXTFElement()->GetAccesskeyNode(getter_AddRefs(accesskey));
308     nsCOMPtr<nsIAttribute> attr(do_QueryInterface(accesskey));
309     if (attr && attr->NodeInfo()->Equals(aName, aNameSpaceID))
310       RegUnregAccessKey(PR_TRUE);
311   }
312 
313   return rv;
314 }
315 
316 PRBool
317 nsXTFElementWrapper::GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, 
318                              nsAString& aResult) const
319 {
320   if (aNameSpaceID==kNameSpaceID_None && HandledByInner(aName)) {
321     // XXX we don't do namespaced attributes yet
322     nsresult rv = mAttributeHandler->GetAttribute(aName, aResult);
323     return NS_SUCCEEDED(rv) && !aResult.IsVoid();
324   }
325   else { // try wrapper
326     return nsXTFElementWrapperBase::GetAttr(aNameSpaceID, aName, aResult);
327   }
328 }
329 
330 PRBool
331 nsXTFElementWrapper::HasAttr(PRInt32 aNameSpaceID, nsIAtom* aName) const
332 {
333   if (aNameSpaceID==kNameSpaceID_None && HandledByInner(aName)) {
334     PRBool rval = PR_FALSE;
335     mAttributeHandler->HasAttribute(aName, &rval);
336     return rval;
337   }
338   else { // try wrapper
339     return nsXTFElementWrapperBase::HasAttr(aNameSpaceID, aName);
340   }
341 }
342 
343 PRBool
344 nsXTFElementWrapper::AttrValueIs(PRInt32 aNameSpaceID,
345                                  nsIAtom* aName,
346                                  const nsAString& aValue,
347                                  nsCaseTreatment aCaseSensitive) const
348 {
349   NS_ASSERTION(aName, "Must have attr name");
350   NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
351 
352   if (aNameSpaceID == kNameSpaceID_None && HandledByInner(aName)) {
353     nsAutoString ourVal;
354     if (!GetAttr(aNameSpaceID, aName, ourVal)) {
355       return PR_FALSE;
356     }
357     return aCaseSensitive == eCaseMatters ?
358       aValue.Equals(ourVal) :
359       aValue.Equals(ourVal, nsCaseInsensitiveStringComparator());
360   }
361 
362   return nsXTFElementWrapperBase::AttrValueIs(aNameSpaceID, aName, aValue,
363                                               aCaseSensitive);
364 }
365 
366 PRBool
367 nsXTFElementWrapper::AttrValueIs(PRInt32 aNameSpaceID,
368                                  nsIAtom* aName,
369                                  nsIAtom* aValue,
370                                  nsCaseTreatment aCaseSensitive) const
371 {
372   NS_ASSERTION(aName, "Must have attr name");
373   NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
374   NS_ASSERTION(aValue, "Null value atom");
375 
376   if (aNameSpaceID == kNameSpaceID_None && HandledByInner(aName)) {
377     nsAutoString ourVal;
378     if (!GetAttr(aNameSpaceID, aName, ourVal)) {
379       return PR_FALSE;
380     }
381     if (aCaseSensitive == eCaseMatters) {
382       return aValue->Equals(ourVal);
383     }
384     nsAutoString val;
385     aValue->ToString(val);
386     return val.Equals(ourVal, nsCaseInsensitiveStringComparator());
387   }
388 
389   return nsXTFElementWrapperBase::AttrValueIs(aNameSpaceID, aName, aValue,
390                                               aCaseSensitive);
391 }
392 
393 PRInt32
394 nsXTFElementWrapper::FindAttrValueIn(PRInt32 aNameSpaceID,
395                                      nsIAtom* aName,
396                                      AttrValuesArray* aValues,
397                                      nsCaseTreatment aCaseSensitive) const
398 {
399   NS_ASSERTION(aName, "Must have attr name");
400   NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
401   NS_ASSERTION(aValues, "Null value array");
402   
403   if (aNameSpaceID == kNameSpaceID_None && HandledByInner(aName)) {
404     nsAutoString ourVal;
405     if (!GetAttr(aNameSpaceID, aName, ourVal)) {
406       return ATTR_MISSING;
407     }
408     
409     for (PRInt32 i = 0; aValues[i]; ++i) {
410       if (aCaseSensitive == eCaseMatters) {
411         if ((*aValues[i])->Equals(ourVal)) {
412           return i;
413         }
414       } else {
415         nsAutoString val;
416         (*aValues[i])->ToString(val);
417         if (val.Equals(ourVal, nsCaseInsensitiveStringComparator())) {
418           return i;
419         }
420       }
421     }
422     return ATTR_VALUE_NO_MATCH;
423   }
424 
425   return nsXTFElementWrapperBase::FindAttrValueIn(aNameSpaceID, aName, aValues,
426                                                   aCaseSensitive);
427 }
428 
429 nsresult
430 nsXTFElementWrapper::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttr, 
431                                PRBool aNotify)
432 {
433   nsresult rv;
434 
435   if (aNameSpaceID == kNameSpaceID_None &&
436       (mNotificationMask & nsIXTFElement::NOTIFY_WILL_REMOVE_ATTRIBUTE))
437     GetXTFElement()->WillRemoveAttribute(aAttr);
438 
439   if (mNotificationMask & nsIXTFElement::NOTIFY_PERFORM_ACCESSKEY) {
440     nsCOMPtr<nsIDOMAttr> accesskey;
441     GetXTFElement()->GetAccesskeyNode(getter_AddRefs(accesskey));
442     nsCOMPtr<nsIAttribute> attr(do_QueryInterface(accesskey));
443     if (attr && attr->NodeInfo()->Equals(aAttr, aNameSpaceID))
444       RegUnregAccessKey(PR_FALSE);
445   }
446 
447   if (aNameSpaceID==kNameSpaceID_None && HandledByInner(aAttr)) {
448     nsDOMSlots *slots = GetExistingDOMSlots();
449     if (slots && slots->mAttributeMap) {
450       slots->mAttributeMap->DropAttribute(aNameSpaceID, aAttr);
451     }
452     rv = mAttributeHandler->RemoveAttribute(aAttr);
453 
454     // XXX if the RemoveAttribute() call fails, we might end up having removed
455     // the attribute from the attribute map even though the attribute is still
456     // on the element
457     // https://bugzilla.mozilla.org/show_bug.cgi?id=296205
458 
459     // XXX mutation events?
460   }
461   else { // try wrapper
462     rv = nsXTFElementWrapperBase::UnsetAttr(aNameSpaceID, aAttr, aNotify);
463   }
464 
465   if (aNameSpaceID == kNameSpaceID_None &&
466       (mNotificationMask & nsIXTFElement::NOTIFY_ATTRIBUTE_REMOVED))
467     GetXTFElement()->AttributeRemoved(aAttr);
468 
469   return rv;
470 }
471 
472 const nsAttrName*
473 nsXTFElementWrapper::GetAttrNameAt(PRUint32 aIndex) const
474 {
475   PRUint32 innerCount=0;
476   if (mAttributeHandler) {
477     mAttributeHandler->GetAttributeCount(&innerCount);
478   }
479   
480   if (aIndex < innerCount) {
481     nsCOMPtr<nsIAtom> localName;
482     nsresult rv = mAttributeHandler->GetAttributeNameAt(aIndex, getter_AddRefs(localName));
483     NS_ENSURE_SUCCESS(rv, nsnull);
484 
485     const_cast<nsXTFElementWrapper*>(this)->mTmpAttrName.SetTo(localName);
486     return &mTmpAttrName;
487   }
488   else { // wrapper handles attrib
489     return nsXTFElementWrapperBase::GetAttrNameAt(aIndex - innerCount);
490   }
491 }
492 
493 PRUint32
494 nsXTFElementWrapper::GetAttrCount() const
495 {
496   PRUint32 innerCount = 0;
497   if (mAttributeHandler) {
498     mAttributeHandler->GetAttributeCount(&innerCount);
499   }
500   // add wrapper attribs
501   return innerCount + nsXTFElementWrapperBase::GetAttrCount();
502 }
503 
504 void
505 nsXTFElementWrapper::BeginAddingChildren()
506 {
507   if (mNotificationMask & nsIXTFElement::NOTIFY_BEGIN_ADDING_CHILDREN)
508     GetXTFElement()->BeginAddingChildren();
509 }
510 
511 nsresult
512 nsXTFElementWrapper::DoneAddingChildren(PRBool aHaveNotified)
513 {
514   if (mNotificationMask & nsIXTFElement::NOTIFY_DONE_ADDING_CHILDREN)
515     GetXTFElement()->DoneAddingChildren();
516 
517   return NS_OK;
518 }
519 
520 already_AddRefed<nsINodeInfo>
521 nsXTFElementWrapper::GetExistingAttrNameFromQName(const nsAString& aStr) const
522 {
523   nsINodeInfo* nodeInfo = nsXTFElementWrapperBase::GetExistingAttrNameFromQName(aStr).get();
524 
525   // Maybe this attribute is handled by our inner element:
526   if (!nodeInfo) {
527     nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aStr);
528     if (HandledByInner(nameAtom)) 
529       mNodeInfo->NodeInfoManager()->GetNodeInfo(nameAtom, nsnull, kNameSpaceID_None, &nodeInfo);
530   }
531   
532   return nodeInfo;
533 }
534 
535 PRInt32
536 nsXTFElementWrapper::IntrinsicState() const
537 {
538   PRInt32 retState = nsXTFElementWrapperBase::IntrinsicState();
539   if (mIntrinsicState & NS_EVENT_STATE_MOZ_READONLY) {
540     retState &= ~NS_EVENT_STATE_MOZ_READWRITE;
541   } else if (mIntrinsicState & NS_EVENT_STATE_MOZ_READWRITE) {
542     retState &= ~NS_EVENT_STATE_MOZ_READONLY;
543   }
544 
545   return  retState | mIntrinsicState;
546 }
547 
548 void
549 nsXTFElementWrapper::PerformAccesskey(PRBool aKeyCausesActivation,
550                                       PRBool aIsTrustedEvent)
551 {
552   if (mNotificationMask & nsIXTFElement::NOTIFY_PERFORM_ACCESSKEY) {
553     nsIDocument* doc = GetCurrentDoc();
554     if (!doc)
555       return;
556 
557     // Get presentation shell 0
558     nsIPresShell *presShell = doc->GetPrimaryShell();
559     if (!presShell)
560       return;
561 
562     nsPresContext *presContext = presShell->GetPresContext();
563     if (!presContext)
564       return;
565 
566     nsIEventStateManager *esm = presContext->EventStateManager();
567     if (esm)
568       esm->ChangeFocusWith(this, nsIEventStateManager::eEventFocusedByKey);
569 
570     if (aKeyCausesActivation)
571       GetXTFElement()->PerformAccesskey();
572   }
573 }
574 
575 nsresult
576 nsXTFElementWrapper::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const
577 {
578   *aResult = nsnull;
579   nsCOMPtr<nsIContent> it;
580   nsContentUtils::GetXTFService()->CreateElement(getter_AddRefs(it),
581                                                  aNodeInfo);
582   if (!it)
583     return NS_ERROR_OUT_OF_MEMORY;
584 
585   nsXTFElementWrapper* wrapper =
586     static_cast<nsXTFElementWrapper*>(it.get());
587   nsresult rv = CopyInnerTo(wrapper);
588 
589   if (NS_SUCCEEDED(rv)) {
590     if (mAttributeHandler) {
591       PRUint32 innerCount = 0;
592       mAttributeHandler->GetAttributeCount(&innerCount);
593       for (PRUint32 i = 0; i < innerCount; ++i) {
594         nsCOMPtr<nsIAtom> attrName;
595         mAttributeHandler->GetAttributeNameAt(i, getter_AddRefs(attrName));
596         if (attrName) {
597           nsAutoString value;
598           if (NS_SUCCEEDED(mAttributeHandler->GetAttribute(attrName, value)))
599             it->SetAttr(kNameSpaceID_None, attrName, value, PR_TRUE);
600         }
601       }
602     }
603     NS_ADDREF(*aResult = it);
604   }
605 
606   // XXX CloneState should take |const nIDOMElement*|
607   wrapper->CloneState(const_cast<nsXTFElementWrapper*>(this));
608   return rv;
609 }
610 
611 //----------------------------------------------------------------------
612 // nsIDOMElement methods:
613 
614 NS_IMETHODIMP
615 nsXTFElementWrapper::GetAttribute(const nsAString& aName, nsAString& aReturn)
616 {
617   const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
618   if (name) {
619     GetAttr(name->NamespaceID(), name->LocalName(), aReturn);
620     return NS_OK;
621   }
622 
623   // Maybe this attribute is handled by our inner element:
624   if (mAttributeHandler) {
625     nsresult rv = nsContentUtils::CheckQName(aName, PR_FALSE);
626     NS_ENSURE_SUCCESS(rv, rv);
627     nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aName);
628     if (HandledByInner(nameAtom)) {
629       GetAttr(kNameSpaceID_None, nameAtom, aReturn);
630       return NS_OK;
631     }
632   }
633   
634   SetDOMStringToNull(aReturn);
635   return NS_OK;
636 }
637 
638 NS_IMETHODIMP
639 nsXTFElementWrapper::RemoveAttribute(const nsAString& aName)
640 {
641   const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
642 
643   if (name) {
644     nsAttrName tmp(*name);
645     return UnsetAttr(name->NamespaceID(), name->LocalName(), PR_TRUE);
646   }
647 
648   // Maybe this attribute is handled by our inner element:
649   if (mAttributeHandler) {
650     nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aName);
651     return UnsetAttr(kNameSpaceID_None, nameAtom, PR_TRUE);
652   }
653 
654   return NS_OK;
655 }
656 
657 NS_IMETHODIMP
658 nsXTFElementWrapper::HasAttribute(const nsAString& aName, PRBool* aReturn)
659 {
660   const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
661   if (name) {
662     *aReturn = PR_TRUE;
663     return NS_OK;
664   }
665   
666   // Maybe this attribute is handled by our inner element:
667   if (mAttributeHandler) {
668     nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aName);
669     *aReturn = HasAttr(kNameSpaceID_None, nameAtom);
670     return NS_OK;
671   }
672 
673   *aReturn = PR_FALSE;
674   return NS_OK;
675 }
676 
677 
678 //----------------------------------------------------------------------
679 // nsIClassInfo implementation
680 
681 /* void getInterfaces (out PRUint32 count, [array, size_is (count), retval] out nsIIDPtr array); */
682 NS_IMETHODIMP 
683 nsXTFElementWrapper::GetInterfaces(PRUint32* aCount, nsIID*** aArray)
684 {
685   *aArray = nsnull;
686   *aCount = 0;
687   PRUint32 baseCount = 0;
688   nsIID** baseArray = nsnull;
689   PRUint32 xtfCount = 0;
690   nsIID** xtfArray = nsnull;
691 
692   nsCOMPtr<nsIClassInfo> baseCi =
693     NS_GetDOMClassInfoInstance(eDOMClassInfo_Element_id);
694   if (baseCi) {
695     baseCi->GetInterfaces(&baseCount, &baseArray);
696   }
697 
698   GetXTFElement()->GetScriptingInterfaces(&xtfCount, &xtfArray);
699   if (!xtfCount) {
700     *aCount = baseCount;
701     *aArray = baseArray;
702     return NS_OK;
703   } else if (!baseCount) {
704     *aCount = xtfCount;
705     *aArray = xtfArray;
706     return NS_OK;
707   }
708 
709   PRUint32 count = baseCount + xtfCount;
710   nsIID** iids = static_cast<nsIID**>
711                             (nsMemory::Alloc(count * sizeof(nsIID*)));
712   NS_ENSURE_TRUE(iids, NS_ERROR_OUT_OF_MEMORY);
713 
714   PRUint32 i = 0;
715   for (; i < baseCount; ++i) {
716     iids[i] = static_cast<nsIID*>
717                          (nsMemory::Clone(baseArray[i], sizeof(nsIID)));
718     if (!iids[i]) {
719       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(baseCount, baseArray);
720       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(xtfCount, xtfArray);
721       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, iids);
722       return NS_ERROR_OUT_OF_MEMORY;
723     }
724   }
725 
726   for (; i < count; ++i) {
727     iids[i] = static_cast<nsIID*>
728                          (nsMemory::Clone(xtfArray[i - baseCount], sizeof(nsIID)));
729     if (!iids[i]) {
730       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(baseCount, baseArray);
731       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(xtfCount, xtfArray);
732       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, iids);
733       return NS_ERROR_OUT_OF_MEMORY;
734     }
735   }
736 
737   NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(baseCount, baseArray);
738   NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(xtfCount, xtfArray);
739   *aArray = iids;
740   *aCount = count;
741 
742   return NS_OK;
743 }
744 
745 /* nsISupports getHelperForLanguage (in PRUint32 language); */
746 NS_IMETHODIMP 
747 nsXTFElementWrapper::GetHelperForLanguage(PRUint32 language,
748                                           nsISupports** aHelper)
749 {
750   *aHelper = nsnull;
751   nsCOMPtr<nsIClassInfo> ci = 
752     NS_GetDOMClassInfoInstance(eDOMClassInfo_Element_id);
753   return
754     ci ? ci->GetHelperForLanguage(language, aHelper) : NS_ERROR_NOT_AVAILABLE;
755 }
756 
757 /* readonly attribute string contractID; */
758 NS_IMETHODIMP 
759 nsXTFElementWrapper::GetContractID(char * *aContractID)
760 {
761   *aContractID = nsnull;
762   return NS_OK;
763 }
764 
765 /* readonly attribute string classDescription; */
766 NS_IMETHODIMP 
767 nsXTFElementWrapper::GetClassDescription(char * *aClassDescription)
768 {
769   *aClassDescription = nsnull;
770   return NS_OK;
771 }
772 
773 /* readonly attribute nsCIDPtr classID; */
774 NS_IMETHODIMP 
775 nsXTFElementWrapper::GetClassID(nsCID * *aClassID)
776 {
777   *aClassID = nsnull;
778   return NS_OK;
779 }
780 
781 /* readonly attribute PRUint32 implementationLanguage; */
782 NS_IMETHODIMP 
783 nsXTFElementWrapper::GetImplementationLanguage(PRUint32 *aImplementationLanguage)
784 {
785   *aImplementationLanguage = nsIProgrammingLanguage::UNKNOWN;
786   return NS_OK;
787 }
788 
789 /* readonly attribute PRUint32 flags; */
790 NS_IMETHODIMP 
791 nsXTFElementWrapper::GetFlags(PRUint32 *aFlags)
792 {
793   *aFlags = nsIClassInfo::DOM_OBJECT;
794   return NS_OK;
795 }
796 
797 /* [notxpcom] readonly attribute nsCID classIDNoAlloc; */
798 NS_IMETHODIMP 
799 nsXTFElementWrapper::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
800 {
801   return NS_ERROR_NOT_AVAILABLE;
802 }
803 
804 //----------------------------------------------------------------------
805 // nsIXTFElementWrapper implementation:
806 
807 /* readonly attribute nsIDOMElement elementNode; */
808 NS_IMETHODIMP
809 nsXTFElementWrapper::GetElementNode(nsIDOMElement * *aElementNode)
810 {
811   *aElementNode = (nsIDOMElement*)this;
812   NS_ADDREF(*aElementNode);
813   return NS_OK;
814 }
815 
816 /* readonly attribute nsIDOMElement documentFrameElement; */
817 NS_IMETHODIMP
818 nsXTFElementWrapper::GetDocumentFrameElement(nsIDOMElement * *aDocumentFrameElement)
819 {
820   *aDocumentFrameElement = nsnull;
821   
822   nsIDocument *doc = GetCurrentDoc();
823   if (!doc) {
824     NS_WARNING("no document");
825     return NS_OK;
826   }
827   nsCOMPtr<nsISupports> container = doc->GetContainer();
828   if (!container) {
829     NS_ERROR("no docshell");
830     return NS_ERROR_FAILURE;
831   }
832   nsCOMPtr<nsPIDOMWindow> pidomwin = do_GetInterface(container);
833   if (!pidomwin) {
834     NS_ERROR("no nsPIDOMWindow interface on docshell");
835     return NS_ERROR_FAILURE;
836   }
837   *aDocumentFrameElement = pidomwin->GetFrameElementInternal();
838   NS_IF_ADDREF(*aDocumentFrameElement);
839   return NS_OK;
840 }
841 
842 /* attribute unsigned long notificationMask; */
843 NS_IMETHODIMP
844 nsXTFElementWrapper::GetNotificationMask(PRUint32 *aNotificationMask)
845 {
846   *aNotificationMask = mNotificationMask;
847   return NS_OK;
848 }
849 NS_IMETHODIMP
850 nsXTFElementWrapper::SetNotificationMask(PRUint32 aNotificationMask)
851 {
852   mNotificationMask = aNotificationMask;
853   return NS_OK;
854 }
855 
856 //----------------------------------------------------------------------
857 // implementation helpers:
858 PRBool
859 nsXTFElementWrapper::QueryInterfaceInner(REFNSIID aIID, void** result)
860 {
861   // We must ensure that the inner element has a distinct xpconnect
862   // identity, so we mustn't aggregate nsIXPConnectWrappedJS:
863   if (aIID.Equals(NS_GET_IID(nsIXPConnectWrappedJS))) return PR_FALSE;
864 
865   GetXTFElement()->QueryInterface(aIID, result);
866   return (*result!=nsnull);
867 }
868 
869 PRBool
870 nsXTFElementWrapper::HandledByInner(nsIAtom *attr) const
871 {
872   PRBool retval = PR_FALSE;
873   if (mAttributeHandler)
874     mAttributeHandler->HandlesAttribute(attr, &retval);
875   return retval;
876 }
877 
878 nsresult
879 nsXTFElementWrapper::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
880 {
881   nsresult rv = NS_OK;
882   if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault ||
883       !(mNotificationMask & nsIXTFElement::NOTIFY_HANDLE_DEFAULT)) {
884     return rv;
885   }
886 
887   if (!aVisitor.mDOMEvent) {
888     // We haven't made a DOMEvent yet.  Force making one now.
889     if (NS_FAILED(rv = nsEventDispatcher::CreateEvent(aVisitor.mPresContext,
890                                                       aVisitor.mEvent,
891                                                       EmptyString(),
892                                                       &aVisitor.mDOMEvent)))
893       return rv;
894   }
895   if (!aVisitor.mDOMEvent)
896     return NS_ERROR_FAILURE;
897   
898   PRBool defaultHandled = PR_FALSE;
899   nsIXTFElement* xtfElement = GetXTFElement();
900   if (xtfElement)
901     rv = xtfElement->HandleDefault(aVisitor.mDOMEvent, &defaultHandled);
902   if (defaultHandled)
903     aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
904   return rv;
905 }
906 
907 NS_IMETHODIMP
908 nsXTFElementWrapper::SetIntrinsicState(PRInt32 aNewState)
909 {
910   nsIDocument *doc = GetCurrentDoc();
911   PRInt32 bits = mIntrinsicState ^ aNewState;
912   
913   if (!doc || !bits)
914     return NS_OK;
915 
916   NS_WARN_IF_FALSE(!((aNewState & NS_EVENT_STATE_MOZ_READONLY) &&
917                    (aNewState & NS_EVENT_STATE_MOZ_READWRITE)),
918                    "Both READONLY and READWRITE are being set.  Yikes!!!");
919 
920   mIntrinsicState = aNewState;
921   mozAutoDocUpdate upd(doc, UPDATE_CONTENT_STATE, PR_TRUE);
922   doc->ContentStatesChanged(this, nsnull, bits);
923 
924   return NS_OK;
925 }
926 
927 nsIAtom *
928 nsXTFElementWrapper::GetClassAttributeName() const
929 {
930   return mClassAttributeName;
931 }
932 
933 const nsAttrValue*
934 nsXTFElementWrapper::GetClasses() const
935 {
936   const nsAttrValue* val = nsnull;
937   nsIAtom* clazzAttr = GetClassAttributeName();
938   if (clazzAttr) {
939     val = mAttrsAndChildren.GetAttr(clazzAttr);
940     // This is possibly the first time we need any classes.
941     if (val && val->Type() == nsAttrValue::eString) {
942       nsAutoString value;
943       val->ToString(value);
944       nsAttrValue newValue;
945       newValue.ParseAtomArray(value);
946       const_cast<nsAttrAndChildArray*>(&mAttrsAndChildren)->
947         SetAndTakeAttr(clazzAttr, newValue);
948     }
949   }
950   return val;
951 }
952 
953 nsresult
954 nsXTFElementWrapper::SetClassAttributeName(nsIAtom* aName)
955 {
956   // The class attribute name can be set only once
957   if (mClassAttributeName || !aName)
958     return NS_ERROR_FAILURE;
959   
960   mClassAttributeName = aName;
961   return NS_OK;
962 }
963 
964 void
965 nsXTFElementWrapper::RegUnregAccessKey(PRBool aDoReg)
966 {
967   nsIDocument* doc = GetCurrentDoc();
968   if (!doc)
969     return;
970 
971   // Get presentation shell 0
972   nsIPresShell *presShell = doc->GetPrimaryShell();
973   if (!presShell)
974     return;
975 
976   nsPresContext *presContext = presShell->GetPresContext();
977   if (!presContext)
978     return;
979 
980   nsIEventStateManager *esm = presContext->EventStateManager();
981   if (!esm)
982     return;
983 
984   // Register or unregister as appropriate.
985   nsCOMPtr<nsIDOMAttr> accesskeyNode;
986   GetXTFElement()->GetAccesskeyNode(getter_AddRefs(accesskeyNode));
987   if (!accesskeyNode)
988     return;
989 
990   nsAutoString accessKey;
991   accesskeyNode->GetValue(accessKey);
992 
993   if (aDoReg && !accessKey.IsEmpty())
994     esm->RegisterAccessKey(this, (PRUint32)accessKey.First());
995   else
996     esm->UnregisterAccessKey(this, (PRUint32)accessKey.First());
997 }
998 
999 nsresult
1000 NS_NewXTFElementWrapper(nsIXTFElement* aXTFElement,
1001                         nsINodeInfo* aNodeInfo,
1002                         nsIContent** aResult)
1003 {
1004   *aResult = nsnull;
1005    NS_ENSURE_ARG(aXTFElement);
1006 
1007   nsXTFElementWrapper* result = new nsXTFElementWrapper(aNodeInfo, aXTFElement);
1008   if (!result) {
1009     return NS_ERROR_OUT_OF_MEMORY;
1010   }
1011 
1012   NS_ADDREF(result);
1013 
1014   nsresult rv = result->Init();
1015   if (NS_FAILED(rv)) {
1016     NS_RELEASE(result);
1017     return rv;
1018   }
1019 
1020   *aResult = result;
1021   return NS_OK;
1022 }
1023