mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-04 14:58:37 +09:00
parent
cedff6e214
commit
a7ba34c672
23 changed files with 140 additions and 1317 deletions
|
|
@ -14,7 +14,6 @@
|
|||
#include "nsIDOMHTMLElement.h"
|
||||
#include "nsIStyleSheetLinkingElement.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/HTMLContentElement.h"
|
||||
#include "nsXBLPrototypeBinding.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
#include "mozilla/StyleSheetInlines.h"
|
||||
|
|
@ -223,35 +222,6 @@ ShadowRoot::GetElementsByClassName(const nsAString& aClasses)
|
|||
return nsContentUtils::GetElementsByClassName(this, aClasses);
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::AddInsertionPoint(HTMLContentElement* aInsertionPoint)
|
||||
{
|
||||
TreeOrderComparator comparator;
|
||||
mInsertionPoints.InsertElementSorted(aInsertionPoint, comparator);
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::RemoveInsertionPoint(HTMLContentElement* aInsertionPoint)
|
||||
{
|
||||
mInsertionPoints.RemoveElement(aInsertionPoint);
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::RemoveDestInsertionPoint(nsIContent* aInsertionPoint,
|
||||
nsTArray<nsIContent*>& aDestInsertionPoints)
|
||||
{
|
||||
// Remove the insertion point from the destination insertion points.
|
||||
// Also remove all succeeding insertion points because it is no longer
|
||||
// possible for the content to be distributed into deeper node trees.
|
||||
int32_t index = aDestInsertionPoints.IndexOf(aInsertionPoint);
|
||||
|
||||
// It's possible that we already removed the insertion point while processing
|
||||
// other insertion point removals.
|
||||
if (index >= 0) {
|
||||
aDestInsertionPoints.SetLength(index);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::DistributionChanged()
|
||||
{
|
||||
|
|
@ -269,133 +239,10 @@ ShadowRoot::DistributionChanged()
|
|||
shell->DestroyFramesForAndRestyle(host);
|
||||
}
|
||||
|
||||
const HTMLContentElement*
|
||||
ShadowRoot::DistributeSingleNode(nsIContent* aContent)
|
||||
{
|
||||
// Find the insertion point to which the content belongs.
|
||||
HTMLContentElement* foundInsertionPoint = nullptr;
|
||||
for (HTMLContentElement* insertionPoint : mInsertionPoints) {
|
||||
if (insertionPoint->Match(aContent)) {
|
||||
if (insertionPoint->MatchedNodes().Contains(aContent)) {
|
||||
// Node is already matched into the insertion point. We are done.
|
||||
return insertionPoint;
|
||||
}
|
||||
|
||||
// Matching may cause the insertion point to drop fallback content.
|
||||
if (insertionPoint->MatchedNodes().IsEmpty() &&
|
||||
insertionPoint->HasChildren()) {
|
||||
// This match will cause the insertion point to drop all fallback
|
||||
// content and used matched nodes instead. Give up on the optimization
|
||||
// and just distribute all nodes.
|
||||
DistributeAllNodes();
|
||||
MOZ_ASSERT(insertionPoint->MatchedNodes().Contains(aContent));
|
||||
return insertionPoint;
|
||||
}
|
||||
foundInsertionPoint = insertionPoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundInsertionPoint) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Find the index into the insertion point.
|
||||
nsCOMArray<nsIContent>& matchedNodes = foundInsertionPoint->MatchedNodes();
|
||||
// Find the appropriate position in the matched node list for the
|
||||
// newly distributed content.
|
||||
bool isIndexFound = false;
|
||||
ExplicitChildIterator childIterator(GetHost());
|
||||
for (uint32_t i = 0; i < matchedNodes.Length(); i++) {
|
||||
// Seek through the host's explicit children until the inserted content
|
||||
// is found or when the current matched node is reached.
|
||||
if (childIterator.Seek(aContent, matchedNodes[i])) {
|
||||
// aContent was found before the current matched node.
|
||||
foundInsertionPoint->InsertMatchedNode(i, aContent);
|
||||
isIndexFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isIndexFound) {
|
||||
// We have still not found an index in the insertion point,
|
||||
// thus it must be at the end.
|
||||
MOZ_ASSERT(childIterator.Seek(aContent, nullptr),
|
||||
"Trying to match a node that is not a candidate to be matched");
|
||||
foundInsertionPoint->AppendMatchedNode(aContent);
|
||||
}
|
||||
|
||||
return foundInsertionPoint;
|
||||
}
|
||||
|
||||
const HTMLContentElement*
|
||||
ShadowRoot::RemoveDistributedNode(nsIContent* aContent)
|
||||
{
|
||||
// Find insertion point containing the content and remove the node.
|
||||
for (HTMLContentElement* insertionPoint : mInsertionPoints) {
|
||||
if (!insertionPoint->MatchedNodes().Contains(aContent)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Removing the matched node may cause the insertion point to use
|
||||
// fallback content.
|
||||
if (insertionPoint->MatchedNodes().Length() == 1 &&
|
||||
insertionPoint->HasChildren()) {
|
||||
// Removing the matched node will cause fallback content to be
|
||||
// used instead. Give up optimization and distribute all nodes.
|
||||
DistributeAllNodes();
|
||||
return insertionPoint;
|
||||
}
|
||||
|
||||
insertionPoint->RemoveMatchedNode(aContent);
|
||||
return insertionPoint;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::DistributeAllNodes()
|
||||
{
|
||||
// Create node pool.
|
||||
nsTArray<nsIContent*> nodePool;
|
||||
ExplicitChildIterator childIterator(GetHost());
|
||||
for (nsIContent* content = childIterator.GetNextChild(); content;
|
||||
content = childIterator.GetNextChild()) {
|
||||
nodePool.AppendElement(content);
|
||||
}
|
||||
|
||||
nsTArray<ShadowRoot*> shadowsToUpdate;
|
||||
|
||||
for (HTMLContentElement* insertionPoint : mInsertionPoints) {
|
||||
insertionPoint->ClearMatchedNodes();
|
||||
// Assign matching nodes from node pool.
|
||||
for (uint32_t j = 0; j < nodePool.Length(); j++) {
|
||||
if (insertionPoint->Match(nodePool[j])) {
|
||||
insertionPoint->AppendMatchedNode(nodePool[j]);
|
||||
nodePool.RemoveElementAt(j--);
|
||||
}
|
||||
}
|
||||
|
||||
// Keep track of instances where the content insertion point is distributed
|
||||
// (parent of insertion point has a ShadowRoot).
|
||||
nsIContent* insertionParent = insertionPoint->GetParent();
|
||||
MOZ_ASSERT(insertionParent, "The only way for an insertion point to be in the"
|
||||
"mInsertionPoints array is to be a descendant of a"
|
||||
"ShadowRoot, in which case, it should have a parent");
|
||||
|
||||
// If the parent of the insertion point has a ShadowRoot, the nodes distributed
|
||||
// to the insertion point must be reprojected to the insertion points of the
|
||||
// parent's ShadowRoot.
|
||||
ShadowRoot* parentShadow = insertionParent->GetShadowRoot();
|
||||
if (parentShadow && !shadowsToUpdate.Contains(parentShadow)) {
|
||||
shadowsToUpdate.AppendElement(parentShadow);
|
||||
}
|
||||
}
|
||||
|
||||
for (ShadowRoot* shadow : shadowsToUpdate) {
|
||||
shadow->DistributeAllNodes();
|
||||
}
|
||||
//XXX Handle <slot>.
|
||||
|
||||
DistributionChanged();
|
||||
}
|
||||
|
|
@ -475,13 +322,6 @@ ShadowRoot::IsPooledNode(nsIContent* aContent) const
|
|||
return true;
|
||||
}
|
||||
|
||||
if (auto* content = HTMLContentElement::FromContentOrNull(container)) {
|
||||
// Fallback content will end up in pool if its parent is a child of the host.
|
||||
return content->IsInsertionPoint() &&
|
||||
content->MatchedNodes().IsEmpty() &&
|
||||
container->GetParentNode() == host;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -497,13 +337,6 @@ ShadowRoot::AttributeChanged(nsIDocument* aDocument,
|
|||
return;
|
||||
}
|
||||
|
||||
// Attributes may change insertion point matching, find its new distribution.
|
||||
//
|
||||
// FIXME(emilio): What about state changes?
|
||||
if (!RedistributeElement(aElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aElement->IsInComposedDoc()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -513,52 +346,10 @@ ShadowRoot::AttributeChanged(nsIDocument* aDocument,
|
|||
return;
|
||||
}
|
||||
|
||||
//XXX optimize this!
|
||||
shell->DestroyFramesForAndRestyle(aElement);
|
||||
}
|
||||
|
||||
bool
|
||||
ShadowRoot::RedistributeElement(Element* aElement)
|
||||
{
|
||||
auto* oldInsertionPoint = RemoveDistributedNode(aElement);
|
||||
auto* newInsertionPoint = DistributeSingleNode(aElement);
|
||||
|
||||
if (oldInsertionPoint == newInsertionPoint) {
|
||||
if (oldInsertionPoint) {
|
||||
if (auto* shadow = oldInsertionPoint->GetParent()->GetShadowRoot()) {
|
||||
return shadow->RedistributeElement(aElement);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
while (oldInsertionPoint) {
|
||||
// Handle the case where the parent of the insertion point has a ShadowRoot.
|
||||
// The node distributed into the insertion point must be reprojected to the
|
||||
// insertion points of the parent's ShadowRoot.
|
||||
auto* shadow = oldInsertionPoint->GetParent()->GetShadowRoot();
|
||||
if (!shadow) {
|
||||
break;
|
||||
}
|
||||
|
||||
oldInsertionPoint = shadow->RemoveDistributedNode(aElement);
|
||||
}
|
||||
|
||||
while (newInsertionPoint) {
|
||||
// Handle the case where the parent of the insertion point has a ShadowRoot.
|
||||
// The node distributed into the insertion point must be reprojected to the
|
||||
// insertion points of the parent's ShadowRoot.
|
||||
auto* shadow = newInsertionPoint->GetParent()->GetShadowRoot();
|
||||
if (!shadow) {
|
||||
break;
|
||||
}
|
||||
|
||||
newInsertionPoint = shadow->DistributeSingleNode(aElement);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::ContentAppended(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
|
|
@ -583,31 +374,6 @@ ShadowRoot::ContentInserted(nsIDocument* aDocument,
|
|||
mInsertionPointChanged = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Add insertion point to destination insertion points of fallback content.
|
||||
if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
|
||||
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
|
||||
if (content && content->MatchedNodes().IsEmpty()) {
|
||||
aChild->DestInsertionPoints().AppendElement(aContainer);
|
||||
}
|
||||
}
|
||||
|
||||
// Watch for new nodes added to the pool because the node
|
||||
// may need to be added to an insertion point.
|
||||
if (IsPooledNode(aChild)) {
|
||||
auto* insertionPoint = DistributeSingleNode(aChild);
|
||||
while (insertionPoint) {
|
||||
// Handle the case where the parent of the insertion point has a ShadowRoot.
|
||||
// The node distributed into the insertion point must be reprojected to the
|
||||
// insertion points of the parent's ShadowRoot.
|
||||
auto* parentShadow = insertionPoint->GetParent()->GetShadowRoot();
|
||||
if (!parentShadow) {
|
||||
break;
|
||||
}
|
||||
|
||||
insertionPoint = parentShadow->DistributeSingleNode(aChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -622,34 +388,6 @@ ShadowRoot::ContentRemoved(nsIDocument* aDocument,
|
|||
mInsertionPointChanged = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear destination insertion points for removed
|
||||
// fallback content.
|
||||
if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
|
||||
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
|
||||
if (content->MatchedNodes().IsEmpty()) {
|
||||
aChild->DestInsertionPoints().Clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Watch for node that is removed from the pool because
|
||||
// it may need to be removed from an insertion point.
|
||||
if (IsPooledNode(aChild)) {
|
||||
auto* insertionPoint = RemoveDistributedNode(aChild);
|
||||
while (insertionPoint) {
|
||||
// Handle the case where the parent of the insertion point has a
|
||||
// ShadowRoot.
|
||||
//
|
||||
// The removed node needs to be removed from the insertion points of the
|
||||
// parent's ShadowRoot.
|
||||
auto* parentShadow = insertionPoint->GetParent()->GetShadowRoot();
|
||||
if (!parentShadow) {
|
||||
break;
|
||||
}
|
||||
|
||||
insertionPoint = parentShadow->RemoveDistributedNode(aChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue