libhtmlpp 1.0.0
Loading...
Searching...
No Matches
css.h
Go to the documentation of this file.
1/*******************************************************************************
2Copyright (c) 2021, Jan Koester jan.koester@gmx.net
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the <organization> nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*******************************************************************************/
27
28#pragma once
29
30#include <string>
31#include <vector>
32#include <map>
33#include <set>
34#include <memory>
35#include <array>
36
37namespace libhtmlpp {
38
40 public:
42 CSSProperty(const std::string &name, const std::string &value);
43 CSSProperty(const CSSProperty &prop);
45
46 CSSProperty& operator=(const CSSProperty &prop);
47
48 const std::string& getName() const;
49 void setName(const std::string &name);
50
51 const std::string& getValue() const;
52 void setValue(const std::string &value);
53
54 private:
55 std::string _Name;
56 std::string _Value;
57 };
58
60 public:
62 CSSDeclaration(const CSSDeclaration &decl);
64
66
67 void addProperty(const std::string &name, const std::string &value);
68 void removeProperty(const std::string &name);
69
70 const CSSProperty* getProperty(const std::string &name) const;
71
72 const std::vector<CSSProperty>& getProperties() const;
73
74 std::string serialize() const;
75
76 void parse(const std::string &input);
77 void clear();
78
79 private:
80 std::vector<CSSProperty> _Properties;
81 };
82
83 class CSSRule {
84 public:
85 CSSRule();
86 CSSRule(const std::string &selector);
87 CSSRule(const CSSRule &rule);
88 ~CSSRule();
89
90 CSSRule& operator=(const CSSRule &rule);
91
92 const std::string& getSelector() const;
93 void setSelector(const std::string &selector);
94
96 const CSSDeclaration& getDeclaration() const;
97
98 std::string serialize(bool formatted = false) const;
99
100 private:
101 std::string _Selector;
102 CSSDeclaration _Declaration;
103 };
104
126 std::string tag;
127 std::vector<std::string> classes;
128 std::string id;
129 std::map<std::string,std::string> attributes;
130 };
131
142 std::string name;
143 std::string op;
144 std::string value;
145 };
146
148 public:
150 CSSStyleSheet(const CSSStyleSheet &sheet);
152
154
155 void parse(const std::string &input);
156
157 void addRule(const CSSRule &rule);
158 void removeRule(size_t index);
159
160 const CSSRule* getRule(size_t index) const;
161 size_t getRuleCount() const;
162
163 const std::vector<CSSRule>& getRules() const;
164
165 std::string serialize(bool formatted = false) const;
166 void clear();
167
168 static CSSDeclaration parseInlineStyle(const std::string &style);
169
221 static bool approximateSelectorMatch(const std::string &selector,
222 const std::string &tag,
223 const std::vector<std::string> &classes,
224 const std::string &id,
225 const std::vector<AncestorFrame> *ancestors = nullptr);
226
270 void collectApproximateMatches(const std::string &tag,
271 const std::string &cssClass,
272 const std::string &id,
273 std::map<std::string,std::string> &props,
274 std::string &mediaRules,
275 std::set<std::string> &seenMediaBlocks,
276 const std::vector<AncestorFrame> *ancestors = nullptr,
277 const std::map<std::string,std::string> *targetAttributes = nullptr) const;
278
279 private:
280 void _skipWhitespace(const std::string &input, size_t &pos) const;
281 void _skipComment(const std::string &input, size_t &pos) const;
282 std::vector<CSSRule> _Rules;
283
284 // collectApproximateMatches is called once per imported HTML element
285 // (see htmlimport.cpp), and re-parsing every rule's selector list
286 // (comma-split, trim, strip combinator, reject unsupported syntax)
287 // fresh on every single one of those calls is pure waste: none of
288 // that depends on the element being matched, only on _Rules, which
289 // doesn't change between them. On a real page-builder site (~2500
290 // rules from ~115 <style> blocks, ~2000 importable elements) that
291 // redundant re-parsing was confirmed to cost over half the total
292 // import time. This caches each rule's already-split/filtered
293 // selector branches the first time collectApproximateMatches runs
294 // after a mutation, so the expensive parsing happens O(rules) times
295 // total instead of O(rules * elements).
296 struct _CompoundCacheBranch {
297 bool skip; // true if this branch's syntax can't be safely evaluated
298 bool isAtRule;
299 std::string atWrapper; // e.g. "@media (max-width: 600px)" -- only set if isAtRule
300 std::string trimmedSelector; // the (possibly per-branch) selector text, for at-rule block reconstruction
301 std::string tag;
302 std::vector<std::string> classes;
303 std::string id;
304 // Attribute-selector conditions found on the TARGET compound
305 // itself (e.g. the "[data-fit=fill]" in ".fade-box[data-fit=
306 // fill]"), verified against collectApproximateMatches's
307 // @p targetAttributes when given -- see AttributeCondition.
308 std::vector<AttributeCondition> attrConditions;
309 bool hadCombinator;
310 // Every compound left of the target one above, left-to-right/
311 // outermost-first (e.g. for ".a .b .c", this holds ".a" and ".b"
312 // -- "c" is the tag/classes/id/hadCombinator fields already
313 // above). Empty tag/classes/id/attrConditions within one entry
314 // means that compound's syntax couldn't be safely evaluated at
315 // all (an unsupported pseudo-class was present -- see
316 // hasUnsupportedSelectorSyntax) -- ancestorChainSatisfies treats
317 // that as vacuously satisfied rather than an unmet requirement.
318 // A compound with ONLY attrConditions (no tag/class/id, e.g.
319 // "[data-fit=fill]") is a real, checkable requirement now that
320 // AncestorFrame can carry an ancestor's own attributes -- see
321 // ancestorChainSatisfies.
323 std::string tag;
324 std::vector<std::string> classes;
325 std::string id;
326 std::vector<AttributeCondition> attrConditions;
327 };
328 std::vector<AncestorCompound> ancestorCompounds;
329 // Approximate CSS specificity of this branch's full selector
330 // text (trimmedSelector), as the standard (id-count,
331 // class/attribute/pseudo-class-count, type/pseudo-element-count)
332 // triple -- see computeSpecificity in css.cpp. Used by
333 // collectApproximateMatches to let a more specific matching rule
334 // win regardless of source order, instead of the plain
335 // last-rule-wins approximation this file used everywhere else.
336 std::array<int,3> specificity{0,0,0};
337 };
338 mutable std::vector<std::vector<_CompoundCacheBranch>> _compoundCache;
339 mutable bool _compoundCacheValid = false;
340 void _rebuildCompoundCache() const;
341 };
342
368 std::string resolveCSSVariables(const std::string &value,
369 const std::map<std::string,std::string> &customProperties,
370 bool *unresolved = nullptr);
371
372}
373
void addProperty(const std::string &name, const std::string &value)
Definition css.cpp:607
void removeProperty(const std::string &name)
Definition css.cpp:622
const std::vector< CSSProperty > & getProperties() const
Definition css.cpp:639
std::string serialize() const
Definition css.cpp:643
const CSSProperty * getProperty(const std::string &name) const
Definition css.cpp:631
void parse(const std::string &input)
Definition css.cpp:655
CSSDeclaration & operator=(const CSSDeclaration &decl)
Definition css.cpp:600
void setName(const std::string &name)
Definition css.cpp:586
const std::string & getName() const
Definition css.cpp:585
void setValue(const std::string &value)
Definition css.cpp:589
CSSProperty & operator=(const CSSProperty &prop)
Definition css.cpp:577
const std::string & getValue() const
Definition css.cpp:588
CSSDeclaration & getDeclaration()
Definition css.cpp:743
std::string serialize(bool formatted=false) const
Definition css.cpp:746
void setSelector(const std::string &selector)
Definition css.cpp:741
CSSRule & operator=(const CSSRule &rule)
Definition css.cpp:732
const std::string & getSelector() const
Definition css.cpp:740
void parse(const std::string &input)
Definition css.cpp:797
const std::vector< CSSRule > & getRules() const
Definition css.cpp:924
void collectApproximateMatches(const std::string &tag, const std::string &cssClass, const std::string &id, std::map< std::string, std::string > &props, std::string &mediaRules, std::set< std::string > &seenMediaBlocks, const std::vector< AncestorFrame > *ancestors=nullptr, const std::map< std::string, std::string > *targetAttributes=nullptr) const
Runs every rule in this sheet through approximateSelectorMatch against the element identified by tag/...
Definition css.cpp:1117
CSSStyleSheet & operator=(const CSSStyleSheet &sheet)
Definition css.cpp:771
static CSSDeclaration parseInlineStyle(const std::string &style)
Definition css.cpp:943
std::string serialize(bool formatted=false) const
Definition css.cpp:928
const CSSRule * getRule(size_t index) const
Definition css.cpp:915
static bool approximateSelectorMatch(const std::string &selector, const std::string &tag, const std::vector< std::string > &classes, const std::string &id, const std::vector< AncestorFrame > *ancestors=nullptr)
Conservative, NOT spec-complete selector match: selector (a single selector, or a comma-separated lis...
Definition css.cpp:949
void addRule(const CSSRule &rule)
Definition css.cpp:903
void removeRule(size_t index)
Definition css.cpp:908
size_t getRuleCount() const
Definition css.cpp:920
Core namespace for the libhtmlpp HTML parsing and printing library.
Definition css.h:37
std::string resolveCSSVariables(const std::string &value, const std::map< std::string, std::string > &customProperties, bool *unresolved=nullptr)
Resolves every var(--name) / var(--name, fallback) reference in value using customProperties (custom-...
Definition css.cpp:1243
One ancestor of the element being matched, for the optional ancestor chain approximateSelectorMatch/c...
Definition css.h:125
std::string tag
Definition css.h:126
std::vector< std::string > classes
Definition css.h:127
std::map< std::string, std::string > attributes
Definition css.h:129
std::string id
Definition css.h:128
One "[name]"/"[name=value]"/"[name~=value]"/etc.
Definition css.h:141