~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/content/xbl/src/nsXBLBinding.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
/* ***** BEGIN LICENSE BLOCK *****
 
3
 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
 
4
 *
 
5
 * The contents of this file are subject to the Netscape Public License
 
6
 * Version 1.1 (the "License"); you may not use this file except in
 
7
 * compliance with the License. You may obtain a copy of the License at
 
8
 * http://www.mozilla.org/NPL/
 
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 Mozilla Communicator client code.
 
16
 *
 
17
 * The Initial Developer of the Original Code is 
 
18
 * Netscape Communications Corporation.
 
19
 * Portions created by the Initial Developer are Copyright (C) 1998
 
20
 * the Initial Developer. All Rights Reserved.
 
21
 *
 
22
 * Original Author: David W. Hyatt (hyatt@netscape.com)
 
23
 * 
 
24
 * Contributor(s):
 
25
 *                 Brendan Eich (brendan@mozilla.org)
 
26
 *                 Scott MacGregor (mscott@netscape.com)
 
27
 *
 
28
 *
 
29
 * Alternatively, the contents of this file may be used under the terms of
 
30
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
31
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
32
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
33
 * of those above. If you wish to allow use of your version of this file only
 
34
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
35
 * use your version of this file under the terms of the NPL, indicate your
 
36
 * decision by deleting the provisions above and replace them with the notice
 
37
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
38
 * the provisions above, a recipient may use your version of this file under
 
39
 * the terms of any one of the NPL, the GPL or the LGPL.
 
40
 *
 
41
 * ***** END LICENSE BLOCK ***** */
 
42
 
 
43
#include "nsCOMPtr.h"
 
44
#include "nsIAtom.h"
 
45
#include "nsIXBLBinding.h"
 
46
#include "nsIXBLDocumentInfo.h"
 
47
#include "nsIInputStream.h"
 
48
#include "nsINameSpaceManager.h"
 
49
#include "nsHashtable.h"
 
50
#include "nsIURI.h"
 
51
#include "nsIURL.h"
 
52
#include "nsIDOMEventReceiver.h"
 
53
#include "nsIChannel.h"
 
54
#include "nsXPIDLString.h"
 
55
#include "nsReadableUtils.h"
 
56
#include "nsIParser.h"
 
57
#include "nsParserCIID.h"
 
58
#include "nsNetUtil.h"
 
59
#include "plstr.h"
 
60
#include "nsIContent.h"
 
61
#include "nsIDocument.h"
 
62
#ifdef MOZ_XUL
 
63
#include "nsIXULDocument.h"
 
64
#endif
 
65
#include "nsIXMLContentSink.h"
 
66
#include "nsContentCID.h"
 
67
#include "nsXMLDocument.h"
 
68
#include "nsIDOMElement.h"
 
69
#include "nsIDOMText.h"
 
70
#include "nsSupportsArray.h"
 
71
#include "nsINameSpace.h"
 
72
#include "jsapi.h"
 
73
#include "nsXBLService.h"
 
74
#include "nsXBLInsertionPoint.h"
 
75
#include "nsIXPConnect.h"
 
76
#include "nsIScriptGlobalObjectOwner.h"
 
77
#include "nsIScriptContext.h"
 
78
#include "nsCRT.h"
 
79
 
 
80
// Event listeners
 
81
#include "nsIEventListenerManager.h"
 
82
#include "nsIDOMMouseListener.h"
 
83
#include "nsIDOMMouseMotionListener.h"
 
84
#include "nsIDOMLoadListener.h"
 
85
#include "nsIDOMFocusListener.h"
 
86
#include "nsIDOMPaintListener.h"
 
87
#include "nsIDOMKeyListener.h"
 
88
#include "nsIDOMFormListener.h"
 
89
#include "nsIDOMXULListener.h"
 
90
#include "nsIDOMDragListener.h"
 
91
#include "nsIDOMMutationListener.h"
 
92
#include "nsIDOMContextMenuListener.h"
 
93
#include "nsIDOMEventGroup.h"
 
94
 
 
95
#include "nsXBLAtoms.h"
 
96
#include "nsXULAtoms.h"
 
97
 
 
98
#include "nsIDOMAttr.h"
 
99
#include "nsIDOMNamedNodeMap.h"
 
100
 
 
101
#include "nsXBLPrototypeHandler.h"
 
102
 
 
103
#include "nsXBLPrototypeBinding.h"
 
104
#include "nsXBLBinding.h"
 
105
 
 
106
#include "prprf.h"
 
107
 
 
108
// Helper classes
 
109
 
 
110
/***********************************************************************/
 
111
//
 
112
// The JS class for XBLBinding
 
113
//
 
114
PR_STATIC_CALLBACK(void)
 
115
XBLFinalize(JSContext *cx, JSObject *obj)
 
116
{
 
117
  nsXBLJSClass* c = NS_STATIC_CAST(nsXBLJSClass*, ::JS_GetClass(cx, obj));
 
118
  c->Drop();
 
119
}
 
120
 
 
121
nsXBLJSClass::nsXBLJSClass(const nsAFlatCString& aClassName)
 
122
{
 
123
  memset(this, 0, sizeof(nsXBLJSClass));
 
124
  next = prev = NS_STATIC_CAST(JSCList*, this);
 
125
  name = ToNewCString(aClassName);
 
126
  addProperty = delProperty = setProperty = getProperty = ::JS_PropertyStub;
 
127
  enumerate = ::JS_EnumerateStub;
 
128
  resolve = ::JS_ResolveStub;
 
129
  convert = ::JS_ConvertStub;
 
130
  finalize = XBLFinalize;
 
131
}
 
132
 
 
133
nsrefcnt
 
134
nsXBLJSClass::Destroy()
 
135
{
 
136
  NS_ASSERTION(next == prev && prev == NS_STATIC_CAST(JSCList*, this),
 
137
               "referenced nsXBLJSClass is on LRU list already!?");
 
138
 
 
139
  if (nsXBLService::gClassTable) {
 
140
    nsCStringKey key(name);
 
141
    (nsXBLService::gClassTable)->Remove(&key);
 
142
  }
 
143
 
 
144
  if (nsXBLService::gClassLRUListLength >= nsXBLService::gClassLRUListQuota) {
 
145
    // Over LRU list quota, just unhash and delete this class.
 
146
    delete this;
 
147
  } else {
 
148
    // Put this most-recently-used class on end of the LRU-sorted freelist.
 
149
    JSCList* mru = NS_STATIC_CAST(JSCList*, this);
 
150
    JS_APPEND_LINK(mru, &nsXBLService::gClassLRUList);
 
151
    nsXBLService::gClassLRUListLength++;
 
152
  }
 
153
 
 
154
  return 0;
 
155
}
 
156
 
 
157
// Implementation /////////////////////////////////////////////////////////////////
 
158
 
 
159
// Implement our nsISupports methods
 
160
NS_IMPL_ISUPPORTS1(nsXBLBinding, nsIXBLBinding)
 
161
 
 
162
// Constructors/Destructors
 
163
nsXBLBinding::nsXBLBinding(nsXBLPrototypeBinding* aBinding)
 
164
: mPrototypeBinding(aBinding),
 
165
  mInsertionPointTable(nsnull),
 
166
  mIsStyleBinding(PR_TRUE),
 
167
  mMarkedForDeath(PR_FALSE)
 
168
{
 
169
  NS_ASSERTION(mPrototypeBinding, "Must have a prototype binding!");
 
170
  // Grab a ref to the document info so the prototype binding won't die
 
171
  NS_ADDREF(mPrototypeBinding->XBLDocumentInfo());
 
172
}
 
173
 
 
174
 
 
175
nsXBLBinding::~nsXBLBinding(void)
 
176
{
 
177
  delete mInsertionPointTable;
 
178
  nsIXBLDocumentInfo* info = mPrototypeBinding->XBLDocumentInfo();
 
179
  NS_RELEASE(info);
 
180
}
 
181
 
 
182
// nsIXBLBinding Interface ////////////////////////////////////////////////////////////////
 
183
 
 
184
NS_IMETHODIMP
 
185
nsXBLBinding::GetBaseBinding(nsIXBLBinding** aResult)
 
186
{
 
187
  *aResult = mNextBinding;
 
188
  NS_IF_ADDREF(*aResult);
 
189
  return NS_OK;
 
190
}
 
191
 
 
192
NS_IMETHODIMP
 
193
nsXBLBinding::SetBaseBinding(nsIXBLBinding* aBinding)
 
