summaryrefslogtreecommitdiff
path: root/dom/xbl/nsXBLPrototypeBinding.h
blob: 4c51a2083f46613b9e653734e7af52796886a92b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef nsXBLPrototypeBinding_h__
#define nsXBLPrototypeBinding_h__

#include "nsAutoPtr.h"
#include "nsClassHashtable.h"
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
#include "nsICSSLoaderObserver.h"
#include "nsInterfaceHashtable.h"
#include "nsWeakReference.h"
#include "nsXBLDocumentInfo.h"
#include "nsXBLProtoImpl.h"
#include "nsXBLProtoImplMethod.h"
#include "nsXBLPrototypeHandler.h"
#include "nsXBLPrototypeResources.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/StyleSheet.h"

class nsIAtom;
class nsIContent;
class nsIDocument;
class nsXBLAttributeEntry;
class nsXBLBinding;
class nsXBLProtoImplField;

// *********************************************************************/
// The XBLPrototypeBinding class

// Instances of this class are owned by the nsXBLDocumentInfo object returned
// by XBLDocumentInfo().  Consumers who want to refcount things should refcount
// that.
class nsXBLPrototypeBinding final :
  public mozilla::SupportsWeakPtr<nsXBLPrototypeBinding>
{
public:
  MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsXBLPrototypeBinding)

  nsIContent* GetBindingElement() const { return mBinding; }
  void SetBindingElement(nsIContent* aElement);

  nsIURI* BindingURI() const { return mBindingURI; }
  nsIURI* AlternateBindingURI() const { return mAlternateBindingURI; }
  nsIURI* DocURI() const { return mXBLDocInfoWeak->DocumentURI(); }
  nsIURI* GetBaseBindingURI() const { return mBaseBindingURI; }

  // Checks if aURI refers to this binding by comparing to both possible
  // binding URIs.
  bool CompareBindingURI(nsIURI* aURI) const;

  bool GetAllowScripts() const;

  nsresult BindingAttached(nsIContent* aBoundElement);
  nsresult BindingDetached(nsIContent* aBoundElement);

  bool LoadResources();
  nsresult AddResource(nsIAtom* aResourceType, const nsAString& aSrc);

  bool InheritsStyle() const { return mInheritStyle; }
  void SetInheritsStyle(bool aInheritStyle) { mInheritStyle = aInheritStyle; }

  nsXBLPrototypeHandler* GetPrototypeHandlers() { return mPrototypeHandler; }
  void SetPrototypeHandlers(nsXBLPrototypeHandler* aHandler) { mPrototypeHandler = aHandler; }

  nsXBLProtoImplAnonymousMethod* GetConstructor();
  nsresult SetConstructor(nsXBLProtoImplAnonymousMethod* aConstructor);
  nsXBLProtoImplAnonymousMethod* GetDestructor();
  nsresult SetDestructor(nsXBLProtoImplAnonymousMethod* aDestructor);

  nsXBLProtoImplField* FindField(const nsString& aFieldName) const
  {
    return mImplementation ? mImplementation->FindField(aFieldName) : nullptr;
  }

  // Resolve all the fields for this binding on the object |obj|.
  // False return means a JS exception was set.
  bool ResolveAllFields(JSContext* cx, JS::Handle<JSObject*> obj) const
  {
    return !mImplementation || mImplementation->ResolveAllFields(cx, obj);
  }

  // Undefine all our fields from object |obj| (which should be a
  // JSObject for a bound element).
  void UndefineFields(JSContext* cx, JS::Handle<JSObject*> obj) const {
    if (mImplementation) {
      mImplementation->UndefineFields(cx, obj);
    }
  }

  const nsString& ClassName() const {
    return mImplementation ? mImplementation->mClassName : EmptyString();
  }

  nsresult InitClass(const nsString& aClassName, JSContext* aContext,
                     JS::Handle<JSObject*> aScriptObject,
                     JS::MutableHandle<JSObject*> aClassObject,
                     bool* aNew);

  nsresult ConstructInterfaceTable(const nsAString& aImpls);

  void SetImplementation(nsXBLProtoImpl* aImpl) { mImplementation = aImpl; }
  nsXBLProtoImpl* GetImplementation() { return mImplementation; }
  nsresult InstallImplementation(nsXBLBinding* aBinding);
  bool HasImplementation() const { return mImplementation != nullptr; }

  void AttributeChanged(nsIAtom* aAttribute, int32_t aNameSpaceID,
                        bool aRemoveFlag, nsIContent* aChangedElement,
                        nsIContent* aAnonymousContent, bool aNotify);

  void SetBasePrototype(nsXBLPrototypeBinding* aBinding);
  nsXBLPrototypeBinding* GetBasePrototype() { return mBaseBinding; }

  nsXBLDocumentInfo* XBLDocumentInfo() const { return mXBLDocInfoWeak; }
  bool IsChrome() { return mXBLDocInfoWeak->IsChrome(); }

  void SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent);

  void AppendStyleSheet(mozilla::StyleSheet* aSheet);
  void RemoveStyleSheet(mozilla::StyleSheet* aSheet);
  void InsertStyleSheetAt(size_t aIndex, mozilla::StyleSheet* aSheet);
  mozilla::StyleSheet* StyleSheetAt(size_t aIndex) const;
  size_t SheetCount() const;
  bool HasStyleSheets() const;
  void AppendStyleSheetsTo(nsTArray<mozilla::StyleSheet*>& aResult) const;

  nsIStyleRuleProcessor* GetRuleProcessor();

  nsresult FlushSkinSheets();

  nsIAtom* GetBaseTag(int32_t* aNamespaceID);
  void SetBaseTag(int32_t aNamespaceID, nsIAtom* aTag);

  bool ImplementsInterface(REFNSIID aIID) const;

  nsresult AddResourceListener(nsIContent* aBoundElement);

  void Initialize();

  nsresult ResolveBaseBinding();

  const nsCOMArray<nsXBLKeyEventHandler>* GetKeyEventHandlers()
  {
    if (!mKeyHandlersRegistered) {
      CreateKeyHandlers();
      mKeyHandlersRegistered = true;
    }

    return &mKeyHandlers;
  }

