changeset 1035:474b9814a8fa

support CSS @import directive
author Johannes Hofmann <Johannes.Hofmann@gmx.de>
date Wed, 08 Apr 2009 16:33:02 +0200
parents 03ac3106d5ac
children bfda92d18f03
files ChangeLog src/css.cc src/cssparser.cc src/cssparser.hh src/html.cc src/html_common.hh src/styleengine.cc src/styleengine.hh
diffstat 8 files changed, 104 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat Apr 04 04:00:57 2009 +0000
+++ b/ChangeLog	Wed Apr 08 16:33:02 2009 +0200
@@ -78,6 +78,7 @@
  - Load <style></style> content only if applicable.
  - Allow negative values for specific CSS properties only.
  - Disable negative margins for now as dw/* does not support them yet.
+ - Support CSS @import directive.
    Patches: Johannes Hofmann
 +- Updated the GPL copyright note in the source files.
    Patch: Detlef Riekenberg
--- a/src/css.cc	Sat Apr 04 04:00:57 2009 +0000
+++ b/src/css.cc	Wed Apr 08 16:33:02 2009 +0200
@@ -482,7 +482,7 @@
      "th {font-weight: bolder; text-align: center}"
      "code, tt, pre, samp, kbd {font-family: monospace}";
 
-   CssParser::parse (this, cssBuf, strlen (cssBuf), CSS_ORIGIN_USER_AGENT);
+   CssParser::parse (NULL, NULL, this, cssBuf, strlen (cssBuf), CSS_ORIGIN_USER_AGENT);
 }
 
 void CssContext::buildUserStyle () {
@@ -490,7 +490,7 @@
    char *filename = dStrconcat(dGethomedir(), "/.dillo/style.css", NULL);
 
    if ((style = a_Misc_file2dstr(filename))) {
-      CssParser::parse (this, style->str, style->len, CSS_ORIGIN_USER);
+      CssParser::parse (NULL, NULL, this, style->str, style->len, CSS_ORIGIN_USER);
       dStr_free (style, 1);
    }
    dFree (filename);
--- a/src/cssparser.cc	Sat Apr 04 04:00:57 2009 +0000
+++ b/src/cssparser.cc	Wed Apr 08 16:33:02 2009 +0200
@@ -1198,17 +1198,91 @@
       nextToken();
 }
 
+char * CssParser::parseUrl() {
+   Dstr *urlStr = NULL;
+
+   if (ttype != CSS_TK_SYMBOL ||
+      dStrcasecmp(tval, "url") != 0)
+      return NULL;
+
+   nextToken();
+
+   if (ttype != CSS_TK_CHAR || tval[0] != '(')
+      return NULL;
+
+   nextToken();
+
+   if (ttype == CSS_TK_STRING) {
+      urlStr = dStr_new(tval);
+      nextToken();
+   } else {
+      urlStr = dStr_new("");
+      while (ttype != CSS_TK_END &&
+             (ttype != CSS_TK_CHAR || tval[0] != ')')) {
+         dStr_append(urlStr, tval);
+         nextToken();
+      }
+   }
+
+   if (ttype != CSS_TK_CHAR || tval[0] != ')') {
+      dStr_free(urlStr, 1);
+      urlStr = NULL;
+   }
+
+   if (urlStr) {
+      char *url = urlStr->str;
+      dStr_free(urlStr, 0);
+      return url;
+   } else {
+      return NULL;
+   }
+}
+
+void CssParser::parseImport(DilloHtml *html, DilloUrl *baseUrl) {
+   char *urlStr = NULL;
+
+   if (html != NULL &&
+      ttype == CSS_TK_SYMBOL &&
+      dStrcasecmp(tval, "import") == 0) {
+      nextToken();
+
+      if (ttype == CSS_TK_SYMBOL &&
+         dStrcasecmp(tval, "url") == 0)
+         urlStr = parseUrl();
+      else if (ttype == CSS_TK_STRING)
+         urlStr = dStrdup (tval);
+
+      /* Skip all tokens until the expected end. */
+      while (!(ttype == CSS_TK_END ||
+            (ttype == CSS_TK_CHAR && (tval[0] == ';'))))
+         nextToken();
+
+      if (urlStr) {
+         MSG("CssParser::parseImport(): @import %s\n", urlStr);
+         DilloUrl *url = a_Html_url_new (html, urlStr, a_Url_str(baseUrl), baseUrl ? 1 : 0);
+         a_Html_load_stylesheet(html, url);
+         a_Url_free(url);
+         dFree (urlStr);
+      }
+   }
+}
+
 const char * CssParser::propertyNameString(CssPropertyName name)
 {
    return Css_property_info[name].symbol;
 }
 