194
{
 
195
  if (mNextBinding) {
 
196
    NS_ERROR("Base XBL binding is already defined!");
 
197
    return NS_OK;
 
198
  }
 
199
 
 
200
  mNextBinding = aBinding; // Comptr handles rel/add
 
201
  return NS_OK;
 
202
}
 
203
 
 
204
NS_IMETHODIMP
 
205
nsXBLBinding::GetAnonymousContent(nsIContent** aResult)
 
206
{
 
207
  *aResult = mContent;
 
208
  NS_IF_ADDREF(*aResult);
 
209
  return NS_OK;
 
210
}
 
211
 
 
212
void
 
213
nsXBLBinding::InstallAnonymousContent(nsIContent* aAnonParent, nsIContent* aElement)
 
214
{
 
215
  // We need to ensure two things.
 
216
  // (1) The anonymous content should be fooled into thinking it's in the bound
 
217
  // element's document.
 
218
  nsCOMPtr<nsIDocument> doc = aElement->GetDocument();
 
219
 
 
220
  aAnonParent->SetDocument(doc, PR_TRUE, AllowScripts());
 
221
 
 
222
  // (2) The children's parent back pointer should not be to this synthetic root
 
223
  // but should instead point to the enclosing parent element.
 
224
  PRUint32 childCount = aAnonParent->GetChildCount();
 
225
  for (PRUint32 i = 0; i < childCount; i++) {
 
226
    nsIContent *child = aAnonParent->GetChildAt(i);
 
227
    child->SetParent(aElement);
 
228
    child->SetBindingParent(mBoundElement);
 
229
 
 
230
#ifdef MOZ_XUL
 
231
    // To make XUL templates work (and other goodies that happen when
 
232
    // an element is added to a XUL document), we need to notify the
 
233
    // XUL document using its special API.
 
234
    nsCOMPtr<nsIXULDocument> xuldoc(do_QueryInterface(doc));
 
235
    if (xuldoc)
 
236
      xuldoc->AddSubtreeToDocument(child);
 
237
#endif
 
238
  }
 
239
}
 
240
 
 
241
NS_IMETHODIMP
 
242
nsXBLBinding::SetAnonymousContent(nsIContent* aParent)
 
243
{
 
244
  // First cache the element.
 
245
  mContent = aParent;
 
246
 
 
247
  InstallAnonymousContent(mContent, mBoundElement);
 
248
  return NS_OK;
 
249
}
 
250
 
 
251
NS_IMETHODIMP
 
252
nsXBLBinding::GetPrototypeBinding(nsXBLPrototypeBinding** aResult)
 
253
{
 
254
  *aResult = mPrototypeBinding;
 
255
  return NS_OK;
 
256
}
 
257
  
 
258
NS_IMETHODIMP
 
259
nsXBLBinding::SetPrototypeBinding(nsXBLPrototypeBinding* aProtoBinding)
 
260
{
 
261
  mPrototypeBinding = aProtoBinding;
 
262
  return NS_OK;
 
263
}
 
264
 
 
265
NS_IMETHODIMP
 
266
nsXBLBinding::GetBindingElement(nsIContent** aResult)
 
267
{
 
268
  *aResult = mPrototypeBinding->GetBindingElement().get();
 
269
  return NS_OK;
 
270
}
 
271
 
 
272
NS_IMETHODIMP
 
273
nsXBLBinding::SetBindingElement(nsIContent* aElement)
 
274
{
 
275
  mPrototypeBinding->SetBindingElement(aElement);
 
276
  return NS_OK;
 
277
}
 
278
 
 
279
NS_IMETHODIMP
 
280
nsXBLBinding::GetBoundElement(nsIContent** aResult)
 
281
{
 
282
  *aResult = mBoundElement;
 
283
  NS_IF_ADDREF(*aResult);
 
284
  return NS_OK;
 
285
}
 
286
 
 
287
NS_IMETHODIMP
 
288
nsXBLBinding::SetBoundElement(nsIContent* aElement)
 
289
{
 
290
  mBoundElement = aElement;
 
291
  if (mNextBinding)
 
292
    mNextBinding->SetBoundElement(aElement);
 
293
  return NS_OK;
 
294
}
 
295
 
 
296
NS_IMETHODIMP
 
297
nsXBLBinding::GetFirstBindingWithConstructor(nsIXBLBinding** aResult)
 
298
{
 
299
  *aResult = nsnull;
 
300
 
 
301
  nsXBLPrototypeHandler* constructor = mPrototypeBinding->GetConstructor();
 
302
  if (constructor) {
 
303
    *aResult = this;
 
304
    NS_ADDREF(*aResult);
 
305
  }
 
306
  else if (mNextBinding)
 
307
    return mNextBinding->GetFirstBindingWithConstructor(aResult);
 
308
 
 
309
  return NS_OK;
 
310
}
 
311
 
 
312
NS_IMETHODIMP
 
313
nsXBLBinding::HasStyleSheets(PRBool* aResolveStyle)
 
314
{
 
315
  // Find out if we need to re-resolve style.  We'll need to do this
 
316
  // if we have additional stylesheets in our binding document.
 
317
  if (mPrototypeBinding->HasStyleSheets()) {
 
318
    *aResolveStyle = PR_TRUE;
 
319
    return NS_OK;
 
320
  }
 
321
 
 
322
  if (mNextBinding)
 
323
    return mNextBinding->HasStyleSheets(aResolveStyle);
 
324
  return NS_OK;
 
325
}
 
326
 
 
327
struct EnumData {
 
328
  nsXBLBinding* mBinding;
 
329
 
 
330
  EnumData(nsXBLBinding* aBinding)
 
331
    :mBinding(aBinding)
 
332
  {};
 
333
};
 
334
 
 
335
struct ContentListData : public EnumData {
 
336
  nsIBindingManager* mBindingManager;
 
337
 
 
338
  ContentListData(nsXBLBinding* aBinding, nsIBindingManager* aManager)
 
339
    :EnumData(aBinding), mBindingManager(aManager)
 
340
  {};
 
341
};
 
342
 
 
343
 
 
344
 
 
345
PR_STATIC_CALLBACK(PRBool)
 
346
BuildContentLists(nsHashKey* aKey, void* aData, void* aClosure)
 
347
{
 
348
  ContentListData* data = (ContentListData*)aClosure;
 
349
  nsIBindingManager* bm = data->mBindingManager;
 
350
  nsXBLBinding* binding = data->mBinding;
 
351
 
 
352
  nsCOMPtr<nsIContent> boundElement;
 
353
  binding->GetBoundElement(getter_AddRefs(boundElement));
 
354
 
 
355
  nsVoidArray* arr = NS_STATIC_CAST(nsVoidArray*, aData);
 
356
  PRInt32 count = arr->Count();
 
357
  
 
358
  if (count == 0)
 
359
    return NS_OK;
 
360
 
 
361
  // XXX Could this array just be altered in place and passed directly to
 
362
  // SetContentListFor?  We'd save space if we could pull this off.
 
363
  nsVoidArray* contentList = new nsVoidArray();
 
364
 
 
365
  // Figure out the relevant content node.
 
366
  nsXBLInsertionPoint* currPoint = NS_STATIC_CAST(nsXBLInsertionPoint*, arr->ElementAt(0));
 
367
  nsCOMPtr<nsIContent> parent = currPoint->GetInsertionParent();
 
368
  PRInt32 currIndex = currPoint->GetInsertionIndex();
 
369
 
 
370
  nsCOMPtr<nsIDOMNodeList> nodeList;
 
371
  if (parent == boundElement) {
 
372
    // We are altering anonymous nodes to accommodate insertion points.
 
373
    binding->GetAnonymousNodes(getter_AddRefs(nodeList));
 
374
  }
 
375
  else {
 
376
    // We are altering the explicit content list of a node to accommodate insertion points.
 
377
    nsCOMPtr<nsIDOMNode> node(do_QueryInterface(parent));
 
378
    node->GetChildNodes(getter_AddRefs(nodeList));
 
379
  }
 
380
 
 
381
  nsXBLInsertionPoint* pseudoPoint = nsnull;
 
382
  PRUint32 childCount;
 
383
  nodeList->GetLength(&childCount);
 
384
  PRInt32 j = 0;
 
385
 
 
386
  for (PRUint32 i = 0; i < childCount; i++) {
 
387
    nsCOMPtr<nsIDOMNode> node;
 
388
    nodeList->Item(i, getter_AddRefs(node));
 
389
    nsCOMPtr<nsIContent> child(do_QueryInterface(node));
 
390
    if (((PRInt32)i) == currIndex) {
 
391
      // Add the currPoint to the supports array.
 
392
      contentList->AppendElement(currPoint);
 
393
 
 
394
      // Get the next real insertion point and update our currIndex.
 
395
      j++;
 
396
      if (j < count) {
 
397
        currPoint = NS_STATIC_CAST(nsXBLInsertionPoint*, arr->ElementAt(j));
 
398
        currIndex = currPoint->GetInsertionIndex();
 
399
      }
 
400
 
 
401
      // Null out our current pseudo-point.
 
402
      pseudoPoint = nsnull;
 
403
    }
 
404
    
 
405
    if (!pseudoPoint) {
 
406
      pseudoPoint = new nsXBLInsertionPoint(parent, (PRUint32) -1, nsnull);
 
407
      contentList->AppendElement(pseudoPoint);
 
408
    }
 
409
 
 
410
    pseudoPoint->AddChild(child);
 
411
  }
 
412
 
 
413
  // Add in all the remaining insertion points.
 
414
  for ( ; j < count; j++) {
 
415
    currPoint = NS_STATIC_CAST(nsXBLInsertionPoint*, arr->ElementAt(j));
 
416
    contentList->AppendElement(currPoint);
 
417
  }
 
418
  
 
419
  // Now set the content list using the binding manager,
 
420
  // If the bound element is the parent, then we alter the anonymous node list
 
421
  // instead.  This allows us to always maintain two distinct lists should
 
422
  // insertion points be nested into an inner binding.
 
423
  if (parent == boundElement)
 
424
    bm->SetAnonymousNodesFor(parent, contentList);
 
425
  else 
 
426
    bm->SetContentListFor(parent, contentList);
 
427
  return PR_TRUE;
 
428
}
 