private:
  nsresult Read(nsIObjectInputStream* aStream,
                nsXBLDocumentInfo* aDocInfo,
                nsIDocument* aDocument,
                uint8_t aFlags);

  /**
   * Read a new binding from the stream aStream into the xbl document aDocument.
   * aDocInfo should be the xbl document info for the binding document.
   * aFlags can contain XBLBinding_Serialize_InheritStyle to indicate that
   * mInheritStyle flag should be set, and XBLBinding_Serialize_IsFirstBinding
   * to indicate the first binding in a document.
   * XBLBinding_Serialize_ChromeOnlyContent indicates that
   * nsXBLPrototypeBinding::mChromeOnlyContent should be true.
   * XBLBinding_Serialize_BindToUntrustedContent indicates that
   * nsXBLPrototypeBinding::mBindToUntrustedContent should be true.
   */
public:
  static nsresult ReadNewBinding(nsIObjectInputStream* aStream,
                                 nsXBLDocumentInfo* aDocInfo,
                                 nsIDocument* aDocument,
                                 uint8_t aFlags);

  /**
   * Write this binding to the stream.
   */
  nsresult Write(nsIObjectOutputStream* aStream);

  /**
   * Read a content node from aStream and return it in aChild.
   * aDocument and aNim are the document and node info manager for the document
   * the child will be inserted into.
   */
  nsresult ReadContentNode(nsIObjectInputStream* aStream,
                           nsIDocument* aDocument,
                           nsNodeInfoManager* aNim,
                           nsIContent** aChild);

  /**
   * Write the content node aNode to aStream.
   *
   * This method is called recursively for each child descendant. For the topmost
   * call, aNode must be an element.
   *
   * Text, CDATA and comment nodes are serialized as:
   *   the constant XBLBinding_Serialize_TextNode, XBLBinding_Serialize_CDATANode
   *     or XBLBinding_Serialize_CommentNode
   *   the text for the node
   * Elements are serialized in the following format:
   *   node's namespace, written with WriteNamespace
   *   node's namespace prefix
   *   node's tag
   *   32-bit attribute count
   *   table of attributes:
   *     attribute's namespace, written with WriteNamespace
   *     attribute's namespace prefix
   *     attribute's tag
   *     attribute's value
   *   attribute forwarding table:
   *     source namespace
   *     source attribute
   *     destination namespace
   *     destination attribute
   *   the constant XBLBinding_Serialize_NoMoreAttributes
   *   32-bit count of the number of child nodes
   *     each child node is serialized in the same manner in sequence
   *   the constant XBLBinding_Serialize_NoContent
   */
  nsresult WriteContentNode(nsIObjectOutputStream* aStream, nsIContent* aNode);

  /**
   * Read or write a namespace id from or to aStream. If the namespace matches
   * one of the built-in ones defined in nsNameSpaceManager.h, it will be written as
   * a single byte with that value. Otherwise, XBLBinding_Serialize_CustomNamespace is
   * written out, followed by a string written with writeWStringZ.
   */
  nsresult ReadNamespace(nsIObjectInputStream* aStream, int32_t& aNameSpaceID);
  nsresult WriteNamespace(nsIObjectOutputStream* aStream, int32_t aNameSpaceID);

