dom/xul/nsXULContentSink.h
author Nika Layzell <nika@thelayzells.com>
Thu, 06 Aug 2020 14:04:13 +0000
changeset 544125 ee09cb88af177571304759bc05c760e3d82fd1ed
parent 481233 dfe7d3650300443755a77f6166bacb5787f11b47
permissions -rw-r--r--
Bug 1656854 - Part 2: Add a BrowsingContextGroup keepalive to BrowserParent shutdown, r=farre In bug 1652085, I added BrowsingContextGroup keepalives while waiting for replies to the discard message, however that message isn't actually sent to the current owner process. Instead, the BrowsingContext is discarded by the PBrowser being destroyed. This should help ensure we also keep the group alive during normal BrowserParent destruction. Differential Revision: https://phabricator.services.mozilla.com/D85897

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 nsXULContentSink_h__
#define nsXULContentSink_h__

#include "mozilla/Attributes.h"
#include "nsIExpatSink.h"
#include "nsIWeakReferenceUtils.h"
#include "nsIXMLContentSink.h"
#include "nsNodeInfoManager.h"
#include "nsXULElement.h"
#include "nsIDTD.h"

class nsIScriptSecurityManager;
class nsAttrName;
class nsXULPrototypeDocument;
class nsXULPrototypeElement;
class nsXULPrototypeNode;

class XULContentSinkImpl final : public nsIXMLContentSink, public nsIExpatSink {
 public:
  XULContentSinkImpl();

  // nsISupports
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  NS_DECL_NSIEXPATSINK

  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(XULContentSinkImpl,
                                           nsIXMLContentSink)

  // nsIContentSink
  NS_IMETHOD WillParse(void) override { return NS_OK; }
  NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode) override;
  NS_IMETHOD DidBuildModel(bool aTerminated) override;
  NS_IMETHOD WillInterrupt(void) override;
  NS_IMETHOD WillResume(void) override;
  NS_IMETHOD SetParser(nsParserBase* aParser) override;
  virtual void FlushPendingNotifications(mozilla::FlushType aType) override {}
  virtual void SetDocumentCharset(NotNull<const Encoding*> aEncoding) override;
  virtual nsISupports* GetTarget() override;

  /**
   * Initialize the content sink, giving it a document with which to communicate
   * with the outside world, and an nsXULPrototypeDocument to build.
   */
  nsresult Init(mozilla::dom::Document* aDocument,
                nsXULPrototypeDocument* aPrototype);

 protected:
  virtual ~XULContentSinkImpl();

  // pseudo-constants
  char16_t* mText;
  int32_t mTextLength;
  int32_t mTextSize;
  bool mConstrainSize;

  nsresult AddAttributes(const char16_t** aAttributes, const uint32_t aAttrLen,
                         nsXULPrototypeElement* aElement);

  nsresult OpenRoot(const char16_t** aAttributes, const uint32_t aAttrLen,
                    mozilla::dom::NodeInfo* aNodeInfo);

  nsresult OpenTag(const char16_t** aAttributes, const uint32_t aAttrLen,
                   const uint32_t aLineNumber,
                   mozilla::dom::NodeInfo* aNodeInfo);

  // If OpenScript returns NS_OK and after it returns our state is eInScript,
  // that means that we created a prototype script and stuck it on
  // mContextStack.  If NS_OK is returned but the state is still
  // eInDocumentElement then we didn't create a prototype script (e.g. the
  // script had an unknown type), and the caller should create a prototype
  // element.
  nsresult OpenScript(const char16_t** aAttributes, const uint32_t aLineNumber);

  static bool IsDataInBuffer(char16_t* aBuffer, int32_t aLength);

  // Text management
  nsresult FlushText(bool aCreateTextNode = true);
  nsresult AddText(const char16_t* aText, int32_t aLength);

  RefPtr<nsNodeInfoManager> mNodeInfoManager;

  nsresult NormalizeAttributeString(const char16_t* aExpatName,
                                    nsAttrName& aName);

 public:
  enum State { eInProlog, eInDocumentElement, eInScript, eInEpilog };

 protected:
  State mState;

  // content stack management
  class ContextStack {
   protected:
    struct Entry {
      RefPtr<nsXULPrototypeNode> mNode;
      // a LOT of nodes have children; preallocate for 8
      nsPrototypeArray mChildren;
      State mState;
      Entry* mNext;
      Entry(RefPtr<nsXULPrototypeNode>&& aNode, State aState, Entry* aNext)
          : mNode(std::move(aNode)),
            mChildren(8),
            mState(aState),
            mNext(aNext) {}
    };

    Entry* mTop;
    int32_t mDepth;

   public:
    ContextStack();
    ~ContextStack();

    int32_t Depth() { return mDepth; }

    void Push(RefPtr<nsXULPrototypeNode>&& aNode, State aState);
    nsresult Pop(State* aState);

    nsresult GetTopNode(RefPtr<nsXULPrototypeNode>& aNode);
    nsresult GetTopChildren(nsPrototypeArray** aChildren);

    void Clear();

    void Traverse(nsCycleCollectionTraversalCallback& aCallback);
  };

  friend class ContextStack;
  ContextStack mContextStack;

  nsWeakPtr mDocument;            // [OWNER]
  nsCOMPtr<nsIURI> mDocumentURL;  // [OWNER]

  RefPtr<nsXULPrototypeDocument> mPrototype;  // [OWNER]

  RefPtr<nsParserBase> mParser;
  nsCOMPtr<nsIScriptSecurityManager> mSecMan;
};

#endif /* nsXULContentSink_h__ */