-void CssParser::parse(CssContext * context,
+void CssParser::parse(DilloHtml *html, DilloUrl *url, CssContext * context,
                       const char *buf,
                       int buflen, CssOrigin origin)
 {
    CssParser parser (context, origin, buf, buflen);
 
+   while (parser.ttype == CSS_TK_CHAR && parser.tval[0] == '@') {
+      parser.nextToken();
+      parser.parseImport(html, url);
+   }
+
    while (parser.ttype != CSS_TK_END)
       parser.parseRuleset();
 }
--- a/src/cssparser.hh	Sat Apr 04 04:00:57 2009 +0000
+++ b/src/cssparser.hh	Wed Apr 08 16:33:02 2009 +0200
@@ -2,6 +2,7 @@
 #define __CSSPARSER_HH__
 
 #include "css.hh"
+#include "html_common.hh"
 
 class CssParser {
    private:
@@ -34,12 +35,14 @@
       void parseDeclaration(CssPropertyList * props,
                             CssPropertyList * importantProps);
       bool parseSimpleSelector(CssSimpleSelector *selector);
+      char *parseUrl();
+      void parseImport(DilloHtml *html, DilloUrl *url);
       CssSelector *parseSelector();
       void parseRuleset();
 
    public:
       static CssPropertyList *parseDeclarationBlock(const char *buf, int buflen);
-      static void parse(CssContext *context, const char *buf, int buflen,
+      static void parse(DilloHtml *html, DilloUrl *url, CssContext *context, const char *buf, int buflen,
                         CssOrigin origin);
       static const char *propertyNameString(CssPropertyName name);
 };
--- a/src/html.cc	Sat Apr 04 04:00:57 2009 +0000
+++ b/src/html.cc	Wed Apr 08 16:33:02 2009 +0200
@@ -110,7 +110,6 @@
                             DilloImage *image);
 static void Html_callback(int Op, CacheClient_t *Client);
 static void Html_tag_cleanup_at_close(DilloHtml *html, int TagIdx);
-static void Html_load_stylesheet(DilloHtml *html, DilloUrl *url);
 
 /*-----------------------------------------------------------------------------
  * Local Data
@@ -1586,7 +1585,7 @@
 
       /* charset is already set, load remote stylesheets now */
       for (int i = 0; i < html->cssUrls->size(); i++) {
-         Html_load_stylesheet(html, html->cssUrls->get(i));
+         a_Html_load_stylesheet(html, html->cssUrls->get(i));
       }
    }
 }