429
 
 
430
PR_STATIC_CALLBACK(PRBool)
 
431
RealizeDefaultContent(nsHashKey* aKey, void* aData, void* aClosure)
 
432
{
 
433
  ContentListData* data = (ContentListData*)aClosure;
 
434
  nsIBindingManager* bm = data->mBindingManager;
 
435
  nsXBLBinding* binding = data->mBinding;
 
436
 
 
437
  nsCOMPtr<nsIContent> boundElement;
 
438
  binding->GetBoundElement(getter_AddRefs(boundElement));
 
439
 
 
440
  nsVoidArray* arr = (nsVoidArray*)aData;
 
441
  PRInt32 count = arr->Count();
 
442
 
 
443
  for (PRInt32 i = 0; i < count; i++) {
 
444
    nsXBLInsertionPoint* currPoint = NS_STATIC_CAST(nsXBLInsertionPoint*, arr->ElementAt(i));
 
445
    PRInt32 insCount = currPoint->ChildCount();
 
446
    
 
447
    if (insCount == 0) {
 
448
      nsCOMPtr<nsIContent> defContent = currPoint->GetDefaultContentTemplate();
 
449
      if (defContent) {
 
450
        // We need to take this template and use it to realize the
 
451
        // actual default content (through cloning).
 
452
        // Clone this insertion point element.
 
453
        nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(defContent));
 
454
        nsCOMPtr<nsIDOMNode> clonedNode;
 
455
        elt->CloneNode(PR_TRUE, getter_AddRefs(clonedNode));
 
456
 
 
457
        nsCOMPtr<nsIContent> insParent = currPoint->GetInsertionParent();
 
458
 
 
459
        // Now that we have the cloned content, install the default content as
 
460
        // if it were additional anonymous content.
 
461
        nsCOMPtr<nsIContent> clonedContent(do_QueryInterface(clonedNode));
 
462
        binding->InstallAnonymousContent(clonedContent, insParent);
 
463
 
 
464
        // Cache the clone so that it can be properly destroyed if/when our
 
465
        // other anonymous content is destroyed.
 
466
        currPoint->SetDefaultContent(clonedContent);
 
467
 
 
468
        // Now make sure the kids of the clone are added to the insertion point as
 
469
        // children.
 
470
        PRUint32 cloneKidCount = clonedContent->GetChildCount();
 
471
        for (PRUint32 k = 0; k < cloneKidCount; k++) {
 
472
          nsIContent *cloneChild = clonedContent->GetChildAt(k);
 
473
          bm->SetInsertionParent(cloneChild, insParent);
 
474
          currPoint->AddChild(cloneChild);
 
475
        }
 
476
      }
 
477
    }
 
478
  }
 
479
 
 
480
  return PR_TRUE;
 
481
}
 
482
 
 
483
PR_STATIC_CALLBACK(PRBool)
 
484
ChangeDocumentForDefaultContent(nsHashKey* aKey, void* aData, void* aClosure)
 
485
{
 
486
  nsVoidArray* arr = NS_STATIC_CAST(nsVoidArray*, aData);
 
487
  PRInt32 count = arr->Count();
 
488
  
 
489
  for (PRInt32 i = 0; i < count; i++) {
 
490
    nsXBLInsertionPoint* currPoint = NS_STATIC_CAST(nsXBLInsertionPoint*, arr->ElementAt(i));
 
491
    nsCOMPtr<nsIContent> defContent = currPoint->GetDefaultContent();
 
492
    
 
493
    if (defContent)
 
494
      defContent->SetDocument(nsnull, PR_TRUE, PR_TRUE);
 
495
  }
 
496
 
 
497
  return PR_TRUE;
 
498
}
 
499
 
 
500
NS_IMETHODIMP
 
501
nsXBLBinding::GenerateAnonymousContent()
 
