diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/css.cc | 141 | ||||
-rw-r--r-- | src/css.hh | 51 | ||||
-rw-r--r-- | src/cssparser.cc | 14 | ||||
-rw-r--r-- | src/dillo.cc | 3 | ||||
-rw-r--r-- | src/form.cc | 2 | ||||
-rw-r--r-- | src/html.cc | 280 | ||||
-rw-r--r-- | src/html_common.hh | 9 | ||||
-rw-r--r-- | src/misc.c | 1 | ||||
-rw-r--r-- | src/styleengine.cc | 10 | ||||
-rw-r--r-- | src/styleengine.hh | 3 | ||||
-rw-r--r-- | src/url.c | 10 |
11 files changed, 356 insertions, 168 deletions
@@ -1,7 +1,7 @@ /* * File: css.cc * - * Copyright 2008-2009 Johannes Hofmann <Johannes.Hofmann@gmx.de> + * Copyright 2008-2014 Johannes Hofmann <Johannes.Hofmann@gmx.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -108,33 +108,31 @@ CssSelector::CssSelector () { struct CombinatorAndSelector *cs; refCount = 0; - selectorList = new lout::misc::SimpleVector - <struct CombinatorAndSelector> (1); - selectorList->increase (); - cs = selectorList->getRef (selectorList->size () - 1); + matchCacheOffset = -1; + selectorList.increase (); + cs = selectorList.getRef (selectorList.size () - 1); - cs->notMatchingBefore = -1; cs->combinator = COMB_NONE; cs->selector = new CssSimpleSelector (); } CssSelector::~CssSelector () { - for (int i = selectorList->size () - 1; i >= 0; i--) - delete selectorList->getRef (i)->selector; - delete selectorList; + for (int i = selectorList.size () - 1; i >= 0; i--) + delete selectorList.getRef (i)->selector; } /** * \brief Return whether selector matches at a given node in the document tree. */ bool CssSelector::match (Doctree *docTree, const DoctreeNode *node, - int i, Combinator comb) { + int i, Combinator comb, MatchCache *matchCache) { + int *matchCacheEntry; assert (node); if (i < 0) return true; - struct CombinatorAndSelector *cs = selectorList->getRef (i); + struct CombinatorAndSelector *cs = selectorList.getRef (i); CssSimpleSelector *sel = cs->selector; switch (comb) { @@ -148,14 +146,16 @@ bool CssSelector::match (Doctree *docTree, const DoctreeNode *node, break; case COMB_DESCENDANT: node = docTree->parent (node); + matchCacheEntry = matchCache->getRef(matchCacheOffset + i); for (const DoctreeNode *n = node; - n && n->num > cs->notMatchingBefore; n = docTree->parent (n)) - if (sel->match (n) && match (docTree, n, i - 1, cs->combinator)) + n && n->num > *matchCacheEntry; n = docTree->parent (n)) + if (sel->match (n) && + match (docTree, n, i - 1, cs->combinator, matchCache)) return true; if (node) // remember that it didn't match to avoid future tests - cs->notMatchingBefore = node->num; + *matchCacheEntry = node->num; return false; break; @@ -167,23 +167,23 @@ bool CssSelector::match (Doctree *docTree, const DoctreeNode *node, return false; // tail recursion should be optimized by the compiler - return match (docTree, node, i - 1, cs->combinator); + return match (docTree, node, i - 1, cs->combinator, matchCache); } void CssSelector::addSimpleSelector (Combinator c) { struct CombinatorAndSelector *cs; - selectorList->increase (); - cs = selectorList->getRef (selectorList->size () - 1); + assert (matchCacheOffset == -1); + selectorList.increase (); + cs = selectorList.getRef (selectorList.size () - 1); cs->combinator = c; - cs->notMatchingBefore = -1; cs->selector = new CssSimpleSelector (); } bool CssSelector::checksPseudoClass () { - for (int i = 0; i < selectorList->size (); i++) - if (selectorList->getRef (i)->selector->getPseudoClass ()) + for (int i = 0; i < selectorList.size (); i++) + if (selectorList.getRef (i)->selector->getPseudoClass ()) return true; return false; } @@ -197,18 +197,18 @@ bool CssSelector::checksPseudoClass () { int CssSelector::specificity () { int spec = 0; - for (int i = 0; i < selectorList->size (); i++) - spec += selectorList->getRef (i)->selector->specificity (); + for (int i = 0; i < selectorList.size (); i++) + spec += selectorList.getRef (i)->selector->specificity (); return spec; } void CssSelector::print () { - for (int i = 0; i < selectorList->size (); i++) { - selectorList->getRef (i)->selector->print (); + for (int i = 0; i < selectorList.size (); i++) { + selectorList.getRef (i)->selector->print (); - if (i < selectorList->size () - 1) { - switch (selectorList->getRef (i + 1)->combinator) { + if (i < selectorList.size () - 1) { + switch (selectorList.getRef (i + 1)->combinator) { case COMB_CHILD: fprintf (stderr, "> "); break; @@ -230,17 +230,13 @@ void CssSelector::print () { CssSimpleSelector::CssSimpleSelector () { element = ELEMENT_ANY; - klass = NULL; id = NULL; pseudo = NULL; } CssSimpleSelector::~CssSimpleSelector () { - if (klass) { - for (int i = 0; i < klass->size (); i++) - dFree (klass->get (i)); - delete klass; - } + for (int i = 0; i < klass.size (); i++) + dFree (klass.get (i)); dFree (id); dFree (pseudo); } @@ -248,10 +244,8 @@ CssSimpleSelector::~CssSimpleSelector () { void CssSimpleSelector::setSelect (SelectType t, const char *v) { switch (t) { case SELECT_CLASS: - if (klass == NULL) - klass = new lout::misc::SimpleVector <char *> (1); - klass->increase (); - klass->set (klass->size () - 1, dStrdup (v)); + klass.increase (); + klass.set (klass.size () - 1, dStrdup (v)); break; case SELECT_PSEUDO_CLASS: if (pseudo == NULL) @@ -279,20 +273,18 @@ bool CssSimpleSelector::match (const DoctreeNode *n) { return false; if (id != NULL && (n->id == NULL || dStrAsciiCasecmp (id, n->id) != 0)) return false; - if (klass != NULL) { - 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) { - found = true; - break; - } + 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) { + found = true; + break; } } - if (! found) - return false; } + if (! found) + return false; } return true; @@ -308,8 +300,7 @@ int CssSimpleSelector::specificity () { if (id) spec += 1 << 20; - if (klass) - spec += klass->size() << 10; + spec += klass.size() << 10; if (pseudo) spec += 1 << 10; if (element != ELEMENT_ANY) @@ -321,11 +312,9 @@ int CssSimpleSelector::specificity () { void CssSimpleSelector::print () { fprintf (stderr, "Element %d, pseudo %s, id %s ", element, pseudo, id); - if (klass != NULL) { - fprintf (stderr, "class "); - for (int i = 0; i < klass->size (); i++) - fprintf (stderr, ".%s", klass->get (i)); - } + fprintf (stderr, "class "); + for (int i = 0; i < klass.size (); i++) + fprintf (stderr, ".%s", klass.get (i)); } CssRule::CssRule (CssSelector *selector, CssPropertyList *props, int pos) { @@ -344,9 +333,9 @@ CssRule::~CssRule () { props->unref (); } -void CssRule::apply (CssPropertyList *props, - Doctree *docTree, const DoctreeNode *node) { - if (selector->match (docTree, node)) +void CssRule::apply (CssPropertyList *props, Doctree *docTree, + const DoctreeNode *node, MatchCache *matchCache) const { + if (selector->match (docTree, node, matchCache)) this->props->apply (props); } @@ -410,6 +399,8 @@ void CssStyleSheet::addRule (CssRule *rule) { } if (ruleList) { + rule->selector->setMatchCacheOffset (matchCacheOffset); + matchCacheOffset += rule->selector->size (); ruleList->insert (rule); } else { assert (top->getElement () == CssSimpleSelector::ELEMENT_NONE); @@ -423,10 +414,10 @@ void CssStyleSheet::addRule (CssRule *rule) { * The properties are set as defined by the rules in the stylesheet that * match at the given node in the document tree. */ -void CssStyleSheet::apply (CssPropertyList *props, - Doctree *docTree, const DoctreeNode *node) { +void CssStyleSheet::apply (CssPropertyList *props, Doctree *docTree, + const DoctreeNode *node, MatchCache *matchCache) const { static const int maxLists = 32; - RuleList *ruleList[maxLists]; + const RuleList *ruleList[maxLists]; int numLists = 0, index[maxLists] = {0}; if (node->id) { @@ -470,7 +461,7 @@ void CssStyleSheet::apply (CssPropertyList *props, int minSpecIndex = -1; for (int i = 0; i < numLists; i++) { - RuleList *rl = ruleList[i]; + const RuleList *rl = ruleList[i]; if (rl && rl->size () > index[i] && (rl->get(index[i])->specificity () < minSpec || @@ -484,8 +475,8 @@ void CssStyleSheet::apply (CssPropertyList *props, } if (minSpecIndex >= 0) { - ruleList[minSpecIndex]->get (index[minSpecIndex])->apply - (props, docTree, node); + CssRule *rule = ruleList[minSpecIndex]->get (index[minSpecIndex]); + rule->apply(props, docTree, node, matchCache); index[minSpecIndex]++; } else { break; @@ -493,8 +484,11 @@ void CssStyleSheet::apply (CssPropertyList *props, } } +CssStyleSheet CssContext::userAgentSheet; + CssContext::CssContext () { pos = 0; + matchCache[CSS_PRIMARY_USER_AGENT].setSize (userAgentSheet.matchCacheOffset, -1); } /** @@ -511,23 +505,28 @@ void CssContext::apply (CssPropertyList *props, Doctree *docTree, CssPropertyList *tagStyle, CssPropertyList *tagStyleImportant, CssPropertyList *nonCssHints) { - sheet[CSS_PRIMARY_USER_AGENT].apply (props, docTree, node); - sheet[CSS_PRIMARY_USER].apply (props, docTree, node); + userAgentSheet.apply (props, docTree, node, + &matchCache[CSS_PRIMARY_USER_AGENT]); + sheet[CSS_PRIMARY_USER].apply (props, docTree, node, + &matchCache[CSS_PRIMARY_USER]); if (nonCssHints) nonCssHints->apply (props); - sheet[CSS_PRIMARY_AUTHOR].apply (props, docTree, node); + sheet[CSS_PRIMARY_AUTHOR].apply (props, docTree, node, + &matchCache[CSS_PRIMARY_AUTHOR]); if (tagStyle) tagStyle->apply (props); - sheet[CSS_PRIMARY_AUTHOR_IMPORTANT].apply (props, docTree, node); + sheet[CSS_PRIMARY_AUTHOR_IMPORTANT].apply (props, docTree, node, + &matchCache[CSS_PRIMARY_AUTHOR_IMPORTANT]); if (tagStyleImportant) tagStyleImportant->apply (props); - sheet[CSS_PRIMARY_USER_IMPORTANT].apply (props, docTree, node); + sheet[CSS_PRIMARY_USER_IMPORTANT].apply (props, docTree, node, + &matchCache[CSS_PRIMARY_USER_IMPORTANT]); } void CssContext::addRule (CssSelector *sel, CssPropertyList *props, @@ -541,8 +540,12 @@ void CssContext::addRule (CssSelector *sel, CssPropertyList *props, !rule->isSafe ()) { MSG_WARN ("Ignoring unsafe author style that might reveal browsing history\n"); delete rule; - } else { + } else if (order == CSS_PRIMARY_USER_AGENT) { + userAgentSheet.addRule (rule); + matchCache[CSS_PRIMARY_USER_AGENT].setSize (userAgentSheet.matchCacheOffset, -1); + } else { sheet[order].addRule (rule); + matchCache[order].setSize (sheet[order].matchCacheOffset, -1); } } } @@ -293,6 +293,7 @@ class CssProperty { switch (type) { case CSS_TYPE_STRING: case CSS_TYPE_SYMBOL: + case CSS_TYPE_URI: dFree (value.strVal); break; case CSS_TYPE_BACKGROUND_POSITION: @@ -335,7 +336,7 @@ class CssSimpleSelector { private: int element; char *pseudo, *id; - lout::misc::SimpleVector <char *> *klass; + lout::misc::SimpleVector <char *> klass; public: enum { @@ -354,7 +355,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 lout::misc::SimpleVector <char *> *getClass () { return &klass; }; inline const char *getPseudoClass () { return pseudo; }; inline const char *getId () { return id; }; inline int getElement () { return element; }; @@ -363,6 +364,11 @@ class CssSimpleSelector { void print (); }; +class MatchCache : public lout::misc::SimpleVector <int> { + public: + MatchCache() : lout::misc::SimpleVector <int> (0) {}; +}; + /** * \brief CSS selector class. * @@ -379,26 +385,31 @@ class CssSelector { private: struct CombinatorAndSelector { - int notMatchingBefore; // used for optimizing CSS selector matching Combinator combinator; CssSimpleSelector *selector; }; - int refCount; - lout::misc::SimpleVector <struct CombinatorAndSelector> *selectorList; + int refCount, matchCacheOffset; + lout::misc::SimpleVector <struct CombinatorAndSelector> selectorList; - bool match (Doctree *dt, const DoctreeNode *node, int i, Combinator comb); + bool match (Doctree *dt, const DoctreeNode *node, int i, Combinator comb, + MatchCache *matchCache); public: CssSelector (); ~CssSelector (); void addSimpleSelector (Combinator c); inline CssSimpleSelector *top () { - return selectorList->getRef (selectorList->size () - 1)->selector; + return selectorList.getRef (selectorList.size () - 1)->selector; + }; + inline int size () { return selectorList.size (); }; + inline bool match (Doctree *dt, const DoctreeNode *node, + MatchCache *matchCache) { + return match (dt, node, selectorList.size () - 1, COMB_NONE, + matchCache); }; - inline int size () { return selectorList->size (); }; - inline bool match (Doctree *dt, const DoctreeNode *node) { - return match (dt, node, selectorList->size () - 1, COMB_NONE); + inline void setMatchCacheOffset (int mo) { + matchCacheOffset = mo; }; int specificity (); bool checksPseudoClass (); @@ -423,8 +434,8 @@ class CssRule { CssRule (CssSelector *selector, CssPropertyList *props, int pos); ~CssRule (); - void apply (CssPropertyList *props, - Doctree *docTree, const DoctreeNode *node); + void apply (CssPropertyList *props, Doctree *docTree, + const DoctreeNode *node, MatchCache *matchCache) const; inline bool isSafe () { return !selector->checksPseudoClass () || props->isSafe (); }; @@ -463,19 +474,23 @@ class CssStyleSheet { <lout::object::ConstString, RuleList > (true, true, 256) {}; }; - static const int ntags = 90 + 10; // \todo don't hardcode + static const int ntags = 90 + 14; // \todo don't hardcode /* 90 is the full number of html4 elements, including those which we have - * implemented. From html 5, let's add: article, header, footer, mark, - * nav, section, aside, figure, figcaption, wbr. + * implemented. From html5, let's add: article, header, footer, mark, + * nav, section, aside, figure, figcaption, wbr, audio, video, source, + * embed. */ RuleList elementTable[ntags], anyTable; RuleMap idTable, classTable; public: + int matchCacheOffset; + + CssStyleSheet () { matchCacheOffset = 0; } void addRule (CssRule *rule); - void apply (CssPropertyList *props, - Doctree *docTree, const DoctreeNode *node); + void apply (CssPropertyList *props, Doctree *docTree, + const DoctreeNode *node, MatchCache *matchCache) const; }; /** @@ -483,7 +498,9 @@ class CssStyleSheet { */ class CssContext { private: + static CssStyleSheet userAgentSheet; CssStyleSheet sheet[CSS_PRIMARY_USER_IMPORTANT + 1]; + MatchCache matchCache[CSS_PRIMARY_USER_IMPORTANT + 1]; int pos; public: diff --git a/src/cssparser.cc b/src/cssparser.cc index 4ff8f4f7..07412a8d 100644 --- a/src/cssparser.cc +++ b/src/cssparser.cc @@ -19,6 +19,7 @@ #include <stdlib.h> #include <stdio.h> +#include "lout/debug.hh" #include "msg.h" #include "colors.h" #include "html_common.hh" @@ -27,7 +28,6 @@ using namespace dw::core::style; -#define DEBUG_MSG(A, B, ...) _MSG(B, __VA_ARGS__) #define MSG_CSS(A, ...) MSG(A, __VA_ARGS__) #define DEBUG_TOKEN_LEVEL 0 #define DEBUG_PARSE_LEVEL 0 @@ -287,7 +287,7 @@ typedef struct { CSS_SHORTHAND_BORDER, /* special, used for 'border' */ CSS_SHORTHAND_FONT, /* special, used for 'font' */ } type; - const CssPropertyName * properties;/* CSS_SHORTHAND_MULTIPLE: + const CssPropertyName *properties; /* CSS_SHORTHAND_MULTIPLE: * must be terminated by -1 * CSS_SHORTHAND_DIRECTIONS: * must have length 4 @@ -728,7 +728,7 @@ bool CssParser::tokenMatchesProperty(CssPropertyName prop, CssValueType *type) dStrAsciiCasecmp(tval, "right") == 0 || dStrAsciiCasecmp(tval, "top") == 0 || dStrAsciiCasecmp(tval, "bottom") == 0)) - return true; + return true; // Fall Through (lenght and percentage) case CSS_TYPE_LENGTH_PERCENTAGE: case CSS_TYPE_LENGTH_PERCENTAGE_NUMBER: @@ -871,7 +871,7 @@ bool CssParser::parseRgbColor(int32_t *c) { bool CssParser::parseValue(CssPropertyName prop, CssValueType type, - CssPropertyValue * val) + CssPropertyValue *val) { CssLengthType lentype; bool found, ret = false; @@ -1199,8 +1199,8 @@ static int Css_shorthand_info_cmp(const void *a, const void *b) ((CssShorthandInfo *) b)->symbol); } -void CssParser::parseDeclaration(CssPropertyList * props, - CssPropertyList * importantProps) +void CssParser::parseDeclaration(CssPropertyList *props, + CssPropertyList *importantProps) { CssPropertyInfo pi = {NULL, {CSS_TYPE_UNUSED}, NULL}, *pip; CssShorthandInfo *sip; @@ -1715,7 +1715,7 @@ void CssParser::ignoreStatement() } } -void CssParser::parse(DilloHtml *html, DilloUrl *url, CssContext * context, +void CssParser::parse(DilloHtml *html, DilloUrl *url, CssContext *context, const char *buf, int buflen, CssOrigin origin) { diff --git a/src/dillo.cc b/src/dillo.cc index 9930ae74..4d96988f 100644 --- a/src/dillo.cc +++ b/src/dillo.cc @@ -52,6 +52,7 @@ #include "cookies.h" #include "domain.h" #include "auth.h" +#include "styleengine.hh" #include "lout/debug.hh" #include "dw/fltkcore.hh" @@ -379,6 +380,7 @@ int main(int argc, char **argv) DBG_OBJ_COLOR("#c0ff80", "dw::*"); DBG_OBJ_COLOR("#c0c0ff", "dw::fltk::*"); DBG_OBJ_COLOR("#ffa0a0", "dw::core::*"); + DBG_OBJ_COLOR("#ffe0a0", "dw::core::style::*"); DBG_OBJ_COLOR ("#80ffa0", "dw::Image"); DBG_OBJ_COLOR ("#f0ff80", "dw::Textblock"); @@ -479,6 +481,7 @@ int main(int argc, char **argv) a_Cookies_init(); a_Auth_init(); a_UIcmd_init(); + StyleEngine::init(); dw::Textblock::setPenaltyHyphen (prefs.penalty_hyphen); dw::Textblock::setPenaltyHyphen2 (prefs.penalty_hyphen_2); diff --git a/src/form.cc b/src/form.cc index c5bb10af..07c12815 100644 --- a/src/form.cc +++ b/src/form.cc @@ -2003,7 +2003,7 @@ static Embed *Html_input_image(DilloHtml *html, const char *tag, int tagsize) html->styleEngine->setPseudoLink (); /* create new image and add it to the button */ - a_Html_image_attrs(html, tag, tagsize); + a_Html_common_image_attrs(html, tag, tagsize); if ((Image = a_Html_image_new(html, tag, tagsize))) { // At this point, we know that Image->ir represents an image // widget. Notice that the order of the casts matters, because diff --git a/src/html.cc b/src/html.cc index 74b90577..3319b35e 100644 --- a/src/html.cc +++ b/src/html.cc @@ -1383,7 +1383,7 @@ static void Html_tag_cleanup_at_close(DilloHtml *html, int new_idx) * by closing them before opening another. * This is not an HTML SPEC restriction , but it avoids lots of trouble * inside dillo (concurrent inputs), and makes almost no sense to have. - */ + */ static void Html_tag_cleanup_nested_inputs(DilloHtml *html, int new_idx) { static int i_BUTTON = a_Html_tag_index("button"), @@ -1696,9 +1696,9 @@ static void Html_tag_close_head(DilloHtml *html) /* match for the well formed start of HEAD section */ if (html->Num_TITLE == 0) BUG_MSG("HEAD section lacks the TITLE element\n"); - + html->InFlags &= ~IN_HEAD; - + /* charset is already set, load remote stylesheets now */ for (int i = 0; i < html->cssUrls->size(); i++) { a_Html_load_stylesheet(html, html->cssUrls->get(i)); @@ -2084,13 +2084,13 @@ static void Html_tag_open_abbr(DilloHtml *html, const char *tag, int tagsize) /* * Read image-associated tag attributes and create new image. */ -void a_Html_image_attrs(DilloHtml *html, const char *tag, int tagsize) +void a_Html_common_image_attrs(DilloHtml *html, const char *tag, int tagsize) { char *width_ptr, *height_ptr; const char *attrbuf; CssLength l_w = CSS_CREATE_LENGTH(0.0, CSS_LENGTH_TYPE_AUTO); CssLength l_h = CSS_CREATE_LENGTH(0.0, CSS_LENGTH_TYPE_AUTO); - int space, border, w = 0, h = 0; + int w = 0, h = 0; if (prefs.show_tooltip && (attrbuf = a_Html_get_attr(html, tag, tagsize, "title"))) { @@ -2126,7 +2126,8 @@ void a_Html_image_attrs(DilloHtml *html, const char *tag, int tagsize) dFree(width_ptr); dFree(height_ptr); width_ptr = height_ptr = NULL; - MSG("a_Html_image_attrs: suspicious image size request %d x %d\n", w, h); + MSG("a_Html_common_image_attrs: suspicious image size request %d x %d\n", + w, h); } else { if (CSS_LENGTH_TYPE(l_w) != CSS_LENGTH_TYPE_AUTO) html->styleEngine->setNonCssHint (CSS_PROPERTY_WIDTH, @@ -2143,55 +2144,6 @@ void a_Html_image_attrs(DilloHtml *html, const char *tag, int tagsize) [...] */ - /* Spacing to the left and right */ - if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "hspace"))) { - space = strtol(attrbuf, NULL, 10); - if (space > 0) { - space = CSS_CREATE_LENGTH(space, CSS_LENGTH_TYPE_PX); - html->styleEngine->setNonCssHint (CSS_PROPERTY_MARGIN_LEFT, - CSS_TYPE_LENGTH_PERCENTAGE, space); - html->styleEngine->setNonCssHint (CSS_PROPERTY_MARGIN_RIGHT, - CSS_TYPE_LENGTH_PERCENTAGE, space); - } - } - - /* Spacing at the top and bottom */ - if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "vspace"))) { - space = strtol(attrbuf, NULL, 10); - if (space > 0) { - space = CSS_CREATE_LENGTH(space, CSS_LENGTH_TYPE_PX); - html->styleEngine->setNonCssHint (CSS_PROPERTY_MARGIN_TOP, - CSS_TYPE_LENGTH_PERCENTAGE, space); - html->styleEngine->setNonCssHint (CSS_PROPERTY_MARGIN_BOTTOM, - CSS_TYPE_LENGTH_PERCENTAGE, space); - } - } - - /* Border */ - if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "border"))) { - border = strtol(attrbuf, NULL, 10); - if (border >= 0) { - border = CSS_CREATE_LENGTH(border, CSS_LENGTH_TYPE_PX); - html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_TOP_WIDTH, - CSS_TYPE_LENGTH_PERCENTAGE, border); - html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_BOTTOM_WIDTH, - CSS_TYPE_LENGTH_PERCENTAGE, border); - html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_LEFT_WIDTH, - CSS_TYPE_LENGTH_PERCENTAGE, border); - html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_RIGHT_WIDTH, - CSS_TYPE_LENGTH_PERCENTAGE, border); - - html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_TOP_STYLE, - CSS_TYPE_ENUM, BORDER_SOLID); - html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_BOTTOM_STYLE, - CSS_TYPE_ENUM, BORDER_SOLID); - html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_LEFT_STYLE, - CSS_TYPE_ENUM, BORDER_SOLID); - html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_RIGHT_STYLE, - CSS_TYPE_ENUM, BORDER_SOLID); - } - } - /* x_img is an index to a list of {url,image} pairs. * We know a_Html_image_new() will use size() as its next index */ html->styleEngine->setNonCssHint (PROPERTY_X_IMG, CSS_TYPE_INTEGER, @@ -2272,7 +2224,60 @@ static bool Html_load_image(BrowserWindow *bw, DilloUrl *url, static void Html_tag_open_img(DilloHtml *html, const char *tag, int tagsize) { - a_Html_image_attrs(html, tag, tagsize); + int space, border; + const char *attrbuf; + + a_Html_common_image_attrs(html, tag, tagsize); + + /* Spacing to the left and right */ + if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "hspace"))) { + space = strtol(attrbuf, NULL, 10); + if (space > 0) { + space = CSS_CREATE_LENGTH(space, CSS_LENGTH_TYPE_PX); + html->styleEngine->setNonCssHint (CSS_PROPERTY_MARGIN_LEFT, + CSS_TYPE_LENGTH_PERCENTAGE, space); + html->styleEngine->setNonCssHint (CSS_PROPERTY_MARGIN_RIGHT, + CSS_TYPE_LENGTH_PERCENTAGE, space); + } + } + + /* Spacing at the top and bottom */ + if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "vspace"))) { + space = strtol(attrbuf, NULL, 10); + if (space > 0) { + space = CSS_CREATE_LENGTH(space, CSS_LENGTH_TYPE_PX); + html->styleEngine->setNonCssHint (CSS_PROPERTY_MARGIN_TOP, + CSS_TYPE_LENGTH_PERCENTAGE, space); + html->styleEngine->setNonCssHint (CSS_PROPERTY_MARGIN_BOTTOM, + CSS_TYPE_LENGTH_PERCENTAGE, space); + } + } + + /* Border */ + if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "border"))) { + border = strtol(attrbuf, NULL, 10); + if (border >= 0) { + border = CSS_CREATE_LENGTH(border, CSS_LENGTH_TYPE_PX); + html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_TOP_WIDTH, + CSS_TYPE_LENGTH_PERCENTAGE, border); + html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_BOTTOM_WIDTH, + CSS_TYPE_LENGTH_PERCENTAGE, border); + html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_LEFT_WIDTH, + CSS_TYPE_LENGTH_PERCENTAGE, border); + html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_RIGHT_WIDTH, + CSS_TYPE_LENGTH_PERCENTAGE, border); + + html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_TOP_STYLE, + CSS_TYPE_ENUM, BORDER_SOLID); + html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_BOTTOM_STYLE, + CSS_TYPE_ENUM, BORDER_SOLID); + html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_LEFT_STYLE, + CSS_TYPE_ENUM, BORDER_SOLID); + html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_RIGHT_STYLE, + CSS_TYPE_ENUM, BORDER_SOLID); + } + } + } /* @@ -2509,10 +2514,156 @@ static void Html_tag_open_object(DilloHtml *html, const char *tag, int tagsize) html->styleEngine->setNonCssHint(PROPERTY_X_LINK, CSS_TYPE_INTEGER, Html_set_new_link(html, &url)); + } + a_Url_free(base_url); +} +static void Html_tag_content_object(DilloHtml *html, const char *tag, + int tagsize) +{ + if (a_Html_get_attr(html, tag, tagsize, "data")) HT2TB(html)->addText("[OBJECT]", html->wordStyle ()); +} + +/* + * <VIDEO> + * Provide a link to the video. + */ +static void Html_tag_open_video(DilloHtml *html, const char *tag, int tagsize) +{ + DilloUrl *url; + const char *attrbuf; + + if (html->InFlags & IN_MEDIA) { + MSG("<video> not handled when already inside a media element.\n"); + return; } - a_Url_free(base_url); + /* TODO: poster attr */ + + if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "src"))) { + url = a_Html_url_new(html, attrbuf, NULL, 0); + dReturn_if_fail ( url != NULL ); + + if (a_Capi_get_flags_with_redirection(url) & CAPI_IsCached) { + html->styleEngine->setPseudoVisited (); + } else { + html->styleEngine->setPseudoLink (); + } + + html->styleEngine->setNonCssHint(PROPERTY_X_LINK, CSS_TYPE_INTEGER, + Html_set_new_link(html, &url)); + + HT2TB(html)->addText("[VIDEO]", html->wordStyle ()); + } + html->InFlags |= IN_MEDIA; +} + +/* + * <AUDIO> + * Provide a link to the audio. + */ +static void Html_tag_open_audio(DilloHtml *html, const char *tag, int tagsize) +{ + DilloUrl *url; + const char *attrbuf; + + if (html->InFlags & IN_MEDIA) { + MSG("<audio> not handled when already inside a media element.\n"); + return; + } + + if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "src"))) { + url = a_Html_url_new(html, attrbuf, NULL, 0); + dReturn_if_fail ( url != NULL ); + + if (a_Capi_get_flags_with_redirection(url) & CAPI_IsCached) { + html->styleEngine->setPseudoVisited (); + } else { + html->styleEngine->setPseudoLink (); + } + + html->styleEngine->setNonCssHint(PROPERTY_X_LINK, CSS_TYPE_INTEGER, + Html_set_new_link(html, &url)); + + HT2TB(html)->addText("[AUDIO]", html->wordStyle ()); + } + html->InFlags |= IN_MEDIA; +} + +/* + * <SOURCE> + * Media resource; provide a link to its address. + */ +static void Html_tag_open_source(DilloHtml *html, const char *tag, + int tagsize) +{ + const char *attrbuf; + + if (!(html->InFlags & IN_MEDIA)) { + BUG_MSG("<source> element not inside a media element.\n"); + return; + } + if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "src"))) { + BUG_MSG("src attribute is required in <source> element.\n"); + return; + } else { + DilloUrl *url = a_Html_url_new(html, attrbuf, NULL, 0); + + dReturn_if_fail ( url != NULL ); + + if (a_Capi_get_flags_with_redirection(url) & CAPI_IsCached) { + html->styleEngine->setPseudoVisited (); + } else { + html->styleEngine->setPseudoLink (); + } + html->styleEngine->setNonCssHint(PROPERTY_X_LINK, CSS_TYPE_INTEGER, + Html_set_new_link(html, &url)); + } +} + +static void Html_tag_content_source(DilloHtml *html, const char *tag, + int tagsize) +{ + if ((html->InFlags & IN_MEDIA) && a_Html_get_attr(html, tag, tagsize,"src")) + HT2TB(html)->addText("[MEDIA SOURCE]", html->wordStyle ()); +} + +/* + * Media (AUDIO/VIDEO) close function + */ +static void Html_tag_close_media(DilloHtml *html) +{ + html->InFlags &= ~IN_MEDIA; +} + +/* + * <EMBED> + * Provide a link to embedded content. + */ +static void Html_tag_open_embed(DilloHtml *html, const char *tag, int tagsize) +{ + const char *attrbuf; + + if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "src"))) { + DilloUrl *url = a_Html_url_new(html, attrbuf, NULL, 0); + + dReturn_if_fail ( url != NULL ); + + if (a_Capi_get_flags_with_redirection(url) & CAPI_IsCached) { + html->styleEngine->setPseudoVisited (); + } else { + html->styleEngine->setPseudoLink (); + } + + html->styleEngine->setNonCssHint(PROPERTY_X_LINK, CSS_TYPE_INTEGER, + Html_set_new_link(html, &url)); + } +} + +static void Html_tag_content_embed(DilloHtml *html,const char *tag,int tagsize) +{ + if (a_Html_get_attr(html, tag, tagsize, "src")) + HT2TB(html)->addText("[EMBED]", html->wordStyle ()); } /* @@ -2997,8 +3148,11 @@ static void Html_tag_open_meta(DilloHtml *html, const char *tag, int tagsize) } else { sprintf(delay_str, "."); } - /* Skip to anything after "URL=" */ - while (*content && *(content++) != '=') ; + /* Skip to anything after "URL=" or ";" if "URL=" is not found */ + if ((p = dStriAsciiStr(content, "url="))) + content = p + strlen("url="); + else if ((p = strstr(content, ";"))) + content = p + strlen(";"); /* Handle the case of a quoted URL */ if (*content == '"' || *content == '\'') { if ((p = strchr(content + 1, *content))) @@ -3280,6 +3434,7 @@ const TagInfo Tags[] = { NULL}, {"article", B8(011110),'R',2, Html_tag_open_default, NULL, NULL}, {"aside", B8(011110),'R',2, Html_tag_open_default, NULL, NULL}, + {"audio", B8(011101),'R',2, Html_tag_open_audio, NULL, Html_tag_close_media}, {"b", B8(010101),'R',2, Html_tag_open_default, NULL, NULL}, {"base", B8(100001),'F',0, Html_tag_open_base, NULL, NULL}, /* basefont 010001 -- obsolete in HTML5 */ @@ -3306,6 +3461,7 @@ const TagInfo Tags[] = { {"dl", B8(011010),'R',2, Html_tag_open_dl, NULL, Html_tag_close_par}, {"dt", B8(010110),'O',1, Html_tag_open_dt, NULL, Html_tag_close_par}, {"em", B8(010101),'R',2, Html_tag_open_default, NULL, NULL}, + {"embed", B8(010001),'F',0, Html_tag_open_embed, Html_tag_content_embed,NULL}, /* fieldset */ {"figcaption", B8(011110),'R',2, Html_tag_open_default, NULL, NULL}, {"figure", B8(011110),'R',2, Html_tag_open_default, NULL, NULL}, @@ -3349,7 +3505,8 @@ const TagInfo Tags[] = { {"nav", B8(011110),'R',2, Html_tag_open_default, NULL, NULL}, /* noframes 1011 -- obsolete in HTML5 */ /* noscript 1011 */ - {"object", B8(111101),'R',2, Html_tag_open_object, NULL, NULL}, + {"object", B8(111101),'R',2, Html_tag_open_object, Html_tag_content_object, + NULL}, {"ol", B8(011010),'R',2, Html_tag_open_ol, NULL, NULL}, {"optgroup", B8(010101),'O',1, Html_tag_open_optgroup, NULL, Html_tag_close_optgroup}, @@ -3364,6 +3521,8 @@ const TagInfo Tags[] = { {"section", B8(011110),'R',2, Html_tag_open_default, NULL, NULL}, {"select", B8(010101),'R',2, Html_tag_open_select,NULL,Html_tag_close_select}, {"small", B8(010101),'R',2, Html_tag_open_default, NULL, NULL}, + {"source", B8(010001),'F',0, Html_tag_open_source, Html_tag_content_source, + NULL}, {"span", B8(010101),'R',2, Html_tag_open_span, NULL, NULL}, {"strike", B8(010101),'R',2, Html_tag_open_default, NULL, NULL}, {"strong", B8(010101),'R',2, Html_tag_open_default, NULL, NULL}, @@ -3388,6 +3547,7 @@ const TagInfo Tags[] = { {"u", B8(010101),'R',2, Html_tag_open_default, NULL, NULL}, {"ul", B8(011010),'R',2, Html_tag_open_ul, NULL, NULL}, {"var", B8(010101),'R',2, Html_tag_open_default, NULL, NULL}, + {"video", B8(011101),'R',2, Html_tag_open_video, NULL, Html_tag_close_media}, {"wbr", B8(010101),'F',0, Html_tag_open_default, Html_tag_content_wbr, NULL} }; #define NTAGS (sizeof(Tags)/sizeof(Tags[0])) diff --git a/src/html_common.hh b/src/html_common.hh index a43d91b7..de3069cb 100644 --- a/src/html_common.hh +++ b/src/html_common.hh @@ -87,8 +87,9 @@ typedef enum { IN_MAP = 1 << 9, IN_PRE = 1 << 10, IN_LI = 1 << 11, - IN_META_HACK = 1 << 12, - IN_EOF = 1 << 13, + IN_MEDIA = 1 << 12, + IN_META_HACK = 1 << 13, + IN_EOF = 1 << 14, } DilloHtmlProcessingState; /* @@ -233,7 +234,7 @@ public: { return styleEngine->wordStyle (bw, base_url); } inline void restyle () { styleEngine->restyle (bw, base_url); } - + }; /* @@ -257,7 +258,7 @@ DilloUrl *a_Html_url_new(DilloHtml *html, const char *url_str, const char *base_url, int use_base_url); -void a_Html_image_attrs(DilloHtml *html, const char *tag, int tagsize); +void a_Html_common_image_attrs(DilloHtml *html, const char *tag, int tagsize); DilloImage *a_Html_image_new(DilloHtml *html, const char *tag, int tagsize); char *a_Html_parse_entities(DilloHtml *html, const char *token, int toksize); @@ -115,6 +115,7 @@ static const ContentType_t MimeTypes[] = { typedef enum { DT_OCTET_STREAM = 0, + DT_PLACEHOLDER, DT_TEXT_HTML, DT_TEXT_PLAIN, DT_IMAGE_GIF, diff --git a/src/styleengine.cc b/src/styleengine.cc index 2da9d8f7..ffc0b0f6 100644 --- a/src/styleengine.cc +++ b/src/styleengine.cc @@ -65,7 +65,6 @@ StyleEngine::StyleEngine (dw::core::Layout *layout) { doctree = new Doctree (); stack = new lout::misc::SimpleVector <Node> (1); cssContext = new CssContext (); - buildUserAgentStyle (); buildUserStyle (); this->layout = layout; importDepth = 0; @@ -548,8 +547,10 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props, attrs->backgroundImage->connectDeletion (new StyleImageDeletionReceiver (clientKey)); } + + a_Url_free (imgUrl); } - break; + break; case CSS_PROPERTY_BACKGROUND_POSITION: computeLength (&attrs->backgroundPositionX, p->value.posVal->posX, attrs->font); @@ -958,7 +959,7 @@ void StyleEngine::parse (DilloHtml *html, DilloUrl *url, const char *buf, * The user agent style defines how dillo renders HTML in the absence of * author or user styles. */ -void StyleEngine::buildUserAgentStyle () { +void StyleEngine::init () { const char *cssBuf = "body {margin: 5px}" "big {font-size: 1.17em}" @@ -1015,7 +1016,8 @@ void StyleEngine::buildUserAgentStyle () { */ "table, caption {font-size: medium; font-weight: normal}"; - CssParser::parse (NULL, NULL, cssContext, cssBuf, strlen (cssBuf), + CssContext context; + CssParser::parse (NULL, NULL, &context, cssBuf, strlen (cssBuf), CSS_ORIGIN_USER_AGENT); } diff --git a/src/styleengine.hh b/src/styleengine.hh index 714553ff..bec4875b 100644 --- a/src/styleengine.hh +++ b/src/styleengine.hh @@ -38,7 +38,6 @@ class StyleEngine { void stackPush (); void stackPop (); - void buildUserAgentStyle (); void buildUserStyle (); dw::core::style::Style *style0 (int i, BrowserWindow *bw, DilloUrl *url); dw::core::style::Style *wordStyle0 (BrowserWindow *bw, DilloUrl *url); @@ -64,6 +63,8 @@ class StyleEngine { dw::core::style::Font *font); public: + static void init (); + StyleEngine (dw::core::Layout *layout); ~StyleEngine (); @@ -688,14 +688,14 @@ static uint_t Url_host_public_internal_dots(const char *host) if (tld_len > 0) { /* These TLDs were chosen by examining the current publicsuffix list - * in September 2013 and picking out those where it was simplest for + * in February 2014 and picking out those where it was simplest for * them to describe the situation by beginning with a "*.[tld]" rule * or every rule was "[something].[tld]". */ - const char *const tlds[] = {"au","bd","bn","ck","cy","er","et","fj", - "fk","gn","gu","il","jm","ke","kh","kp", - "kw","lb","lr","mm","mt","mz","ni","np", - "nz","pg","tr","uk","ye","za","zm","zw"}; + const char *const tlds[] = {"bd","bn","ck","cy","er","et","fj","fk", + "gu","il","jm","ke","kh","kw","mm","mz", + "ni","np","nz","pg","tr","uk","ye","za", + "zm","zw"}; uint_t i, tld_num = sizeof(tlds) / sizeof(tlds[0]); for (i = 0; i < tld_num; i++) { |