@@ -1670,7 +1669,7 @@
 static void Html_tag_close_style(DilloHtml *html, int TagIdx)
 {
    if (prefs.parse_embedded_css && html->loadCssFromStash)
-      html->styleEngine->parse(html->Stash->str, html->Stash->len,
+      html->styleEngine->parse(html, NULL, html->Stash->str, html->Stash->len,
                                CSS_ORIGIN_AUTHOR);
 }
 
@@ -2868,18 +2867,18 @@
 /*
  * Tell cache to retrieve a stylesheet
  */
-static void Html_load_stylesheet(DilloHtml *html, DilloUrl *url)
+void a_Html_load_stylesheet(DilloHtml *html, DilloUrl *url)
 {
    char *data;
    int len;
 
-   dReturn_if (url == NULL);
+   dReturn_if (url == NULL || ! prefs.load_stylesheets);
 
    _MSG("Html_load_stylesheet: ");
    if (a_Capi_get_buf(url, &data, &len)) {
       _MSG("cached URL=%s len=%d", URL_STR(url), len);
       if (a_Capi_get_flags(url) & CAPI_Completed)
-         html->styleEngine->parse(data, len, CSS_ORIGIN_AUTHOR);
+         html->styleEngine->parse(html, url, data, len, CSS_ORIGIN_AUTHOR);
       a_Capi_unref_buf(url);
    } else {
       /* Fill a Web structure for the cache query */
@@ -2923,7 +2922,6 @@
    }
    /* Remote stylesheets enabled? */
    dReturn_if_fail (prefs.load_stylesheets);
-
    /* CSS stylesheet link */
    if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "rel")) ||
        dStrcasecmp(attrbuf, "stylesheet"))
--- a/src/html_common.hh	Sat Apr 04 04:00:57 2009 +0000
+++ b/src/html_common.hh	Wed Apr 08 16:33:02 2009 +0200
@@ -255,4 +255,6 @@
                                 const char *tag, int tagsize,
                                 CssPropertyList *props);
 
+void a_Html_load_stylesheet(DilloHtml *html, DilloUrl *url);
+
 #endif /* __HTML_COMMON_HH__ */
--- a/src/styleengine.cc	Sat Apr 04 04:00:57 2009 +0000
+++ b/src/styleengine.cc	Wed Apr 08 16:33:02 2009 +0200
@@ -12,6 +12,7 @@
 #include <stdio.h>
 #include <math.h>
 #include "../dlib/dlib.h"
+#include "msg.h"
 #include "prefs.h"
 #include "html_common.hh"
 #include "styleengine.hh"
@@ -26,6 +27,7 @@
    cssContext = new CssContext ();
    this->layout = layout;
    num = 0;
+   importDepth = 0;
 
    stack->increase ();
    Node *n =  stack->getRef (stack->size () - 1);
@@ -561,6 +563,13 @@
    return stack->getRef (stack->size () - 1)->wordStyle;
 }
 
-void StyleEngine::parse (const char *buf, int buflen, CssOrigin origin) {
-   CssParser::parse (cssContext, buf, buflen, origin);
+void StyleEngine::parse (DilloHtml *html, DilloUrl *url, const char *buf, int buflen, CssOrigin origin) {
+   if (importDepth > 10) { // avoid looping with recursive @import directives
+      MSG_WARN("Maximum depth of CSS @import reached - ignoring stylesheet.\n");
+      return;
+   }
+
+   importDepth++;
+   CssParser::parse (html, url, cssContext, buf, buflen, origin);
+   importDepth--;
 }
--- a/src/styleengine.hh	Sat Apr 04 04:00:57 2009 +0000
+++ b/src/styleengine.hh	Wed Apr 08 16:33:02 2009 +0200
@@ -1,6 +1,8 @@
 #ifndef __STYLEENGINE_HH__
 #define __STYLEENGINE_HH__
 
+class StyleEngine;
+
 #include "dw/core.hh"
 #include "doctree.hh"
 #include "css.hh"
@@ -20,6 +22,7 @@
       lout::misc::SimpleVector <Node> *stack;
       CssContext *cssContext;
       int num;
+      int importDepth;
 
       dw::core::style::Style *style0 (CssPropertyList *nonCssHints = NULL);
       dw::core::style::Style *wordStyle0 (CssPropertyList *nonCssHints = NULL);
@@ -46,7 +49,7 @@
             return NULL;
       };
 
-      void parse (const char *buf, int buflen, CssOrigin origin);
+      void parse (DilloHtml *html, DilloUrl *url, const char *buf, int buflen, CssOrigin origin);
       void startElement (int tag);
       void startElement (const char *tagname);
       void setId (const char *id);