502
{
 
503
  // Fetch the content element for this binding.
 
504
  nsCOMPtr<nsIContent> content;
 
505
  GetImmediateChild(nsXBLAtoms::content, getter_AddRefs(content));
 
506
 
 
507
  if (!content) {
 
508
    // We have no anonymous content.
 
509
    if (mNextBinding)
 
510
      return mNextBinding->GenerateAnonymousContent();
 
511
    else return NS_OK;
 
512
  }
 
513
     
 
514
  // Find out if we're really building kids or if we're just
 
515
  // using the attribute-setting shorthand hack.
 
516
  PRUint32 contentCount = content->GetChildCount();
 
517
 
 
518
  // Plan to build the content by default.
 
519
  PRBool hasContent = (contentCount > 0);
 
520
  PRBool hasInsertionPoints = mPrototypeBinding->HasInsertionPoints();
 
521
 
 
522
#ifdef DEBUG
 
523
  // See if there's an includes attribute.
 
524
  nsAutoString includes;
 
525
  content->GetAttr(kNameSpaceID_None, nsXBLAtoms::includes, includes);
 
526
  if (!includes.IsEmpty()) {
 
527
    nsCAutoString id;
 
528
    mPrototypeBinding->GetID(id);
 
529
    nsCAutoString message("An XBL Binding with an id of ");
 
530
    message += id;
 
531
    message += " and found in the file ";
 
532
    nsCAutoString uri;
 
533
    mPrototypeBinding->DocURI()->GetSpec(uri);
 
534
    message += uri;
 
535
    message += " is still using the deprecated\n<content includes=\"\"> syntax! Use <children> instead!\n"; 
 
536
    NS_WARNING(message.get());
 
537
  }
 
538
#endif
 
539
 
 
540
  if (hasContent || hasInsertionPoints) {
 
541
    nsIDocument* doc = mBoundElement->GetDocument();
 
542
 
 
543
    // XXX doc will be null if we're in the midst of paint suppression.
 
544
    if (! doc)
 
545
      return NS_OK;
 
546
    
 
547
    nsIBindingManager *bindingManager = doc->GetBindingManager();
 
548
 
 
549
    nsCOMPtr<nsIDOMNodeList> children;
 
550
    bindingManager->GetContentListFor(mBoundElement, getter_AddRefs(children));
 
551
 
 
552
    nsCOMPtr<nsIDOMNode> node;
 
553
    nsCOMPtr<nsIContent> childContent;
 
554
    PRUint32 length;
 
555
    children->GetLength(&length);
 
556
    if (length > 0 && !hasInsertionPoints) {
 
557
      // There are children being placed underneath us, but we have no specified
 
558
      // insertion points, and therefore no place to put the kids.  Don't generate
 
559
      // anonymous content.
 
560
      // Special case template and observes.
 
561
      for (PRUint32 i = 0; i < length; i++) {
 
562
        children->Item(i, getter_AddRefs(node));
 
563
        childContent = do_QueryInterface(node);
 
564
 
 
565
        nsINodeInfo *ni = childContent->GetNodeInfo();
 
566
 
 
567
        if (!ni || (!ni->Equals(nsXULAtoms::observes, kNameSpaceID_XUL) &&
 
568
                    !ni->Equals(nsXULAtoms::templateAtom, kNameSpaceID_XUL))) {
 
569
          hasContent = PR_FALSE;
 
570
          break;
 
571
        }
 
572
      }
 
573
    }
 
574
 
 
575
    if (hasContent || hasInsertionPoints) {
 
576
      nsCOMPtr<nsIContent> clonedContent;
 
577
      nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(content));
 
578
 
 
579
      nsCOMPtr<nsIDOMNode> clonedNode;
 
580
      domElement->CloneNode(PR_TRUE, getter_AddRefs(clonedNode));
 
581
  
 
582
      clonedContent = do_QueryInterface(clonedNode);
 
583
      SetAnonymousContent(clonedContent);
 
584
 
 
585
      if (hasInsertionPoints) {
 
586
        // Now check and see if we have a single insertion point 
 
587
        // or multiple insertion points.
 
588
      
 
589
        // Enumerate the prototype binding's insertion table to build
 
590
        // our table of instantiated insertion points.
 
591
        mPrototypeBinding->InstantiateInsertionPoints(this);
 
592
 
 
593
        // We now have our insertion point table constructed.  We
 
594
        // enumerate this table.  For each array of insertion points
 
595
        // bundled under the same content node, we generate a content
 
596
        // list.  In the case of the bound element, we generate a new
 
597
        // anonymous node list that will be used in place of the binding's
 
598
        // cached anonymous node list.
 
599
        ContentListData data(this, bindingManager);
 
600
        mInsertionPointTable->Enumerate(BuildContentLists, &data);
 
601
      
 
602
        // We need to place the children
 
603
        // at their respective insertion points.
 
604
        nsCOMPtr<nsIContent> singlePoint;
 
605
        PRUint32 index = 0;
 
606
        PRBool multiplePoints = PR_FALSE;
 
607
        nsCOMPtr<nsIContent> singleDefaultContent;
 
608
        GetSingleInsertionPoint(getter_AddRefs(singlePoint), &index, 
 
609
                                &multiplePoints, getter_AddRefs(singleDefaultContent));
 
610
      
 
611
        if (children) {
 
612
          if (multiplePoints) {
 
613
            // We must walk the entire content list in order to determine where
 
614
            // each child belongs.
 
615
            children->GetLength(&length);
 
616
            for (PRUint32 i = 0; i < length; i++) {
 
617
              children->Item(i, getter_AddRefs(node));
 
618
              childContent = do_QueryInterface(node);
 
619
 
 
620
              // Now determine the insertion point in the prototype table.
 
621
              nsCOMPtr<nsIContent> point;
 
622
              PRUint32 index;
 
623
              nsCOMPtr<nsIContent> defContent;
 
624
              GetInsertionPoint(childContent, getter_AddRefs(point), &index, getter_AddRefs(defContent));
 
625
              bindingManager->SetInsertionParent(childContent, point);
 
626
 
 
627
              // Find the correct nsIXBLInsertion point in our table.
 
628
              nsVoidArray* arr;
 
629
              GetInsertionPointsFor(point, &arr);
 
630
              nsXBLInsertionPoint* insertionPoint = nsnull;
 
631
              PRInt32 arrCount = arr->Count();
 
632
              for (PRInt32 j = 0; j < arrCount; j++) {
 
633
                insertionPoint = NS_STATIC_CAST(nsXBLInsertionPoint*, arr->ElementAt(j));
 
634
                if (insertionPoint->Matches(point, index))
 
635
                  break;
 
636
                insertionPoint = nsnull;
 
637
              }
 
638
 
 
639
              if (insertionPoint) 
 
640
                insertionPoint->AddChild(childContent);
 
641
              else {
 
642
                // We were unable to place this child.  All anonymous content
 
643
                // should be thrown out.  Special-case template and observes.
 
644
 
 
645
                nsINodeInfo *ni = childContent->GetNodeInfo();
 
646
 
 
647
                if (!ni ||
 
648
                    (!ni->Equals(nsXULAtoms::observes, kNameSpaceID_XUL) &&
 
649
                     !ni->Equals(nsXULAtoms::templateAtom, kNameSpaceID_XUL))) {
 
650
                  // Kill all anonymous content.
 
651
                  mContent = nsnull;
 
652
                  bindingManager->SetContentListFor(mBoundElement, nsnull);
 
653
                  bindingManager->SetAnonymousNodesFor(mBoundElement, nsnull);
 
654
                  return NS_OK;
 
655
                }
 
656
              }
 
657
            }
 
658
          }
 
659
          else {
 
660
            // All of our children are shunted to this single insertion point.
 
661
            nsVoidArray* arr;
 
662
            GetInsertionPointsFor(singlePoint, &arr);
 
663
            nsXBLInsertionPoint* insertionPoint = NS_STATIC_CAST(nsXBLInsertionPoint*, arr->ElementAt(0));
 
664
        
 
665
            nsCOMPtr<nsIDOMNode> node;
 
666
            nsCOMPtr<nsIContent> content;
 
667
            PRUint32 length;
 
668
            children->GetLength(&length);
 
669
          
 
670
            for (PRUint32 i = 0; i < length; i++) {
 
671
              children->Item(i, getter_AddRefs(node));
 
672
              content = do_QueryInterface(node);
 
673
              bindingManager->SetInsertionParent(content, singlePoint);
 
674
              insertionPoint->AddChild(content);
 
675
            }
 
676
          }
 
677
        }
 
678
 
 
679
        // Now that all of our children have been added, we need to walk all of our
 
680
        // nsIXBLInsertion points to see if any of them have default content that
 
681
        // needs to be built.
 
682
        mInsertionPointTable->Enumerate(RealizeDefaultContent, &data);
 
683
      }
 
684
    }
 
685
 
 
686
    mPrototypeBinding->SetInitialAttributes(mBoundElement, mContent);
 
687
  }
 
688
 
 
689
  // Always check the content element for potential attributes.
 
690
  // This shorthand hack always happens, even when we didn't
 
691
  // build anonymous content.
 
692
  PRUint32 length = content->GetAttrCount();
 
693
 
 
694
  PRInt32 namespaceID;
 
695
  nsCOMPtr<nsIAtom> name;
 
696
  nsCOMPtr<nsIAtom> prefix;
 
697
 
 
698
  for (PRUint32 i = 0; i < length; ++i) {
 
699
    content->GetAttrNameAt(i, &namespaceID, getter_AddRefs(name),
 
700
                           getter_AddRefs(prefix));
 
701
 
 
702
    if (name != nsXBLAtoms::includes) {
 
703
      nsAutoString value;
 
704
      mBoundElement->GetAttr(namespaceID, name, value);
 
705
      if (value.IsEmpty()) {
 
706
        nsAutoString value2;
 
707
        content->GetAttr(namespaceID, name, value2);
 
708
        mBoundElement->SetAttr(namespaceID, name, value2, PR_FALSE);
 
709
      }
 
710
    }
 
711
 
 
712
    // Conserve space by wiping the attributes off the clone.
 
713
    if (mContent)
 
714
      mContent->UnsetAttr(namespaceID, name, PR_FALSE);
 
715
  }
 
716
  
 
717
  return NS_OK;
 
718
}
 
719
 
 
720
NS_IMETHODIMP
 
721
nsXBLBinding::InstallEventHandlers()
 
