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