|
|
@@ -15,7 +15,7 @@
|
|
|
*
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
* all copies or substantial portions of the Software.
|
|
|
- *
|
|
|
+ *
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
@@ -41,14 +41,19 @@ StyleSheetNode::StyleSheetNode()
|
|
|
CalculateAndSetSpecificity();
|
|
|
}
|
|
|
|
|
|
-StyleSheetNode::StyleSheetNode(StyleSheetNode* parent, const String& tag, const String& id, const StringList& classes, const StringList& pseudo_classes, const StructuralSelectorList& structural_selectors, bool child_combinator)
|
|
|
- : parent(parent), tag(tag), id(id), class_names(classes), pseudo_class_names(pseudo_classes), structural_selectors(structural_selectors), child_combinator(child_combinator)
|
|
|
+StyleSheetNode::StyleSheetNode(StyleSheetNode* parent, const String& tag, const String& id, const StringList& classes,
|
|
|
+ const StringList& pseudo_classes, const StructuralSelectorList& structural_selectors, SelectorCombinator combinator) :
|
|
|
+ parent(parent),
|
|
|
+ tag(tag), id(id), class_names(classes), pseudo_class_names(pseudo_classes), structural_selectors(structural_selectors), combinator(combinator)
|
|
|
{
|
|
|
CalculateAndSetSpecificity();
|
|
|
}
|
|
|
|
|
|
-StyleSheetNode::StyleSheetNode(StyleSheetNode* parent, String&& tag, String&& id, StringList&& classes, StringList&& pseudo_classes, StructuralSelectorList&& structural_selectors, bool child_combinator)
|
|
|
- : parent(parent), tag(std::move(tag)), id(std::move(id)), class_names(std::move(classes)), pseudo_class_names(std::move(pseudo_classes)), structural_selectors(std::move(structural_selectors)), child_combinator(child_combinator)
|
|
|
+StyleSheetNode::StyleSheetNode(StyleSheetNode* parent, String&& tag, String&& id, StringList&& classes, StringList&& pseudo_classes,
|
|
|
+ StructuralSelectorList&& structural_selectors, SelectorCombinator combinator) :
|
|
|
+ parent(parent),
|
|
|
+ tag(std::move(tag)), id(std::move(id)), class_names(std::move(classes)), pseudo_class_names(std::move(pseudo_classes)),
|
|
|
+ structural_selectors(std::move(structural_selectors)), combinator(combinator)
|
|
|
{
|
|
|
CalculateAndSetSpecificity();
|
|
|
}
|
|
|
@@ -58,12 +63,13 @@ StyleSheetNode* StyleSheetNode::GetOrCreateChildNode(const StyleSheetNode& other
|
|
|
// See if we match the target child
|
|
|
for (const auto& child : children)
|
|
|
{
|
|
|
- if (child->EqualRequirements(other.tag, other.id, other.class_names, other.pseudo_class_names, other.structural_selectors, other.child_combinator))
|
|
|
+ if (child->EqualRequirements(other.tag, other.id, other.class_names, other.pseudo_class_names, other.structural_selectors, other.combinator))
|
|
|
return child.get();
|
|
|
}
|
|
|
|
|
|
// We don't, so create a new child
|
|
|
- auto child = MakeUnique<StyleSheetNode>(this, other.tag, other.id, other.class_names, other.pseudo_class_names, other.structural_selectors, other.child_combinator);
|
|
|
+ auto child = MakeUnique<StyleSheetNode>(this, other.tag, other.id, other.class_names, other.pseudo_class_names, other.structural_selectors,
|
|
|
+ other.combinator);
|
|
|
StyleSheetNode* result = child.get();
|
|
|
|
|
|
children.push_back(std::move(child));
|
|
|
@@ -71,17 +77,19 @@ StyleSheetNode* StyleSheetNode::GetOrCreateChildNode(const StyleSheetNode& other
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-StyleSheetNode* StyleSheetNode::GetOrCreateChildNode(String&& tag, String&& id, StringList&& classes, StringList&& pseudo_classes, StructuralSelectorList&& structural_pseudo_classes, bool child_combinator)
|
|
|
+StyleSheetNode* StyleSheetNode::GetOrCreateChildNode(String&& tag, String&& id, StringList&& classes, StringList&& pseudo_classes,
|
|
|
+ StructuralSelectorList&& structural_pseudo_classes, SelectorCombinator combinator)
|
|
|
{
|
|
|
// See if we match an existing child
|
|
|
for (const auto& child : children)
|
|
|
{
|
|
|
- if (child->EqualRequirements(tag, id, classes, pseudo_classes, structural_pseudo_classes, child_combinator))
|
|
|
+ if (child->EqualRequirements(tag, id, classes, pseudo_classes, structural_pseudo_classes, combinator))
|
|
|
return child.get();
|
|
|
}
|
|
|
|
|
|
// We don't, so create a new child
|
|
|
- auto child = MakeUnique<StyleSheetNode>(this, std::move(tag), std::move(id), std::move(classes), std::move(pseudo_classes), std::move(structural_pseudo_classes), child_combinator);
|
|
|
+ auto child = MakeUnique<StyleSheetNode>(this, std::move(tag), std::move(id), std::move(classes), std::move(pseudo_classes),
|
|
|
+ std::move(structural_pseudo_classes), combinator);
|
|
|
StyleSheetNode* result = child.get();
|
|
|
|
|
|
children.push_back(std::move(child));
|
|
|
@@ -108,11 +116,11 @@ UniquePtr<StyleSheetNode> StyleSheetNode::DeepCopy(StyleSheetNode* in_parent) co
|
|
|
{
|
|
|
RMLUI_ZoneScoped;
|
|
|
|
|
|
- auto node = MakeUnique<StyleSheetNode>(in_parent, tag, id, class_names, pseudo_class_names, structural_selectors, child_combinator);
|
|
|
+ auto node = MakeUnique<StyleSheetNode>(in_parent, tag, id, class_names, pseudo_class_names, structural_selectors, combinator);
|
|
|
|
|
|
node->properties = properties;
|
|
|
node->children.resize(children.size());
|
|
|
-
|
|
|
+
|
|
|
for (size_t i = 0; i < children.size(); i++)
|
|
|
{
|
|
|
node->children[i] = children[i]->DeepCopy(node.get());
|
|
|
@@ -178,7 +186,8 @@ bool StyleSheetNode::SetStructurallyVolatileRecursive(bool ancestor_is_structura
|
|
|
return (self_is_structural_pseudo_class || descendant_is_structural_pseudo_class);
|
|
|
}
|
|
|
|
|
|
-bool StyleSheetNode::EqualRequirements(const String& _tag, const String& _id, const StringList& _class_names, const StringList& _pseudo_class_names, const StructuralSelectorList& _structural_selectors, bool _child_combinator) const
|
|
|
+bool StyleSheetNode::EqualRequirements(const String& _tag, const String& _id, const StringList& _class_names, const StringList& _pseudo_class_names,
|
|
|
+ const StructuralSelectorList& _structural_selectors, SelectorCombinator _combinator) const
|
|
|
{
|
|
|
if (tag != _tag)
|
|
|
return false;
|
|
|
@@ -190,7 +199,7 @@ bool StyleSheetNode::EqualRequirements(const String& _tag, const String& _id, co
|
|
|
return false;
|
|
|
if (structural_selectors != _structural_selectors)
|
|
|
return false;
|
|
|
- if (child_combinator != _child_combinator)
|
|
|
+ if (combinator != _combinator)
|
|
|
return false;
|
|
|
|
|
|
return true;
|
|
|
@@ -256,7 +265,7 @@ inline bool StyleSheetNode::MatchStructuralSelector(const Element* element) cons
|
|
|
if (!node_selector.selector->IsApplicable(element, node_selector.a, node_selector.b))
|
|
|
return false;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
@@ -286,17 +295,39 @@ bool StyleSheetNode::IsApplicable(const Element* const in_element) const
|
|
|
|
|
|
const Element* element = in_element;
|
|
|
|
|
|
- // Walk up through all our parent nodes, each one of them must be matched by some ancestor element.
|
|
|
- for(const StyleSheetNode* node = parent; node && node->parent; node = node->parent)
|
|
|
+ // Walk up through all our parent nodes, each one of them must be matched by some ancestor or sibling element.
|
|
|
+ for (const StyleSheetNode* node = parent; node && node->parent; node = node->parent)
|
|
|
{
|
|
|
- // Try a match on every element ancestor. If it succeeds, we continue on to the next node.
|
|
|
- for(element = element->GetParentNode(); element; element = element->GetParentNode())
|
|
|
+ switch (node->combinator)
|
|
|
+ {
|
|
|
+ case SelectorCombinator::None:
|
|
|
+ case SelectorCombinator::Child:
|
|
|
{
|
|
|
- if (node->Match(element))
|
|
|
- break;
|
|
|
- // If we have a child combinator on the node, we must match this first ancestor.
|
|
|
- else if (node->child_combinator)
|
|
|
- return false;
|
|
|
+ // Try a match on every element ancestor. If it succeeds, we continue on to the next node.
|
|
|
+ for (element = element->GetParentNode(); element; element = element->GetParentNode())
|
|
|
+ {
|
|
|
+ if (node->Match(element))
|
|
|
+ break;
|
|
|
+ // If the node has a child combinator we must match this first ancestor.
|
|
|
+ else if (node->combinator == SelectorCombinator::Child)
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case SelectorCombinator::NextSibling:
|
|
|
+ case SelectorCombinator::SubsequentSibling:
|
|
|
+ {
|
|
|
+ // Try a match on every element ancestor. If it succeeds, we continue on to the next node.
|
|
|
+ for (element = element->GetPreviousSibling(); element; element = element->GetPreviousSibling())
|
|
|
+ {
|
|
|
+ if (node->Match(element))
|
|
|
+ break;
|
|
|
+ // If the node has a next-sibling combinator we must match this first sibling.
|
|
|
+ else if (node->combinator == SelectorCombinator::NextSibling)
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
// We have run out of element ancestors before we matched every node. Bail out.
|
|
|
@@ -316,7 +347,6 @@ bool StyleSheetNode::IsStructurallyVolatile() const
|
|
|
return is_structurally_volatile;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
void StyleSheetNode::CalculateAndSetSpecificity()
|
|
|
{
|
|
|
// Calculate the specificity of just this node; tags are worth 10,000, IDs 1,000,000 and other specifiers (classes
|
|
|
@@ -329,9 +359,9 @@ void StyleSheetNode::CalculateAndSetSpecificity()
|
|
|
if (!id.empty())
|
|
|
specificity += 1'000'000;
|
|
|
|
|
|
- specificity += 100'000*(int)class_names.size();
|
|
|
- specificity += 100'000*(int)pseudo_class_names.size();
|
|
|
- specificity += 100'000*(int)structural_selectors.size();
|
|
|
+ specificity += 100'000 * (int)class_names.size();
|
|
|
+ specificity += 100'000 * (int)pseudo_class_names.size();
|
|
|
+ specificity += 100'000 * (int)structural_selectors.size();
|
|
|
|
|
|
// Add our parent's specificity onto ours.
|
|
|
if (parent)
|