DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (b6d82b1a6b02)

VCS Links

Line Code
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
/* -*- 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/. */

/* State that is passed down to BindToTree. */

#ifndef mozilla_dom_BindContext_h__
#define mozilla_dom_BindContext_h__

#include "nsXBLBinding.h"
#include "mozilla/Attributes.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ShadowRoot.h"

namespace mozilla {
namespace dom {

struct MOZ_STACK_CLASS BindContext final {
  struct NestingLevel;
  friend struct NestingLevel;

  // The document that owns the tree we're getting bound to.
  //
  // This is mostly an optimization to avoid silly pointer-chases to get the
  // OwnerDoc().
  Document& OwnerDoc() const { return mDoc; }

  // Whether we're getting connected.
  //
  // https://dom.spec.whatwg.org/#connected
  bool InComposedDoc() const { return mInComposedDoc; }

  // Whether we're getting bound to the document tree.
  //
  // https://dom.spec.whatwg.org/#in-a-document-tree
  bool InUncomposedDoc() const { return mInUncomposedDoc; }

  Document* GetComposedDoc() const { return mInComposedDoc ? &mDoc : nullptr; }

  Document* GetUncomposedDoc() const {
    return mInUncomposedDoc ? &mDoc : nullptr;
  }

  // Whether our subtree root is changing as a result of this operation.
  bool SubtreeRootChanges() const { return mSubtreeRootChanges; }

  // Returns the binding parent of the subtree to be inserted.
  //
  // This can be null.
  Element* GetBindingParent() const { return mBindingParent; }

  // This constructor should be used for regular appends to content.
  explicit BindContext(nsINode& aParent)
      : mDoc(*aParent.OwnerDoc()),
        mBindingParent(aParent.IsContent()
                           ? aParent.AsContent()->GetBindingParent()
                           : nullptr),
        mInComposedDoc(aParent.IsInComposedDoc()),
        mInUncomposedDoc(aParent.IsInUncomposedDoc()),
        mSubtreeRootChanges(true),
        mCollectingDisplayedNodeDataDuringLoad(
            ShouldCollectDisplayedNodeDataDuringLoad(mInComposedDoc, mDoc,
                                                     aParent)) {}

  // When re-binding a shadow host into a tree, we re-bind all the shadow tree
  // from the root. In that case, the shadow tree contents remain within the
  // same subtree root.  So children should avoid doing silly things like adding
  // themselves to the ShadowRoot's id table twice or what not.
  //
  // This constructor is only meant to be used in that situation.
  explicit BindContext(ShadowRoot& aShadowRoot)
      : mDoc(*aShadowRoot.OwnerDoc()),
        mBindingParent(aShadowRoot.Host()),
        mInComposedDoc(aShadowRoot.IsInComposedDoc()),
        mInUncomposedDoc(false),
        mSubtreeRootChanges(false),
        mCollectingDisplayedNodeDataDuringLoad(
            ShouldCollectDisplayedNodeDataDuringLoad(mInComposedDoc, mDoc,
                                                     aShadowRoot)) {}

  // This constructor is meant to be used when inserting native-anonymous
  // children into a subtree.
  enum ForNativeAnonymous { ForNativeAnonymous };
  BindContext(Element& aParentElement, enum ForNativeAnonymous)
      : mDoc(*aParentElement.OwnerDoc()),
        mBindingParent(&aParentElement),
        mInComposedDoc(aParentElement.IsInComposedDoc()),
        mInUncomposedDoc(aParentElement.IsInUncomposedDoc()),
        mSubtreeRootChanges(true),
        mCollectingDisplayedNodeDataDuringLoad(
            ShouldCollectDisplayedNodeDataDuringLoad(mInComposedDoc, mDoc,
                                                     aParentElement)) {
    MOZ_ASSERT(mInComposedDoc, "Binding NAC in a disconnected subtree?");
  }

  // This is meant to be used to bind XBL anonymous content.
  BindContext(nsXBLBinding& aBinding, Element& aParentElement)
      : mDoc(*aParentElement.OwnerDoc()),
        mBindingParent(aBinding.GetBoundElement()),
        mInComposedDoc(aParentElement.IsInComposedDoc()),
        mInUncomposedDoc(aParentElement.IsInUncomposedDoc()),
        mSubtreeRootChanges(true),
        mCollectingDisplayedNodeDataDuringLoad(
            ShouldCollectDisplayedNodeDataDuringLoad(mInComposedDoc, mDoc,
                                                     aParentElement)) {}

  bool CollectingDisplayedNodeDataDuringLoad() const {
    return mCollectingDisplayedNodeDataDuringLoad;
  }

 private:
  static bool IsLikelyUndisplayed(const nsINode& aParent) {
    return aParent.IsAnyOfHTMLElements(nsGkAtoms::style, nsGkAtoms::script);
  }

  static bool ShouldCollectDisplayedNodeDataDuringLoad(bool aConnected,
                                                       Document& aDoc,
                                                       nsINode& aParent) {
    return aDoc.GetReadyStateEnum() == Document::READYSTATE_LOADING &&
           aConnected && !IsLikelyUndisplayed(aParent);
  }

  Document& mDoc;

  Element* const mBindingParent;

  const bool mInComposedDoc;
  const bool mInUncomposedDoc;

  // Whether the bind operation will change the subtree root of the content
  // we're binding.
  const bool mSubtreeRootChanges;

  // Whether it's likely that we're in an undisplayed part of the DOM.
  //
  // NOTE(emilio): We don't inherit this in BindContext's for Shadow DOM or XBL
  // or such. This means that if you have a shadow tree inside an undisplayed
  // element it will be incorrectly counted.  But given our current definition
  // of undisplayed element this is not likely to matter in practice.
  bool mCollectingDisplayedNodeDataDuringLoad;
};

struct MOZ_STACK_CLASS BindContext::NestingLevel {
  explicit NestingLevel(BindContext& aContext, const Element& aParent)
      : mRestoreCollecting(aContext.mCollectingDisplayedNodeDataDuringLoad) {
    if (aContext.mCollectingDisplayedNodeDataDuringLoad) {
      aContext.mCollectingDisplayedNodeDataDuringLoad =
          BindContext::IsLikelyUndisplayed(aParent);
    }
  }

 private:
  AutoRestore<bool> mRestoreCollecting;
};

}  // namespace dom
}  // namespace mozilla

#endif