722
{
 
723
  // Don't install handlers if scripts aren't allowed.
 
724
  if (AllowScripts()) {
 
725
    // Fetch the handlers prototypes for this binding.
 
726
    nsXBLPrototypeHandler* handlerChain = mPrototypeBinding->GetPrototypeHandlers();
 
727
 
 
728
    if (handlerChain) {
 
729
      nsCOMPtr<nsIDOMEventReceiver> receiver = do_QueryInterface(mBoundElement);
 
730
      nsCOMPtr<nsIDOM3EventTarget> target = do_QueryInterface(receiver);
 
731
      nsCOMPtr<nsIDOMEventGroup> systemEventGroup;
 
732
 
 
733
      nsXBLPrototypeHandler* curr;
 
734
      for (curr = handlerChain; curr; curr = curr->GetNextHandler()) {
 
735
        // Fetch the event type.
 
736
        nsCOMPtr<nsIAtom> eventAtom = curr->GetEventName();
 
737
        if (!eventAtom ||
 
738
            eventAtom == nsXBLAtoms::keyup ||
 
739
            eventAtom == nsXBLAtoms::keydown ||
 
740
            eventAtom == nsXBLAtoms::keypress)
 
741
          continue;
 
742
 
 
743
        nsAutoString type;
 
744
        eventAtom->ToString(type);
 
745
 
 
746
        // Figure out if we're using capturing or not.
 
747
        PRBool useCapture = (curr->GetPhase() == NS_PHASE_CAPTURING);
 
748
 
 
749
        // If this is a command, add it in the system event group, otherwise 
 
750
        // add it to the standard event group.
 
751
 
 
752
        // This is a weak ref. systemEventGroup above is already a
 
753
        // strong ref, so we are guaranteed it will not go away.
 
754
        nsIDOMEventGroup* eventGroup = nsnull;
 
755
        if (curr->GetType() & NS_HANDLER_TYPE_XBL_COMMAND) {
 
756
          if (!systemEventGroup)
 
757
            receiver->GetSystemEventGroup(getter_AddRefs(systemEventGroup));
 
758
          eventGroup = systemEventGroup;
 
759
        }
 
760
 
 
761
        nsXBLEventHandler* handler = curr->GetEventHandler();
 
762
        if (handler) {
 
763
          target->AddGroupedEventListener(type, handler, useCapture,
 
764
                                          eventGroup);
 
765
        }
 
766
      }
 
767
 
 
768
      const nsCOMArray<nsXBLKeyEventHandler>* keyHandlers =
 
769
        mPrototypeBinding->GetKeyEventHandlers();
 
770
      PRInt32 i;
 
771
      for (i = 0; i < keyHandlers->Count(); ++i) {
 
772
        nsXBLKeyEventHandler* handler = keyHandlers->ObjectAt(i);
 
773
 
 
774
        nsAutoString type;
 
775
        handler->GetEventName(type);
 
776
 
 
777
        // Figure out if we're using capturing or not.
 
778
        PRBool useCapture = (handler->GetPhase() == NS_PHASE_CAPTURING);
 
779
 
 
780
        // If this is a command, add it in the system event group, otherwise 
 
781
        // add it to the standard event group.
 
782
 
 
783
        // This is a weak ref. systemEventGroup above is already a
 
784
        // strong ref, so we are guaranteed it will not go away.
 
785
        nsIDOMEventGroup* eventGroup = nsnull;
 
786
        if (handler->GetType() & NS_HANDLER_TYPE_XBL_COMMAND) {
 
787
          if (!systemEventGroup)
 
788
            receiver->GetSystemEventGroup(getter_AddRefs(systemEventGroup));
 
789
          eventGroup = systemEventGroup;
 
790
        }
 
791
 
 
792
        target->AddGroupedEventListener(type, handler, useCapture, eventGroup);
 
793
      }
 
794
    }
 
795
  }
 
796
 
 
797
  if (mNextBinding)
 
798
    mNextBinding->InstallEventHandlers();
 
799
 
 
800
  return NS_OK;
 
801
}
 
802
 
 
803
NS_IMETHODIMP
 
804
nsXBLBinding::InstallImplementation()
 
805
{
 
806
  // Always install the base class properties first, so that
 
807
  // derived classes can reference the base class properties.
 
808
 
 
809
  if (mNextBinding)
 
810
    mNextBinding->InstallImplementation();
 
811
 
 
812
  // iterate through each property in the prototype's list and install the property.
 
813
  if (AllowScripts())
 
814
    mPrototypeBinding->InstallImplementation(mBoundElement);
 
815
 
 
816
  return NS_OK;
 
817
}
 
818
 
 
819
NS_IMETHODIMP
 
820
nsXBLBinding::GetBaseTag(PRInt32* aNameSpaceID, nsIAtom** aResult)
 
821
{
 
822
  mPrototypeBinding->GetBaseTag(aNameSpaceID, aResult);
 
823
  if (!*aResult && mNextBinding)
 
824
    return mNextBinding->GetBaseTag(aNameSpaceID, aResult);
 
825
  return NS_OK;
 
826
}
 
827
 
 
828
NS_IMETHODIMP
 
829
nsXBLBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID,
 
830
                               PRBool aRemoveFlag, PRBool aNotify)
 
831
{
 
832
  // XXX Change if we ever allow multiple bindings in a chain to contribute anonymous content
 
833
  if (!mContent) {
 
834
    if (mNextBinding)
 
835
      return mNextBinding->AttributeChanged(aAttribute, aNameSpaceID,
 
836
                                            aRemoveFlag, aNotify);
 
837
    return NS_OK;
 
838
  }
 
839
 
 
840
  mPrototypeBinding->AttributeChanged(aAttribute, aNameSpaceID, aRemoveFlag,
 
841
                                      mBoundElement, mContent, aNotify);
 
842
  return NS_OK;
 
843
}
 
844
 
 
845
NS_IMETHODIMP
 
846
nsXBLBinding::ExecuteAttachedHandler()
 
847
{
 
848
  if (mNextBinding)
 
849
    mNextBinding->ExecuteAttachedHandler();
 
850
 
 
851
  nsCOMPtr<nsIDOMEventReceiver> rec(do_QueryInterface(mBoundElement));
 
852
  mPrototypeBinding->BindingAttached(rec);
 
853
 
 
854
  return NS_OK;
 
855
}
 
856
 
 
857
NS_IMETHODIMP 
 
858
nsXBLBinding::ExecuteDetachedHandler()
 
859
{
 
860
  nsCOMPtr<nsIDOMEventReceiver> rec(do_QueryInterface(mBoundElement));
 
861
  mPrototypeBinding->BindingDetached(rec);
 
862
 
 
863
  if (mNextBinding)
 
864
    mNextBinding->ExecuteDetachedHandler();
 
865
 
 
866
  return NS_OK;
 
867
}
 
868
 
 
869
NS_IMETHODIMP
 
870
nsXBLBinding::UnhookEventHandlers()
 
871
{
 
872
  nsXBLPrototypeHandler* handlerChain = mPrototypeBinding->GetPrototypeHandlers();
 
873
 
 
874
  if (handlerChain) {
 
875
    nsCOMPtr<nsIDOMEventReceiver> receiver = do_QueryInterface(mBoundElement);
 
876
    nsCOMPtr<nsIDOM3EventTarget> target = do_QueryInterface(receiver);
 
877
    nsCOMPtr<nsIDOMEventGroup> systemEventGroup;
 
878
 
 
879
    nsXBLPrototypeHandler* curr;
 
880
    for (curr = handlerChain; curr; curr = curr->GetNextHandler()) {
 
881
      nsXBLEventHandler* handler = curr->GetCachedEventHandler();
 
882
      if (handler) {
 
883
        nsCOMPtr<nsIAtom> eventAtom = curr->GetEventName();
 
884
        if (!eventAtom ||
 
885
            eventAtom == nsXBLAtoms::keyup ||
 
886
            eventAtom == nsXBLAtoms::keydown ||
 
887
            eventAtom == nsXBLAtoms::keypress)
 
888
          continue;
 
889
 
 
890
        nsAutoString type;
 
891
        eventAtom->ToString(type);
 
892
 
 
893
        // Figure out if we're using capturing or not.
 
894
        PRBool useCapture = (curr->GetPhase() == NS_PHASE_CAPTURING);
 
895
 
 
896
        // If this is a command, remove it from the system event group, otherwise 
 
897
        // remove it from the standard event group.
 
898
 
 
899
        // This is a weak ref. systemEventGroup above is already a
 
900
        // strong ref, so we are guaranteed it will not go away.
 
901
        nsIDOMEventGroup* eventGroup = nsnull;
 
902
        if (curr->GetType() & NS_HANDLER_TYPE_XBL_COMMAND) {
 
903
          if (!systemEventGroup)
 
904
            receiver->GetSystemEventGroup(getter_AddRefs(systemEventGroup));
 
905
          eventGroup = systemEventGroup;
 
906
        }
 
907
 
 
908
        target->RemoveGroupedEventListener(type, handler, useCapture,
 
909
                                           eventGroup);
 
910
      }
 
911
    }
 
912
 
 
913
    const nsCOMArray<nsXBLKeyEventHandler>* keyHandlers =
 
914
      mPrototypeBinding->GetKeyEventHandlers();
 
915
    PRInt32 i;
 
916
    for (i = 0; i < keyHandlers->Count(); ++i) {
 
917
      nsXBLKeyEventHandler* handler = keyHandlers->ObjectAt(i);
 
918
 
 
919
      nsAutoString type;
 
920
      handler->GetEventName(type);
 
921
 
 
922
      // Figure out if we're using capturing or not.
 
923
      PRBool useCapture = (handler->GetPhase() == NS_PHASE_CAPTURING);
 
924
 
 
925
      // If this is a command, remove it from the system event group, otherwise 
 
926
      // remove it from the standard event group.
 
927
 
 
928
      // This is a weak ref. systemEventGroup above is already a
 
929
      // strong ref, so we are guaranteed it will not go away.
 
930
      nsIDOMEventGroup* eventGroup = nsnull;
 
931
      if (handler->GetType() & NS_HANDLER_TYPE_XBL_COMMAND) {
 
932
        if (!systemEventGroup)
 
933
          receiver->GetSystemEventGroup(getter_AddRefs(systemEventGroup));
 
934
        eventGroup = systemEventGroup;
 
935
      }
 
936
 
 
937
      target->RemoveGroupedEventListener(type, handler, useCapture,
 
938
                                         eventGroup);
 
939
    }
 
940
  }
 
941
  
 
942
  return NS_OK;
 
943
}
 
