content/base/public/nsReferencedElement.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/base/public/nsReferencedElement.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,186 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 sw=2 et tw=78: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef NSREFERENCEDELEMENT_H_
    1.11 +#define NSREFERENCEDELEMENT_H_
    1.12 +
    1.13 +#include "mozilla/Attributes.h"
    1.14 +#include "mozilla/dom/Element.h"
    1.15 +#include "nsIAtom.h"
    1.16 +#include "nsIDocument.h"
    1.17 +#include "nsThreadUtils.h"
    1.18 +#include "nsAutoPtr.h"
    1.19 +
    1.20 +class nsIURI;
    1.21 +class nsCycleCollectionCallback;
    1.22 +
    1.23 +/**
    1.24 + * Class to track what element is referenced by a given ID.
    1.25 + * 
    1.26 + * To use it, call Reset() to set it up to watch a given URI. Call get()
    1.27 + * anytime to determine the referenced element (which may be null if
    1.28 + * the element isn't found). When the element changes, ElementChanged
    1.29 + * will be called, so subclass this class if you want to receive that
    1.30 + * notification. ElementChanged runs at safe-for-script time, i.e. outside
    1.31 + * of the content update. Call Unlink() if you want to stop watching
    1.32 + * for changes (get() will then return null).
    1.33 + *
    1.34 + * By default this is a single-shot tracker --- i.e., when ElementChanged
    1.35 + * fires, we will automatically stop tracking. get() will continue to return
    1.36 + * the changed-to element.
    1.37 + * Override IsPersistent to return true if you want to keep tracking after
    1.38 + * the first change.
    1.39 + */
    1.40 +class nsReferencedElement {
    1.41 +public:
    1.42 +  typedef mozilla::dom::Element Element;
    1.43 +
    1.44 +  nsReferencedElement() {}
    1.45 +  ~nsReferencedElement() {
    1.46 +    Unlink();
    1.47 +  }
    1.48 +
    1.49 +  /**
    1.50 +   * Find which element, if any, is referenced.
    1.51 +   */
    1.52 +  Element* get() { return mElement; }
    1.53 +
    1.54 +  /**
    1.55 +   * Set up the reference. This can be called multiple times to
    1.56 +   * change which reference is being tracked, but these changes
    1.57 +   * do not trigger ElementChanged.
    1.58 +   * @param aFrom the source element for context
    1.59 +   * @param aURI the URI containing a hash-reference to the element
    1.60 +   * @param aWatch if false, then we do not set up the notifications to track
    1.61 +   * changes, so ElementChanged won't fire and get() will always return the same
    1.62 +   * value, the current element for the ID.
    1.63 +   * @param aReferenceImage whether the ID references image elements which are
    1.64 +   * subject to the document's mozSetImageElement overriding mechanism.
    1.65 +   */
    1.66 +  void Reset(nsIContent* aFrom, nsIURI* aURI, bool aWatch = true,
    1.67 +             bool aReferenceImage = false);
    1.68 +
    1.69 +  /**
    1.70 +   * A variation on Reset() to set up a reference that consists of the ID of
    1.71 +   * an element in the same document as aFrom.
    1.72 +   * @param aFrom the source element for context
    1.73 +   * @param aID the ID of the element
    1.74 +   * @param aWatch if false, then we do not set up the notifications to track
    1.75 +   * changes, so ElementChanged won't fire and get() will always return the same
    1.76 +   * value, the current element for the ID.
    1.77 +   */
    1.78 +  void ResetWithID(nsIContent* aFrom, const nsString& aID,
    1.79 +                   bool aWatch = true);
    1.80 +
    1.81 +  /**
    1.82 +   * Clears the reference. ElementChanged is not triggered. get() will return
    1.83 +   * null.
    1.84 +   */
    1.85 +  void Unlink();
    1.86 +
    1.87 +  void Traverse(nsCycleCollectionTraversalCallback* aCB);
    1.88 +  
    1.89 +protected:
    1.90 +  /**
    1.91 +   * Override this to be notified of element changes. Don't forget
    1.92 +   * to call this superclass method to change mElement. This is called
    1.93 +   * at script-runnable time.
    1.94 +   */
    1.95 +  virtual void ElementChanged(Element* aFrom, Element* aTo) {
    1.96 +    mElement = aTo;
    1.97 +  }
    1.98 +
    1.99 +  /**
   1.100 +   * Override this to convert from a single-shot notification to
   1.101 +   * a persistent notification.
   1.102 +   */
   1.103 +  virtual bool IsPersistent() { return false; }
   1.104 +
   1.105 +  /**
   1.106 +   * Set ourselves up with our new document.  Note that aDocument might be
   1.107 +   * null.  Either aWatch must be false or aRef must be empty.
   1.108 +   */
   1.109 +  void HaveNewDocument(nsIDocument* aDocument, bool aWatch,
   1.110 +                       const nsString& aRef);
   1.111 +  
   1.112 +private:
   1.113 +  static bool Observe(Element* aOldElement,
   1.114 +                        Element* aNewElement, void* aData);
   1.115 +
   1.116 +  class Notification : public nsISupports {
   1.117 +  public:
   1.118 +    virtual void SetTo(Element* aTo) = 0;
   1.119 +    virtual void Clear() { mTarget = nullptr; }
   1.120 +    virtual ~Notification() {}
   1.121 +  protected:
   1.122 +    Notification(nsReferencedElement* aTarget)
   1.123 +      : mTarget(aTarget)
   1.124 +    {
   1.125 +      NS_PRECONDITION(aTarget, "Must have a target");
   1.126 +    }
   1.127 +    nsReferencedElement* mTarget;
   1.128 +  };
   1.129 +
   1.130 +  class ChangeNotification : public nsRunnable,
   1.131 +                             public Notification
   1.132 +  {
   1.133 +  public:
   1.134 +    ChangeNotification(nsReferencedElement* aTarget,
   1.135 +                       Element* aFrom, Element* aTo)
   1.136 +      : Notification(aTarget), mFrom(aFrom), mTo(aTo)
   1.137 +    {}
   1.138 +    virtual ~ChangeNotification() {}
   1.139 +
   1.140 +    NS_DECL_ISUPPORTS_INHERITED
   1.141 +    NS_IMETHOD Run() MOZ_OVERRIDE {
   1.142 +      if (mTarget) {
   1.143 +        mTarget->mPendingNotification = nullptr;
   1.144 +        mTarget->ElementChanged(mFrom, mTo);
   1.145 +      }
   1.146 +      return NS_OK;
   1.147 +    }
   1.148 +    virtual void SetTo(Element* aTo) { mTo = aTo; }
   1.149 +    virtual void Clear()
   1.150 +    {
   1.151 +      Notification::Clear(); mFrom = nullptr; mTo = nullptr;
   1.152 +    }
   1.153 +  protected:
   1.154 +    nsRefPtr<Element> mFrom;
   1.155 +    nsRefPtr<Element> mTo;
   1.156 +  };
   1.157 +  friend class ChangeNotification;
   1.158 +
   1.159 +  class DocumentLoadNotification : public Notification,
   1.160 +                                   public nsIObserver
   1.161 +  {
   1.162 +  public:
   1.163 +    DocumentLoadNotification(nsReferencedElement* aTarget,
   1.164 +                             const nsString& aRef) :
   1.165 +      Notification(aTarget)
   1.166 +    {
   1.167 +      if (!mTarget->IsPersistent()) {
   1.168 +        mRef = aRef;
   1.169 +      }
   1.170 +    }
   1.171 +    virtual ~DocumentLoadNotification() {}
   1.172 +
   1.173 +    NS_DECL_ISUPPORTS
   1.174 +    NS_DECL_NSIOBSERVER
   1.175 +  private:
   1.176 +    virtual void SetTo(Element* aTo) { }
   1.177 +
   1.178 +    nsString mRef;
   1.179 +  };
   1.180 +  friend class DocumentLoadNotification;
   1.181 +  
   1.182 +  nsCOMPtr<nsIAtom>      mWatchID;
   1.183 +  nsCOMPtr<nsIDocument>  mWatchDocument;
   1.184 +  nsRefPtr<Element> mElement;
   1.185 +  nsRefPtr<Notification> mPendingNotification;
   1.186 +  bool                   mReferencingImage;
   1.187 +};
   1.188 +
   1.189 +#endif /*NSREFERENCEDELEMENT_H_*/

mercurial