A major lift.
Quite a few uses of raw memory management had to be struck down, in a batch. It could have been a bit more precise to do some of the lower dependencies first, but I didn't start there with my analysis.
This commit is contained in:
114
src/css.cc
114
src/css.cc
@ -15,6 +15,8 @@
|
||||
#include "html_common.hh"
|
||||
#include "css.hh"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace dw::core::style;
|
||||
|
||||
void CssProperty::print () {
|
||||
@ -235,8 +237,6 @@ CssSimpleSelector::CssSimpleSelector () {
|
||||
}
|
||||
|
||||
CssSimpleSelector::~CssSimpleSelector () {
|
||||
for (int i = 0; i < klass.size (); i++)
|
||||
dFree (klass.get (i));
|
||||
dFree (id);
|
||||
dFree (pseudo);
|
||||
}
|
||||
@ -244,8 +244,7 @@ CssSimpleSelector::~CssSimpleSelector () {
|
||||
void CssSimpleSelector::setSelect (SelectType t, const char *v) {
|
||||
switch (t) {
|
||||
case SELECT_CLASS:
|
||||
klass.increase ();
|
||||
klass.set (klass.size () - 1, dStrdup (v));
|
||||
klass.push_back(v);
|
||||
break;
|
||||
case SELECT_PSEUDO_CLASS:
|
||||
if (pseudo == NULL)
|
||||
@ -275,9 +274,9 @@ bool CssSimpleSelector::match (const DoctreeNode *n) {
|
||||
return false;
|
||||
for (int i = 0; i < klass.size (); i++) {
|
||||
bool found = false;
|
||||
if (n->klass != NULL) {
|
||||
for (int j = 0; j < n->klass->size (); j++) {
|
||||
if (dStrAsciiCasecmp (klass.get(i), n->klass->get(j)) == 0) {
|
||||
if (n->klass.has_value()) {
|
||||
for (int j = 0; j < n->klass.value().size (); j++) {
|
||||
if (dStrAsciiCasecmp (klass.at(i).c_str(), n->klass.value().at(j).c_str()) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@ -314,14 +313,13 @@ void CssSimpleSelector::print () {
|
||||
element, pseudo, id);
|
||||
fprintf (stderr, "class ");
|
||||
for (int i = 0; i < klass.size (); i++)
|
||||
fprintf (stderr, ".%s", klass.get (i));
|
||||
fprintf (stderr, ".%s", klass.at (i).c_str());
|
||||
}
|
||||
|
||||
CssRule::CssRule (CssSelector *selector, CssPropertyList *props, int pos) {
|
||||
CssRule::CssRule (std::shared_ptr< CssSelector > selector, CssPropertyList *props, int pos) {
|
||||
assert (selector->size () > 0);
|
||||
|
||||
this->selector = selector;
|
||||
this->selector->ref ();
|
||||
this->selector= selector;
|
||||
this->props = props;
|
||||
this->props->ref ();
|
||||
this->pos = pos;
|
||||
@ -329,7 +327,6 @@ CssRule::CssRule (CssSelector *selector, CssPropertyList *props, int pos) {
|
||||
}
|
||||
|
||||
CssRule::~CssRule () {
|
||||
selector->unref ();
|
||||
props->unref ();
|
||||
}
|
||||
|
||||
@ -351,16 +348,13 @@ void CssRule::print () {
|
||||
* will be added behind the others.
|
||||
* This gives later added rules more weight.
|
||||
*/
|
||||
void CssStyleSheet::RuleList::insert (CssRule *rule) {
|
||||
increase ();
|
||||
int i = size () - 1;
|
||||
void
|
||||
CssStyleSheet::RuleList::insert( std::shared_ptr< CssRule > rule )
|
||||
{
|
||||
auto where= std::upper_bound( begin( rules ), end( rules ), rule,
|
||||
[&]( const auto &l, const auto &r ) { return l->specificity() < r->specificity(); } );
|
||||
|
||||
while (i > 0 && rule->specificity () < get (i - 1)->specificity ()) {
|
||||
*getRef (i) = get (i - 1);
|
||||
i--;
|
||||
}
|
||||
|
||||
*getRef (i) = rule;
|
||||
rules.insert( where, rule );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -369,42 +363,43 @@ void CssStyleSheet::RuleList::insert (CssRule *rule) {
|
||||
* To improve matching performance the rules are organized into
|
||||
* rule lists based on the topmost simple selector of their selector.
|
||||
*/
|
||||
void CssStyleSheet::addRule (CssRule *rule) {
|
||||
void CssStyleSheet::addRule (std::shared_ptr< CssRule > rule) {
|
||||
CssSimpleSelector *top = rule->selector->top ();
|
||||
RuleList *ruleList = NULL;
|
||||
lout::object::ConstString *string;
|
||||
std::shared_ptr< RuleList > ruleList;
|
||||
std::string string;
|
||||
|
||||
if (top->getId ()) {
|
||||
string = new lout::object::ConstString (top->getId ());
|
||||
ruleList = idTable.get (string);
|
||||
if (ruleList == NULL) {
|
||||
ruleList = new RuleList ();
|
||||
idTable.put (string, ruleList);
|
||||
string = top->getId ();
|
||||
if (not idTable.contains(string)) {
|
||||
ruleList= std::make_shared< RuleList > ();
|
||||
idTable.emplace (string, ruleList);
|
||||
} else {
|
||||
delete string;
|
||||
ruleList= idTable.at(string);
|
||||
}
|
||||
} else if (top->getClass () && top->getClass ()->size () > 0) {
|
||||
string = new lout::object::ConstString (top->getClass ()->get (0));
|
||||
ruleList = classTable.get (string);
|
||||
if (ruleList == NULL) {
|
||||
ruleList = new RuleList;
|
||||
classTable.put (string, ruleList);
|
||||
assert( ruleList );
|
||||
} else if (top->getClass ().size () > 0) {
|
||||
string = top->getClass ().at (0);
|
||||
if (not classTable.contains(string)) {
|
||||
ruleList = std::make_shared< RuleList >();
|
||||
classTable.emplace (string, ruleList);
|
||||
} else {
|
||||
delete string;
|
||||
ruleList= classTable.at(string);
|
||||
}
|
||||
assert( ruleList );
|
||||
} else if (top->getElement () >= 0 && top->getElement () < ntags) {
|
||||
ruleList = &elementTable[top->getElement ()];
|
||||
ruleList = elementTable[top->getElement ()];
|
||||
assert( ruleList );
|
||||
} else if (top->getElement () == CssSimpleSelector::ELEMENT_ANY) {
|
||||
ruleList = &anyTable;
|
||||
ruleList = anyTable;
|
||||
assert( ruleList );
|
||||
}
|
||||
|
||||
if (ruleList) {
|
||||
ruleList->insert (rule);
|
||||
ruleList->insert( rule );
|
||||
if (rule->selector->getRequiredMatchCache () > requiredMatchCache)
|
||||
requiredMatchCache = rule->selector->getRequiredMatchCache ();
|
||||
} else {
|
||||
assert (top->getElement () == CssSimpleSelector::ELEMENT_NONE);
|
||||
delete rule;
|
||||
}
|
||||
}
|
||||
|
||||
@ -417,13 +412,11 @@ void CssStyleSheet::addRule (CssRule *rule) {
|
||||
void CssStyleSheet::apply (CssPropertyList *props, Doctree *docTree,
|
||||
const DoctreeNode *node, MatchCache *matchCache) const {
|
||||
static const int maxLists = 32;
|
||||
const RuleList *ruleList[maxLists];
|
||||
std::array< std::shared_ptr< const RuleList >, maxLists > ruleList;
|
||||
int numLists = 0, index[maxLists] = {0};
|
||||
|
||||
if (node->id) {
|
||||
lout::object::ConstString idString (node->id);
|
||||
|
||||
ruleList[numLists] = idTable.get (&idString);
|
||||
ruleList[numLists] = idTable.contains( node->id ) ? idTable.at (node->id) : nullptr;
|
||||
if (ruleList[numLists])
|
||||
numLists++;
|
||||
}
|
||||
@ -435,19 +428,19 @@ void CssStyleSheet::apply (CssPropertyList *props, Doctree *docTree,
|
||||
break;
|
||||
}
|
||||
|
||||
lout::object::ConstString classString (node->klass->get (i));
|
||||
const std::string classString= node->klass.value().at( i );
|
||||
|
||||
ruleList[numLists] = classTable.get (&classString);
|
||||
ruleList[numLists] = classTable.contains( classString ) ? classTable.at (classString) : nullptr;
|
||||
if (ruleList[numLists])
|
||||
numLists++;
|
||||
}
|
||||
}
|
||||
|
||||
ruleList[numLists] = &elementTable[node->element];
|
||||
ruleList[numLists] = elementTable[node->element];
|
||||
if (ruleList[numLists])
|
||||
numLists++;
|
||||
|
||||
ruleList[numLists] = &anyTable;
|
||||
ruleList[numLists] = anyTable;
|
||||
if (ruleList[numLists])
|
||||
numLists++;
|
||||
|
||||
@ -461,21 +454,21 @@ void CssStyleSheet::apply (CssPropertyList *props, Doctree *docTree,
|
||||
int minSpecIndex = -1;
|
||||
|
||||
for (int i = 0; i < numLists; i++) {
|
||||
const RuleList *rl = ruleList[i];
|
||||
std::shared_ptr< const RuleList > rl = ruleList[i];
|
||||
|
||||
if (rl && rl->size () > index[i] &&
|
||||
(rl->get(index[i])->specificity () < minSpec ||
|
||||
(rl->get(index[i])->specificity () == minSpec &&
|
||||
rl->get(index[i])->position () < minPos))) {
|
||||
(rl->at(index[i])->specificity () < minSpec ||
|
||||
(rl->at(index[i])->specificity () == minSpec &&
|
||||
rl->at(index[i])->position () < minPos))) {
|
||||
|
||||
minSpec = rl->get(index[i])->specificity ();
|
||||
minPos = rl->get(index[i])->position ();
|
||||
minSpec = rl->at(index[i])->specificity ();
|
||||
minPos = rl->at(index[i])->position ();
|
||||
minSpecIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (minSpecIndex >= 0) {
|
||||
CssRule *rule = ruleList[minSpecIndex]->get (index[minSpecIndex]);
|
||||
auto &rule = ruleList[minSpecIndex]->at (index[minSpecIndex]);
|
||||
rule->apply(props, docTree, node, matchCache);
|
||||
index[minSpecIndex]++;
|
||||
} else {
|
||||
@ -526,26 +519,25 @@ void CssContext::apply (CssPropertyList *props, Doctree *docTree,
|
||||
sheet[CSS_PRIMARY_USER_IMPORTANT].apply (props, docTree, node, &matchCache);
|
||||
}
|
||||
|
||||
void CssContext::addRule (CssSelector *sel, CssPropertyList *props,
|
||||
void CssContext::addRule (std::shared_ptr< CssSelector > sel, CssPropertyList *props,
|
||||
CssPrimaryOrder order) {
|
||||
|
||||
if (props->size () > 0) {
|
||||
CssRule *rule = new CssRule (sel, props, pos++);
|
||||
auto rule = std::make_unique< CssRule >(sel, props, pos++);
|
||||
|
||||
if ((order == CSS_PRIMARY_AUTHOR ||
|
||||
order == CSS_PRIMARY_AUTHOR_IMPORTANT) &&
|
||||
!rule->isSafe ()) {
|
||||
_MSG_WARN ("Ignoring unsafe author style that might reveal browsing history\n");
|
||||
delete rule;
|
||||
} else {
|
||||
rule->selector->setMatchCacheOffset(matchCache.size ());
|
||||
if (rule->selector->getRequiredMatchCache () > matchCache.size ())
|
||||
matchCache.setSize (rule->selector->getRequiredMatchCache (), -1);
|
||||
|
||||
if (order == CSS_PRIMARY_USER_AGENT) {
|
||||
userAgentSheet.addRule (rule);
|
||||
userAgentSheet.addRule (std::move(rule));
|
||||
} else {
|
||||
sheet[order].addRule (rule);
|
||||
sheet[order].addRule (std::move(rule));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
59
src/css.hh
59
src/css.hh
@ -13,10 +13,18 @@
|
||||
#ifndef __CSS_HH__
|
||||
#define __CSS_HH__
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <map>
|
||||
|
||||
#include "dw/core.hh"
|
||||
#include "doctree.hh"
|
||||
#include "html.hh"
|
||||
|
||||
#include <Alepha/Utility/evaluate.h>
|
||||
|
||||
/* Origin and weight. Used only internally.*/
|
||||
typedef enum {
|
||||
CSS_PRIMARY_USER_AGENT,
|
||||
@ -356,7 +364,7 @@ class CssSimpleSelector {
|
||||
private:
|
||||
int element;
|
||||
char *pseudo, *id;
|
||||
lout::misc::SimpleVector <char *> klass;
|
||||
std::vector< std::string > klass;
|
||||
|
||||
public:
|
||||
enum {
|
||||
@ -375,7 +383,7 @@ class CssSimpleSelector {
|
||||
~CssSimpleSelector ();
|
||||
inline void setElement (int e) { element = e; };
|
||||
void setSelect (SelectType t, const char *v);
|
||||
inline lout::misc::SimpleVector <char *> *getClass () { return &klass; };
|
||||
inline std::vector< std::string > &getClass () { return klass; };
|
||||
inline const char *getPseudoClass () { return pseudo; };
|
||||
inline const char *getId () { return id; };
|
||||
inline int getElement () { return element; };
|
||||
@ -438,8 +446,6 @@ class CssSelector {
|
||||
int specificity ();
|
||||
bool checksPseudoClass ();
|
||||
void print ();
|
||||
inline void ref () { refCount++; }
|
||||
inline void unref () { if (--refCount == 0) delete this; }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -453,9 +459,9 @@ class CssRule {
|
||||
int spec, pos;
|
||||
|
||||
public:
|
||||
CssSelector *selector;
|
||||
std::shared_ptr< CssSelector > selector;
|
||||
|
||||
CssRule (CssSelector *selector, CssPropertyList *props, int pos);
|
||||
CssRule (std::shared_ptr< CssSelector > selector, CssPropertyList *props, int pos);
|
||||
~CssRule ();
|
||||
|
||||
void apply (CssPropertyList *props, Doctree *docTree,
|
||||
@ -475,20 +481,19 @@ class CssRule {
|
||||
*/
|
||||
class CssStyleSheet {
|
||||
private:
|
||||
class RuleList : public lout::misc::SimpleVector <CssRule*>,
|
||||
public lout::object::Object {
|
||||
public:
|
||||
RuleList () : lout::misc::SimpleVector <CssRule*> (1) {};
|
||||
~RuleList () {
|
||||
for (int i = 0; i < size (); i++)
|
||||
delete get (i);
|
||||
};
|
||||
class RuleList
|
||||
{
|
||||
private:
|
||||
std::vector< std::shared_ptr< CssRule > > rules;
|
||||
|
||||
void insert (CssRule *rule);
|
||||
inline bool equals (lout::object::Object *other) {
|
||||
return this == other;
|
||||
};
|
||||
inline int hashValue () { return (intptr_t) this; };
|
||||
public:
|
||||
void insert( std::shared_ptr< CssRule > rule );
|
||||
|
||||
constexpr std::size_t size() const noexcept { return rules.size(); }
|
||||
constexpr bool empty() const noexcept { return rules.empty(); }
|
||||
|
||||
template< typename Self >
|
||||
auto &&at( this Self &&self, const std::size_t index ) { return self.rules.at( index ); }
|
||||
};
|
||||
|
||||
class RuleMap : public lout::container::typed::HashTable
|
||||
@ -500,13 +505,21 @@ class CssStyleSheet {
|
||||
|
||||
static const int ntags = HTML_NTAGS;
|
||||
|
||||
RuleList elementTable[ntags], anyTable;
|
||||
RuleMap idTable, classTable;
|
||||
using ElementTable= std::array< std::shared_ptr< RuleList >, ntags >;
|
||||
ElementTable elementTable= Alepha::Utility::evaluate <=[]
|
||||
{
|
||||
ElementTable rv;
|
||||
std::generate( begin( rv ), end( rv ), &std::make_unique< RuleList > );
|
||||
return rv;
|
||||
};
|
||||
std::shared_ptr< RuleList > anyTable= std::make_unique< RuleList >();
|
||||
std::map< std::string, std::shared_ptr< RuleList > > idTable;
|
||||
std::map< std::string, std::shared_ptr< RuleList > > classTable;
|
||||
int requiredMatchCache;
|
||||
|
||||
public:
|
||||
CssStyleSheet () { requiredMatchCache = 0; }
|
||||
void addRule (CssRule *rule);
|
||||
void addRule (std::shared_ptr< CssRule > rule);
|
||||
void apply (CssPropertyList *props, Doctree *docTree,
|
||||
const DoctreeNode *node, MatchCache *matchCache) const;
|
||||
int getRequiredMatchCache () { return requiredMatchCache; }
|
||||
@ -525,7 +538,7 @@ class CssContext {
|
||||
public:
|
||||
CssContext ();
|
||||
|
||||
void addRule (CssSelector *sel, CssPropertyList *props,
|
||||
void addRule (std::shared_ptr< CssSelector > sel, CssPropertyList *props,
|
||||
CssPrimaryOrder order);
|
||||
void apply (CssPropertyList *props,
|
||||
Doctree *docTree, DoctreeNode *node,
|
||||
|
@ -1476,14 +1476,13 @@ bool CssParser::parseSimpleSelector(CssSimpleSelector *selector)
|
||||
return true;
|
||||
}
|
||||
|
||||
CssSelector *CssParser::parseSelector()
|
||||
std::unique_ptr< CssSelector > CssParser::parseSelector()
|
||||
{
|
||||
CssSelector *selector = new CssSelector ();
|
||||
auto selector = std::make_unique< CssSelector >();
|
||||
|
||||
while (true) {
|
||||
if (! parseSimpleSelector (selector->top ())) {
|
||||
delete selector;
|
||||
selector = NULL;
|
||||
selector = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1499,8 +1498,7 @@ CssSelector *CssParser::parseSelector()
|
||||
} else if (ttype != CSS_TK_END && spaceSeparated) {
|
||||
selector->addSimpleSelector (CssSelector::COMB_DESCENDANT);
|
||||
} else {
|
||||
delete selector;
|
||||
selector = NULL;
|
||||
selector = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1515,17 +1513,15 @@ CssSelector *CssParser::parseSelector()
|
||||
|
||||
void CssParser::parseRuleset()
|
||||
{
|
||||
std::vector < CssSelector * > list;
|
||||
std::vector < std::shared_ptr< CssSelector > > list;
|
||||
CssPropertyList *props, *importantProps;
|
||||
CssSelector *selector;
|
||||
|
||||
|
||||
while (true) {
|
||||
selector = parseSelector();
|
||||
auto selector= parseSelector();
|
||||
|
||||
if (selector) {
|
||||
selector->ref();
|
||||
list.push_back(selector);
|
||||
list.push_back(std::move( selector ));
|
||||
}
|
||||
|
||||
// \todo dump whole ruleset in case of parse error as required by CSS 2.1
|
||||
@ -1559,7 +1555,7 @@ void CssParser::parseRuleset()
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < list.size(); i++) {
|
||||
CssSelector *s = list.at(i);
|
||||
const auto &s = list.at(i);
|
||||
|
||||
if (origin == CSS_ORIGIN_USER_AGENT) {
|
||||
context->addRule(s, props, CSS_PRIMARY_USER_AGENT);
|
||||
@ -1570,8 +1566,6 @@ void CssParser::parseRuleset()
|
||||
context->addRule(s, props, CSS_PRIMARY_AUTHOR);
|
||||
context->addRule(s, importantProps, CSS_PRIMARY_AUTHOR_IMPORTANT);
|
||||
}
|
||||
|
||||
s->unref();
|
||||
}
|
||||
|
||||
props->unref();
|
||||
|
@ -43,7 +43,7 @@ class CssParser {
|
||||
char *parseUrl();
|
||||
void parseImport(DilloHtml *html);
|
||||
void parseMedia();
|
||||
CssSelector *parseSelector();
|
||||
std::unique_ptr< CssSelector > parseSelector();
|
||||
void parseRuleset();
|
||||
void ignoreBlock();
|
||||
void ignoreStatement();
|
||||
|
@ -3,6 +3,9 @@
|
||||
|
||||
#include "lout/misc.hh"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class DoctreeNode {
|
||||
public:
|
||||
DoctreeNode *parent;
|
||||
@ -10,7 +13,7 @@ class DoctreeNode {
|
||||
DoctreeNode *lastChild;
|
||||
int num; // unique ascending id
|
||||
int element;
|
||||
lout::misc::SimpleVector<char*> *klass;
|
||||
std::optional< std::vector< std::string > > klass;
|
||||
const char *pseudo;
|
||||
const char *id;
|
||||
|
||||
@ -18,7 +21,6 @@ class DoctreeNode {
|
||||
parent = NULL;
|
||||
sibling = NULL;
|
||||
lastChild = NULL;
|
||||
klass = NULL;
|
||||
pseudo = NULL;
|
||||
id = NULL;
|
||||
element = 0;
|
||||
@ -31,11 +33,6 @@ class DoctreeNode {
|
||||
lastChild = lastChild->sibling;
|
||||
delete n;
|
||||
}
|
||||
if (klass) {
|
||||
for (int i = 0; i < klass->size (); i++)
|
||||
dFree (klass->get(i));
|
||||
delete klass;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -165,18 +165,16 @@ void StyleEngine::setId (const char *id) {
|
||||
/**
|
||||
* \brief split a string at sep chars and return a SimpleVector of strings
|
||||
*/
|
||||
static lout::misc::SimpleVector<char *> *splitStr (const char *str, char sep) {
|
||||
static std::vector< std::string > splitStr (const char *str, char sep) {
|
||||
const char *p1 = NULL;
|
||||
lout::misc::SimpleVector<char *> *list =
|
||||
new lout::misc::SimpleVector<char *> (1);
|
||||
std::vector< std::string > list;
|
||||
|
||||
for (;; str++) {
|
||||
if (*str != '\0' && *str != sep) {
|
||||
if (!p1)
|
||||
p1 = str;
|
||||
} else if (p1) {
|
||||
list->increase ();
|
||||
list->set (list->size () - 1, dStrndup (p1, str - p1));
|
||||
list.emplace_back( p1, str - p1 );
|
||||
p1 = NULL;
|
||||
}
|
||||
|
||||
@ -189,7 +187,7 @@ static lout::misc::SimpleVector<char *> *splitStr (const char *str, char sep) {
|
||||
|
||||
void StyleEngine::setClass (const char *klass) {
|
||||
DoctreeNode *dn = doctree->top ();
|
||||
assert (dn->klass == NULL);
|
||||
assert (not dn->klass.has_value());
|
||||
dn->klass = splitStr (klass, ' ');
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user