944
 
 
945
NS_IMETHODIMP
 
946
nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument)
 
947
{
 
948
  if (aOldDocument != aNewDocument) {
 
949
    if (mNextBinding)
 
950
      mNextBinding->ChangeDocument(aOldDocument, aNewDocument);
 
951
 
 
952
    // Only style bindings get their prototypes unhooked.
 
953
    if (mIsStyleBinding) {
 
954
      // Now the binding dies.  Unhook our prototypes.
 
955
      nsCOMPtr<nsIContent> interfaceElement;
 
956
      GetImmediateChild(nsXBLAtoms::implementation, getter_AddRefs(interfaceElement));
 
957
 
 
958
      if (interfaceElement) { 
 
959
        nsIScriptGlobalObject *global = aOldDocument->GetScriptGlobalObject();
 
960
        if (global) {
 
961
          nsIScriptContext *context = global->GetContext();
 
962
          if (context) {
 
963
            JSContext *jscontext = (JSContext *)context->GetNativeContext();
 
964
 
 
965
            nsresult rv;
 
966
            nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(),
 
967
                                                     &rv));
 
968
            NS_ENSURE_SUCCESS(rv, rv);
 
969
 
 
970
            nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
 
971
 
 
972
            rv = xpc->WrapNative(jscontext, ::JS_GetGlobalObject(jscontext),
 
973
                                 mBoundElement, NS_GET_IID(nsISupports),
 
974
                                 getter_AddRefs(wrapper));
 
975
            NS_ENSURE_SUCCESS(rv, rv);
 
976
 
 
977
            JSObject* scriptObject = nsnull;
 
978
            rv = wrapper->GetJSObject(&scriptObject);
 
979
            NS_ENSURE_SUCCESS(rv, rv);
 
980
 
 
981
            // XXX Stay in sync! What if a layered binding has an
 
982
            // <interface>?!
 
983
 
 
984
            // XXX Sanity check to make sure our class name matches
 
985
            // Pull ourselves out of the proto chain.
 
986
            JSObject* ourProto = ::JS_GetPrototype(jscontext, scriptObject);
 
987
            if (ourProto)
 
988
            {
 
989
              JSObject* grandProto = ::JS_GetPrototype(jscontext, ourProto);
 
990
              ::JS_SetPrototype(jscontext, scriptObject, grandProto);
 
991
            }
 
992
 
 
993
            // Don't remove the reference from the document to the
 
994
            // wrapper here since it'll be removed by the element
 
995
            // itself when that's taken out of the document.
 
996
          }
 
997
        }
 
998
      }
 
999
    }
 
1000
 
 
1001
    // Update the anonymous content.
 
1002
    nsCOMPtr<nsIContent> anonymous;
 
1003
    GetAnonymousContent(getter_AddRefs(anonymous));
 
1004
    if (anonymous) {
 
1005
      // Also kill the default content within all our insertion points.
 
1006
      if (mInsertionPointTable)
 
1007
        mInsertionPointTable->Enumerate(ChangeDocumentForDefaultContent,
 
1008
                                        nsnull);
 
1009
 
 
1010
#ifdef MOZ_XUL
 
1011
      nsCOMPtr<nsIXULDocument> xuldoc(do_QueryInterface(aOldDocument));
 
1012
#endif
 
1013
 
 
1014
      anonymous->SetDocument(nsnull, PR_TRUE, PR_TRUE); // Kill it.
 
1015
 
 
1016
#ifdef MOZ_XUL
 
1017
      // To make XUL templates work (and other XUL-specific stuff),
 
1018
      // we'll need to notify it using its add & remove APIs. Grab the
 
1019
      // interface now...
 
1020
      if (xuldoc)
 
1021
        xuldoc->RemoveSubtreeFromDocument(anonymous);
 
1022
#endif
 
1023
    }
 
1024
  }
 
1025
 
 
1026
  return NS_OK;
 
1027
}
 
1028
 
 
1029
NS_IMETHODIMP_(nsIURI*)
 
1030
nsXBLBinding::BindingURI() const
 
1031
{
 
1032
  return mPrototypeBinding->BindingURI();
 
1033
}
 
1034
 
 
1035
NS_IMETHODIMP_(nsIURI*) 
 
1036
nsXBLBinding::DocURI() const
 
1037
{
 
1038
  return mPrototypeBinding->DocURI();
 
1039
}
 
1040
 
 
1041
NS_IMETHODIMP 
 
1042
nsXBLBinding::GetID(nsACString& aResult) const
 
1043
{
 
1044
  return mPrototypeBinding->GetID(aResult);
 
1045
}
 
1046
 
 
1047
NS_IMETHODIMP
 
1048
nsXBLBinding::InheritsStyle(PRBool* aResult)
 
1049
{
 
1050
  // XXX Will have to change if we ever allow multiple bindings to contribute anonymous content.
 
1051
  // Most derived binding with anonymous content determines style inheritance for now.
 
1052
 
 
1053
  // XXX What about bindings with <content> but no kids, e.g., my treecell-text binding?
 
1054
  if (mContent) {
 
1055
    *aResult = mPrototypeBinding->InheritsStyle();
 
1056
    return NS_OK;
 
1057
  }
 
1058
  
 
1059
  if (mNextBinding)
 
1060
    return mNextBinding->InheritsStyle(aResult);
 
1061
 
 
1062
  return NS_OK;
 
1063
}
 
1064
 
 
1065
NS_IMETHODIMP
 
1066
nsXBLBinding::WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc, void* aData)
 
1067
{
 
1068
  nsresult rv = NS_OK;
 
1069
  if (mNextBinding) {
 
1070
    rv = mNextBinding->WalkRules(aFunc, aData);
 
1071
    if (NS_FAILED(rv))
 
1072
      return rv;
 
1073
  }
 
1074
 
 
1075
  nsCOMArray<nsIStyleRuleProcessor> *rules = mPrototypeBinding->GetRuleProcessors();
 
1076
  if (rules)
 
1077
    rules->EnumerateForwards(aFunc, aData);
 
1078
  
 
1079
  return rv;
 
1080
}
 
1081
 
 
1082
// Internal helper methods ////////////////////////////////////////////////////////////////
 
1083
 
 
1084
// static
 
1085
nsresult
 
1086
nsXBLBinding::DoInitJSClass(JSContext *cx, JSObject *global, JSObject *obj,
 
1087
                            const nsAFlatCString& aClassName,
 
1088
                            void **aClassObject)
 
