Commit c77ec057 authored by Jan Köster's avatar Jan Köster
Browse files

test

parent 52da8ff7
Loading
Loading
Loading
Loading
+46 −7
Original line number Diff line number Diff line
@@ -153,17 +153,54 @@ namespace {
        return matchSel;
    }

    // Selector syntax this matcher can't safely evaluate -- attribute
    // selectors and pseudo-classes/elements describe context (an ancestor's
    // attribute) or state (":hover") this matcher has no way to check, and
    // "*" would blanket-match every element. Guessing wrong here is worse
    // than not matching at all.
    // Selector syntax this matcher can't safely evaluate -- pseudo-
    // classes/elements describe state (":hover") this matcher has no way to
    // check, and "*" would blanket-match every element. Guessing wrong here
    // is worse than not matching at all. Attribute selectors ("[href]") are
    // handled separately (see stripAttributeSelectors) rather than rejected
    // here, since by the time this runs they've already been removed from
    // whatever compound they were attached to.
    bool hasUnsupportedSelectorSyntax(const std::string &matchSel) {
        return matchSel.find('[') != std::string::npos ||
               matchSel.find(':') != std::string::npos ||
        return matchSel.find(':') != std::string::npos ||
               matchSel == "*";
    }

    // Removes every "[...]" attribute-selector segment from a compound
    // selector (already combinator-stripped -- see stripCombinator), so a
    // compound like ".card[data-variant=featured]" is still checkable on
    // its verifiable ".card" part instead of being thrown away entirely.
    // This matcher has no per-element attribute map to verify the
    // condition itself (collectApproximateMatches only ever gets a single
    // element's tag/class/id, see its own doc comment), so the condition is
    // simply ignored rather than guessed -- on a component-library site
    // (e.g. a page builder) nearly every layout/visibility toggle is
    // expressed as "known class + [data-variant=x]" rather than a distinct
    // class per variant, so rejecting the whole compound meant NONE of
    // those rules were ever seen. This can still occasionally pick a
    // sibling variant's declarations when several "[data-variant=...]"
    // rules share the same base class (last rule of equal priority wins,
    // the same cascade approximation used everywhere else in this file),
    // but that is far closer to the source page than matching nothing.
    // Malformed/unterminated "[" is left in place rather than risk
    // corrupting the rest of the compound.
    std::string stripAttributeSelectors(const std::string &matchSel) {
        if (matchSel.find('[') == std::string::npos) return matchSel;
        std::string out;
        out.reserve(matchSel.size());
        size_t pos = 0;
        while (pos < matchSel.size()) {
            if (matchSel[pos] == '[') {
                size_t close = matchSel.find(']', pos + 1);
                if (close == std::string::npos) { out += matchSel.substr(pos); break; }
                pos = close + 1;
            } else {
                out += matchSel[pos];
                ++pos;
            }
        }
        return out;
    }

    // Finds the index of the ')' matching the '(' at `openPos` (which must
    // point at '(' itself), respecting nested parens. Returns npos if
    // unterminated.
@@ -664,6 +701,7 @@ bool libhtmlpp::CSSStyleSheet::approximateSelectorMatch(const std::string &selec

        bool hadCombinator = false;
        std::string matchSel = stripCombinator(singleSel, hadCombinator);
        matchSel = stripAttributeSelectors(matchSel);
        if (hasUnsupportedSelectorSyntax(matchSel)) continue;

        CompoundParts compound = parseCompoundSelector(matchSel);
@@ -756,6 +794,7 @@ void libhtmlpp::CSSStyleSheet::_rebuildCompoundCache() const {

                    bool hadCombinator = false;
                    std::string matchSel = stripCombinator(singleSel, hadCombinator);
                    matchSel = stripAttributeSelectors(matchSel);
                    if (hasUnsupportedSelectorSyntax(matchSel)) {
                        branch.skip = true;
                    } else {