public:
  nsXBLPrototypeBinding();
  ~nsXBLPrototypeBinding();

  // Init must be called after construction to initialize the prototype
  // binding.  It may well throw errors (eg on out-of-memory).  Do not confuse
  // this with the Initialize() method, which must be called after the
  // binding's handlers, properties, etc are all set.
  nsresult Init(const nsACString& aRef,
                nsXBLDocumentInfo* aInfo,
                nsIContent* aElement,
                bool aFirstBinding = false);

  void Traverse(nsCycleCollectionTraversalCallback &cb) const;
  void Unlink();
  void Trace(const TraceCallbacks& aCallbacks, void *aClosure) const;

// Internal member functions.
public:
  /**
   * GetImmediateChild locates the immediate child of our binding element which
   * has the localname given by aTag and is in the XBL namespace.
   */
  nsIContent* GetImmediateChild(nsIAtom* aTag);
  nsIContent* LocateInstance(nsIContent* aBoundElt,
                             nsIContent* aTemplRoot,
                             nsIContent* aCopyRoot,
                             nsIContent* aTemplChild);

  bool ChromeOnlyContent() { return mChromeOnlyContent; }
  bool BindToUntrustedContent() { return mBindToUntrustedContent; }

  typedef nsClassHashtable<nsISupportsHashKey, nsXBLAttributeEntry> InnerAttributeTable;

protected:
  // Ensure that mAttributeTable has been created.
  void EnsureAttributeTable();
  // Ad an entry to the attribute table
  void AddToAttributeTable(int32_t aSourceNamespaceID, nsIAtom* aSourceTag,
                           int32_t aDestNamespaceID, nsIAtom* aDestTag,
                           nsIContent* aContent);
  void ConstructAttributeTable(nsIContent* aElement);
  void CreateKeyHandlers();

private:
  void EnsureResources();

// MEMBER VARIABLES
protected:
  nsCOMPtr<nsIURI> mBindingURI;
  nsCOMPtr<nsIURI> mAlternateBindingURI; // Alternate id-less URI that is only non-null on the first binding.
  nsCOMPtr<nsIContent> mBinding; // Strong. We own a ref to our content element in the binding doc.
  nsAutoPtr<nsXBLPrototypeHandler> mPrototypeHandler; // Strong. DocInfo owns us, and we own the handlers.

  // the url of the base binding
  nsCOMPtr<nsIURI> mBaseBindingURI;

  nsXBLProtoImpl* mImplementation; // Our prototype implementation (includes methods, properties, fields,
                                   // the constructor, and the destructor).

  // Weak.  The docinfo will own our base binding.
  mozilla::WeakPtr<nsXBLPrototypeBinding> mBaseBinding;
  bool mInheritStyle;
  bool mCheckedBaseProto;
  bool mKeyHandlersRegistered;
  bool mChromeOnlyContent;
  bool mBindToUntrustedContent;

  nsAutoPtr<nsXBLPrototypeResources> mResources; // If we have any resources, this will be non-null.

  nsXBLDocumentInfo* mXBLDocInfoWeak; // A pointer back to our doc info.  Weak, since it owns us.

  // A table for attribute containers. Namespace IDs are used as
  // keys in the table. Containers are InnerAttributeTables.
  // This table is used to efficiently handle attribute changes.
  nsAutoPtr<nsClassHashtable<nsUint32HashKey, InnerAttributeTable>> mAttributeTable;

  class IIDHashKey : public PLDHashEntryHdr
  {
  public:
    typedef const nsIID& KeyType;
    typedef const nsIID* KeyTypePointer;

    explicit IIDHashKey(const nsIID* aKey)
      : mKey(*aKey)
    {}
    IIDHashKey(const IIDHashKey& aOther)
      : mKey(aOther.GetKey())
    {}
    ~IIDHashKey()
    {}

    KeyType GetKey() const
    {
      return mKey;
    }
    bool KeyEquals(const KeyTypePointer aKey) const
    {
      return mKey.Equals(*aKey);
    }

    static KeyTypePointer KeyToPointer(KeyType aKey)
    {
      return &aKey;
    }
    static PLDHashNumber HashKey(const KeyTypePointer aKey)
    {
      // Just use the 32-bit m0 field.
      return aKey->m0;
    }

    enum { ALLOW_MEMMOVE = true };

  private:
    nsIID mKey;
  };
  nsInterfaceHashtable<IIDHashKey, nsIContent> mInterfaceTable; // A table of cached interfaces that we support.

  int32_t mBaseNameSpaceID;    // If we extend a tagname/namespace, then that information will
  nsCOMPtr<nsIAtom> mBaseTag;  // be stored in here.

  nsCOMArray<nsXBLKeyEventHandler> mKeyHandlers;
};

#endif