1089
{
 
1090
  // First ensure our JS class is initialized.
 
1091
  jsval val;
 
1092
  JSObject* proto;
 
1093
 
 
1094
  nsCAutoString className(aClassName);
 
1095
  // Retrieve the current prototype of obj.
 
1096
  JSObject* parent_proto = ::JS_GetPrototype(cx, obj);
 
1097
  if (parent_proto) {
 
1098
    // We need to create a unique classname based on aClassName and
 
1099
    // parent_proto.  Append a space (an invalid URI character) to ensure that
 
1100
    // we don't have accidental collisions with the case when parent_proto is
 
1101
    // null and aClassName ends in some bizarre numbers (yeah, it's unlikely).
 
1102
    jsid parent_proto_id;
 
1103
    if (!::JS_GetObjectId(cx, parent_proto, &parent_proto_id)) {
 
1104
      // Probably OOM
 
1105
      return NS_ERROR_OUT_OF_MEMORY;
 
1106
    }
 
1107
 
 
1108
    // One space, maybe "0x", at most 16 chars (on a 64-bit system) of long,
 
1109
    // and a null-terminator (which PR_snprintf ensures is there even if the
 
1110
    // string representation of what we're printing does not fit in the buffer
 
1111
    // provided).
 
1112
    char buf[20];
 
1113
    PR_snprintf(buf, sizeof(buf), " %lx", parent_proto_id);
 
1114
    className.Append(buf);
 
1115
  }
 
1116
 
 
1117
  if ((!::JS_LookupPropertyWithFlags(cx, global, className.get(),
 
1118
                                     JSRESOLVE_CLASSNAME,
 
1119
                                     &val)) ||
 
1120
      JSVAL_IS_PRIMITIVE(val)) {
 
1121
    // We need to initialize the class.
 
1122
 
 
1123
    nsXBLJSClass* c;
 
1124
    void* classObject;
 
1125
    nsCStringKey key(className);
 
1126
    classObject = (nsXBLService::gClassTable)->Get(&key);
 
1127
 
 
1128
    if (classObject) {
 
1129
      c = NS_STATIC_CAST(nsXBLJSClass*, classObject);
 
1130
 
 
1131
      // If c is on the LRU list (i.e., not linked to itself), remove it now!
 
1132
      JSCList* link = NS_STATIC_CAST(JSCList*, c);
 
1133
      if (c->next != link) {
 
1134
        JS_REMOVE_AND_INIT_LINK(link);
 
1135
        nsXBLService::gClassLRUListLength--;
 
1136
      }
 
1137
    } else {
 
1138
      if (JS_CLIST_IS_EMPTY(&nsXBLService::gClassLRUList)) {
 
1139
        // We need to create a struct for this class.
 
1140
        c = new nsXBLJSClass(className);
 
1141
 
 
1142
        if (!c)
 
1143
          return NS_ERROR_OUT_OF_MEMORY;
 
1144
      } else {
 
1145
        // Pull the least recently used class struct off the list.
 
1146
        JSCList* lru = (nsXBLService::gClassLRUList).next;
 
1147
        JS_REMOVE_AND_INIT_LINK(lru);
 
1148
        nsXBLService::gClassLRUListLength--;
 
1149
 
 
1150
        // Remove any mapping from the old name to the class struct.
 
1151
        c = NS_STATIC_CAST(nsXBLJSClass*, lru);
 
1152
        nsCStringKey oldKey(c->name);
 
1153
        (nsXBLService::gClassTable)->Remove(&oldKey);
 
1154
 
 
1155
        // Change the class name and we're done.
 
1156
        nsMemory::Free((void*) c->name);
 
1157
        c->name = ToNewCString(className);
 
1158
      }
 
1159
 
 
1160
      // Add c to our table.
 
1161
      (nsXBLService::gClassTable)->Put(&key, (void*)c);
 
1162
    }
 
1163
 
 
1164
    // The prototype holds a strong reference to its class struct.
 
1165
    c->Hold();
 
1166
 
 
1167
    // Make a new object prototyped by parent_proto and parented by global.
 
1168
    proto = ::JS_InitClass(cx,                  // context
 
1169
                           global,              // global object
 
1170
                           parent_proto,        // parent proto 
 
1171
                           c,                   // JSClass
 
1172
                           nsnull,              // JSNative ctor
 
1173
                           0,                   // ctor args
 
1174
                           nsnull,              // proto props
 
1175
                           nsnull,              // proto funcs
 
1176
                           nsnull,              // ctor props (static)
 
1177
                           nsnull);             // ctor funcs (static)
 
1178
    if (!proto) {
 
1179
      // This will happen if we're OOM or if the security manager
 
1180
      // denies defining the new class...
 
1181
 
 
1182
      (nsXBLService::gClassTable)->Remove(&key);
 
1183
 
 
1184
      c->Drop();
 
1185
 
 
1186
      return NS_ERROR_OUT_OF_MEMORY;
 
1187
    }
 
1188
 
 
1189
    *aClassObject = (void*)proto;
 
1190
  }
 
1191
  else {
 
1192
    proto = JSVAL_TO_OBJECT(val);
 
1193
  }
 
1194
 
 
1195
  // Set the prototype of our object to be the new class.
 
1196
  if (!::JS_SetPrototype(cx, obj, proto)) {
 
1197
    return NS_ERROR_FAILURE;
 
1198
  }
 
1199
 
 
1200
  return NS_OK;
 
1201
}
 
1202
 
 
1203
 
 
1204
nsresult
 
1205
nsXBLBinding::InitClass(const nsCString& aClassName,
 
1206
                        nsIScriptContext* aContext, 
 
1207
                        nsIDocument* aDocument, void** aScriptObject,
 
1208
                        void** aClassObject)
 
1209
{
 
1210
  *aClassObject = nsnull;
 
1211
  *aScriptObject = nsnull;
 
1212
 
 
1213
  nsresult rv;
 
1214
 
 
1215
  // Obtain the bound element's current script object.
 
1216
  nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
 
1217
  NS_ENSURE_SUCCESS(rv, rv);
 
1218
 
 
1219
  JSContext* cx = (JSContext*)aContext->GetNativeContext();
 
1220
 
 
1221
  nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
 
1222
 
 
1223
  JSObject* global = ::JS_GetGlobalObject(cx);
 
1224
 
 
1225
  rv = xpc->WrapNative(cx, global, mBoundElement, NS_GET_IID(nsISupports),
 
1226
                       getter_AddRefs(wrapper));
 
1227
  NS_ENSURE_SUCCESS(rv, rv);
 
1228
 
 
1229
  JSObject* object = nsnull;
 
1230
  rv = wrapper->GetJSObject(&object);
 
1231
  NS_ENSURE_SUCCESS(rv, rv);
 
1232
 
 
1233
  *aScriptObject = object;
 
1234
 
 
1235
  // First ensure our JS class is initialized.
 
1236
 
 
1237
  rv = DoInitJSClass(cx, global, object, aClassName, aClassObject);
 
1238
  NS_ENSURE_SUCCESS(rv, rv);
 
1239
 
 
1240
  // Root mBoundElement so that it doesn't lose it's binding
 
1241
  nsIDocument* doc = mBoundElement->GetDocument();
 
1242
 
 
1243
  if (doc) {
 
1244
    nsCOMPtr<nsIXPConnectWrappedNative> native_wrapper =
 
1245
      do_QueryInterface(wrapper);
 
1246
 
 
1247
    if (native_wrapper) {
 
1248
      doc->AddReference(mBoundElement, native_wrapper);
 
1249
    }
 
1250
  }
 
1251
 
 
1252
  return NS_OK;
 
1253
}
 
1254
 
 
1255
void
 
1256
nsXBLBinding::GetImmediateChild(nsIAtom* aTag, nsIContent** aResult) 
 
1257
{
 
1258
  nsCOMPtr<nsIContent> binding = mPrototypeBinding->GetBindingElement();
 
1259
 
 
1260
  *aResult = nsnull;
 
1261
  PRUint32 childCount = binding->GetChildCount();
 
1262
 
 
1263
  for (PRUint32 i = 0; i < childCount; i++) {
 
1264
    nsIContent *child = binding->GetChildAt(i);
 
1265
 
 
1266
    if (aTag == child->Tag()) {
 
1267
      *aResult = child;
 
1268
      NS_ADDREF(*aResult);
 
1269
      return;
 
1270
    }
 
1271
  }
 
1272
}
 
1273
 
 
1274
PRBool
 
1275
nsXBLBinding::IsInExcludesList(nsIAtom* aTag, const nsString& aList) 
 
1276
 
1277
  nsAutoString element;
 
1278
  aTag->ToString(element);
 
1279
 
 
1280
  if (aList == NS_LITERAL_STRING("*"))
 
1281
      return PR_TRUE; // match _everything_!
 
1282
 
 
1283
  PRInt32 indx = aList.Find(element, 0);
 
1284
  if (indx == -1)
 
1285
    return PR_FALSE; // not in the list at all
 
1286
 
 
1287
  // okay, now make sure it's not a substring snafu; e.g., 'ur'
 
1288
  // found inside of 'blur'.
 
1289
  if (indx > 0) {
 
1290
    PRUnichar ch = aList[indx - 1];
 
1291
    if (! nsCRT::IsAsciiSpace(ch) && ch != PRUnichar('|'))
 
1292
      return PR_FALSE;
 
1293
  }
 
1294
 
 
1295
  if (indx + element.Length() < aList.Length()) {
 
1296
    PRUnichar ch = aList[indx + element.Length()];
 
1297
    if (! nsCRT::IsAsciiSpace(ch) && ch != PRUnichar('|'))
 
1298
      return PR_FALSE;
 
1299
  }
 
1300
 
 
1301
  return PR_TRUE;
 
1302
}
 
1303
 
 
1304
NS_IMETHODIMP
 
1305
nsXBLBinding::AddScriptEventListener(nsIContent* aElement, nsIAtom* aName,
 
1306
                                     const nsString& aValue)
 
