| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_CHILD_NODE_PART_H_ |
| #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_CHILD_NODE_PART_H_ |
| |
| #include "third_party/blink/renderer/bindings/core/v8/v8_union_node_string_trustedscript.h" |
| #include "third_party/blink/renderer/core/core_export.h" |
| #include "third_party/blink/renderer/core/dom/container_node.h" |
| #include "third_party/blink/renderer/core/dom/node.h" |
| #include "third_party/blink/renderer/core/dom/node_part.h" |
| #include "third_party/blink/renderer/core/dom/part_root.h" |
| #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" |
| #include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h" |
| #include "third_party/blink/renderer/platform/heap/garbage_collected.h" |
| #include "third_party/blink/renderer/platform/heap/member.h" |
| |
| namespace blink { |
| |
| class PartInit; |
| class PartRootCloneOptions; |
| |
| // Implementation of the ChildNodePart class, which is part of the DOM Parts |
| // API. A ChildNodePart stores a reference to a range of nodes within the |
| // children of a single parent |Node| in the DOM tree. |
| class CORE_EXPORT ChildNodePart : public Part, public PartRoot { |
| DEFINE_WRAPPERTYPEINFO(); |
| |
| public: |
| static ChildNodePart* Create(PartRootUnion* root_union, |
| Node* previous_sibling, |
| Node* next_sibling, |
| const PartInit* init, |
| ExceptionState& exception_state); |
| ChildNodePart(PartRoot& root, |
| Node& previous_sibling, |
| Node& next_sibling, |
| const PartInit* init) |
| : ChildNodePart(root, |
| previous_sibling, |
| next_sibling, |
| init && init->hasMetadata() ? init->metadata() |
| : Vector<String>()) {} |
| ChildNodePart(PartRoot& root, |
| Node& previous_sibling, |
| Node& next_sibling, |
| Vector<String> metadata); |
| ChildNodePart(const ChildNodePart&) = delete; |
| ~ChildNodePart() override = default; |
| |
| void Trace(Visitor* visitor) const override; |
| bool IsValid() const override; |
| Node* NodeToSortBy() const override; |
| Part* ClonePart(NodeCloningData&, Node&) const override; |
| PartRoot* GetAsPartRoot() const override { |
| return const_cast<ChildNodePart*>(this); |
| } |
| |
| Document& GetDocument() const override; |
| bool IsDocumentPartRoot() const override { return false; } |
| Node* FirstIncludedChildNode() const override { |
| return previous_sibling_.Get(); |
| } |
| Node* LastIncludedChildNode() const override { return next_sibling_.Get(); } |
| |
| // ChildNodePart API |
| void disconnect() override; |
| PartRootUnion* clone(ExceptionState& exception_state) { |
| return clone(nullptr, exception_state); |
| } |
| PartRootUnion* clone(PartRootCloneOptions*, ExceptionState&); |
| ContainerNode* rootContainer() const override; |
| ContainerNode* parentNode() const { return previous_sibling_->parentNode(); } |
| Node* previousSibling() const { return previous_sibling_.Get(); } |
| Node* nextSibling() const { return next_sibling_.Get(); } |
| void setNextSibling(Node& next_sibling); |
| HeapVector<Member<Node>> children() const; |
| void replaceChildren( |
| const HeapVector<Member<V8UnionNodeOrStringOrTrustedScript>>& nodes, |
| ExceptionState& exception_state); |
| |
| protected: |
| const PartRoot* GetParentPartRoot() const override { return root(); } |
| |
| private: |
| // Checks if this ChildNodePart is valid. This should only be called if the |
| // cached validity is dirty. |
| bool CheckValidity(); |
| |
| Member<Node> previous_sibling_; |
| Member<Node> next_sibling_; |
| }; |
| |
| // A ChildNodePart is valid if: |
| // 1. The base |Part| is valid (it has a |root|). |
| // 2. previous_sibling_ and next_sibling_ are non-null. |
| // 3. previous_sibling_ and next_sibling_ have the same (non-null) parent. |
| // 4. previous_sibling_ comes strictly before next_sibling_ in the tree. |
| inline bool ChildNodePart::IsValid() const { |
| if (!Part::IsValid()) { |
| return false; |
| } |
| if (!previous_sibling_ || !next_sibling_) { |
| return false; |
| } |
| ContainerNode* parent = parentNode(); |
| if (!parent) { |
| return false; |
| } |
| if (next_sibling_->parentNode() != parent) { |
| return false; |
| } |
| if (previous_sibling_ == next_sibling_) { |
| return false; |
| } |
| Node* left = previous_sibling_.Get(); |
| do { |
| left = left->nextSibling(); |
| if (left == next_sibling_) { |
| return true; |
| } |
| } while (left); |
| return false; |
| } |
| |
| } // namespace blink |
| |
| #endif // THIRD_PARTY_BLINK_RENDERER_CORE_DOM_CHILD_NODE_PART_H_ |