|
|
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