1307
{
 
1308
  nsAutoString val;
 
1309
  aName->ToString(val);
 
1310
  
 
1311
  nsAutoString eventStr(NS_LITERAL_STRING("on"));
 
1312
  eventStr += val;
 
1313
 
 
1314
  nsCOMPtr<nsIAtom> eventName = do_GetAtom(eventStr);
 
1315
 
 
1316
  nsresult rv;
 
1317
 
 
1318
  nsCOMPtr<nsIDOMEventReceiver> receiver(do_QueryInterface(aElement));
 
1319
  if (!receiver)
 
1320
    return NS_OK;
 
1321
 
 
1322
  nsCOMPtr<nsIEventListenerManager> manager;
 
1323
  rv = receiver->GetListenerManager(getter_AddRefs(manager));
 
1324
  if (NS_FAILED(rv)) return rv;
 
1325
 
 
1326
  rv = manager->AddScriptEventListener(receiver, eventName, aValue, PR_FALSE);
 
1327
 
 
1328
  return rv;
 
1329
}
 
1330
 
 
1331
nsresult
 
1332
nsXBLBinding::GetTextData(nsIContent *aParent, nsString& aResult)
 
1333
{
 
1334
  aResult.Truncate(0);
 
1335
 
 
1336
  PRUint32 textCount = aParent->GetChildCount();
 
1337
  nsAutoString answer;
 
1338
  for (PRUint32 j = 0; j < textCount; j++) {
 
1339
    // Get the child.
 
1340
    nsCOMPtr<nsIDOMText> text(do_QueryInterface(aParent->GetChildAt(j)));
 
1341
    if (text) {
 
1342
      nsAutoString data;
 
1343
      text->GetData(data);
 
1344
      aResult += data;
 
1345
    }
 
1346
  }
 
1347
  return NS_OK;
 
1348
}
 
1349
 
 
1350
PRBool
 
1351
nsXBLBinding::AllowScripts()
 
1352
{
 
1353
  PRBool result;
 
1354
  mPrototypeBinding->GetAllowScripts(&result);
 
1355
  return result;
 
1356
}
 
1357
 
 
1358
PR_STATIC_CALLBACK(PRBool)
 
1359
DeleteVoidArray(nsHashKey* aKey, void* aData, void* aClosure)
 
1360
{
 
1361
  delete NS_STATIC_CAST(nsVoidArray*, aData);
 
1362
  return PR_TRUE;
 
1363
}
 
1364
 
 
1365
NS_IMETHODIMP
 
1366
nsXBLBinding::GetInsertionPointsFor(nsIContent* aParent, nsVoidArray** aResult)
 
1367
{
 
1368
  if (!mInsertionPointTable) {
 
1369
    mInsertionPointTable = new nsObjectHashtable(nsnull, nsnull,
 
1370
                                                 DeleteVoidArray, nsnull, 4);
 
1371
 
 
1372
    NS_ENSURE_TRUE(mInsertionPointTable, NS_ERROR_OUT_OF_MEMORY);
 
1373
  }
 
1374
 
 
1375
  nsISupportsKey key(aParent);
 
1376
  *aResult = NS_STATIC_CAST(nsVoidArray*, mInsertionPointTable->Get(&key));
 
1377
 
 
1378
  if (!*aResult) {
 
1379
    *aResult = new nsVoidArray();
 
1380
    NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
 
1381
    mInsertionPointTable->Put(&key, *aResult);
 
1382
  }
 
1383
 
 
1384
  return NS_OK;
 
1385
}
 
1386
 
 
1387
NS_IMETHODIMP
 
1388
nsXBLBinding::GetInsertionPoint(nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex, 
 
1389
                                nsIContent** aDefaultContent)
 
1390
{
 
1391
  *aResult = nsnull;
 
1392
  *aDefaultContent = nsnull;
 
1393
  if (mContent)
 
1394
    mPrototypeBinding->GetInsertionPoint(mBoundElement, mContent, aChild, aResult, aIndex, aDefaultContent);
 
1395
  else if (mNextBinding)
 
1396
    return mNextBinding->GetInsertionPoint(aChild, aResult, aIndex, aDefaultContent);
 
1397
  return NS_OK;
 
1398
}
 
1399
 
 
1400
NS_IMETHODIMP
 
1401
nsXBLBinding::GetSingleInsertionPoint(nsIContent** aResult, PRUint32* aIndex, PRBool* aMultipleInsertionPoints,
 
1402
                                      nsIContent** aDefaultContent)
 
1403
{
 
1404
  *aResult = nsnull;
 
1405
  *aDefaultContent = nsnull;
 
1406
  *aMultipleInsertionPoints = PR_FALSE;
 
1407
  if (mContent)
 
1408
    mPrototypeBinding->GetSingleInsertionPoint(mBoundElement, mContent, aResult, aIndex, 
 
1409
                                               aMultipleInsertionPoints, aDefaultContent);
 
1410
  else if (mNextBinding)
 
1411
    return mNextBinding->GetSingleInsertionPoint(aResult, aIndex, aMultipleInsertionPoints, aDefaultContent);
 
1412
  return NS_OK;
 
1413
}
 
1414
 
 
1415
NS_IMETHODIMP
 
1416
nsXBLBinding::GetRootBinding(nsIXBLBinding** aResult)
 
1417
{
 
1418
  if (mNextBinding)
 
1419
    return mNextBinding->GetRootBinding(aResult);
 
1420
 
 
1421
  *aResult = this;
 
1422
  NS_ADDREF(this);
 
1423
  return NS_OK;
 
1424
}
 
1425
 
 
1426
NS_IMETHODIMP
 
1427
nsXBLBinding::GetFirstStyleBinding(nsIXBLBinding** aResult)
 
1428
{
 
1429
  if (mIsStyleBinding) {
 
1430
    *aResult = this;
 
1431
    NS_ADDREF(this);
 
1432
    return NS_OK;
 
1433
  }
 
1434
  else if (mNextBinding)
 
1435
    return mNextBinding->GetFirstStyleBinding(aResult);
 
1436
 
 
1437
  *aResult = nsnull;
 
1438
  return NS_OK;
 
1439
}
 
1440
 
 
1441
NS_IMETHODIMP
 
1442
nsXBLBinding::MarkForDeath()
 
1443
{
 
1444
  mMarkedForDeath = PR_TRUE;
 
1445
  ExecuteDetachedHandler();
 
1446
  return NS_OK;
 
1447
}
 
1448
 
 
1449
NS_IMETHODIMP
 
1450
nsXBLBinding::MarkedForDeath(PRBool* aResult)
 
1451
{
 
1452
  *aResult = mMarkedForDeath;
 
1453
  return NS_OK;
 
1454
}
 
1455
 
 
1456
NS_IMETHODIMP
 
1457
nsXBLBinding::ImplementsInterface(REFNSIID aIID, PRBool* aResult)
 
1458
{
 
1459
  *aResult = mPrototypeBinding->ImplementsInterface(aIID);
 
1460
  if (!*aResult && mNextBinding)
 
1461
    return mNextBinding->ImplementsInterface(aIID, aResult);
 
1462
  return NS_OK;
 
1463
}
 
1464
 
 
1465
NS_IMETHODIMP
 
1466
nsXBLBinding::GetAnonymousNodes(nsIDOMNodeList** aResult)
 
1467
{
 
1468
  *aResult = nsnull;
 
1469
  if (mContent) {
 
1470
    nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(mContent));
 
1471
    return elt->GetChildNodes(aResult);
 
1472
  }
 
1473
  else if (mNextBinding)
 
1474
    return mNextBinding->GetAnonymousNodes(aResult);
 
1475
  return NS_OK;
 
1476
}
 
1477
 
 
1478
NS_IMETHODIMP
 
1479
nsXBLBinding::ShouldBuildChildFrames(PRBool* aResult)
 
1480
{
 
1481
  *aResult = PR_TRUE;
 
1482
  if (mContent)
 
1483
    *aResult = mPrototypeBinding->ShouldBuildChildFrames();
 
1484
  else if (mNextBinding) 
 
1485
    return mNextBinding->ShouldBuildChildFrames(aResult);
 
1486
 
 
1487
  return NS_OK;
 
1488
}
 
1489
 
 
1490
// Creation Routine ///////////////////////////////////////////////////////////////////////
 
1491
 
 
1492
nsresult
 
1493
NS_NewXBLBinding(nsXBLPrototypeBinding* aBinding, nsIXBLBinding** aResult)
 
1494
{
 
1495
  *aResult = new nsXBLBinding(aBinding);
 
1496
  if (!*aResult)
 
1497
    return NS_ERROR_OUT_OF_MEMORY;
 
1498
  NS_ADDREF(*aResult);
 
1499
  return NS_OK;
 
1500
}