changeset 774:c40b6d8a1e79

merge with CSS branch
author Jorge Arellano Cid <jcid@dillo.org>
date Fri, 16 Jan 2009 14:32:20 -0300
parents e06bbc31cb4d (current diff) c1dd6bdfffe0 (diff)
children a0230b2a4a32
files .hgtags
diffstat 69 files changed, 4038 insertions(+), 1624 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Fri Jan 16 14:20:49 2009 -0300
+++ b/.hgtags	Fri Jan 16 14:32:20 2009 -0300
@@ -1,3 +1,4 @@
 009c4cf944331789ae47689d4dbefeb845900fb6 release-2_0
 aa944fb43c5686ad5de0b759011883889df1fee2 start
 96a14e974cfbca56647e2f503698f196a4b614b4 2.1-noCss
+
--- a/ChangeLog	Fri Jan 16 14:20:49 2009 -0300
+++ b/ChangeLog	Fri Jan 16 14:32:20 2009 -0300
@@ -50,7 +50,8 @@
  ? Trying a new iconv() test in configure.in.
  - Allowed the rc parser to skip whitespace around the equal sign.
  - Fixed the parser not to call Html_tag_close_* functions twice.
-!- Started code cleanup of the image code mainly in dicache.c.
+ - Implemented CSS Stylesheet loading.
+ - Made a big cleanup of cache.c WRT charset decoding (fixes bugs).
    Patches: Jorge Arellano Cid
 
 dw
@@ -59,6 +60,8 @@
    Patch: place (AKA corvid)
 +- Cleaned up unused code in fltkviewbase.
    Patch: Johannes Hofmann
++- Added lout/msg.h and normalized debug messages to use it.
+   Patch: Jorge Arellano Cid
 
 -----------------------------------------------------------------------------
 
--- a/dillorc	Fri Jan 16 14:20:49 2009 -0300
+++ b/dillorc	Fri Jan 16 14:32:20 2009 -0300
@@ -18,6 +18,8 @@
 # (there's a toggle button near the bug meter to change this on-the-fly)
 #load_images=YES
 
+# Change this if you want to disable loading of CSS stylesheets.
+#load_stylesheets=YES
 
 # Change the buffering scheme for drawing
 # 0 no double buffering - useful for debugging
--- a/dw/fltkimgbuf.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/dw/fltkimgbuf.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -21,6 +21,7 @@
 
 
 #include "fltkcore.hh"
+#include "../lout/msg.h"
 #include "../lout/misc.hh"
 
 #include <fltk/draw.h>
@@ -35,13 +36,13 @@
 
 FltkImgbuf::FltkImgbuf (Type type, int width, int height)
 {
-   //printf("FltkImgbuf: new root %p\n", this);
+   _MSG("FltkImgbuf: new root %p\n", this);
    init (type, width, height, NULL);
 }
 
 FltkImgbuf::FltkImgbuf (Type type, int width, int height, FltkImgbuf *root)
 {
-   //printf("FltkImgbuf: new scaled %p, root is %p\n", this, root);
+   _MSG("FltkImgbuf: new scaled %p, root is %p\n", this, root);
    init (type, width, height, root);
 }
 
@@ -58,8 +59,7 @@
       case RGB:  bpp = 3; break;
       default:   bpp = 1; break;
    }
-   //fprintf(stderr,"FltkImgbuf::init width=%d height=%d bpp=%d\n",
-   //        width, height, bpp);
+   _MSG("FltkImgbuf::init width=%d height=%d bpp=%d\n", width, height, bpp);
    rawdata = new uchar[bpp * width * height];
    // Set light-gray as interim background color.
    memset(rawdata, 222, width*height*bpp);
@@ -85,12 +85,7 @@
 
 FltkImgbuf::~FltkImgbuf ()
 {
-   //printf ("FltkImgbuf::~FltkImgbuf (%s)\n", isRoot() ? "root" : "scaled");
-
-   //if (root)
-   //   printf("FltkImgbuf[scaled %p, root is %p]: deleted\n", this, root);
-   //else
-   //   printf("FltkImgbuf[root %p]: deleted\n", this);
+   _MSG("~FltkImgbuf[%s %p] deleted\n", isRoot() ? "root":"scaled", this);
 
    if (!isRoot())
       root->detachScaledBuf (this);
@@ -110,8 +105,8 @@
 {
    scaledBuffers->detachRef (scaledBuf);
 
-   //printf("FltkImgbuf[root %p]: scaled buffer %p is detached, %d left\n",
-   //       this, scaledBuf, scaledBuffers->size ());
+   _MSG("FltkImgbuf[root %p]: scaled buffer %p is detached, %d left\n",
+        this, scaledBuf, scaledBuffers->size ());
 
    if (refCount == 0 && scaledBuffers->isEmpty () && deleteOnUnref)
       // If the root buffer is not used anymore, but this is the last scaled
@@ -175,7 +170,7 @@
 
 core::Imgbuf* FltkImgbuf::getScaledBuf (int width, int height)
 {
-   if (root)
+   if (!isRoot())
       return root->getScaledBuf (width, height);
    
    if (width == this->width && height == this->height) {
@@ -207,8 +202,8 @@
       area->y = row;
       area->width = width;
       area->height = 1;
-      //fprintf(stderr,"::getRowArea: area x=%d y=%d width=%d height=%d\n",
-      //        area->x, area->y, area->width, area->height);
+      _MSG("::getRowArea: area x=%d y=%d width=%d height=%d\n",
+           area->x, area->y, area->width, area->height);
    } else {
       // scaled buffer
       int sr1 = scaledY (row);
@@ -218,8 +213,8 @@
       area->y = sr1;
       area->width = width;
       area->height = sr2 - sr1;
-      //fprintf(stderr,"::getRowArea: area x=%d y=%d width=%d height=%d\n",
-      //        area->x, area->y, area->width, area->height);
+      _MSG("::getRowArea: area x=%d y=%d width=%d height=%d\n",
+           area->x, area->y, area->width, area->height);
    }
 }
 
@@ -238,28 +233,30 @@
    refCount++;
 
    //if (root)
-   //   printf("FltkImgbuf[scaled %p, root is %p]: ref() => %d\n",
-   //          this, root, refCount);
+   //   MSG("FltkImgbuf[scaled %p, root is %p]: ref() => %d\n",
+   //        this, root, refCount);
    //else
-   //   printf("FltkImgbuf[root %p]: ref() => %d\n", this, refCount);
+   //   MSG("FltkImgbuf[root %p]: ref() => %d\n", this, refCount);
 }
 
 void FltkImgbuf::unref ()
 {
    //if (root)
-   //   printf("FltkImgbuf[scaled %p, root is %p]: ref() => %d\n",
-   //          this, root, refCount - 1);
+   //   MSG("FltkImgbuf[scaled %p, root is %p]: ref() => %d\n",
+   //       this, root, refCount - 1);
    //else
-   //   printf("FltkImgbuf[root %p]: ref() => %d\n", this, refCount - 1);
+   //   MSG("FltkImgbuf[root %p]: ref() => %d\n", this, refCount - 1);
 
    if (--refCount == 0) {
       if (isRoot ()) {
          // Root buffer, it must be ensured that no scaled buffers are left.
          // See also FltkImgbuf::detachScaledBuf().
-         if (scaledBuffers->isEmpty () && deleteOnUnref)
+         if (scaledBuffers->isEmpty () && deleteOnUnref) {
             delete this;
-         else
-            printf("FltkImgbuf[root %p]: not deleted\n", this);
+         } else {
+            _MSG("FltkImgbuf[root %p]: not deleted. numScaled=%d\n",
+                 this, scaledBuffers->size ());
+         }
       } else
          // Scaled buffer buffer, simply delete it.
          delete this;
@@ -293,29 +290,15 @@
 }
 
 void FltkImgbuf::draw (::fltk::Widget *target, int xRoot, int yRoot,
-                   int x, int y, int width, int height)
+                       int x, int y, int width, int height)
 {
-   // TODO (i):  Implementation.
-   // TODO (ii): Clarify the question, whether "target" is the current widget
-   //            (and so has not to be passed at all).
-
-/*
-   setcolor (0);
+   // TODO: Clarify the question, whether "target" is the current widget
+   //       (and so has not to be passed at all).
 
-   for (int row = y; row < y + height; row++) {
-      if (copiedRows->get (row)) {
-         ::fltk::Rectangle rect (x + xRoot, row + yRoot, width, 1);
-         fillrect (rect);
-      }
-   }
-*/
+   _MSG("::draw: xRoot=%d x=%d yRoot=%d y=%d width=%d height=%d\n"
+        "        this->width=%d this->height=%d\n",
+        xRoot, x, yRoot, y, width, height, this->width, this->height);
 
-   //fprintf(stderr,"::draw: xRoot=%d x=%d yRoot=%d y=%d width=%d height=%d\n"
-   //        "        this->width=%d this->height=%d\n",
-   //        xRoot, x, yRoot, y, width, height, this->width, this->height);
-
-//{
-#if 1
    if (x > this->width || y > this->height) {
       return;
    }
@@ -328,19 +311,10 @@
       height = this->height - y;
    }
 
-   // almost OK for rows. For some unknown reason it trims the bottom and 
-   // rightmost parts when scrolling.
+   // Draw 
    ::fltk::Rectangle rect (xRoot + x, yRoot + y, width, height);
    PixelType ptype = (type == RGBA) ? ::fltk::RGBA : ::fltk::RGB;
    drawimage(rawdata+bpp*(y*this->width + x),ptype,rect,bpp*this->width);
-
-#else
-   // OK for full image.
-   ::fltk::Rectangle rect (xRoot, yRoot, this->width, this->height);
-   PixelType ptype = (type == RGBA) ? ::fltk::RGBA : ::fltk::RGB;
-   drawimage(rawdata,ptype,rect);
-#endif
-//}
 }
 
 } // namespace dw
--- a/dw/fltkplatform.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/dw/fltkplatform.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -25,6 +25,7 @@
 #include <fltk/draw.h>
 #include <fltk/run.h>
 #include <fltk/events.h>
+#include <fltk/Monitor.h>
 #include <fltk/utf.h>
 #include <stdio.h>
 
@@ -54,7 +55,6 @@
 
    font = ::fltk::font(name, fa);
    if(font == NULL) {
-      fprintf(stderr, "No font '%s', using default sans-serif font.\n", name);
       /*
        * If using xft, fltk::HELVETICA just means sans, fltk::COURIER
        * means mono, and fltk::TIMES means serif.
@@ -100,11 +100,9 @@
       new container::typed::HashTable <dw::core::style::ColorAttrs,
                                        FltkColor> (false, false);
 
-FltkColor::FltkColor (int color, core::style::Color::Type type):
-   Color (color, type)
+FltkColor::FltkColor (int color): Color (color)
 {
    this->color = color;
-   this->type = type;
 
    /*
     * fltk/setcolor.cxx:
@@ -122,13 +120,10 @@
       colors[SHADING_NORMAL] = ::fltk::BLACK;
    if (!(colors[SHADING_INVERSE] = shadeColor (color, SHADING_INVERSE) << 8))
       colors[SHADING_INVERSE] = ::fltk::BLACK;
-
-   if(type == core::style::Color::TYPE_SHADED) {
-      if (!(colors[SHADING_DARK] = shadeColor (color, SHADING_DARK) << 8))
-         colors[SHADING_DARK] = ::fltk::BLACK;
-      if (!(colors[SHADING_LIGHT] = shadeColor (color, SHADING_LIGHT) << 8))
-         colors[SHADING_LIGHT] = ::fltk::BLACK;
-   }
+   if (!(colors[SHADING_DARK] = shadeColor (color, SHADING_DARK) << 8))
+      colors[SHADING_DARK] = ::fltk::BLACK;
+   if (!(colors[SHADING_LIGHT] = shadeColor (color, SHADING_LIGHT) << 8))
+      colors[SHADING_LIGHT] = ::fltk::BLACK;
 }
 
 FltkColor::~FltkColor ()
@@ -136,13 +131,13 @@
    colorsTable->remove (this);
 }
 
-FltkColor * FltkColor::create (int col, core::style::Color::Type type)
+FltkColor * FltkColor::create (int col)
 {
-   ColorAttrs attrs(col, type);
+   ColorAttrs attrs(col);
    FltkColor *color = colorsTable->get (&attrs);
 
    if (color == NULL) {
-      color = new FltkColor (col, type);
+      color = new FltkColor (col);
       colorsTable->put (color, color);
    }
 
@@ -302,6 +297,16 @@
    return utf8back (&text[idx - 1], text, &text[strlen (text)]) - text;
 }
 
+float FltkPlatform::dpiX ()
+{
+   return ::fltk::Monitor::all ().dpi_x ();
+}
+
+float FltkPlatform::dpiY ()
+{
+   return ::fltk::Monitor::all ().dpi_y ();
+}
+
 void FltkPlatform::generalStaticIdle (void *data)
 {
    ((FltkPlatform*)data)->generalIdle();
@@ -375,14 +380,9 @@
    return FltkFont::create (attrs);
 }
 
-core::style::Color *FltkPlatform::createSimpleColor (int color)
+core::style::Color *FltkPlatform::createColor (int color)
 {
-   return FltkColor::create (color, core::style::Color::TYPE_SIMPLE);
-}
-
-core::style::Color *FltkPlatform::createShadedColor (int color)
-{
-   return FltkColor::create (color, core::style::Color::TYPE_SHADED);
+   return FltkColor::create (color);
 }
 
 void FltkPlatform::copySelection(const char *text)
--- a/dw/fltkplatform.hh	Fri Jan 16 14:20:49 2009 -0300
+++ b/dw/fltkplatform.hh	Fri Jan 16 14:32:20 2009 -0300
@@ -34,13 +34,13 @@
    static lout::container::typed::HashTable <dw::core::style::ColorAttrs,
                                        FltkColor> *colorsTable;
 
-   FltkColor (int color, core::style::Color::Type type);
+   FltkColor (int color);
    ~FltkColor ();
 
 public:
    int colors[SHADING_NUM];
 
-   static FltkColor *create(int color, core::style::Color::Type type);
+   static FltkColor *create(int color);
 };
 
 
@@ -126,14 +126,15 @@
    int textWidth (core::style::Font *font, const char *text, int len);
    int nextGlyph (const char *text, int idx);
    int prevGlyph (const char *text, int idx);
+   float dpiX ();
+   float dpiY ();
    
    int addIdle (void (core::Layout::*func) ());
    void removeIdle (int idleId);
    
    core::style::Font *createFont (core::style::FontAttrs *attrs,
                                       bool tryEverything);
-   core::style::Color *createSimpleColor (int color);
-   core::style::Color *createShadedColor (int color);
+   core::style::Color *createColor (int color);
    
    core::Imgbuf *createImgbuf (core::Imgbuf::Type type, int width, int height);
 
--- a/dw/fltkui.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/dw/fltkui.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -23,6 +23,7 @@
 #include "fltkcore.hh"
 #include "fltkflatview.hh"
 #include "fltkcomplexbutton.hh"
+#include "../lout/msg.h"
 #include "../lout/misc.hh"
 
 #include <stdio.h>
@@ -120,7 +121,7 @@
       }
    }
 
-   fprintf (stderr, "FltkResource::detachView: View not found.");
+   MSG_WARN("FltkResource::detachView: View not found.");
 }
 
 void FltkResource::sizeAllocate (core::Allocation *allocation)
@@ -444,9 +445,8 @@
       }
    }
 
-   fprintf (stderr,
-            "FltkComplexButtonResourceResource::detachView: View not "
-            "found.\n");
+   MSG_WARN("FltkComplexButtonResourceResource::detachView: "
+            "View not found.\n");
 }
 
 void FltkComplexButtonResource::sizeAllocate (core::Allocation *allocation)
@@ -597,7 +597,7 @@
     * The Back or Forward, buttons, or the first click on a rendered
     * page. BUG: this must be investigated and reported to FLTK2 team
     */
-   printf ("when = %d\n", widget->when ());
+   MSG("when = %d\n", widget->when ());
    if ((widget->when () & ::fltk::WHEN_ENTER_KEY_ALWAYS) &&
        (::fltk::event_key() == ::fltk::ReturnKey))
       ((FltkEntryResource*)data)->emitActivate ();
@@ -648,11 +648,11 @@
 
    // Check values. Upper bound check is left to the caller.
    if (numCols < 1) {
-      fprintf (stderr, "WARNING: numCols = %d is set to 1.\n", numCols);
+      MSG_WARN("numCols = %d is set to 1.\n", numCols);
       numCols = 1;
    }
    if (numRows < 1) {
-      fprintf (stderr, "WARNING: numRows = %d is set to 1.\n", numRows);
+      MSG_WARN("numRows = %d is set to 1.\n", numRows);
       numRows = 1;
    }
 
--- a/dw/fltkviewbase.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/dw/fltkviewbase.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -30,6 +30,7 @@
 #include <fltk/run.h>
 
 #include <stdio.h>
+#include "../lout/msg.h"
 
 using namespace fltk;
 using namespace lout::object;
@@ -203,7 +204,7 @@
                                  translateViewXToCanvasX (event_x ()),
                                  translateViewYToCanvasY (event_y ()),
                                  getDwButtonState (), event_button ());
-      //printf ("PUSH => %s\n", processed ? "true" : "false");
+      _MSG("PUSH => %s\n", processed ? "true" : "false");
       if (processed) {
          /* pressed dw content; give focus to the view */
          ::fltk::focus(this);
@@ -216,7 +217,7 @@
                                    translateViewXToCanvasX (event_x ()),
                                    translateViewYToCanvasY (event_y ()),
                                    getDwButtonState (), event_button ());
-      //printf ("RELEASE => %s\n", processed ? "true" : "false");
+      _MSG("RELEASE => %s\n", processed ? "true" : "false");
       return processed ? true : Group::handle (event);
 
    case MOVE:
@@ -227,7 +228,7 @@
                                   translateViewXToCanvasX (mouse_x),
                                   translateViewYToCanvasY (mouse_y),
                                   getDwButtonState ());
-      //printf ("MOVE => %s\n", processed ? "true" : "false");
+      _MSG("MOVE => %s\n", processed ? "true" : "false");
       return processed ? true : Group::handle (event);
 
    case DRAG:
@@ -236,7 +237,7 @@
                                   translateViewXToCanvasX (event_x ()),
                                   translateViewYToCanvasY (event_y ()),
                                   getDwButtonState ());
-      //printf ("DRAG => %s\n", processed ? "true" : "false");
+      _MSG("DRAG => %s\n", processed ? "true" : "false");
       return processed ? true : Group::handle (event);
 
    case ENTER:
@@ -306,7 +307,7 @@
       "CURSOR_HELP"
    };
 
-   printf ("Cursor changes to '%s'.\n", cursorName[cursor]);
+   MSG("Cursor changes to '%s'.\n", cursorName[cursor]);
    */
 
    /** \bug Does not work */
--- a/dw/fltkviewport.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/dw/fltkviewport.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -27,6 +27,7 @@
 #include <fltk/events.h>
 
 #include <stdio.h>
+#include "../lout/msg.h"
 
 using namespace fltk;
 using namespace lout::object;
@@ -211,7 +212,7 @@
 
 int FltkViewport::handle (int event)
 {
-   //printf("FltkViewport::handle %d\n", event);
+   _MSG("FltkViewport::handle %d\n", event);
 
    if (hscrollbar->Rectangle::contains (event_x (), event_y ()) &&
        !(event_state() & (SHIFT | CTRL | ALT)) &&
--- a/dw/image.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/dw/image.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -21,6 +21,7 @@
 
 
 #include "image.hh"
+#include "../lout/msg.h"
 #include "../lout/misc.hh"
 
 namespace dw {
@@ -197,15 +198,15 @@
    dx = getStyle()->boxDiffWidth ();
    dy = getStyle()->boxDiffHeight ();
 #if 0
-   printf("boxDiffHeight = %d + %d, buffer=%p\n",
-          getStyle()->boxOffsetY(), getStyle()->boxRestHeight(), buffer);
-   printf("getContentWidth() = allocation.width - style->boxDiffWidth ()"
-          " = %d - %d = %d\n",
-          this->allocation.width, getStyle()->boxDiffWidth(),
-          this->allocation.width - getStyle()->boxDiffWidth());
-   printf("getContentHeight() = getHeight() - style->boxDiffHeight ()"
-          " = %d - %d = %d\n", this->getHeight(), getStyle()->boxDiffHeight(),
-          this->getHeight() - getStyle()->boxDiffHeight());
+   MSG("boxDiffHeight = %d + %d, buffer=%p\n",
+       getStyle()->boxOffsetY(), getStyle()->boxRestHeight(), buffer);
+   MSG("getContentWidth() = allocation.width - style->boxDiffWidth ()"
+       " = %d - %d = %d\n",
+       this->allocation.width, getStyle()->boxDiffWidth(),
+       this->allocation.width - getStyle()->boxDiffWidth());
+   MSG("getContentHeight() = getHeight() - style->boxDiffHeight ()"
+       " = %d - %d = %d\n", this->getHeight(), getStyle()->boxDiffHeight(),
+       this->getHeight() - getStyle()->boxDiffHeight());
 #endif
    if (buffer && (getContentWidth () > 0 || getContentHeight () > 0)) {
       // Zero content size : simply wait...
--- a/dw/layout.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/dw/layout.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -22,6 +22,7 @@
 
 #include "core.hh"
 
+#include "../lout/msg.h"
 #include "../lout/debug.hh"
 #include "../lout/misc.hh"
 
@@ -128,7 +129,7 @@
 void Layout::addWidget (Widget *widget)
 {
    if (topLevel) {
-      fprintf (stderr, "widget already set\n");
+      MSG_WARN("widget already set\n");
       return;
    }
 
@@ -261,8 +262,8 @@
                         bool scrollingInterrupted)
 {
    if (usesViewport) {
-      //printf ("scrollTo (%d, %d, %s)\n",
-      //        x, y, scrollingInterrupted ? "true" : "false");
+      _MSG("scrollTo (%d, %d, %s)\n",
+           x, y, scrollingInterrupted ? "true" : "false");
 
       scrollTargetHpos = hpos;
       scrollTargetVpos = vpos;
@@ -353,7 +354,7 @@
       canvasAscent + canvasDescent - (viewportHeight - hScrollbarThickness));
    scrollY = misc::max (scrollY, 0);
 
- //printf("adjustScrollPos: scrollX=%d scrollY=%d\n", scrollX, scrollY);
+   _MSG("adjustScrollPos: scrollX=%d scrollY=%d\n", scrollX, scrollY);
 }
 
 bool Layout::calcScrollInto (int requestedValue, int requestedSize,
@@ -413,7 +414,7 @@
  */
 void Layout::setAnchor (const char *anchor)
 {
-   //printf ("setAnchor (%s)\n", anchor);
+   _MSG("setAnchor (%s)\n", anchor);
 
    if (requestedAnchor)
       delete requestedAnchor;
@@ -523,7 +524,7 @@
 void Layout::resizeIdle ()
 {
    //static int calls = 0;
-   //printf(" Layout::resizeIdle calls = %d\n", ++calls);
+   //MSG(" Layout::resizeIdle calls = %d\n", ++calls);
 
    while (resizeIdleId != -1) {
       // Reset already here, since in this function, queueResize() may be
@@ -739,8 +740,8 @@
  */
 Widget *Layout::getWidgetAtPoint (int x, int y)
 {
-   //_MSG ("------------------------------------------------------------\n");
-   //_MSG ("widget at (%d, %d)\n", x, y);
+   _MSG ("------------------------------------------------------------\n");
+   _MSG ("widget at (%d, %d)\n", x, y);
    if (topLevel)
       return topLevel->getWidgetAtPoint (x, y, 0);
    else
@@ -879,8 +880,8 @@
  */
 void Layout::viewportSizeChanged (View *view, int width, int height)
 {
-   //printf("Layout::viewportSizeChanged w=%d h=%d new_w=%d new_h=%d\n",
-   //       viewportWidth, viewportHeight, width, height);
+   _MSG("Layout::viewportSizeChanged w=%d h=%d new_w=%d new_h=%d\n",
+        viewportWidth, viewportHeight, width, height);
 
    /* If the width has become higher, we test again, whether the vertical
     * scrollbar (so to speak) can be hidden again. */
--- a/dw/layout.hh	Fri Jan 16 14:20:49 2009 -0300
+++ b/dw/layout.hh	Fri Jan 16 14:32:20 2009 -0300
@@ -216,19 +216,24 @@
       return platform->prevGlyph (text, idx);
    }
 
+   inline float dpiX ()
+   {
+      return platform->dpiX ();
+   }
+
+   inline float dpiY ()
+   {
+      return platform->dpiY ();
+   }
+
    inline style::Font *createFont (style::FontAttrs *attrs, bool tryEverything)
    {
       return  platform->createFont (attrs, tryEverything);
    }
 
-   inline style::Color *createSimpleColor (int color)
+   inline style::Color *createColor (int color)
    {
-      return platform->createSimpleColor (color);
-   }
-
-   inline style::Color *createShadedColor (int color)
-   {
-      return platform->createShadedColor (color);
+      return platform->createColor (color);
    }
 
    inline Imgbuf *createImgbuf (Imgbuf::Type type, int width, int height)
--- a/dw/platform.hh	Fri Jan 16 14:20:49 2009 -0300
+++ b/dw/platform.hh	Fri Jan 16 14:32:20 2009 -0300
@@ -66,6 +66,16 @@
     * \brief Return the index of the previous glyph in string text.
     */
    virtual int prevGlyph (const char *text, int idx) = 0;
+
+   /**
+    * \brief Return screen resolution in x-direction.
+    */
+   virtual float dpiX () = 0;
+
+   /**
+    * \brief Return screen resolution in y-direction.
+    */
+   virtual float dpiY () = 0;
  
    /*
     * ---------------------------------------------------------
@@ -110,15 +120,9 @@
                                     bool tryEverything) = 0;
  
    /**
-    * \brief Create a simple color resource for a given 0xrrggbb value.
+    * \brief Create a color resource for a given 0xrrggbb value.
     */
-   virtual style::Color *createSimpleColor (int color) = 0;
-
-   /**
-    * \brief Create a shaded color resource for a given 0xrrggbb value.
-    */
-   virtual style::Color *createShadedColor (int color) = 0;
-
+   virtual style::Color *createColor (int color) = 0;
 
    /*
     * --------------------
--- a/dw/style.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/dw/style.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -26,6 +26,7 @@
 #include <ctype.h>
 
 #include "core.hh"
+#include "../lout/msg.h"
 
 namespace dw {
 namespace core {
@@ -64,11 +65,9 @@
  */
 void StyleAttrs::resetValues ()
 {
-   x_link = -1;
    x_img = -1;
    x_tooltip = NULL;
 
-   textAlign = TEXT_ALIGN_LEFT; /* ??? */
    valign = VALIGN_MIDDLE;
    textAlignChar = '.';
    backgroundColor = NULL;
@@ -84,8 +83,6 @@
    vBorderSpacing = 0;
 
    display = DISPLAY_INLINE;
-   whiteSpace = WHITE_SPACE_NORMAL;
-   cursor = CURSOR_DEFAULT; /** \todo Check CSS specification again. */
 }
 
 /**
@@ -328,7 +325,7 @@
    }
 
    if (font == NULL)
-      fprintf (stderr, "Could not find any font.\n");
+      MSG_WARN("Could not find any font.\n");
 
    return font;
 }
@@ -338,12 +335,12 @@
 bool ColorAttrs::equals(object::Object *other)
 {
    ColorAttrs *oc = (ColorAttrs*)other;
-   return this == oc || (color == oc->color && type == oc->type);
+   return this == oc || (color == oc->color);
 }
 
 int ColorAttrs::hashValue()
 {
-   return color ^ type;
+   return color;
 }
 
 Color::~Color ()
@@ -407,21 +404,11 @@
 }
 
   
-Color *Color::create (Layout *layout, int col, Type type)
+Color *Color::create (Layout *layout, int col)
 {
-   ColorAttrs attrs(col, type);
-   Color *color = NULL;
+   ColorAttrs attrs(col);
 
-   switch (type) {
-      case TYPE_SIMPLE:
-         color = layout->createSimpleColor (col);
-         break;
-      case TYPE_SHADED:
-         color = layout->createShadedColor (col);
-         break;
-   }
-
-   return color;
+   return layout->createColor (col);
 }
 
 // ----------------------------------------------------------------------
@@ -464,11 +451,10 @@
             points[3][1] = y1 + width;
          }
 
-         /*
-         printf ("drawPolygon: (%d, %d) .. (%d, %d) .. (%d, %d) .. (%d, %d)\n",
-                 points[0][0], points[0][1], points[1][0], points[1][1],
-                 points[2][0], points[2][1], points[3][0], points[3][1]);
-         */
+         _MSG("drawPolygon: (%d, %d) .. (%d, %d) .. (%d, %d) .. (%d, %d)\n",
+              points[0][0], points[0][1], points[1][0], points[1][1],
+              points[2][0], points[2][1], points[3][0], points[3][1]);
+
          view->drawPolygon (color, shading, true, points, 4);
       }
    }
@@ -488,9 +474,6 @@
    Color::Shading top, right, bottom, left;
    int xb1, yb1, xb2, yb2, xp1, yp1, xp2, yp2;
 
-   if (style->borderStyle.top == BORDER_NONE)
-      return;
-
    xb1 = x + style->margin.left;
    yb1 = y + style->margin.top;
    xb2 = xb1 + width - style->margin.left - style->margin.right;
@@ -521,18 +504,25 @@
       break;
    }
 
-   drawPolygon (view, style->borderColor.top, top, xb1, yb1, xb2, yb1,
-                style->borderWidth.top, style->borderWidth.left,
-                - style->borderWidth.right);
-   drawPolygon (view, style->borderColor.right, right, xb2, yb1, xb2, yb2,
-                - style->borderWidth.right, style->borderWidth.top,
-                - style->borderWidth.bottom);
-   drawPolygon (view, style->borderColor.bottom, bottom, xb1, yb2, xb2, yb2,
-                - style->borderWidth.bottom, style->borderWidth.left,
-                - style->borderWidth.right);
-   drawPolygon (view, style->borderColor.left, left, xb1, yb1, xb1, yb2,
-                style->borderWidth.left, style->borderWidth.top,
-                - style->borderWidth.bottom);
+   if (style->borderStyle.top != BORDER_NONE && style->borderColor.top)
+      drawPolygon (view, style->borderColor.top, top, xb1, yb1, xb2, yb1,
+                   style->borderWidth.top, style->borderWidth.left,
+                   - style->borderWidth.right);
+
+   if (style->borderStyle.right != BORDER_NONE && style->borderColor.right)
+      drawPolygon (view, style->borderColor.right, right, xb2, yb1, xb2, yb2,
+                   - style->borderWidth.right, style->borderWidth.top,
+                   - style->borderWidth.bottom);
+
+   if (style->borderStyle.bottom != BORDER_NONE && style->borderColor.bottom)
+      drawPolygon (view, style->borderColor.bottom, bottom, xb1, yb2, xb2, yb2,
+                   - style->borderWidth.bottom, style->borderWidth.left,
+                   - style->borderWidth.right);
+
+   if (style->borderStyle.left != BORDER_NONE && style->borderColor.left)
+      drawPolygon (view, style->borderColor.left, left, xb1, yb1, xb1, yb2,
+                   style->borderWidth.left, style->borderWidth.top,
+                   - style->borderWidth.bottom);
 }
 
 
--- a/dw/style.hh	Fri Jan 16 14:20:49 2009 -0300
+++ b/dw/style.hh	Fri Jan 16 14:32:20 2009 -0300
@@ -591,22 +591,16 @@
  */
 class ColorAttrs: public object::Object
 {
-public:
-   enum Type { TYPE_SIMPLE, TYPE_SHADED };
-
 protected:
    int color;
-   Type type;
 
 public:
-   inline ColorAttrs(int color, Type type)
+   inline ColorAttrs(int color)
    {
       this->color = color;
-      this->type = type;
    }
 
    inline int getColor () { return color; }
-   inline Type getType () { return type; }
 
    bool equals(object::Object *other);
    int hashValue();
@@ -621,12 +615,11 @@
 private:
    int refCount;
 
-   static Color *create (Layout *layout, int color, Type type);
    void remove(dw::core::Layout *layout);
-    int shadeColor (int color, int d);
+   int shadeColor (int color, int d);
 
 protected:
-   inline Color (int color, Type type): ColorAttrs (color, type) {
+   inline Color (int color): ColorAttrs (color) {
       refCount = 0; }
    virtual ~Color ();
 
@@ -638,15 +631,7 @@
    int shadeColor (int color, Shading shading);
 
 public:
-   inline static Color *createSimple (Layout *layout, int color)
-   {
-      return create (layout, color, TYPE_SIMPLE);
-   }
-
-   inline static Color *createShaded (Layout *layout, int color)
-   {
-      return create (layout, color, TYPE_SHADED);
-   }
+   static Color *create (Layout *layout, int color);
 
    inline void ref () { refCount++; }
    inline void unref ()
--- a/dw/table.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/dw/table.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -21,6 +21,7 @@
 //#define DBG
 
 #include "table.hh"
+#include "../lout/msg.h"
 #include "../lout/misc.hh"
 
 #define MAX misc::max
@@ -141,10 +142,8 @@
               core::style::absLengthVal(getStyle()->width));
    }
 
-#ifdef DBG
-   printf(" Table::getExtremesImpl, {%d, %d} numCols=%d\n",
-          extremes->minWidth, extremes->maxWidth, numCols);
-#endif
+   _MSG(" Table::getExtremesImpl, {%d, %d} numCols=%d\n",
+       extremes->minWidth, extremes->maxWidth, numCols);
 }
 
 void Table::sizeAllocateImpl (core::Allocation *allocation)
@@ -203,9 +202,7 @@
 {  
    // If limitTextWidth is set, a queueResize may also be necessary.
    if (availWidth != width || limitTextWidth) {
-#ifdef DBG
-      printf(" Table::setWidth %d\n", width);
-#endif
+      _MSG(" Table::setWidth %d\n", width);
       availWidth = width;
       queueResize (0, false);
    }
@@ -277,22 +274,22 @@
    // We limit the values for colspan and rowspan to 50, to avoid
    // attacks by malicious web pages.
    if (colspan > 50 || colspan < 0) {
-      fprintf (stderr, "WARNING: colspan = %d is set to 50.\n", colspan);
+      MSG_WARN("colspan = %d is set to 50.\n", colspan);
       colspan = 50;
    }
    if (rowspan > 50 || rowspan <= 0) {
-      fprintf (stderr, "WARNING: rowspan = %d is set to 50.\n", rowspan);
+      MSG_WARN("rowspan = %d is set to 50.\n", rowspan);
       rowspan = 50;
    }
 
    if (numRows == 0) {
       // to prevent a crash
-      fprintf (stderr, "WARNING: Cell without row.\n");
+      MSG_WARN("Cell without row.\n");
       addRow (NULL);
    }
 
    if (rowClosed) {
-      fprintf (stderr, "WARNING: Last cell had colspan=0.\n");
+      MSG_WARN("Last cell had colspan=0.\n");
       addRow (NULL);
    }
 
@@ -308,10 +305,9 @@
           child->type == Child::SPAN_SPACE)
       curCol++;
 
-#ifdef DBG
-   printf("Table::addCell numCols=%d,curCol=%d,colspan=%d,colspanEff=%d\n",
-          numCols, curCol, colspan, colspanEff);
-#endif
+   _MSG("Table::addCell numCols=%d,curCol=%d,colspan=%d,colspanEff=%d\n",
+       numCols, curCol, colspan, colspanEff);
+
    // Increase children array, when necessary.
    if (curRow + rowspan > numRows)
       reallocChildren (numCols, curRow + rowspan);
@@ -351,18 +347,18 @@
       for (int col = 0; col < numCols; col++) {
          int n = row * numCols + col;
          if (!(child = children->get (n))) {
-            printf("[null     ] ");
+            MSG("[null     ] ");
          } else if (children->get(n)->type == Child::CELL) {
-            printf("[CELL rs=%d] ", child->cell.rowspan);
+            MSG("[CELL rs=%d] ", child->cell.rowspan);
          } else if (children->get(n)->type == Child::SPAN_SPACE) {
-            printf("[SPAN rs=%d] ", child->cell.rowspan);
+            MSG("[SPAN rs=%d] ", child->cell.rowspan);
          } else {
-            printf("[Unk.     ] ");
+            MSG("[Unk.     ] ");
          }
       }
-      printf("\n");
+      MSG("\n");
    }
-   printf("\n");
+   MSG("\n");
 #endif
 }
 
@@ -503,28 +499,28 @@
       totalWidth = availWidth;
       forceTotalWidth = 0;
    }
-#ifdef DBG
-   printf(" availWidth = %d\n", availWidth);
-   printf(" totalWidth1 = %d\n", totalWidth);
-#endif
+
+   _MSG(" availWidth = %d\n", availWidth);
+   _MSG(" totalWidth1 = %d\n", totalWidth);
+
    if (totalWidth < extremes.minWidth)
       totalWidth = extremes.minWidth;
    totalWidth = totalWidth
                 - (numCols + 1) * getStyle()->hBorderSpacing
                 - getStyle()->boxDiffWidth ();
-#ifdef DBG
-   printf(" totalWidth2 = %d curCol=%d\n", totalWidth,curCol);
-#endif
+
+   _MSG(" totalWidth2 = %d curCol=%d\n", totalWidth,curCol);
+
 
    colWidths->setSize (numCols, 0);
    cumHeight->setSize (numRows + 1, 0);
    rowSpanCells->setSize (0);
    baseline->setSize (numRows);
-#ifdef DBG
-   printf(" extremes = %d,%d\n", extremes.minWidth, extremes.maxWidth);
-   printf(" getStyle()->boxDiffWidth() = %d\n", getStyle()->boxDiffWidth());
-   printf(" getStyle()->hBorderSpacing = %d\n", getStyle()->hBorderSpacing);
-#endif
+
+   _MSG(" extremes = %d,%d\n", extremes.minWidth, extremes.maxWidth);
+   _MSG(" getStyle()->boxDiffWidth() = %d\n", getStyle()->boxDiffWidth());
+   _MSG(" getStyle()->hBorderSpacing = %d\n", getStyle()->hBorderSpacing);
+
 
    apportion_percentages2 (totalWidth, forceTotalWidth);
    if (!hasColPercent)
@@ -583,10 +579,9 @@
          continue;
 
       // Cell size is too small.
-#ifdef DBG
-      printf("Short cell %d, sumRows=%d spanHeight=%d\n",
-             n,sumRows,spanHeight);
-#endif
+      _MSG("Short cell %d, sumRows=%d spanHeight=%d\n",
+          n,sumRows,spanHeight);
+
       // Fill height array
       if (!rowHeight) {
          rowHeight = new int[numRows];
@@ -594,10 +589,10 @@
             rowHeight[i] = cumHeight->get(i+1) - cumHeight->get(i);
       }
 #ifdef DBG
-      printf (" rowHeight { ");
+      MSG(" rowHeight { ");
       for (int i = 0; i < numRows; i++)
-         printf ("%d ", rowHeight[i]);
-      printf ("}\n");
+         MSG("%d ", rowHeight[i]);
+      MSG("}\n");
 #endif
 
       // Calc new row sizes for this span.
@@ -607,12 +602,12 @@
             sumRows == 0 ? (int)((float)(spanHeight-cumHnew_i)/(row+rs-i)) :
             (sumRows-cumh_i) <= 0 ? 0 :
             (int)((float)(spanHeight-cumHnew_i)*rowHeight[i]/(sumRows-cumh_i));
-#ifdef DBG
-         printf (" i=%-3d h=%d hnew_i=%d =%d*%d/%d   cumh_i=%d cumHnew_i=%d\n",
-                 i,rowHeight[i],hnew_i,
-                 spanHeight-cumHnew_i,rowHeight[i],sumRows-cumh_i,
-                 cumh_i, cumHnew_i);
-#endif
+
+         _MSG(" i=%-3d h=%d hnew_i=%d =%d*%d/%d   cumh_i=%d cumHnew_i=%d\n",
+             i,rowHeight[i],hnew_i,
+             spanHeight-cumHnew_i,rowHeight[i],sumRows-cumh_i,
+             cumh_i, cumHnew_i);
+
          cumHnew_i += hnew_i;
          cumh_i += rowHeight[i];
          rowHeight[i] = hnew_i;
@@ -642,9 +637,8 @@
  */
 void Table::forceCalcColumnExtremes ()
 {
-#ifdef DBG
-   printf("  Table::forceCalcColumnExtremes  numCols=%d\n", numCols);
-#endif
+   _MSG("  Table::forceCalcColumnExtremes  numCols=%d\n", numCols);
+
    if (numCols == 0)
       return;
 
@@ -678,13 +672,13 @@
                cellMinW = cellExtremes.minWidth;
                cellMaxW = cellExtremes.maxWidth;
             }
-#ifdef DBG
-            printf("FCCE, col%d colMin,colMax,cellMin,cellMax = %d,%d,%d,%d\n",
-                   col,
-                   colExtremes->getRef(col)->minWidth,
-                   colExtremes->getRef(col)->maxWidth,
-                   cellMinW, cellMaxW);
-#endif
+
+            _MSG("FCCE, col%d colMin,colMax,cellMin,cellMax = %d,%d,%d,%d\n",
+                col,
+                colExtremes->getRef(col)->minWidth,
+                colExtremes->getRef(col)->maxWidth,
+                cellMinW, cellMaxW);
+
             colExtremes->getRef(col)->minWidth =
                MAX (colExtremes->getRef(col)->minWidth, cellMinW);
             colExtremes->getRef(col)->maxWidth =
@@ -737,10 +731,10 @@
          minSumCols += colExtremes->getRef(col+i)->minWidth;
          maxSumCols += colExtremes->getRef(col+i)->maxWidth;
       }
-#ifdef DBG
-      printf("cs=%d spanWidth=%d,%d sumCols=%d,%d\n",
-              cs,cellMinW,cellMaxW,minSumCols,maxSumCols);
-#endif
+
+      _MSG("cs=%d spanWidth=%d,%d sumCols=%d,%d\n",
+          cs,cellMinW,cellMaxW,minSumCols,maxSumCols);
+
       if (minSumCols >= cellMinW && maxSumCols >= cellMaxW)
          continue;
 
@@ -785,7 +779,7 @@
             int d_a = colExtremes->getRef(i)->maxWidth;
             int d_w = curAppW > 0 ? (int)((float)curExtraW * d_a/curAppW) : 0;
             if (d_a < 0||d_w < 0) {
-               printf("d_a=%d d_w=%d\n",d_a,d_w);
+               MSG("d_a=%d d_w=%d\n",d_a,d_w);
                exit(1);
             }
             wMin = colExtremes->getRef(i)->minWidth + d_w;
@@ -809,19 +803,19 @@
          cumMaxWnew += wMax;
          cumMaxWold += colExtremes->getRef(i)->maxWidth;
          colExtremes->getRef(i)->maxWidth = wMax;
-#ifdef DBG
-         printf ("i=%d, wMin=%d wMax=%d cumMaxWold=%d\n",
-                  i,wMin,wMax,cumMaxWold);
-#endif
+
+         _MSG("i=%d, wMin=%d wMax=%d cumMaxWold=%d\n",
+             i,wMin,wMax,cumMaxWold);
+
       }
 #ifdef DBG
-      printf ("col min,max: [");
+      MSG("col min,max: [");
       for (int i = 0; i < numCols; i++)
-         printf ("%d,%d ", 
-                 colExtremes->getRef(i)->minWidth,
-                 colExtremes->getRef(i)->maxWidth);
-      printf ("]\n");
-      printf ("getStyle()->hBorderSpacing = %d\n", getStyle()->hBorderSpacing);
+         MSG("%d,%d ",
+             colExtremes->getRef(i)->minWidth,
+             colExtremes->getRef(i)->maxWidth);
+      MSG("]\n");
+      MSG("getStyle()->hBorderSpacing = %d\n", getStyle()->hBorderSpacing);
 #endif
    }
 }
@@ -835,13 +829,13 @@
    if (colExtremes->size() == 0)
       return;
 #ifdef DBG
-   printf("app2, availWidth=%d, totalWidth=%d, forceTotalWidth=%d\n",
-          availWidth, totalWidth, forceTotalWidth);
-   printf("app2, extremes: ( ");
+   MSG("app2, availWidth=%d, totalWidth=%d, forceTotalWidth=%d\n",
+       availWidth, totalWidth, forceTotalWidth);
+   MSG("app2, extremes: ( ");
    for (int i = 0; i < colExtremes->size (); i++)
-      printf("%d,%d ",
-             colExtremes->get(i).minWidth, colExtremes->get(i).maxWidth);
-   printf(")\n");
+      MSG("%d,%d ",
+          colExtremes->get(i).minWidth, colExtremes->get(i).maxWidth);
+   MSG(")\n");
 #endif
    int minAutoWidth = 0, maxAutoWidth = 0, availAutoWidth = totalWidth;
    for (int col = 0; col < numCols; col++) {
@@ -871,10 +865,9 @@
    int curMaxWidth = maxAutoWidth;
    int curNewWidth = minAutoWidth;
    for (int col = 0; col < numCols; col++) {
-#ifdef DBG
-      printf("app2, col %d, minWidth=%d maxWidth=%d\n",
-             col,extremes->get(col).minWidth, colExtremes->get(col).maxWidth);
-#endif
+      _MSG("app2, col %d, minWidth=%d maxWidth=%d\n",
+          col,extremes->get(col).minWidth, colExtremes->get(col).maxWidth);
+
       if (colPercents->get(col) != LEN_AUTO)
          continue;
 
@@ -882,19 +875,19 @@
       int colMaxWidth = colExtremes->getRef(col)->maxWidth;
       int w = (curMaxWidth <= 0) ? 0 :
                  (int)((float)curTargetWidth * colMaxWidth/curMaxWidth);
-#ifdef DBG
-      printf("app2, curTargetWidth=%d colMaxWidth=%d curMaxWidth=%d "
-             "curNewWidth=%d  ",
-             curTargetWidth, colMaxWidth,curMaxWidth,curNewWidth);
-      printf("w = %d, ", w);
-#endif
+
+      _MSG("app2, curTargetWidth=%d colMaxWidth=%d curMaxWidth=%d "
+          "curNewWidth=%d  ",
+          curTargetWidth, colMaxWidth,curMaxWidth,curNewWidth);
+      _MSG("w = %d, ", w);
+
       if (w <= colMinWidth)
          w = colMinWidth;
       else if (curNewWidth - colMinWidth + w > curTargetWidth)
          w = colMinWidth + curExtraWidth;
-#ifdef DBG
-      printf("w = %d\n", w);
-#endif
+
+      _MSG("w = %d\n", w);
+
       curNewWidth -= colMinWidth;
       curMaxWidth -= colMaxWidth;
       curExtraWidth -= (w - colMinWidth);
@@ -902,10 +895,10 @@
       setColWidth (col, w);
    }
 #ifdef DBG
-   printf("app2, result: ( ");
+   MSG("app2, result: ( ");
    for (int i = 0; i < colWidths->size (); i++)
-      printf("%d ", colWidths->get (i));
-   printf(")\n");
+      MSG("%d ", colWidths->get (i));
+   MSG(")\n");
 #endif
 }
 
@@ -917,19 +910,17 @@
       return;
 
    // If there's a table-wide percentage, totalWidth comes already scaled.
-#ifdef DBG
-   printf("APP_P, availWidth=%d, totalWidth=%d, forceTotalWidth=%d\n",
-          availWidth, totalWidth, forceTotalWidth);
-#endif
+   _MSG("APP_P, availWidth=%d, totalWidth=%d, forceTotalWidth=%d\n",
+       availWidth, totalWidth, forceTotalWidth);
 
    if (!hasColPercent) {
 #ifdef DBG
-      printf("APP_P, only a table-wide percentage\n");
-      printf("APP_P, extremes = { ");
+      MSG("APP_P, only a table-wide percentage\n");
+      MSG("APP_P, extremes = { ");
       for (int col = 0; col < numCols; col++)
-         printf("%d,%d ", colExtremes->getRef(col)->minWidth,
-                          colExtremes->getRef(col)->maxWidth);
-      printf("}\n");
+         MSG("%d,%d ", colExtremes->getRef(col)->minWidth,
+                       colExtremes->getRef(col)->maxWidth);
+      MSG("}\n");
 #endif
       // It has only a table-wide percentage. Apportion non-absolute widths.
       int sumMaxWidth = 0, perAvailWidth = totalWidth;
@@ -939,10 +930,10 @@
          else
             sumMaxWidth += colExtremes->getRef(col)->maxWidth;
       }
-#ifdef DBG
-      printf("APP_P, perAvailWidth=%d, sumMaxWidth=%d\n",
-             perAvailWidth, sumMaxWidth);
-#endif
+
+      _MSG("APP_P, perAvailWidth=%d, sumMaxWidth=%d\n",
+          perAvailWidth, sumMaxWidth);
+
       for (int col = 0; col < numCols; col++) {
          int max_wi = colExtremes->getRef(col)->maxWidth, new_wi;
          if (colPercents->get(col) != LEN_ABS) {
@@ -954,17 +945,16 @@
          }
       }
 #ifdef DBG
-      printf("APP_P, result = { ");
+      MSG("APP_P, result = { ");
       for (int col = 0; col < numCols; col++)
-         printf("%d ", result->get(col));
-      printf("}\n");
+         MSG("%d ", result->get(col));
+      MSG("}\n");
 #endif
 
    } else {
       // we'll have to apportion...
-#ifdef DBG
-      printf("APP_P, we'll have to apportion...\n");
-#endif
+      _MSG("APP_P, we'll have to apportion...\n");
+
       // Calculate cumPercent and available space
       float cumPercent = 0.0f;
       int hasAutoCol = 0;
@@ -979,11 +969,10 @@
          }
          sumMinWidth += colExtremes->getRef(col)->minWidth;
          sumMaxWidth += colExtremes->getRef(col)->maxWidth;
-#ifdef DBG
-         printf("APP_P, col %d minWidth=%d maxWidth=%d\n", col,
-                colExtremes->getRef(col)->minWidth,
-                colExtremes->getRef(col)->maxWidth);
-#endif
+
+         _MSG("APP_P, col %d minWidth=%d maxWidth=%d\n", col,
+             colExtremes->getRef(col)->minWidth,
+             colExtremes->getRef(col)->maxWidth);
       }
       int oldTotalWidth = totalWidth;
       if (!forceTotalWidth) {
@@ -1011,11 +1000,11 @@
          workingWidth = totalWidth;
          curPerWidth = sumMinWidth;
       }
-#ifdef DBG
-      printf("APP_P, oldTotalWidth=%d totalWidth=%d"
-             " workingWidth=%d extraWidth=%d sumMinNonPer=%d\n",
-             oldTotalWidth,totalWidth,workingWidth,extraWidth,sumMinNonPer);
-#endif
+
+      _MSG("APP_P, oldTotalWidth=%d totalWidth=%d"
+          " workingWidth=%d extraWidth=%d sumMinNonPer=%d\n",
+          oldTotalWidth,totalWidth,workingWidth,extraWidth,sumMinNonPer);
+
       for (int col = 0; col < numCols; col++) {
          int colMinWidth = colExtremes->getRef(col)->minWidth;
          if (colPercents->get(col) >= 0.0f) {
@@ -1035,20 +1024,20 @@
       if (cumPercent < 0.99f) {
          // Will have to apportion the other columns
 #ifdef DBG
-         printf("APP_P, extremes: ( ");
+         MSG("APP_P, extremes: ( ");
          for (int i = 0; i < colExtremes->size (); i++)
-            printf("%d,%d ",
-                   colExtremes->get(i).minWidth, colExtremes->get(i).maxWidth);
-         printf(")\n");
+            MSG("%d,%d ",
+                colExtremes->get(i).minWidth, colExtremes->get(i).maxWidth);
+         MSG(")\n");
 #endif
          curPerWidth -= sumMinNonPer;
          int perWidth = (int)(curPerWidth/cumPercent);
          totalWidth = MAX (totalWidth, perWidth);
          totalWidth = misc::min (totalWidth, oldTotalWidth);
-#ifdef DBG
-         printf("APP_P, curPerWidth=%d perWidth=%d, totalWidth=%d\n",
-                curPerWidth, perWidth, totalWidth);
-#endif
+
+         _MSG("APP_P, curPerWidth=%d perWidth=%d, totalWidth=%d\n",
+             curPerWidth, perWidth, totalWidth);
+
          if (hasAutoCol == 0) {
             // Special case, cumPercent < 100% and no other columns to expand.
             // We'll honor totalWidth by expanding the percentage cols.
@@ -1062,22 +1051,22 @@
          }
       }
 #ifdef DBG
-      printf("APP_P, result ={ ");
+      MSG("APP_P, result ={ ");
       for (int col = 0; col < numCols; col++)
-         printf("%d ", colWidths->get(col));
-      printf("}\n");
+         MSG("%d ", colWidths->get(col));
+      MSG("}\n");
 #endif
       apportion2 (totalWidth, 2);
 
 #ifdef DBG
-      printf("APP_P, percent={");
+      MSG("APP_P, percent={");
       for (int col = 0; col < numCols; col++)
-         printf("%f ", colPercents->get(col));
-      printf("}\n");
-      printf("APP_P, result ={ ");
+         MSG("%f ", colPercents->get(col));
+      MSG("}\n");
+      MSG("APP_P, result ={ ");
       for (int col = 0; col < numCols; col++)
-         printf("%d ", colWidths->get(col));
-      printf("}\n");
+         MSG("%d ", colWidths->get(col));
+      MSG("}\n");
 #endif
    }
 }
--- a/dw/textblock.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/dw/textblock.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -21,6 +21,7 @@
 
 
 #include "textblock.hh"
+#include "../lout/msg.h"
 #include "../lout/misc.hh"
 
 #include <stdio.h>
@@ -260,8 +261,8 @@
                   extremes->minWidth = wordExtremes.minWidth;
             }
 
-            //printf("parMax = %d, wordMaxWidth=%d, prevWordSpace=%d\n",
-            //       parMax, wordExtremes.maxWidth, prevWordSpace);
+            _MSG("parMax = %d, wordMaxWidth=%d, prevWordSpace=%d\n",
+                 parMax, wordExtremes.maxWidth, prevWordSpace);
             if (word->content.type != core::Content::BREAK)
                parMax += prevWordSpace;
             parMax += wordExtremes.maxWidth;
@@ -1077,8 +1078,8 @@
       widget->setAscent (availAscent);
       widget->setDescent (availDescent);
       widget->sizeRequest (size);
-      size->ascent -= widget->getStyle()->margin.top;
-      size->descent -= widget->getStyle()->margin.bottom;
+//      size->ascent -= widget->getStyle()->margin.top;
+//      size->descent -= widget->getStyle()->margin.bottom;
    } else {
       /* TODO: Use margin.{top|bottom} here, like above.
        * (No harm for the next future.) */
@@ -1417,7 +1418,7 @@
          break;
 
       default:
-         fprintf (stderr,  "BUG!!! at (%d, %d).\n", xWorld, yWorldBase + diff);
+         MSG_ERR("at (%d, %d).\n", xWorld, yWorldBase + diff);
          break;
       }
 
@@ -1921,14 +1922,14 @@
             case core::Content::TEXT:
             {  core::style::Style *old_style = word->style;
                styleAttrs = *old_style;
-               styleAttrs.color = core::style::Color::createSimple (layout,
-                                                                    newColor);
+               styleAttrs.color = core::style::Color::create (layout,
+                                                              newColor);
                word->style = core::style::Style::create (layout, &styleAttrs);
                old_style->unref();
                old_style = word->spaceStyle;
                styleAttrs = *old_style;
-               styleAttrs.color = core::style::Color::createSimple (layout,
-                                                                    newColor);
+               styleAttrs.color = core::style::Color::create (layout,
+                                                              newColor);
                word->spaceStyle =
                                core::style::Style::create(layout, &styleAttrs);
                old_style->unref();
@@ -1937,10 +1938,10 @@
             case core::Content::WIDGET:
             {  core::Widget *widget = word->content.widget;
                styleAttrs = *widget->getStyle();
-               styleAttrs.color = core::style::Color::createSimple (layout,
-                                                                    newColor);
+               styleAttrs.color = core::style::Color::create (layout,
+                                                              newColor);
                styleAttrs.setBorderColor(
-                           core::style::Color::createShaded(layout, newColor));
+                           core::style::Color::create (layout, newColor));
                widget->setStyle(
                              core::style::Style::create (layout, &styleAttrs));
                break;
--- a/dw/types.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/dw/types.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -21,6 +21,7 @@
 
 
 #include "core.hh"
+#include "../lout/msg.h"
 
 namespace dw {
 namespace core {
@@ -180,8 +181,8 @@
    bool cross =
       linesCross0 (ax1, ay1, ax2, ay2, bx1, by1, bx2, by2) &&
       linesCross0 (bx1, by1, bx2, by2, ax1, ay1, ax2, ay2);
-   //printf ("(%d, %d) - (%d, %d) and (%d, %d) - (%d, %d) cross? %s.\n",
-   //        ax1, ay1, ax2, ay2, bx1, by1, bx2, by2, cross ? "Yes" : "No");
+   _MSG("(%d, %d) - (%d, %d) and (%d, %d) - (%d, %d) cross? %s.\n",
+        ax1, ay1, ax2, ay2, bx1, by1, bx2, by2, cross ? "Yes" : "No");
    return cross;
 }
 
--- a/dw/widget.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/dw/widget.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -22,6 +22,7 @@
 
 #include "core.hh"
 
+#include "../lout/msg.h"
 #include "../lout/debug.hh"
 
 using namespace lout::object;
@@ -315,7 +316,7 @@
 {
    /** \todo Maybe only the intersection? */
    layout->queueDraw (x + allocation.x, y + allocation.y, width, height);
- //printf("Widget::queueDrawArea x=%d y=%d w=%d h=%d\n", x, y, width, height);
+   _MSG("Widget::queueDrawArea x=%d y=%d w=%d h=%d\n", x, y, width, height);
 }
 
 /**
@@ -547,7 +548,7 @@
       widget = widget->parent;
    }
 
-   fprintf (stderr, "No background color found!\n");
+   MSG_WARN("No background color found!\n");
    return NULL;
 
 }
@@ -692,7 +693,7 @@
    /* Search upwards. */
    while (widget1 != widget2) {
       if (widget1->parent == NULL) {
-         fprintf (stderr, "widgets in different trees\n");
+         MSG_WARN("widgets in different trees\n");
          return NULL;
       }
       
--- a/lout/Makefile.am	Fri Jan 16 14:20:49 2009 -0300
+++ b/lout/Makefile.am	Fri Jan 16 14:32:20 2009 -0300
@@ -11,4 +11,5 @@
 	object.cc \
 	object.hh \
 	signal.cc \
-	signal.hh
+	signal.hh \
+	msg.h
--- a/lout/misc.hh	Fri Jan 16 14:20:49 2009 -0300
+++ b/lout/misc.hh	Fri Jan 16 14:32:20 2009 -0300
@@ -112,6 +112,14 @@
       this->array = NULL;
    }
 
+   inline SimpleVector (const SimpleVector &o) {
+      this->array = NULL;
+      this->num = o.num;
+      this->numAlloc = o.numAlloc;
+      resize ();
+      memcpy (this->array, o.array, sizeof (T) * num);
+   }
+
    inline ~SimpleVector ()
    {
       if (this->array)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lout/msg.h	Fri Jan 16 14:32:20 2009 -0300
@@ -0,0 +1,43 @@
+#ifndef __MSG_H__
+#define __MSG_H__
+
+#include <stdio.h>
+
+/*#include "prefs.h"*/
+#define prefs_show_msg    1
+
+#define D_STMT_START      do
+#define D_STMT_END        while (0)
+
+/*
+ * You can disable any MSG* macro by adding the '_' prefix.
+ */
+#define _MSG(...)
+#define _MSG_WARN(...)
+#define _MSG_HTTP(...)
+
+
+#define MSG(...)                                   \
+   D_STMT_START {                                  \
+      if (prefs_show_msg){                         \
+         printf(__VA_ARGS__);                      \
+         fflush (stdout);                          \
+      }                                            \
+   } D_STMT_END
+
+#define MSG_WARN(...)                              \
+   D_STMT_START {                                  \
+      if (prefs_show_msg)                          \
+         printf("** WARNING **: " __VA_ARGS__);    \
+   } D_STMT_END
+
+#define MSG_ERR(...)                               \
+   D_STMT_START {                                  \
+      if (prefs_show_msg)                          \
+         printf("** ERROR **: " __VA_ARGS__);      \
+   } D_STMT_END
+
+#define MSG_HTTP(...)                              \
+   printf("HTTP warning: " __VA_ARGS__)
+
+#endif /* __MSG_H__ */
--- a/src/Makefile.am	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/Makefile.am	Fri Jan 16 14:32:20 2009 -0300
@@ -67,6 +67,13 @@
 	dicache.h \
 	capi.c \
 	capi.h \
+	css.cc \
+	css.hh \
+	cssparser.cc \
+	cssparser.hh \
+	doctree.hh \
+	styleengine.cc \
+	styleengine.hh \
 	plain.cc \
 	html.cc \
 	html.hh \
@@ -82,6 +89,8 @@
 	gif.c \
 	jpeg.c \
 	png.c \
+	imgbuf.cc \
+	imgbuf.hh \
 	image.cc \
 	image.hh \
 	menu.hh \
--- a/src/bw.c	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/bw.c	Fri Jan 16 14:32:20 2009 -0300
@@ -63,6 +63,7 @@
    bw->ImageClients = dList_new(8);
    bw->NumImages = 0;
    bw->NumImagesGot = 0;
+   bw->NumPendingStyleSheets = 0;
    bw->PageUrls = dList_new(8);
    bw->Docs = dList_new(8);
 
@@ -253,6 +254,9 @@
    /* Zero image-progress data */
    bw->NumImages = 0;
    bw->NumImagesGot = 0;
+
+   /* Zero stylesheet counter */
+   bw->NumPendingStyleSheets = 0;
 }
 
 /*--------------------------------------------------------------------------*/
--- a/src/bw.h	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/bw.h	Fri Jan 16 14:32:20 2009 -0300
@@ -38,6 +38,8 @@
    int NumImages;
    /* Number of images already loaded */
    int NumImagesGot;
+   /* Number of not yet arrived style sheets */
+   int NumPendingStyleSheets;
    /* List of all Urls requested by this page (and its types) */
    Dlist *PageUrls;
 
@@ -57,8 +59,7 @@
     * redirection loops (accounts for WEB_RootUrl only) */
    int redirect_level;
 
-   /* TODO: maybe this fits better in the linkblock.
-    * Although having it here avoids having a signal for handling it. */
+   /* HTML-bugs detected at parse time */
    int num_page_bugs;
    Dstr *page_bugs;
 };
--- a/src/cache.c	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/cache.c	Fri Jan 16 14:32:20 2009 -0300
@@ -161,6 +161,7 @@
    ClientKey = Cache_client_make_key();
    NewClient->Key = ClientKey;
    NewClient->Url = Url;
+   NewClient->Version = 0;
    NewClient->Buf = NULL;
    NewClient->Callback = Callback;
    NewClient->CbData = CbData;
@@ -424,6 +425,7 @@
       entry->DataRefcount++;
       _MSG("DataRefcount++: %d\n", entry->DataRefcount);
       if (entry->CharsetDecoder && entry->DataRefcount == 1) {
+         dStr_free(entry->UTF8Data, 1);
          entry->UTF8Data = a_Decode_process(entry->CharsetDecoder,
                                             entry->Data->str,
                                             entry->Data->len);
@@ -483,40 +485,33 @@
  * Change Content-Type for cache entry found by url.
  * Return new content type.
  */
-const char *a_Cache_set_content_type(const DilloUrl *url, const char *ctype,
-                                     bool_t force)
+const char *a_Cache_set_content_type(const DilloUrl *url, const char *ctype)
 {
+   char *charset;
    const char *curr;
    CacheEntry_t *entry = Cache_entry_search_with_redirect(url);
 
-   if (!entry)
-      return NULL;
+   dReturn_val_if_fail (entry != NULL, NULL);
+
+   MSG("a_Cache_set_content_type {%s} {%s}\n", ctype, URL_STR(url));
 
    curr = Cache_current_content_type(entry);
-   if (entry->TypeMeta && (force == FALSE)) {
-      /* it's already been set */
-      return curr;
-  }
-
-   if (a_Misc_content_type_cmp(curr, ctype)) {
-      char *charset;
-
-      dFree(entry->TypeMeta);
+   if (entry->TypeMeta) {
+      /* Type is already been set. Do nothing.
+       * Multiple META elements? */
+   } else if (a_Misc_content_type_cmp(curr, ctype)) {
+      /* TypeMeta not set, and META gives one different from default */
       curr = entry->TypeMeta = dStrdup(ctype);
-
       if (entry->CharsetDecoder)
          a_Decode_free(entry->CharsetDecoder);
       a_Misc_parse_content_type(ctype, NULL, NULL, &charset);
       entry->CharsetDecoder = a_Decode_charset_init(charset);
       dFree(charset);
 
+      /* Invalidate UTF8Data */
       dStr_free(entry->UTF8Data, 1);
-      if (entry->CharsetDecoder && entry->DataRefcount > 0)
-         entry->UTF8Data = a_Decode_process(entry->CharsetDecoder,
-                                            entry->Data->str,
-                                            entry->Data->len);
-      else
-         entry->UTF8Data = NULL;
+      entry->UTF8Data = NULL;
+
    }
 
    return curr;
@@ -632,7 +627,7 @@
 static void Cache_parse_header(CacheEntry_t *entry)
 {
    char *header = entry->Header->str;
-   char *Length, *Type, *location_str, *encoding, *charset;
+   char *Length, *Type, *location_str, *encoding;
 #ifndef DISABLE_COOKIES
    Dlist *Cookies;
 #endif
@@ -641,6 +636,8 @@
    void *data;
    int i;
 
+   _MSG("Cache_parse_header\n");
+
    if (entry->Header->len > 12) {
       if (header[9] == '1' && header[10] == '0' && header[11] == '0') {
          /* 100: Continue. The "real" header has not come yet. */
@@ -751,18 +748,11 @@
          MSG_HTTP("Server didn't send Content-Type in header.\n");
       }
    } else {
+      /* This HTTP Content-Type is not trusted. It's checked against real data
+       * in Cache_process_queue(); only then CA_GotContentType becomes true. */
       entry->TypeHdr = Type;
-      _MSG("Content-Type {%s} {%s}\n", Type, URL_STR(entry->Url));
-      /* This Content-Type is not trusted. It's checked against real data
-       * in Cache_process_queue(); only then CA_GotContentType becomes true.
-       */
-      a_Misc_parse_content_type(Type, NULL, NULL, &charset);
-      if (charset) {
-         entry->CharsetDecoder = a_Decode_charset_init(charset);
-         if (entry->CharsetDecoder)
-            entry->UTF8Data = dStr_new("");
-         dFree(charset);
-      }
+      _MSG("TypeHdr  {%s} {%s}\n", Type, URL_STR(entry->Url));
+      _MSG("TypeMeta {%s}\n", entry->TypeMeta);
    }
 }
 
@@ -783,7 +773,7 @@
          continue;
       if (N == 1 && (buf[i] == ' ' || buf[i] == '\t')) {
          /* unfold multiple-line header */
-         MSG("Multiple-line header!\n");
+         _MSG("Multiple-line header!\n");
          dStr_erase(hdr, hdr->len - 1, 1);
       }
       N = (buf[i] == '\n') ? N + 1 : 0;
@@ -812,15 +802,60 @@
 void a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size,
                           const DilloUrl *Url)
 {
-   int offset = 0;
-   int len;
+   int offset, len;
    const char *str;
+   Dstr *dstr1, *dstr2, *dstr3;
    CacheEntry_t *entry = Cache_entry_search(Url);
 
    /* Assert a valid entry (not aborted) */
    dReturn_if_fail (entry != NULL);
 
-   if (Op == IOClose) {
+   _MSG("__a_Cache_process_dbuf__\n");
+
+   if (Op == IORead) {
+      /* 
+       * Cache_get_header() will set CA_GotHeader if it has a full header, and
+       * Cache_parse_header() will unset it if the header ends being
+       * merely an informational response from the server (i.e., 100 Continue)
+       */
+      for (offset = 0; !(entry->Flags & CA_GotHeader) &&
+           (len = Cache_get_header(entry, buf + offset, buf_size - offset));
+           Cache_parse_header(entry) ) {
+         offset += len;
+      }
+
+      if (entry->Flags & CA_GotHeader) {
+         str = buf + offset;
+         len = buf_size - offset;
+         entry->TransferSize += len;
+         dstr1 = dstr2 = dstr3 = NULL;
+
+         /* Decode arrived data (<= 3 stages) */
+         if (entry->TransferDecoder) {
+            dstr1 = a_Decode_process(entry->TransferDecoder, str, len);
+            str = dstr1->str;
+            len = dstr1->len;
+         }
+         if (entry->ContentDecoder) {
+            dstr2 = a_Decode_process(entry->ContentDecoder, str, len);
+            str = dstr2->str;
+            len = dstr2->len;
+         }
+         dStr_append_l(entry->Data, str, len);
+         if (entry->CharsetDecoder && entry->UTF8Data) {
+            dstr3 = a_Decode_process(entry->CharsetDecoder, str, len);
+            dStr_append_l(entry->UTF8Data, dstr3->str, dstr3->len);
+         }
+         dStr_free(dstr1, 1);
+         dStr_free(dstr2, 1);
+         dStr_free(dstr3, 1);
+      
+         if (entry->Data->len)
+            entry->Flags &= ~CA_IsEmpty;
+
+         Cache_process_queue(entry);
+      }
+   } else if (Op == IOClose) {
       if ((entry->Flags & CA_GotLength) &&
           (entry->ExpectedSize != entry->TransferSize)) {
          MSG_HTTP("Content-Length does NOT match message body,\n"
@@ -843,61 +878,11 @@
       if (entry->Flags & CA_GotHeader) {
          Cache_unref_data(entry);
       }
-      return;
+
    } else if (Op == IOAbort) {
       /* unused */
       MSG("a_Cache_process_dbuf Op = IOAbort; not implemented!\n");
-      return;
-   }
-
-   /*
-    * Cache_get_header() will set CA_GotHeader if it has a full header, and
-    * Cache_parse_header() will unset it if the header turns out to have been
-    * merely an informational response from the server (i.e., 100 Continue)
-    */
-   while (!(entry->Flags & CA_GotHeader) &&
-          (len = Cache_get_header(entry, buf + offset, buf_size - offset))) {
-      offset += len;
-      /* Let's scan, allocate, and set things according to header info */
-      Cache_parse_header(entry);
    }
-
-   if (!(entry->Flags & CA_GotHeader))
-      return;
-
-   str = buf + offset;
-   len = buf_size - offset;
-   entry->TransferSize += len;
-
-   if (entry->TransferDecoder) {
-      Dstr *dbuf = a_Decode_process(entry->TransferDecoder, str, len);
-      str = dbuf->str;
-      len = dbuf->len;
-      dStr_free(dbuf, 0);
-   }
-   if (entry->ContentDecoder) {
-      Dstr *dbuf = a_Decode_process(entry->ContentDecoder, str, len);
-      if (entry->TransferDecoder)
-         dFree((char *)str);
-      str = dbuf->str;
-      len = dbuf->len;
-      dStr_free(dbuf, 0);
-   }
-   dStr_append_l(entry->Data, str, len);
-
-   if (entry->UTF8Data) {
-      Dstr *dbuf = a_Decode_process(entry->CharsetDecoder, str, len);
-      dStr_append_l(entry->UTF8Data, dbuf->str, dbuf->len);
-      dStr_free(dbuf, 1);
-   }
-
-   if (entry->TransferDecoder || entry->ContentDecoder)
-      dFree((char *)str);
-
-   if (entry->Data->len)
-      entry->Flags &= ~CA_IsEmpty;
-
-   Cache_process_queue(entry);
 }
 
 /*
@@ -1258,9 +1243,14 @@
 void a_Cache_stop_client(int Key)
 {
    CacheClient_t *Client;
+   DICacheEntry *DicEntry;
 
    if ((Client = dList_find_custom(ClientQueue, INT2VOIDP(Key),
                                    Cache_client_by_key_cmp))) {
+      DicEntry = a_Dicache_get_entry(Client->Url, Client->Version);
+      if (DicEntry) {
+         a_Dicache_unref(Client->Url, Client->Version);
+      }
       Cache_client_dequeue(Client, NULLKey);
    } else {
       _MSG("WARNING: Cache_stop_client, nonexistent client\n");
--- a/src/cache.h	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/cache.h	Fri Jan 16 14:32:20 2009 -0300
@@ -46,6 +46,7 @@
 struct _CacheClient {
    int Key;                 /* Primary Key for this client */
    const DilloUrl *Url;     /* Pointer to a cache entry Url */
+   int Version;             /* Dicache version of this Url (0 if not used) */
    void *Buf;               /* Pointer to cache-data */
    uint_t BufSize;          /* Valid size of cache-data */
    CA_Callback_t Callback;  /* Client function */
@@ -61,8 +62,7 @@
 int a_Cache_get_buf(const DilloUrl *Url, char **PBuf, int *BufSize);
 void a_Cache_unref_buf(const DilloUrl *Url);
 const char *a_Cache_get_content_type(const DilloUrl *url);
-const char *a_Cache_set_content_type(const DilloUrl *url, const char *ctype,
-                                     bool_t force);
+const char *a_Cache_set_content_type(const DilloUrl *url, const char *ctype);
 uint_t a_Cache_get_flags(const DilloUrl *url);
 void a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size,
                           const DilloUrl *Url);
--- a/src/capi.c	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/capi.c	Fri Jan 16 14:32:20 2009 -0300
@@ -421,10 +421,9 @@
 /*
  * Set the Content-Type for the URL. 
  */
-const char *a_Capi_set_content_type(const DilloUrl *url, const char *ctype,
-                                        bool_t force)
+const char *a_Capi_set_content_type(const DilloUrl *url, const char *ctype)
 {
-   return a_Cache_set_content_type(url, ctype, force);
+   return a_Cache_set_content_type(url, ctype);
 }
 
 /*
--- a/src/capi.h	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/capi.h	Fri Jan 16 14:32:20 2009 -0300
@@ -26,8 +26,7 @@
 int a_Capi_get_buf(const DilloUrl *Url, char **PBuf, int *BufSize);
 void a_Capi_unref_buf(const DilloUrl *Url);
 const char *a_Capi_get_content_type(const DilloUrl *url);
-const char *a_Capi_set_content_type(const DilloUrl *url, const char *ctype,
-                                    bool_t force);
+const char *a_Capi_set_content_type(const DilloUrl *url, const char *ctype);
 int a_Capi_get_flags(const DilloUrl *Url);
 int a_Capi_dpi_send_cmd(DilloUrl *url, void *bw, char *cmd, char *server,
                          int flags);
--- a/src/colors.c	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/colors.c	Fri Jan 16 14:32:20 2009 -0300
@@ -204,7 +204,7 @@
 #define NCOLORS   (sizeof(color_keyword) / sizeof(struct key))
 
 /*
- * Parse a color in hex (RRGGBB)
+ * Parse a color in hex (RRGGBB) or (RGB)
  *
  * Return Value:
  *   parsed color if successful (err = 0),
@@ -219,7 +219,12 @@
   ret_color = strtol(s, &tail, 16);
   if (tail - s == 6)
      *err = 0;
-  else
+  else if (tail - s == 3) {       /* #RGB as allowed by CSS */
+     *err = 0;
+	 ret_color = ((ret_color & 0xf00) << 12) | ((ret_color & 0xf00) << 8) |
+                 ((ret_color & 0x0f0) << 8) | ((ret_color & 0x0f0) << 4) |
+				 ((ret_color & 0x00f) << 4) | ((ret_color & 0x00f) << 0);
+  } else
      ret_color = default_color;
 
   return ret_color;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/css.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -0,0 +1,412 @@
+/*
+ * File: css.cc
+ *
+ * Copyright 2008 Jorge Arellano Cid <jcid@dillo.org>
+ *
+ * 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
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include "../dlib/dlib.h"
+#include "prefs.h"
+#include "html_common.hh"
+#include "css.hh"
+#include "cssparser.hh"
+
+using namespace dw::core::style;
+
+void CssProperty::print () {
+   fprintf (stderr, "%s - %d\n", Css_property_info[name].symbol, value.intVal);
+}
+
+void CssPropertyList::set (CssProperty::Name name, CssProperty::Value value) {
+   for (int i = 0; i < size (); i++)
+      if (getRef (i)->name == name) {
+         getRef (i)->value = value;
+         return;
+      }
+
+   increase ();
+   getRef (size () - 1)->name = name;
+   getRef (size () - 1)->value = value;
+}
+
+void CssPropertyList::apply (CssPropertyList *props) {
+   for (int i = 0; i < size (); i++)
+      props->set (getRef (i)->name, getRef (i)->value);
+}
+
+void CssPropertyList::print () {
+   for (int i = 0; i < size (); i++)
+      getRef (i)->print ();
+}
+
+CssSelector::CssSelector (int element, const char *klass,
+                          const char *pseudo, const char *id) {
+   refCount = 0;
+   selectorList = new lout::misc::SimpleVector
+                                  <struct CombinatorAndSelector> (1);
+   selectorList->increase ();
+   selectorList->getRef (0)->notMatchingBefore = -1;
+   top ()->element = element;
+   top ()->klass = klass;
+   top ()->pseudo = pseudo;
+   top ()->id = id;
+};
+
+CssSelector::~CssSelector () {
+   delete selectorList;
+}
+
+bool CssSelector::match (Doctree *docTree) {
+   CssSimpleSelector *sel;
+   Combinator comb;
+   int *notMatchingBefore;
+   const DoctreeNode *n, *node = docTree->top ();
+
+   assert (selectorList->size () > 0);
+
+   sel = top ();
+   
+   if (! sel->match (node))
+      return false;
+
+   for (int i = selectorList->size () - 2; i >= 0; i--) {
+      sel = &selectorList->getRef (i)->selector;
+      comb = selectorList->getRef (i + 1)->combinator;
+      notMatchingBefore = &selectorList->getRef (i + 1)->notMatchingBefore;
+      node = docTree->parent (node);
+
+      if (node == NULL)
+         return false;
+     
+      switch (comb) {
+         case CHILD:
+            if (!sel->match (node))
+               return false;
+            break;
+         case DESCENDENT:
+            n = node;
+
+            while (true) {
+               if (node == NULL || node->num < *notMatchingBefore) {
+                  *notMatchingBefore = n->num;
+                  return false;
+               }
+
+               if (sel->match (node))
+                  break;
+
+               node = docTree->parent (node);
+            }
+            break;
+         default:
+            return false; // \todo implement other combinators
+      }
+   } 
+   
+   return true;
+}
+
+void CssSelector::addSimpleSelector (Combinator c, int element,
+                                     const char *klass, const char *pseudo,
+                                     const char *id) {
+   selectorList->increase ();
+
+   selectorList->getRef (selectorList->size () - 1)->combinator = c;
+   selectorList->getRef (selectorList->size () - 1)->notMatchingBefore = -1;
+   top ()->element = element;
+   top ()->klass = klass;
+   top ()->pseudo = pseudo;
+   top ()->id = id;
+
+}
+
+void CssSelector::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) {
+            case CHILD:
+               fprintf (stderr, "> ");
+               break;
+            case DESCENDENT:
+               fprintf (stderr, "\" \" ");
+               break;
+            default:
+               fprintf (stderr, "? ");
+               break;
+         }
+      }
+   }
+
+   fprintf (stderr, "\n");
+}
+
+bool CssSimpleSelector::match (const DoctreeNode *n) {
+   if (element != ELEMENT_ANY && element != n->element)
+      return false;
+   if (klass != NULL &&
+      (n->klass == NULL || strcasecmp (klass, n->klass) != 0))
+      return false;
+   if (pseudo != NULL &&
+      (n->pseudo == NULL || strcasecmp (pseudo, n->pseudo) != 0))
+      return false;
+   if (id != NULL && (n->id == NULL || strcasecmp (id, n->id) != 0))
+      return false;
+   
+   return true;
+}
+
+void CssSimpleSelector::print () {
+   fprintf (stderr, "Element %d, class %s, pseudo %s, id %s ",
+      element, klass, pseudo, id);
+}
+
+CssRule::CssRule (CssSelector *selector, CssPropertyList *props) {
+   this->selector = selector;
+   this->selector->ref ();
+   this->props = props;
+   this->props->ref ();
+};
+
+CssRule::~CssRule () {
+   selector->unref ();
+   props->unref ();
+};
+
+void CssRule::apply (CssPropertyList *props, Doctree *docTree) {
+   if (selector->match (docTree))
+      this->props->apply (props);
+}
+
+void CssRule::print () {
+   selector->print ();
+   props->print ();
+}
+
+CssStyleSheet::CssStyleSheet () {
+   for (int i = 0; i < ntags; i++)
+      elementTable[i] = new RuleList ();
+
+   idTable = new RuleMap ();
+   classTable = new RuleMap ();
+   anyTable = new RuleList ();
+}
+
+CssStyleSheet::~CssStyleSheet () {
+   for (int i = 0; i < ntags; i++)
+      delete elementTable[i];
+   delete idTable;
+   delete classTable;
+   delete anyTable;
+}
+
+void CssStyleSheet::addRule (CssRule *rule) {
+   CssSimpleSelector *top = rule->selector->top ();
+   RuleList *ruleList = NULL;
+   lout::object::ConstString *string;
+   
+   if (top->id) {
+      string = new lout::object::ConstString (top->id);
+      ruleList = idTable->get (string);
+      if (ruleList == NULL) {
+         ruleList = new RuleList ();
+         idTable->put (string, ruleList);
+      } else {
+         delete string;
+      }
+   } else if (top->klass) {
+      string = new lout::object::ConstString (top->klass);
+      ruleList = classTable->get (string);
+      if (ruleList == NULL) {
+         ruleList = new RuleList;
+         classTable->put (string, ruleList);
+      } else {
+         delete string;
+      }
+   } else if (top->element >= 0 && top->element < ntags) {
+      ruleList = elementTable[top->element];
+   } else if (top->element == CssSimpleSelector::ELEMENT_ANY) {
+      ruleList = anyTable;
+   }
+
+   if (ruleList) {
+      ruleList->increase ();
+      *ruleList->getRef (ruleList->size() - 1) = rule;
+   }
+}
+
+void CssStyleSheet::addRule (CssSelector *selector, CssPropertyList *props) {
+   CssRule *rule = new CssRule (selector, props);
+   addRule (rule);
+}
+
+void CssStyleSheet::apply (CssPropertyList *props, Doctree *docTree) {
+   RuleList *ruleList[4] = {NULL, NULL, NULL, NULL};
+   const DoctreeNode *top = docTree->top ();
+   
+   if (top->id) {
+      lout::object::String idString (top->id);
+
+      ruleList[3] = idTable->get (&idString);
+   }
+
+   if (top->klass) {
+      lout::object::String classString (top->klass);
+
+      ruleList[2] = classTable->get (&classString);
+   }
+
+   ruleList[1] = elementTable[docTree->top ()->element];
+   ruleList[0] = anyTable;
+
+#if 0
+   fprintf(stderr, "==> ");
+   for (int j = 0; j < 4; j++)
+      fprintf(stderr, "%d ", ruleList[j]?ruleList[j]->size():0);
+   fprintf(stderr, "\n");
+#endif
+
+   for (int i = 0;; i++) {
+      int n = 0;
+
+      for (int j = 0; j < 4; j++) {
+         if (ruleList[j] && ruleList[j]->size () > i) {
+            ruleList[j]->get (i)->apply (props, docTree);
+            n++;
+         }
+      }
+
+      if (n == 0)
+         break;
+   } 
+}
+
+CssStyleSheet *CssContext::userAgentStyle;
+CssStyleSheet *CssContext::userStyle;
+CssStyleSheet *CssContext::userImportantStyle;
+
+CssContext::CssContext () {
+   for (int o = CSS_PRIMARY_USER_AGENT; o < CSS_PRIMARY_LAST; o++)
+      sheet[o] = NULL;
+
+   if (userAgentStyle == NULL) {
+      userAgentStyle = new CssStyleSheet ();
+      userStyle = new CssStyleSheet ();
+      userImportantStyle = new CssStyleSheet ();
+
+      sheet[CSS_PRIMARY_USER_AGENT] = userAgentStyle;
+      sheet[CSS_PRIMARY_USER] = userStyle;
+      sheet[CSS_PRIMARY_USER_IMPORTANT] = userImportantStyle;
+
+      buildUserAgentStyle ();
+      buildUserStyle ();
+   }
+
+   sheet[CSS_PRIMARY_USER_AGENT] = userAgentStyle;
+   sheet[CSS_PRIMARY_USER] = userStyle;
+   sheet[CSS_PRIMARY_USER_IMPORTANT] = userImportantStyle;
+}
+
+CssContext::~CssContext () {
+   for (int o = CSS_PRIMARY_USER_AGENT; o < CSS_PRIMARY_LAST; o++)
+      if (sheet[o] != userAgentStyle && sheet[o] != userStyle &&
+          sheet[o] != userImportantStyle)
+         delete sheet[o];
+}
+
+void CssContext::apply (CssPropertyList *props, Doctree *docTree,
+         CssPropertyList *tagStyle, CssPropertyList *nonCssHints) {
+
+   for (int o = CSS_PRIMARY_USER_AGENT; o <= CSS_PRIMARY_USER; o++)
+      if (sheet[o])
+         sheet[o]->apply (props, docTree);
+
+   if (nonCssHints)
+        nonCssHints->apply (props);
+
+   for (int o = CSS_PRIMARY_AUTHOR; o <= CSS_PRIMARY_USER_IMPORTANT; o++)
+      if (sheet[o])
+         sheet[o]->apply (props, docTree);
+
+   if (tagStyle)
+        tagStyle->apply (props);
+}
+
+void CssContext::addRule (CssRule *rule, CssPrimaryOrder order) {
+   if (sheet[order] == NULL)
+      sheet[order] = new CssStyleSheet ();
+
+   sheet[order]->addRule (rule);
+
+//  fprintf(stderr, "Adding Rule (%d)\n", order);
+//  rule->print ();
+}
+
+void CssContext::buildUserAgentStyle () {
+   const char *cssBuf =
+     "body  {background-color: #dcd1ba; font-family: helvetica; color: black;" 
+     "       margin: 5px}"
+     "big {font-size: 1.17em}"
+     "blockquote, dd {margin-left: 40px; margin-right: 40px}"
+     "center {text-align: center}"
+     "dt {font-weight: bolder}"
+     ":link {color: blue; text-decoration: underline; cursor: pointer}"
+     ":visited {color: green; text-decoration: underline; cursor: pointer}"
+     "h1, h2, h3, h4, h5, h6, b, strong {font-weight: bolder}"
+     "i, em, cite, address {font-style: italic}"
+     "img:link, img:visited {border: 1px solid}"
+     "frameset, ul, ol, dir {margin-left: 40px}"
+     "h1 {font-size: 2em; margin-top: .67em; margin-bottom: 0}"
+     "h2 {font-size: 1.5em; margin-top: .75em; margin-bottom: 0}"
+     "h3 {font-size: 1.17em; margin-top: .83em; margin-bottom: 0}"
+     "h4 {margin-top: 1.12em; margin-bottom: 0}"
+     "h5 {font-size: 0.83em; margin-top: 1.5em; margin-bottom: 0}"
+     "h6 {font-size: 0.75em; margin-top: 1.67em; margin-bottom: 0}"
+     "hr {width: 100%; border: 1px inset}"
+     "li {margin-top: 0.1em}"
+     "pre {white-space: pre}"
+     "ol {list-style-type: decimal}"
+     "ul {list-style-type: disc}"
+     "ul > ul {list-style-type: circle}"
+     "ul > ul > ul {list-style-type: square}"
+     "ul > ul > ul > ul {list-style-type: disc}"
+     "u {text-decoration: underline}"
+     "small, sub, sup { font-size: 0.83em}"
+     "sub { vertical-align: sub}"
+     "sup { vertical-align: super}"
+     "s, strike, del { text-decoration: line-through}"
+     "table {border-style: outset; border-spacing: 1px}"
+     "td {border-style: inset; padding: 2px}"
+     "thead, tbody, tfoot { vertical-align: middle}"
+     "th { font-weight: bolder; text-align: center}"
+     "code, tt, pre, samp, kbd {font-family: courier}";
+
+   a_Css_parse (this, cssBuf, strlen (cssBuf), 0, CSS_ORIGIN_USER_AGENT);
+}
+
+void CssContext::buildUserStyle () {
+   char buf[1024];
+   char *filename;
+
+   filename = dStrconcat(dGethomedir(), "/.dillo/style.css", NULL);
+   FILE *fp = fopen (filename, "r");
+   if (fp) {
+      Dstr *style = dStr_sized_new (1024);
+      size_t len;
+   
+      while ((len = fread (buf, 1, sizeof (buf), fp)))
+         dStr_append_l (style, buf, len);
+
+      a_Css_parse (this, style->str, style->len, 0, CSS_ORIGIN_USER);
+      dStr_free (style, 1);
+   }
+
+   dFree (filename);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/css.hh	Fri Jan 16 14:32:20 2009 -0300
@@ -0,0 +1,335 @@
+#ifndef __CSS_HH__
+#define __CSS_HH__
+
+#include "dw/core.hh"
+#include "doctree.hh"
+
+/* Origin and weight. Used only internally.*/
+typedef enum {
+   CSS_PRIMARY_USER_AGENT,
+   CSS_PRIMARY_USER,
+   CSS_PRIMARY_AUTHOR,
+   CSS_PRIMARY_AUTHOR_IMPORTANT,
+   CSS_PRIMARY_USER_IMPORTANT,
+   CSS_PRIMARY_LAST,
+} CssPrimaryOrder;
+
+/*
+ * Lengths are represented as int in the following way:
+ * 
+ *    +---+ - - - +---+---+- - - - - -+---+---+---+---+
+ *    | integer part  | decimal fraction  |   type    |
+ *    +---+ - - - +---+---+- - - - - -+---+---+---+---+
+ *     n-1          19  18              3   2  1   0
+ *
+ *    | <------ fixed point value ------> |
+ *
+ * where type is one of the CSS_LENGTH_TYPE_* values.
+ */
+
+typedef int CssLength;
+
+enum {
+   CSS_LENGTH_TYPE_PX,
+   CSS_LENGTH_TYPE_MM,         /* "cm", "in", "pt" and "pc" are converted into
+                                  millimeters. */
+   CSS_LENGTH_TYPE_EM,
+   CSS_LENGTH_TYPE_EX,
+   CSS_LENGTH_TYPE_PERCENTAGE,
+   CSS_LENGTH_TYPE_RELATIVE,   /* This does not exist in CSS but
+                                  is used in HTML */
+   CSS_LENGTH_TYPE_AUTO        /* This can be used as a simple value. */
+};
+
+#define CSS_CREATE_LENGTH(v, t) ( ( (int)((v) * (1 << 19)) & ~7 ) | (t) )
+#define CSS_LENGTH_VALUE(l)     ( ( (float)((l) & ~7) ) / (1 << 19) )
+#define CSS_LENGTH_TYPE(l)      ((l) & 7)
+
+/**
+ * \brief This class holds a CSS property and value pair.
+ */
+class CssProperty {
+   public:
+      typedef union {
+         int intVal;
+         const char *strVal;
+      } Value;
+
+      typedef enum {
+         CSS_PROPERTY_BACKGROUND_ATTACHMENT,
+         CSS_PROPERTY_BACKGROUND_COLOR,
+         CSS_PROPERTY_BACKGROUND_IMAGE,
+         CSS_PROPERTY_BACKGROUND_POSITION,
+         CSS_PROPERTY_BACKGROUND_REPEAT,
+         CSS_PROPERTY_BORDER_BOTTOM_COLOR,
+         CSS_PROPERTY_BORDER_BOTTOM_STYLE,
+         CSS_PROPERTY_BORDER_BOTTOM_WIDTH,
+         CSS_PROPERTY_BORDER_COLLAPSE,
+         CSS_PROPERTY_BORDER_LEFT_COLOR,
+         CSS_PROPERTY_BORDER_LEFT_STYLE,
+         CSS_PROPERTY_BORDER_LEFT_WIDTH,
+         CSS_PROPERTY_BORDER_RIGHT_COLOR,
+         CSS_PROPERTY_BORDER_RIGHT_STYLE,
+         CSS_PROPERTY_BORDER_RIGHT_WIDTH,
+         CSS_PROPERTY_BORDER_SPACING,
+         CSS_PROPERTY_BORDER_TOP_COLOR,
+         CSS_PROPERTY_BORDER_TOP_STYLE,
+         CSS_PROPERTY_BORDER_TOP_WIDTH,
+         CSS_PROPERTY_BOTTOM,
+         CSS_PROPERTY_CAPTION_SIDE,
+         CSS_PROPERTY_CLEAR,
+         CSS_PROPERTY_CLIP,
+         CSS_PROPERTY_COLOR,
+         CSS_PROPERTY_CONTENT,
+         CSS_PROPERTY_COUNTER_INCREMENT,
+         CSS_PROPERTY_COUNTER_RESET,
+         CSS_PROPERTY_CURSOR,
+         CSS_PROPERTY_DIRECTION,
+         CSS_PROPERTY_DISPLAY,
+         CSS_PROPERTY_EMPTY_CELLS,
+         CSS_PROPERTY_FLOAT,
+         CSS_PROPERTY_FONT_FAMILY,
+         CSS_PROPERTY_FONT_SIZE,
+         CSS_PROPERTY_FONT_SIZE_ADJUST,
+         CSS_PROPERTY_FONT_STRETCH,
+         CSS_PROPERTY_FONT_STYLE,
+         CSS_PROPERTY_FONT_VARIANT,
+         CSS_PROPERTY_FONT_WEIGHT,
+         CSS_PROPERTY_HEIGHT,
+         CSS_PROPERTY_LEFT,
+         CSS_PROPERTY_LETTER_SPACING,
+         CSS_PROPERTY_LINE_HEIGHT,
+         CSS_PROPERTY_LIST_STYLE_IMAGE,
+         CSS_PROPERTY_LIST_STYLE_POSITION,
+         CSS_PROPERTY_LIST_STYLE_TYPE,
+         CSS_PROPERTY_MARGIN_BOTTOM,
+         CSS_PROPERTY_MARGIN_LEFT,
+         CSS_PROPERTY_MARGIN_RIGHT,
+         CSS_PROPERTY_MARGIN_TOP,
+         CSS_PROPERTY_MARKER_OFFSET,
+         CSS_PROPERTY_MARKS,
+         CSS_PROPERTY_MAX_HEIGHT,
+         CSS_PROPERTY_MAX_WIDTH,
+         CSS_PROPERTY_MIN_HEIGHT,
+         CSS_PROPERTY_MIN_WIDTH,
+         CSS_PROPERTY_OUTLINE_COLOR,
+         CSS_PROPERTY_OUTLINE_STYLE,
+         CSS_PROPERTY_OUTLINE_WIDTH,
+         CSS_PROPERTY_OVERFLOW,
+         CSS_PROPERTY_PADDING_BOTTOM,
+         CSS_PROPERTY_PADDING_LEFT,
+         CSS_PROPERTY_PADDING_RIGHT,
+         CSS_PROPERTY_PADDING_TOP,
+         CSS_PROPERTY_POSITION,
+         CSS_PROPERTY_QUOTES,
+         CSS_PROPERTY_RIGHT,
+         CSS_PROPERTY_TEXT_ALIGN,
+         CSS_PROPERTY_TEXT_DECORATION,
+         CSS_PROPERTY_TEXT_INDENT,
+         CSS_PROPERTY_TEXT_SHADOW,
+         CSS_PROPERTY_TEXT_TRANSFORM,
+         CSS_PROPERTY_TOP,
+         CSS_PROPERTY_UNICODE_BIDI,
+         CSS_PROPERTY_VERTICAL_ALIGN,
+         CSS_PROPERTY_VISIBILITY,
+         CSS_PROPERTY_WHITE_SPACE,
+         CSS_PROPERTY_WIDTH,
+         CSS_PROPERTY_WORD_SPACING,
+         CSS_PROPERTY_Z_INDEX,
+         CSS_PROPERTY_X_LINK,
+         CSS_PROPERTY_X_COLSPAN,
+         CSS_PROPERTY_X_ROWSPAN,
+         PROPERTY_X_LINK,
+         PROPERTY_X_IMG,
+         PROPERTY_X_TOOLTIP,
+         CSS_PROPERTY_LAST
+      } Name;
+
+      typedef enum {
+         CSS_FONT_WEIGHT_LIGHTER = -1,
+         CSS_FONT_WEIGHT_BOLDER = -2,
+         CSS_FONT_WEIGHT_STEP = 300,
+         /* Some special font weights. */
+         CSS_FONT_WEIGHT_LIGHT = 100,
+         CSS_FONT_WEIGHT_NORMAL = 400,
+         CSS_FONT_WEIGHT_BOLD = 700,
+         CSS_FONT_WEIGHT_MIN = 100,
+         CSS_FONT_WEIGHT_MAX = 900,
+      } FontWeightExtensions;
+
+      Name name;
+      Value value;
+
+      void print ();
+};
+
+/**
+ * \brief A list of CssProperty objects.
+ */ 
+class CssPropertyList : public lout::misc::SimpleVector <CssProperty> {
+      int refCount;
+
+   public:
+      CssPropertyList() : lout::misc::SimpleVector <CssProperty> (1) {
+         refCount = 0;
+      };
+      CssPropertyList(const CssPropertyList &p) :
+         lout::misc::SimpleVector <CssProperty> (p) {
+         refCount = 0;
+      };
+
+      void set (CssProperty::Name name, CssProperty::Value value);
+      void set (CssProperty::Name name, const char *value) {
+         CssProperty::Value v;
+         v.strVal = value;
+         set (name, v);
+      };
+      void set (CssProperty::Name name, int value) {
+         CssProperty::Value v;
+         v.intVal = value;
+         set (name, v);
+      };
+      void apply (CssPropertyList *props);
+      void print ();
+      inline void ref () { refCount++; }
+      inline void unref () { if(--refCount == 0) delete this; }
+};
+
+class CssSimpleSelector {
+   public:
+      enum {
+         ELEMENT_NONE = -1,
+         ELEMENT_ANY = -2,
+      };
+
+      int element;
+      const char *klass, *pseudo, *id;
+
+      bool match (const DoctreeNode *node);
+      void print ();
+};
+
+/**
+ * \brief CSS selector class.
+ * \todo Implement missing selector options.
+ */
+class CssSelector {
+   public:
+      typedef enum {
+         DESCENDENT,
+         CHILD,
+         ADJACENT_SIBLING,
+      } Combinator;
+
+   private:
+      struct CombinatorAndSelector {
+         int notMatchingBefore; // used for optimizing CSS selector matching
+         Combinator combinator;
+         CssSimpleSelector selector;
+      };
+
+      int refCount;
+      lout::misc::SimpleVector <struct CombinatorAndSelector> *selectorList;
+
+   public:
+      CssSelector (int element = CssSimpleSelector::ELEMENT_ANY,
+                   const char *klass = NULL,
+                   const char *pseudo = NULL, const char *id = NULL);
+      ~CssSelector ();
+      void addSimpleSelector (Combinator c,
+                              int element = CssSimpleSelector::ELEMENT_ANY,
+                              const char *klass = NULL,
+                              const char *pseudo = NULL, const char *id=NULL);
+      inline CssSimpleSelector *top () {
+         return &selectorList->getRef (selectorList->size () - 1)->selector;
+      };
+
+      bool match (Doctree *dt);
+      void print ();
+      inline void ref () { refCount++; }
+      inline void unref () { if(--refCount == 0) delete this; }
+};
+
+/**
+ * \brief A CssSelector CssPropertyList pair.
+ *  The CssPropertyList is applied if the CssSelector matches.
+ */
+class CssRule {
+   private:
+      CssPropertyList *props;
+
+   public:
+      CssSelector *selector;
+
+      CssRule (CssSelector *selector, CssPropertyList *props);
+      ~CssRule ();
+
+      void apply (CssPropertyList *props, Doctree *docTree);
+      void print ();
+};
+
+/**
+ * \brief A list of CssRules.
+ * In apply () all matching rules are applied.
+ */
+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);
+            };
+
+            bool equals (lout::object::Object *other) { return this == other; };
+            int hashValue () { return (intptr_t) this; };
+      };
+
+      class RuleMap : public lout::container::typed::HashTable
+                             <lout::object::ConstString, RuleList > {
+         public:
+            RuleMap () : lout::container::typed::HashTable
+                    <lout::object::ConstString, RuleList > (true, true, 256) {};
+      };
+
+      static const int ntags = 90; // \todo replace 90
+      RuleList *elementTable[ntags];
+
+      RuleMap *idTable;
+      RuleMap *classTable;
+      RuleList *anyTable;
+
+   public:
+      CssStyleSheet();
+      ~CssStyleSheet();
+      void addRule (CssRule *rule);
+      void addRule (CssSelector *selector, CssPropertyList *props);
+      void apply (CssPropertyList *props, Doctree *docTree);
+};
+
+/**
+ * \brief A set of CssStyleSheets.
+ */
+class CssContext {
+   private:
+      static CssStyleSheet *userAgentStyle;
+      static CssStyleSheet *userStyle;
+      static CssStyleSheet *userImportantStyle;
+      CssStyleSheet *sheet[CSS_PRIMARY_USER_IMPORTANT + 1];
+
+      void buildUserAgentStyle ();
+      void buildUserStyle ();
+
+   public:
+      CssContext ();
+      ~CssContext ();
+
+      void addRule (CssRule *rule, CssPrimaryOrder order);
+      void apply (CssPropertyList *props,
+         Doctree *docTree,
+         CssPropertyList *tagStyle, CssPropertyList *nonCssHints);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cssparser.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -0,0 +1,1167 @@
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "msg.h"
+#include "colors.h"
+#include "html_common.hh"
+#include "css.hh"
+#include "cssparser.hh"
+
+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
+#define DEBUG_CREATE_LEVEL  0
+
+#define DEBUG_LEVEL 10
+
+/* Applies to symbol lengths and string literals. */
+#define MAX_STR_LEN 256
+
+static const char *Css_border_style_enum_vals[] = {
+   "none", "hidden", "dotted", "dashed", "solid", "double", "groove",
+   "ridge", "inset", "outset", NULL
+};
+
+static const char *Css_cursor_enum_vals[] = {
+   "crosshair", "default", "pointer", "move", "e_resize", "ne_resize",
+   "nw_resize", "n_resize", "se_resize", "sw_resize", "s_resize",
+   "w_resize", "text", "wait", "help", NULL
+};
+
+static const char *Css_display_enum_vals[DISPLAY_LAST + 1] = {
+   "block", "inline", "list-item", "table", "table-row-group",
+   "table-header-group", "table-footer-group", "table-row",
+   "table-cell", NULL
+};
+
+static const char *Css_font_style_enum_vals[] = {
+   "normal", "italic", "oblique", NULL
+};
+
+static const char *Css_list_style_type_enum_vals[] = {
+   "disc", "circle", "square", "decimal", "decimal-leading-zero",
+   "lower-roman", "upper-roman", "lower-greek", "lower-alpha",
+   "lower-latin", "upper-alpha", "upper-latin", "hebrew", "armenian",
+   "georgian", "cjk-ideographic", "hiragana", "katakana", "hiragana-iroha",
+   "katakana-iroha", "none", NULL
+};
+
+static const char *Css_text_align_enum_vals[] = {
+   "left", "right", "center", "justify", "string", NULL
+};
+
+static const char *Css_text_decoration_enum_vals[] = {
+   "underline", "overline", "line-through", "blink", NULL
+};
+
+static const char *Css_vertical_align_vals[] = {
+   "top", "bottom", "middle", "baseline", "sub", "super", NULL
+};
+
+static const char *Css_white_space_vals[] = {
+   "normal", "pre", "nowrap", NULL
+};
+
+CssPropertyInfo Css_property_info[CssProperty::CSS_PROPERTY_LAST] = {
+   {"background-attachment", CSS_TYPE_UNUSED, NULL},
+   {"background-color", CSS_TYPE_COLOR, NULL},
+   {"background-image", CSS_TYPE_UNUSED, NULL},
+   {"background-position", CSS_TYPE_UNUSED, NULL},
+   {"background-repeat", CSS_TYPE_UNUSED, NULL},
+   {"border-bottom-color", CSS_TYPE_COLOR, NULL},
+   {"border-bottom-style", CSS_TYPE_ENUM, Css_border_style_enum_vals},
+   {"border-bottom-width", CSS_TYPE_LENGTH, NULL},
+   {"border-collapse", CSS_TYPE_UNUSED, NULL},
+   {"border-left-color", CSS_TYPE_COLOR, NULL},
+   {"border-left-style", CSS_TYPE_ENUM, Css_border_style_enum_vals},
+   {"border-left-width", CSS_TYPE_LENGTH, NULL},
+   {"border-right-color", CSS_TYPE_COLOR, NULL},
+   {"border-right-style", CSS_TYPE_ENUM, Css_border_style_enum_vals},
+   {"border-right-width", CSS_TYPE_LENGTH, NULL},
+   {"border-spacing", CSS_TYPE_LENGTH, NULL},
+   {"border-top-color", CSS_TYPE_COLOR, NULL},
+   {"border-top-style", CSS_TYPE_ENUM, Css_border_style_enum_vals},
+   {"border-top-width", CSS_TYPE_LENGTH, NULL},
+   {"bottom", CSS_TYPE_UNUSED, NULL},
+   {"caption-side", CSS_TYPE_UNUSED, NULL},
+   {"clear", CSS_TYPE_UNUSED, NULL},
+   {"clip", CSS_TYPE_UNUSED, NULL},
+   {"color", CSS_TYPE_COLOR, NULL},
+   {"content", CSS_TYPE_STRING, NULL},
+   {"counter-increment", CSS_TYPE_UNUSED, NULL},
+   {"counter-reset", CSS_TYPE_UNUSED, NULL},
+   {"cursor", CSS_TYPE_ENUM, Css_cursor_enum_vals},
+   {"direction", CSS_TYPE_UNUSED, NULL},
+   {"display", CSS_TYPE_ENUM, Css_display_enum_vals},
+   {"empty-cells", CSS_TYPE_UNUSED, NULL},
+   {"float", CSS_TYPE_UNUSED, NULL},
+   {"font-family", CSS_TYPE_SYMBOL, NULL},
+   {"font-size", CSS_TYPE_LENGTH_PERCENTAGE, NULL},
+   {"font-size-adjust", CSS_TYPE_UNUSED, NULL},
+   {"font-stretch", CSS_TYPE_UNUSED, NULL},
+   {"font-style", CSS_TYPE_ENUM, Css_font_style_enum_vals},
+   {"font-variant", CSS_TYPE_UNUSED, NULL},
+   {"font-weight", CSS_TYPE_FONT_WEIGHT, NULL},
+   {"height", CSS_TYPE_LENGTH_PERCENTAGE, NULL},
+   {"left", CSS_TYPE_UNUSED, NULL},
+   {"letter-spacing", CSS_TYPE_UNUSED, NULL},
+   {"line-height", CSS_TYPE_UNUSED, NULL},
+   {"list-style-image", CSS_TYPE_UNUSED, NULL},
+   {"list-style-position", CSS_TYPE_UNUSED, NULL},
+   {"list-style-type", CSS_TYPE_ENUM, Css_list_style_type_enum_vals},
+   {"margin-bottom", CSS_TYPE_LENGTH, NULL},
+   {"margin-left", CSS_TYPE_LENGTH, NULL},
+   {"margin-right", CSS_TYPE_LENGTH, NULL},
+   {"margin-top", CSS_TYPE_LENGTH, NULL},
+   {"marker-offset", CSS_TYPE_UNUSED, NULL},
+   {"marks", CSS_TYPE_UNUSED, NULL},
+   {"max-height", CSS_TYPE_UNUSED, NULL},
+   {"max-width", CSS_TYPE_UNUSED, NULL},
+   {"min-height", CSS_TYPE_UNUSED, NULL},
+   {"min-width", CSS_TYPE_UNUSED, NULL},
+   {"outline-color", CSS_TYPE_UNUSED, NULL},
+   {"outline-style", CSS_TYPE_UNUSED, NULL},
+   {"outline-width", CSS_TYPE_UNUSED, NULL},
+   {"overflow", CSS_TYPE_UNUSED, NULL},
+   {"padding-bottom", CSS_TYPE_LENGTH, NULL},
+   {"padding-left", CSS_TYPE_LENGTH, NULL},
+   {"padding-right", CSS_TYPE_LENGTH, NULL},
+   {"padding-top", CSS_TYPE_LENGTH, NULL},
+   {"position", CSS_TYPE_UNUSED, NULL},
+   {"quotes", CSS_TYPE_UNUSED, NULL},
+   {"right", CSS_TYPE_UNUSED, NULL},
+   {"text-align", CSS_TYPE_ENUM, Css_text_align_enum_vals},
+   {"text-decoration", CSS_TYPE_MULTI_ENUM, Css_text_decoration_enum_vals},
+   {"text-indent", CSS_TYPE_UNUSED, NULL},
+   {"text-shadow", CSS_TYPE_UNUSED, NULL},
+   {"text-transform", CSS_TYPE_UNUSED, NULL},
+   {"top", CSS_TYPE_UNUSED, NULL},
+   {"unicode-bidi", CSS_TYPE_UNUSED, NULL},
+   {"vertical-align", CSS_TYPE_ENUM, Css_vertical_align_vals},
+   {"visibility", CSS_TYPE_UNUSED, NULL},
+   {"white-space", CSS_TYPE_ENUM, Css_white_space_vals},
+   {"width", CSS_TYPE_LENGTH_PERCENTAGE, NULL},
+   {"word-spacing", CSS_TYPE_UNUSED, NULL},
+   {"z-index", CSS_TYPE_UNUSED, NULL},
+
+   /* These are extensions, for internal used, and never parsed. */
+   {"x-link", CSS_TYPE_INTEGER, NULL},
+   {"x-colspan", CSS_TYPE_INTEGER, NULL},
+   {"x-rowspan", CSS_TYPE_INTEGER, NULL},
+
+   {"last", CSS_TYPE_UNUSED, NULL},
+};
+
+#define CSS_SHORTHAND_NUM 14
+
+typedef struct {
+   const char *symbol;
+   enum {
+      CSS_SHORTHAND_MULTIPLE,   /* [ p1 || p2 || ...], the property pi is
+                                 * determined  by the type */
+      CSS_SHORTHAND_DIRECTIONS, /* <t>{1,4} */
+      CSS_SHORTHAND_BORDER,     /* special, used for 'border' */
+      CSS_SHORTHAND_FONT,       /* special, used for 'font' */
+   } type;
+   CssProperty::Name * properties;      /* CSS_SHORTHAND_MULTIPLE:
+                                         *   must be terminated by -1
+                                         * CSS_SHORTHAND_DIRECTIONS:
+                                         *   must have length 4
+                                         * CSS_SHORTHAND_BORDERS:
+                                         *   must have length 12
+                                         * CSS_SHORTHAND_FONT:
+                                         *   unused */
+} CssShorthandInfo;
+
+CssProperty::Name Css_background_properties[] = {
+   CssProperty::CSS_PROPERTY_BACKGROUND_COLOR,
+   CssProperty::CSS_PROPERTY_BACKGROUND_IMAGE,
+   CssProperty::CSS_PROPERTY_BACKGROUND_REPEAT,
+   CssProperty::CSS_PROPERTY_BACKGROUND_ATTACHMENT,
+   CssProperty::CSS_PROPERTY_BACKGROUND_POSITION,
+   (CssProperty::Name) - 1
+};
+
+CssProperty::Name Css_border_bottom_properties[] = {
+   CssProperty::CSS_PROPERTY_BORDER_BOTTOM_WIDTH,
+   CssProperty::CSS_PROPERTY_BORDER_BOTTOM_STYLE,
+   CssProperty::CSS_PROPERTY_BORDER_BOTTOM_COLOR,
+   (CssProperty::Name) - 1
+};
+
+CssProperty::Name Css_border_color_properties[4] = {
+   CssProperty::CSS_PROPERTY_BORDER_TOP_COLOR,
+   CssProperty::CSS_PROPERTY_BORDER_BOTTOM_COLOR,
+   CssProperty::CSS_PROPERTY_BORDER_LEFT_COLOR,
+   CssProperty::CSS_PROPERTY_BORDER_RIGHT_COLOR
+};
+
+CssProperty::Name Css_border_left_properties[] = {
+   CssProperty::CSS_PROPERTY_BORDER_LEFT_WIDTH,
+   CssProperty::CSS_PROPERTY_BORDER_LEFT_STYLE,
+   CssProperty::CSS_PROPERTY_BORDER_LEFT_COLOR,
+   (CssProperty::Name) - 1
+};
+
+CssProperty::Name Css_border_right_properties[] = {
+   CssProperty::CSS_PROPERTY_BORDER_RIGHT_WIDTH,
+   CssProperty::CSS_PROPERTY_BORDER_RIGHT_STYLE,
+   CssProperty::CSS_PROPERTY_BORDER_RIGHT_COLOR,
+   (CssProperty::Name) - 1
+};
+
+CssProperty::Name Css_border_style_properties[4] = {
+   CssProperty::CSS_PROPERTY_BORDER_TOP_STYLE,
+   CssProperty::CSS_PROPERTY_BORDER_BOTTOM_STYLE,
+   CssProperty::CSS_PROPERTY_BORDER_LEFT_STYLE,
+   CssProperty::CSS_PROPERTY_BORDER_RIGHT_STYLE
+};
+
+CssProperty::Name Css_border_top_properties[] = {
+   CssProperty::CSS_PROPERTY_BORDER_TOP_WIDTH,
+   CssProperty::CSS_PROPERTY_BORDER_TOP_STYLE,
+   CssProperty::CSS_PROPERTY_BORDER_TOP_COLOR,
+   (CssProperty::Name) - 1
+};
+
+CssProperty::Name Css_border_width_properties[4] = {
+   CssProperty::CSS_PROPERTY_BORDER_TOP_WIDTH,
+   CssProperty::CSS_PROPERTY_BORDER_BOTTOM_WIDTH,
+   CssProperty::CSS_PROPERTY_BORDER_LEFT_WIDTH,
+   CssProperty::CSS_PROPERTY_BORDER_RIGHT_WIDTH
+};
+
+CssProperty::Name Css_list_style_properties[] = {
+   CssProperty::CSS_PROPERTY_LIST_STYLE_TYPE,
+   CssProperty::CSS_PROPERTY_LIST_STYLE_POSITION,
+   CssProperty::CSS_PROPERTY_LIST_STYLE_IMAGE,
+   (CssProperty::Name) - 1
+};
+
+CssProperty::Name Css_margin_properties[4] = {
+   CssProperty::CSS_PROPERTY_MARGIN_TOP,
+   CssProperty::CSS_PROPERTY_MARGIN_BOTTOM,
+   CssProperty::CSS_PROPERTY_MARGIN_LEFT,
+   CssProperty::CSS_PROPERTY_MARGIN_RIGHT
+};
+
+CssProperty::Name Css_outline_properties[] = {
+   CssProperty::CSS_PROPERTY_OUTLINE_COLOR,
+   CssProperty::CSS_PROPERTY_OUTLINE_STYLE,
+   CssProperty::CSS_PROPERTY_OUTLINE_WIDTH,
+   (CssProperty::Name) - 1
+};
+
+CssProperty::Name Css_padding_properties[4] = {
+   CssProperty::CSS_PROPERTY_PADDING_TOP,
+   CssProperty::CSS_PROPERTY_PADDING_BOTTOM,
+   CssProperty::CSS_PROPERTY_PADDING_LEFT,
+   CssProperty::CSS_PROPERTY_PADDING_RIGHT
+};
+
+CssProperty::Name Css_border_properties[12] = {
+   CssProperty::CSS_PROPERTY_BORDER_TOP_WIDTH,
+   CssProperty::CSS_PROPERTY_BORDER_TOP_STYLE,
+   CssProperty::CSS_PROPERTY_BORDER_TOP_COLOR,
+   CssProperty::CSS_PROPERTY_BORDER_BOTTOM_WIDTH,
+   CssProperty::CSS_PROPERTY_BORDER_BOTTOM_STYLE,
+   CssProperty::CSS_PROPERTY_BORDER_BOTTOM_COLOR,
+   CssProperty::CSS_PROPERTY_BORDER_LEFT_WIDTH,
+   CssProperty::CSS_PROPERTY_BORDER_LEFT_STYLE,
+   CssProperty::CSS_PROPERTY_BORDER_LEFT_COLOR,
+   CssProperty::CSS_PROPERTY_BORDER_RIGHT_WIDTH,
+   CssProperty::CSS_PROPERTY_BORDER_RIGHT_STYLE,
+   CssProperty::CSS_PROPERTY_BORDER_RIGHT_COLOR
+};
+
+static CssShorthandInfo Css_shorthand_info[CSS_SHORTHAND_NUM] = {
+   {"background", CssShorthandInfo::CSS_SHORTHAND_MULTIPLE,
+    Css_background_properties},
+   {"border", CssShorthandInfo::CSS_SHORTHAND_BORDER,
+    Css_border_properties},
+   {"border-bottom", CssShorthandInfo::CSS_SHORTHAND_MULTIPLE,
+    Css_border_bottom_properties},
+   {"border-color", CssShorthandInfo::CSS_SHORTHAND_DIRECTIONS,
+    Css_border_color_properties},
+   {"border-left", CssShorthandInfo::CSS_SHORTHAND_MULTIPLE,
+    Css_border_left_properties},
+   {"border-right", CssShorthandInfo::CSS_SHORTHAND_MULTIPLE,
+    Css_border_right_properties},
+   {"border-style", CssShorthandInfo::CSS_SHORTHAND_DIRECTIONS,
+    Css_border_style_properties},
+   {"border-top", CssShorthandInfo::CSS_SHORTHAND_MULTIPLE,
+    Css_border_top_properties},
+   {"border-width", CssShorthandInfo::CSS_SHORTHAND_DIRECTIONS,
+    Css_border_width_properties},
+   {"font", CssShorthandInfo::CSS_SHORTHAND_FONT, NULL},
+   {"list-style", CssShorthandInfo::CSS_SHORTHAND_MULTIPLE,
+    Css_list_style_properties},
+   {"margin", CssShorthandInfo::CSS_SHORTHAND_DIRECTIONS,
+    Css_margin_properties},
+   {"outline", CssShorthandInfo::CSS_SHORTHAND_MULTIPLE,
+    Css_outline_properties},
+   {"padding", CssShorthandInfo::CSS_SHORTHAND_DIRECTIONS,
+    Css_padding_properties},
+};
+
+/* ----------------------------------------------------------------------
+ *    Initialization, Cleanup
+ * ---------------------------------------------------------------------- */
+
+static int values_num;
+
+void a_Css_init(void)
+{
+   values_num = 0;
+}
+
+void a_Css_freeall(void)
+{
+   if (values_num)
+      fprintf(stderr, "%d CSS values left", values_num);
+}
+
+/* ----------------------------------------------------------------------
+ *    Parsing
+ * ---------------------------------------------------------------------- */
+
+typedef enum {
+   CSS_TK_DECINT, CSS_TK_FLOAT, CSS_TK_COLOR, CSS_TK_SYMBOL, CSS_TK_STRING,
+   CSS_TK_CHAR, CSS_TK_END
+} CssTokenType;
+
+typedef struct {
+   CssContext *context;
+   int order_count;
+   CssOrigin origin;
+
+   const char *buf;
+   int buflen, bufptr;
+
+   CssTokenType ttype;
+   char tval[MAX_STR_LEN];
+   bool within_block;
+   bool space_separated; /* used when parsing CSS selectors */
+} CssParser;
+
+/*
+ * Gets the next character from the buffer, or EOF.
+ */
+static int Css_getc(CssParser * parser)
+{
+   int c;
+
+   if (parser->bufptr >= parser->buflen)
+      c = EOF;
+   else
+      c = parser->buf[parser->bufptr];
+
+   /* The buffer pointer is increased in any case, so that Css_ungetc works
+    * correctly at the end of the buffer. */
+   parser->bufptr++;
+   return c;
+}
+
+/*
+ * Undoes the last Css_getc().
+ */
+static void Css_ungetc(CssParser * parser)
+{
+   parser->bufptr--;
+}
+
+static void Css_next_token(CssParser * parser)
+{
+   int c, c1, d, i, j;
+   bool point_allowed;
+   char hexbuf[5];
+   bool escaped;
+
+   parser->space_separated = false;
+
+   c = Css_getc(parser);
+
+   while (true) {
+      if (isspace(c)) { // ignore whitespace
+         parser->space_separated = true;
+         c = Css_getc(parser);
+      } else if (c == '/') { // ignore comments
+         d = Css_getc(parser);
+         if (d == '*') {
+            c = Css_getc(parser);
+            d = Css_getc(parser);
+            while (d != EOF && (c != '*' || d != '/')) {
+               c = d;
+               d = Css_getc(parser);
+            }
+            c = Css_getc(parser);
+         } else {
+            Css_ungetc(parser);
+            break;
+         }
+      } else {
+         break;
+      }
+   }
+
+   if (isdigit(c)) {
+      parser->ttype = CSS_TK_DECINT;
+      point_allowed = true;
+
+      parser->tval[0] = c;
+      i = 1;
+      c = Css_getc(parser);
+      while (isdigit(c) || (point_allowed && c == '.')) {
+         if (c == '.') {
+            parser->ttype = CSS_TK_FLOAT;
+            point_allowed = false;      /* Only one point read. */
+         }
+
+         if (i < MAX_STR_LEN - 1) {
+            parser->tval[i] = c;
+            i++;
+         }
+         /* else silently truncated */
+         c = Css_getc(parser);
+      }
+      parser->tval[i] = 0;
+      Css_ungetc(parser);
+
+      DEBUG_MSG(DEBUG_TOKEN_LEVEL, "token number %s\n", parser->tval);
+      return;
+   }
+
+   if (isalpha(c) || c == '_' || c == '-') {
+      parser->ttype = CSS_TK_SYMBOL;
+
+      parser->tval[0] = c;
+      i = 1;
+      c = Css_getc(parser);
+      while (isalnum(c) || c == '_' || c == '-') {
+         if (i < MAX_STR_LEN - 1) {
+            parser->tval[i] = c;
+            i++;
+         }                      /* else silently truncated */
+         c = Css_getc(parser);
+      }
+      parser->tval[i] = 0;
+      Css_ungetc(parser);
+      DEBUG_MSG(DEBUG_TOKEN_LEVEL, "token symbol '%s'\n", parser->tval);
+      return;
+   }
+
+   if (c == '"' || c == '\'') {
+      c1 = c;
+      parser->ttype = CSS_TK_STRING;
+
+      i = 0;
+      c = Css_getc(parser);
+      escaped = false;
+
+      while (c != EOF && (escaped || c != c1)) {
+         if (c == '\\') {
+            escaped = true;
+            d = Css_getc(parser);
+            if (isxdigit(d)) {
+               /* Read hex Unicode char. (Actually, strings are yet only 8 
+                * bit.) */
+               hexbuf[0] = d;
+               j = 1;
+               d = Css_getc(parser);
+               while (j < 4 && isxdigit(d)) {
+                  hexbuf[j] = d;
+                  j++;
+                  d = Css_getc(parser);
+               }
+               hexbuf[j] = 0;
+               Css_ungetc(parser);
+               c = strtol(hexbuf, NULL, 16);
+            } else
+               /* Take next character literally. */
+               c = Css_getc(parser);
+         } else
+            escaped = false;
+
+         if (i < MAX_STR_LEN - 1) {
+            parser->tval[i] = c;
+            i++;
+         }                      /* else silently truncated */
+         c = Css_getc(parser);
+      }
+      parser->tval[i] = 0;
+      /* No Css_ungetc(). */
+      DEBUG_MSG(DEBUG_TOKEN_LEVEL, "token string '%s'\n", parser->tval);
+      return;
+   }
+
+   /*
+    * Within blocks, '#' starts a color, outside, it is used in selectors.
+    */
+   if (c == '#' && parser->within_block) {
+      parser->ttype = CSS_TK_COLOR;
+
+      parser->tval[0] = c;
+      i = 1;
+      c = Css_getc(parser);
+      while (isxdigit(c)) {
+         if (i < MAX_STR_LEN - 1) {
+            parser->tval[i] = c;
+            i++;
+         }                      /* else silently truncated */
+         c = Css_getc(parser);
+      }
+      parser->tval[i] = 0;
+      Css_ungetc(parser);
+      DEBUG_MSG(DEBUG_TOKEN_LEVEL, "token color '%s'\n", parser->tval);
+      return;
+   }
+
+   if (c == EOF) {
+      DEBUG_MSG(DEBUG_TOKEN_LEVEL, "token %s\n", "EOF");
+      parser->ttype = CSS_TK_END;
+      return;
+   }
+
+   parser->ttype = CSS_TK_CHAR;
+   parser->tval[0] = c;
+   parser->tval[1] = 0;
+   DEBUG_MSG(DEBUG_TOKEN_LEVEL, "token char '%c'\n", c);
+}
+
+
+static bool Css_token_matches_property(CssParser * parser,
+                                       CssProperty::Name prop)
+{
+   int i, err = 1;
+
+   switch (Css_property_info[prop].type) {
+   case CSS_TYPE_ENUM:
+      if (parser->ttype == CSS_TK_SYMBOL) {
+         for (i = 0; Css_property_info[prop].enum_symbols[i]; i++)
+            if (strcmp(parser->tval,
+                       Css_property_info[prop].enum_symbols[i]) == 0)
+               return true;
+      }
+      return false;
+
+   case CSS_TYPE_MULTI_ENUM:
+      if (parser->ttype == CSS_TK_SYMBOL) {
+         if (strcmp(parser->tval, "none") != 0)
+            return true;
+         else {
+            for (i = 0; Css_property_info[prop].enum_symbols[i]; i++) {
+               if (strcmp(parser->tval,
+                          Css_property_info[prop].enum_symbols[i]) == 0)
+                  return true;
+            }
+         }
+      }
+      return true;
+
+   case CSS_TYPE_LENGTH_PERCENTAGE:
+   case CSS_TYPE_LENGTH:
+      return parser->ttype == CSS_TK_DECINT ||
+          parser->ttype == CSS_TK_FLOAT || (parser->ttype == CSS_TK_SYMBOL
+                                            && strcmp(parser->tval,
+                                                      "auto") == 0);
+
+   case CSS_TYPE_COLOR:
+      return (parser->ttype == CSS_TK_COLOR ||
+              parser->ttype == CSS_TK_SYMBOL) &&
+          a_Color_parse(parser->tval, -1, &err) != -1;
+
+   case CSS_TYPE_STRING:
+      return parser->ttype == CSS_TK_STRING;
+
+   case CSS_TYPE_SYMBOL:
+      return parser->ttype == CSS_TK_SYMBOL;
+
+   case CSS_TYPE_FONT_WEIGHT:
+      if (parser->ttype == CSS_TK_DECINT) {
+         i = atoi(parser->tval);
+         return i >= 100 && i <= 900;
+      } else
+         return (parser->ttype == CSS_TK_SYMBOL &&
+                 (strcmp(parser->tval, "normal") == 0 ||
+                  strcmp(parser->tval, "bold") == 0 ||
+                  strcmp(parser->tval, "bolder") == 0 ||
+                  strcmp(parser->tval, "lighter") == 0));
+      break;
+
+   case CSS_TYPE_UNUSED:
+      return false;
+
+   case CSS_TYPE_INTEGER:
+      /* Not used for parser values. */
+   default:
+      assert(false);
+      return false;
+   }
+}
+
+static bool Css_parse_value(CssParser * parser,
+                            CssProperty::Name prop,
+                            CssProperty::Value * val)
+{
+   int i, lentype;
+   bool found, ret = false;
+   float fval;
+   int ival, err = 1;
+
+   switch (Css_property_info[prop].type) {
+   case CSS_TYPE_ENUM:
+      if (parser->ttype == CSS_TK_SYMBOL) {
+         for (i = 0; Css_property_info[prop].enum_symbols[i]; i++)
+            if (strcmp(parser->tval,
+                       Css_property_info[prop].enum_symbols[i]) == 0) {
+               val->intVal = i;
+               ret = true;
+               break;
+            }
+         Css_next_token(parser);
+      }
+      break;
+
+   case CSS_TYPE_MULTI_ENUM:
+      val->intVal = 0;
+      ret = true;
+
+      while (parser->ttype == CSS_TK_SYMBOL) {
+         if (strcmp(parser->tval, "none") != 0) {
+            for (i = 0, found = false;
+                 !found && Css_property_info[prop].enum_symbols[i]; i++) {
+               if (strcmp(parser->tval,
+                          Css_property_info[prop].enum_symbols[i]) == 0)
+                  val->intVal |= (1 << i);
+            }
+         }
+         Css_next_token(parser);
+      }
+      break;
+
+   case CSS_TYPE_LENGTH_PERCENTAGE:
+   case CSS_TYPE_LENGTH:
+      if (parser->ttype == CSS_TK_DECINT || parser->ttype == CSS_TK_FLOAT) {
+         fval = atof(parser->tval);
+         lentype = CSS_LENGTH_TYPE_PX;  /* Actually, there must be a unit,
+                                         * except for num == 0. */
+
+         ret = true;
+
+         Css_next_token(parser);
+         if (parser->ttype == CSS_TK_SYMBOL) {
+            if (strcmp(parser->tval, "px") == 0) {
+               lentype = CSS_LENGTH_TYPE_PX;
+               Css_next_token(parser);
+            } else if (strcmp(parser->tval, "mm") == 0) {
+               lentype = CSS_LENGTH_TYPE_MM;
+               Css_next_token(parser);
+            } else if (strcmp(parser->tval, "cm") == 0) {
+               lentype = CSS_LENGTH_TYPE_MM;
+               fval *= 10;
+               Css_next_token(parser);
+            } else if (strcmp(parser->tval, "in") == 0) {
+               lentype = CSS_LENGTH_TYPE_MM;
+               fval *= 25.4;
+               Css_next_token(parser);
+            } else if (strcmp(parser->tval, "pt") == 0) {
+               lentype = CSS_LENGTH_TYPE_MM;
+               fval *= (25.4 / 72);
+               Css_next_token(parser);
+            } else if (strcmp(parser->tval, "pc") == 0) {
+               lentype = CSS_LENGTH_TYPE_MM;
+               fval *= (25.4 / 6);
+               Css_next_token(parser);
+            } else if (strcmp(parser->tval, "em") == 0) {
+               lentype = CSS_LENGTH_TYPE_EM;
+               Css_next_token(parser);
+            } else if (strcmp(parser->tval, "ex") == 0) {
+               lentype = CSS_LENGTH_TYPE_EX;
+               Css_next_token(parser);
+            }
+         } else if (Css_property_info[prop].type ==
+                    CSS_TYPE_LENGTH_PERCENTAGE &&
+                    parser->ttype == CSS_TK_CHAR &&
+                    parser->tval[0] == '%') {
+            fval /= 100;
+            lentype = CSS_LENGTH_TYPE_PERCENTAGE;
+            Css_next_token(parser);
+         }
+
+         val->intVal = CSS_CREATE_LENGTH(fval, lentype);
+      } else if (parser->ttype == CSS_TK_SYMBOL &&
+                 strcmp(parser->tval, "auto") == 0) {
+         val->intVal = CSS_LENGTH_TYPE_AUTO;
+      }
+      break;
+
+   case CSS_TYPE_COLOR:
+      if (parser->ttype == CSS_TK_COLOR) {
+         val->intVal = a_Color_parse(parser->tval, -1, &err);
+         if (err)
+            MSG_CSS("color is not in \"%s\" format\n", "#RRGGBB");
+         else
+            ret = true;
+         Css_next_token(parser);
+      } else if (parser->ttype == CSS_TK_SYMBOL) {
+         val->intVal = a_Color_parse(parser->tval, -1, &err);
+         if (err)
+            MSG_CSS("color is not in \"%s\" format\n", "#RRGGBB");
+         else
+            ret = true;
+         Css_next_token(parser);
+      }
+      break;
+
+   case CSS_TYPE_STRING:
+      if (parser->ttype == CSS_TK_STRING) {
+         val->strVal = dStrdup(parser->tval);
+         Css_next_token(parser);
+      }
+      break;
+
+   case CSS_TYPE_SYMBOL:
+      if (parser->ttype == CSS_TK_SYMBOL) {
+         val->strVal = dStrdup(parser->tval);
+         ret = true;
+         Css_next_token(parser);
+      }
+      break;
+
+   case CSS_TYPE_FONT_WEIGHT:
+      ival = 0;
+      if (parser->ttype == CSS_TK_DECINT) {
+         ival = atoi(parser->tval);
+         if (ival < 100 || ival > 900)
+            /* invalid */
+            ival = 0;
+      } else if (parser->ttype == CSS_TK_SYMBOL) {
+         if (strcmp(parser->tval, "normal") == 0)
+            ival = CssProperty::CSS_FONT_WEIGHT_NORMAL;
+         if (strcmp(parser->tval, "bold") == 0)
+            ival = CssProperty::CSS_FONT_WEIGHT_BOLD;
+         if (strcmp(parser->tval, "bolder") == 0)
+            ival = CssProperty::CSS_FONT_WEIGHT_BOLDER;
+         if (strcmp(parser->tval, "lighter") == 0)
+            ival = CssProperty::CSS_FONT_WEIGHT_LIGHTER;
+      }
+
+      if (ival != 0) {
+         val->intVal = ival;
+         ret = true;
+         Css_next_token(parser);
+      }
+      break;
+
+   case CSS_TYPE_UNUSED:
+      /* nothing */
+      break;
+
+   case CSS_TYPE_INTEGER:
+      /* Not used for parser values. */
+   default:
+      assert(false);            /* not reached */
+   }
+
+   return ret;
+}
+
+static bool Css_parse_weight(CssParser * parser)
+{
+   if (parser->ttype == CSS_TK_CHAR && parser->tval[0] == '!') {
+      Css_next_token(parser);
+      if (parser->ttype == CSS_TK_SYMBOL &&
+          strcmp(parser->tval, "important") == 0) {
+         Css_next_token(parser);
+         return true;
+      }
+   }
+
+   return false;
+}
+
+/*
+ * bsearch(3) compare function for searching properties
+ */
+static int Css_property_info_cmp(const void *a, const void *b)
+{
+   return strcmp(((CssPropertyInfo *) a)->symbol,
+                 ((CssPropertyInfo *) b)->symbol);
+}
+
+
+/*
+ * bsearch(3) compare function for searching shorthands
+ */
+static int Css_shorthand_info_cmp(const void *a, const void *b)
+{
+   return strcmp(((CssShorthandInfo *) a)->symbol,
+                 ((CssShorthandInfo *) b)->symbol);
+}
+
+static void Css_parse_declaration(CssParser * parser,
+                                  CssPropertyList * props,
+                                  CssPropertyList * importantProps)
+{
+   CssPropertyInfo pi, *pip;
+   CssShorthandInfo si, *sip;
+
+   CssProperty::Name prop;
+   CssProperty::Value val, dir_vals[4];
+   bool found, weight;
+   int sh_index, i, j, n;
+   int dir_set[4][4] = {
+      /* 1 value  */ {0, 0, 0, 0},
+      /* 2 values */ {0, 0, 1, 1},
+      /* 3 values */ {0, 2, 1, 1},
+      /* 4 values */ {0, 2, 3, 1}
+   };
+
+   if (parser->ttype == CSS_TK_SYMBOL) {
+      pi.symbol = parser->tval;
+      pip =
+          (CssPropertyInfo *) bsearch(&pi, Css_property_info,
+                                      CSS_NUM_PARSED_PROPERTIES,
+                                      sizeof(CssPropertyInfo),
+                                      Css_property_info_cmp);
+      if (pip) {
+         prop = (CssProperty::Name) (pip - Css_property_info);
+         Css_next_token(parser);
+         if (parser->ttype == CSS_TK_CHAR && parser->tval[0] == ':') {
+            Css_next_token(parser);
+            if (Css_parse_value(parser, prop, &val)) {
+               weight = Css_parse_weight(parser);
+               if (weight)
+                  importantProps->set(prop, val);
+               else
+                  props->set(prop, val);
+            }
+         }
+      } else {
+         /* Try shorthands. */
+         si.symbol = parser->tval;
+         sip =
+             (CssShorthandInfo *) bsearch(&pi, Css_shorthand_info,
+                                          CSS_SHORTHAND_NUM,
+                                          sizeof(CssShorthandInfo),
+                                          Css_shorthand_info_cmp);
+         if (sip) {
+            sh_index = sip - Css_shorthand_info;
+            Css_next_token(parser);
+            if (parser->ttype == CSS_TK_CHAR && parser->tval[0] == ':') {
+               Css_next_token(parser);
+
+               switch (Css_shorthand_info[sh_index].type) {
+               case CssShorthandInfo::CSS_SHORTHAND_MULTIPLE:
+                  do {
+                     for (found = false, i = 0;
+                          !found &&
+                          Css_shorthand_info[sh_index].properties[i] != -1;
+                          i++)
+                        if (Css_token_matches_property(parser,
+                                                       Css_shorthand_info
+                                                       [sh_index].
+                                                       properties[i])) {
+                           found = true;
+                           DEBUG_MSG(DEBUG_PARSE_LEVEL,
+                                     "will assign to '%s'\n",
+                                     Css_property_info
+                                     [Css_shorthand_info[sh_index]
+                                      .properties[i]].symbol);
+                           if (Css_parse_value(parser,
+                                               Css_shorthand_info[sh_index]
+                                               .properties[i], &val)) {
+                              weight = Css_parse_weight(parser);
+                              if (weight)
+                                 importantProps->
+                                     set(Css_shorthand_info[sh_index].
+                                         properties[i], val);
+                              else
+                                 props->set(Css_shorthand_info[sh_index].
+                                            properties[i], val);
+                           }
+                        }
+                  } while (found);
+                  break;
+
+               case CssShorthandInfo::CSS_SHORTHAND_DIRECTIONS:
+                  n = 0;
+                  while (n < 4) {
+                     if (Css_token_matches_property(parser,
+                                                    Css_shorthand_info
+                                                    [sh_index].
+                                                    properties[0]) &&
+                         Css_parse_value(parser,
+                                         Css_shorthand_info[sh_index]
+                                         .properties[0], &val)) {
+                        dir_vals[n] = val;
+                        n++;
+                     } else
+                        break;
+                  }
+
+                  weight = Css_parse_weight(parser);
+                  if (n > 0) {
+                     for (i = 0; i < 4; i++)
+                        if (weight)
+                           importantProps->set(Css_shorthand_info[sh_index]
+                                               .properties[i],
+                                               dir_vals[dir_set[n - 1]
+                                                        [i]]);
+                        else
+                           props->set(Css_shorthand_info[sh_index]
+                                      .properties[i],
+                                      dir_vals[dir_set[n - 1][i]]);
+                  } else
+                     MSG_CSS("no values for shorthand property '%s'\n",
+                             Css_shorthand_info[sh_index].symbol);
+
+                  break;
+
+               case CssShorthandInfo::CSS_SHORTHAND_BORDER:
+                  do {
+                     for (found = false, i = 0;
+                          !found && i < 3;
+                          i++)
+                        if (Css_token_matches_property(parser,
+                                                       Css_shorthand_info
+                                                       [sh_index].
+                                                       properties[i])) {
+                           found = true;
+                           if (Css_parse_value(parser,
+                                               Css_shorthand_info[sh_index]
+                                               .properties[i], &val)) {
+                              weight = Css_parse_weight(parser);
+                              for (j = 0; j < 4; j++)
+                                 if (weight)
+                                    importantProps->
+                                       set(Css_shorthand_info[sh_index].
+                                          properties[j * 3 + i], val);
+                                 else
+                                    props->set(Css_shorthand_info[sh_index].
+                                       properties[j * 3 + i], val);
+                           }
+                        }
+                  } while (found);
+                  break;
+
+               case CssShorthandInfo::CSS_SHORTHAND_FONT:
+                  /* todo: Not yet implemented. */
+                  break;
+               }
+            }
+         }
+      }
+   }
+
+   /* Skip all tokens until the expected end. */
+   while (!(parser->ttype == CSS_TK_END ||
+            (parser->ttype == CSS_TK_CHAR &&
+             (parser->tval[0] == ';' || parser->tval[0] == '}'))))
+      Css_next_token(parser);
+
+   if (parser->ttype == CSS_TK_CHAR && parser->tval[0] == ';')
+      Css_next_token(parser);
+}
+
+static bool Css_parse_simple_selector(CssParser * parser,
+                                      CssSimpleSelector *selector) {
+   const char *p, **pp;
+
+   if (parser->ttype == CSS_TK_SYMBOL) {
+      selector->element = a_Html_tag_index(parser->tval);
+      Css_next_token(parser);
+      if (parser->space_separated)
+         return true;
+   } else if (parser->ttype == CSS_TK_CHAR && parser->tval[0] == '*') {
+      selector->element = CssSimpleSelector::ELEMENT_ANY;
+      Css_next_token(parser);
+      if (parser->space_separated)
+         return true;
+   } else if (parser->ttype == CSS_TK_CHAR && 
+              (parser->tval[0] == '#' ||
+               parser->tval[0] == '.' ||
+               parser->tval[0] == ':')) {
+      // nothing to be done in this case
+   } else {
+      return false;
+   }
+
+   do {
+      pp = NULL;
+      if (parser->ttype == CSS_TK_CHAR) {
+         switch (parser->tval[0]) {
+            case '#':
+               pp = &selector->id;
+               break;
+            case '.':
+               pp = &selector->klass;
+               break;
+            case ':':
+               pp = &selector->pseudo;
+               break;
+         }
+      }
+
+      if (pp) {
+         Css_next_token(parser);
+         if (parser->space_separated)
+            return true;
+
+         if (parser->ttype == CSS_TK_SYMBOL ||
+            parser->ttype == CSS_TK_DECINT) {
+               if (*pp == NULL)
+                  *pp = dStrdup(parser->tval);
+               Css_next_token(parser);
+         } else if (parser->ttype == CSS_TK_FLOAT) {
+            /* In this case, we are actually interested in three tokens:
+             * number, '.', number. Instead, we have a decimal fraction,
+             * which we split up again. */
+            p = strchr(parser->tval, '.');
+            if (*pp == NULL)
+               *pp = dStrndup(parser->tval, p - parser->tval);
+            if (selector->klass == NULL)
+               selector->klass = dStrdup(p + 1);
+            Css_next_token(parser);
+         }
+         if (parser->space_separated)
+            return true;
+      }
+   } while (pp);
+
+   DEBUG_MSG(DEBUG_PARSE_LEVEL, "end of simple selector (%s, %s, %s, %d)\n",
+      selector->id, selector->klass,
+      selector->pseudo, selector->element);
+
+   return true;
+}
+
+static CssSelector *Css_parse_selector(CssParser * parser) {
+   CssSelector *selector = new CssSelector ();
+
+   while (true) {
+      if (! Css_parse_simple_selector (parser, selector->top ())) {
+         delete selector;
+         selector = NULL;
+         break;
+      }
+
+      if (parser->ttype == CSS_TK_CHAR &&
+         (parser->tval[0] == ',' || parser->tval[0] == '{')) {
+         break;
+      } else if (parser->ttype == CSS_TK_CHAR && parser->tval[0] == '>') {
+         selector->addSimpleSelector (CssSelector::CHILD);
+         Css_next_token(parser);
+      } else if (parser->ttype != CSS_TK_END && parser->space_separated) {
+         selector->addSimpleSelector (CssSelector::DESCENDENT);
+      } else {
+         delete selector;
+         selector = NULL;
+         break;
+      }
+   }
+
+   while (parser->ttype != CSS_TK_END &&
+          (parser->ttype != CSS_TK_CHAR ||
+           (parser->tval[0] != ',' && parser->tval[0] != '{')))
+         Css_next_token(parser);
+
+   return selector;
+}
+
+static void Css_parse_ruleset(CssParser * parser)
+{
+   lout::misc::SimpleVector < CssSelector * >*list;
+   CssPropertyList *props, *importantProps;
+   CssSelector *selector;
+
+   list = new lout::misc::SimpleVector < CssSelector * >(1);
+
+   while (true) {
+      selector = Css_parse_selector(parser);
+
+      if (selector) {
+         selector->ref();
+         list->increase();
+         list->set(list->size() - 1, selector);
+      }
+
+      if (parser->ttype == CSS_TK_CHAR && parser->tval[0] == ',')
+         /* To read the next token. */
+         Css_next_token(parser);
+      else
+         /* No more selectors. */
+         break;
+   }
+
+   DEBUG_MSG(DEBUG_PARSE_LEVEL, "end of %s\n", "selectors");
+
+   props = new CssPropertyList();
+   props->ref();
+   importantProps = new CssPropertyList();
+   importantProps->ref();
+
+   /* Read block. ('{' has already been read.) */
+   if (parser->ttype != CSS_TK_END) {
+      parser->within_block = true;
+      Css_next_token(parser);
+      do
+         Css_parse_declaration(parser, props, importantProps);
+      while (!(parser->ttype == CSS_TK_END ||
+               (parser->ttype == CSS_TK_CHAR && parser->tval[0] == '}')));
+      parser->within_block = false;
+   }
+
+   for (int i = 0; i < list->size(); i++) {
+      CssSelector *s = list->get(i);
+
+      if (parser->origin == CSS_ORIGIN_USER_AGENT) {
+         parser->context->addRule(new CssRule(s, props),
+                                  CSS_PRIMARY_USER_AGENT);
+      } else if (parser->origin == CSS_ORIGIN_USER) {
+         parser->context->addRule(new CssRule(s, props), CSS_PRIMARY_USER);
+         parser->context->addRule(new CssRule(s, importantProps),
+                                  CSS_PRIMARY_USER_IMPORTANT);
+      } else if (parser->origin == CSS_ORIGIN_AUTHOR) {
+         parser->context->addRule(new CssRule(s, props),
+                                  CSS_PRIMARY_AUTHOR);
+         parser->context->addRule(new CssRule(s, importantProps),
+                                  CSS_PRIMARY_AUTHOR_IMPORTANT);
+      }
+
+      s->unref();
+   }
+
+   props->unref();
+   importantProps->unref();
+
+   delete list;
+
+   if (parser->ttype == CSS_TK_CHAR && parser->tval[0] == '}')
+      Css_next_token(parser);
+}
+
+void a_Css_parse(CssContext * context,
+                 const char *buf,
+                 int buflen, int order_count, CssOrigin origin)
+{
+   CssParser parser;
+
+   parser.context = context;
+   parser.buf = buf;
+   parser.buflen = buflen;
+   parser.bufptr = 0;
+   parser.order_count = 0;
+   parser.origin = origin;
+   parser.within_block = false;
+   parser.space_separated = false;
+
+   Css_next_token(&parser);
+   while (parser.ttype != CSS_TK_END)
+      Css_parse_ruleset(&parser);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cssparser.hh	Fri Jan 16 14:32:20 2009 -0300
@@ -0,0 +1,63 @@
+#ifndef __CSSPARSER_HH__
+#define __CSSPARSER_HH__
+
+#include "css.hh"
+
+/* The last three ones are never parsed. */
+#define CSS_NUM_INTERNAL_PROPERTIES 3
+#define CSS_NUM_PARSED_PROPERTIES \
+   (CssProperty::CSS_PROPERTY_LAST - CSS_NUM_INTERNAL_PROPERTIES)
+
+
+typedef enum {
+   CSS_TYPE_INTEGER,            /* This type is only used internally, for x-*
+                                   properties. */
+   CSS_TYPE_ENUM,               /* Value is i, if represented by
+                                   enum_symbols[i]. */
+   CSS_TYPE_MULTI_ENUM,         /* For all enum_symbols[i], 1 << i are
+                                   combined. */
+   CSS_TYPE_LENGTH_PERCENTAGE,  /* <length> or <percentage>. Represented by
+                                   CssLength. */
+   CSS_TYPE_LENGTH,             /* <length>, represented as CssLength.
+                                   Note: In some cases, CSS_TYPE_LENGTH is used
+                                   instead of CSS_TYPE_LENGTH_PERCENTAGE,
+                                   only because Dw cannot handle percentages
+                                   in this particular case (e.g.
+                                   'margin-*-width'). */
+   CSS_TYPE_COLOR,              /* Represented as integer. */
+   CSS_TYPE_FONT_WEIGHT,        /* this very special and only used by
+                                   'font-weight' */
+   CSS_TYPE_STRING,             /* <string> */
+   CSS_TYPE_SYMBOL,             /* Symbols, which are directly copied (as
+                                   opposed to CSS_TYPE_ENUM and 
+                                   CSS_TYPE_MULTI_ENUM). Used for
+                                   'font-family'. */
+   CSS_TYPE_UNUSED              /* Not yet used. Will itself get unused some
+                                   day. */
+} CssValueType;
+
+typedef enum {
+   CSS_ORIGIN_USER_AGENT,
+   CSS_ORIGIN_USER,
+   CSS_ORIGIN_AUTHOR,
+} CssOrigin;
+
+typedef struct {
+   const char *symbol;
+   CssValueType type;
+   const char **enum_symbols;
+} CssPropertyInfo;
+
+
+void        a_Css_init                        (void);
+void        a_Css_freeall                     (void);
+
+void        a_Css_parse                       (CssContext *context,
+                                               const char *buf,
+                                               int buflen,
+                                               int order_count,
+                                               CssOrigin origin);
+
+extern CssPropertyInfo Css_property_info[CssProperty::CSS_PROPERTY_LAST];
+
+#endif // __CSS_H__
--- a/src/dicache.c	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/dicache.c	Fri Jan 16 14:32:20 2009 -0300
@@ -14,7 +14,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "msg.h"
 #include "image.hh"
+#include "imgbuf.hh"
 #include "web.hh"
 #include "dicache.h"
 #include "cache.h"
@@ -78,7 +80,6 @@
    entry->height = 0;
    entry->type = DILLO_IMG_TYPE_NOTSET;
    entry->cmap = NULL;
-   entry->linebuf = NULL;
    entry->v_imgbuf = NULL;
    entry->RefCount = 1;
    entry->TotalSize = 0;
@@ -86,7 +87,11 @@
    entry->ScanNumber = 0;
    entry->BitVec = NULL;
    entry->State = DIC_Empty;
-   entry->version = 0;
+   entry->version = 1;
+
+   entry->Decoder = NULL;
+   entry->DecoderData = NULL;
+   entry->DecodedSize = 0;
 
    entry->next = NULL;
 
@@ -128,41 +133,31 @@
 }
 
 /*
- * Search an entry in the dicache (given the Url).
- * Return value: a pointer to the entry of the _newest_ (i.e. highest)
- *               version if found; NULL otherwise.
+ * Search a particular version of a URL in the Dicache.
+ * Return value: a pointer to the entry if found; NULL otherwise.
+ *
+ * Notes: DIC_Last means last version of the image.
+ *        version zero is not allowed.
  */
-DICacheEntry *a_Dicache_get_entry(const DilloUrl *Url)
+DICacheEntry *a_Dicache_get_entry(const DilloUrl *Url, int version)
 {
    DICacheNode *node;
-   DICacheEntry *entry;
+   DICacheEntry *entry = NULL;
+
+   dReturn_val_if_fail(version != 0, NULL);
 
    node = dList_find_sorted(CachedIMGs, Url, Dicache_node_by_url_cmp);
-
-   if (!node || !node->valid)
-      return NULL;
-
-   for (entry = node->first; (entry && entry->next); entry = entry->next);
-
-   return entry;
-}
-
-/*
- * Search a particular version of a URL in the Dicache.
- * Return value: a pointer to the entry if found; NULL otherwise.
- */
-static DICacheEntry *Dicache_get_entry_version(const DilloUrl *Url,
-                                               int version)
-{
-   DICacheNode *node;
-   DICacheEntry *entry;
-
-   node = dList_find_sorted(CachedIMGs, Url, Dicache_node_by_url_cmp);
-   entry = (node) ? node->first : NULL;
-
-   while (entry && entry->version != version)
-      entry = entry->next;
-
+   if (node) {
+      if (version == DIC_Last) {
+         if (node->valid) {
+            entry = node->first;
+            for ( ;  (entry && entry->next); entry = entry->next);
+         }
+      } else {
+         entry = node->first;
+         for ( ; entry && entry->version != version; entry = entry->next) ;
+      }
+   }
    return entry;
 }
 
@@ -185,9 +180,8 @@
    if (entry) {
       /* Eliminate this dicache entry */
       dFree(entry->cmap);
-      dFree(entry->linebuf);
       a_Bitvec_free(entry->BitVec);
-      a_Image_imgbuf_unref(entry->v_imgbuf);
+      a_Imgbuf_unref(entry->v_imgbuf);
       dicache_size_total -= entry->TotalSize;
 
       if (node->first == entry) {
@@ -213,8 +207,7 @@
 {
    DICacheEntry *entry;
 
-   if ((entry = Dicache_get_entry_version(Url, version))) {
-      /*if (--entry->RefCount == 0 && (entry->next || !prefs.use_dicache)) {*/
+   if ((entry = a_Dicache_get_entry(Url, version))) {
       if (--entry->RefCount == 0) {
          Dicache_remove(Url, version);
       }
@@ -228,7 +221,7 @@
 {
    DICacheEntry *entry;
 
-   if ((entry = Dicache_get_entry_version(Url, version))) {
+   if ((entry = a_Dicache_get_entry(Url, version))) {
       ++entry->RefCount;
    }
    return entry;
@@ -236,7 +229,8 @@
 
 /*
  * Invalidate this entry. This is used for the reloading mechanism.
- * Can't erase current versions, but a_Dicache_get_entry must return NULL.
+ * Can't erase current versions, but a_Dicache_get_entry(url, DIC_Last)
+ * must return NULL.
  */
 void a_Dicache_invalidate_entry(const DilloUrl *Url)
 {
@@ -251,6 +245,135 @@
 /* ------------------------------------------------------------------------- */
 
 /*
+ * Set image's width, height & type
+ * (By now, we'll use the image information despite the html tags --Jcid)
+ */
+void a_Dicache_set_parms(DilloUrl *url, int version, DilloImage *Image,
+                         uint_t width, uint_t height, DilloImgType type)
+{
+   DICacheEntry *DicEntry;
+
+   _MSG("a_Dicache_set_parms (%s)\n", URL_STR(url));
+   dReturn_if_fail ( Image != NULL && width && height );
+   /* Find the DicEntry for this Image */
+   DicEntry = a_Dicache_get_entry(url, version);
+   dReturn_if_fail ( DicEntry != NULL );
+   /* Parameters already set? */
+   dReturn_if_fail ( DicEntry->State < DIC_SetParms );
+
+   _MSG("  RefCount=%d version=%d\n", DicEntry->RefCount, DicEntry->version);
+
+   /* BUG: there's just one image-type now */
+   #define I_RGB 0
+   DicEntry->v_imgbuf = a_Imgbuf_new(Image->dw, I_RGB, width, height);
+
+   DicEntry->TotalSize = width * height * 3;
+   DicEntry->width = width;
+   DicEntry->height = height;
+   DicEntry->type = type;
+   DicEntry->BitVec = a_Bitvec_new((int)height);
+   DicEntry->State = DIC_SetParms;
+
+   dicache_size_total += DicEntry->TotalSize;
+}
+
+/*
+ * Implement the set_cmap method for the Image
+ */
+void a_Dicache_set_cmap(DilloUrl *url, int version, DilloImage *Image,
+                        const uchar_t *cmap, uint_t num_colors,
+                        int num_colors_max, int bg_index)
+{
+   DICacheEntry *DicEntry = a_Dicache_get_entry(url, version);
+
+   _MSG("a_Dicache_set_cmap\n");
+   dReturn_if_fail ( DicEntry != NULL );
+
+   dFree(DicEntry->cmap);
+   DicEntry->cmap = dNew0(uchar_t, 3 * num_colors_max);
+   memcpy(DicEntry->cmap, cmap, 3 * num_colors);
+   if (bg_index >= 0 && (uint_t)bg_index < num_colors) {
+      DicEntry->cmap[bg_index * 3]     = (Image->bg_color >> 16) & 0xff;
+      DicEntry->cmap[bg_index * 3 + 1] = (Image->bg_color >> 8) & 0xff;
+      DicEntry->cmap[bg_index * 3 + 2] = (Image->bg_color) & 0xff;
+   }
+
+   DicEntry->State = DIC_SetCmap;
+}
+
+/*
+ * Reset for a new scan from a multiple-scan image.
+ */
+void a_Dicache_new_scan(const DilloUrl *url, int version)
+{
+   DICacheEntry *DicEntry;
+
+   _MSG("a_Dicache_new_scan\n");
+   dReturn_if_fail ( url != NULL );
+   DicEntry = a_Dicache_get_entry(url, version);
+   dReturn_if_fail ( DicEntry != NULL );
+   if (DicEntry->State < DIC_SetParms) {
+      MSG("a_Dicache_new_scan before DIC_SetParms\n");
+      exit(-1);
+   }
+   a_Bitvec_clear(DicEntry->BitVec);
+   DicEntry->ScanNumber++;
+}
+
+/*
+ * Implement the write method
+ * (Write a scan line into the Dicache entry)
+ * buf: row buffer
+ * Y  : row number
+ */
+void a_Dicache_write(DilloImage *Image, DilloUrl *url, int version,
+                     const uchar_t *buf, uint_t Y)
+{
+   DICacheEntry *DicEntry;
+
+   _MSG("a_Dicache_write\n");
+   dReturn_if_fail ( Image != NULL );
+   DicEntry = a_Dicache_get_entry(url, version);
+   dReturn_if_fail ( DicEntry != NULL );
+   dReturn_if_fail ( DicEntry->width > 0 && DicEntry->height > 0 );
+
+   /* update the common buffer in the imgbuf */
+   a_Imgbuf_update(DicEntry->v_imgbuf, buf, DicEntry->type,
+                   DicEntry->cmap, DicEntry->width, DicEntry->height, Y);
+
+   DicEntry->Y = Y;
+   a_Bitvec_set_bit(DicEntry->BitVec, (int)Y);
+   DicEntry->State = DIC_Write;
+}
+
+/*
+ * Implement the close method of the decoding process
+ */
+void a_Dicache_close(DilloUrl *url, int version, CacheClient_t *Client)
+{
+   DilloWeb *Web = Client->Web;
+   DICacheEntry *DicEntry = a_Dicache_get_entry(url, version);
+
+   dReturn_if_fail ( DicEntry != NULL );
+
+   /* a_Dicache_unref() may free DicEntry */
+   _MSG("a_Dicache_close RefCount=%d\n", DicEntry->RefCount - 1);
+
+   if (DicEntry->State < DIC_Close) {
+      DicEntry->State = DIC_Close;
+      dFree(DicEntry->cmap);
+      DicEntry->cmap = NULL;
+      DicEntry->Decoder = NULL;
+      DicEntry->DecoderData = NULL;
+   }
+   a_Dicache_unref(url, version);
+
+   a_Bw_close_client(Web->bw, Client->Key);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
  * This function is a cache client; (but feeds its clients from dicache)
  */
 void a_Dicache_callback(int Op, CacheClient_t *Client)
@@ -258,10 +381,27 @@
    uint_t i;
    DilloWeb *Web = Client->Web;
    DilloImage *Image = Web->Image;
-   DICacheEntry *DicEntry = a_Dicache_get_entry(Web->url);
+   DICacheEntry *DicEntry = a_Dicache_get_entry(Web->url, DIC_Last);
 
    dReturn_if_fail ( DicEntry != NULL );
 
+   /* Copy the version number in the Client */
+   if (Client->Version == 0)
+      Client->Version = DicEntry->version;
+
+   /* Only call the decoder when necessary */
+   if (Op == CA_Send && DicEntry->State < DIC_Close &&
+       DicEntry->DecodedSize < Client->BufSize) {
+      DicEntry->Decoder(Op, Client);
+      DicEntry->DecodedSize = Client->BufSize;
+   } else if (Op == CA_Close || Op == CA_Abort) {
+      if (DicEntry->State < DIC_Close) {
+         DicEntry->Decoder(Op, Client);
+      } else {
+         a_Dicache_close(DicEntry->url, DicEntry->version, Client);
+      }
+   }
+
    /* when the data stream is not an image 'v_imgbuf' remains NULL */
    if (Op == CA_Send && DicEntry->v_imgbuf) {
       if (Image->height == 0 && DicEntry->State >= DIC_SetParms) {
@@ -276,15 +416,13 @@
             for (i = 0; i < DicEntry->height; ++i)
                if (a_Bitvec_get_bit(DicEntry->BitVec, (int)i) &&
                    !a_Bitvec_get_bit(Image->BitVec, (int)i) )
-                  a_Image_write(Image, DicEntry->v_imgbuf,
-                                DicEntry->linebuf, i, FALSE);
+                  a_Image_write(Image, i);
          } else {
             for (i = 0; i < DicEntry->height; ++i) {
                if (a_Bitvec_get_bit(DicEntry->BitVec, (int)i) ||
                    !a_Bitvec_get_bit(Image->BitVec, (int)i)   ||
                    DicEntry->ScanNumber > Image->ScanNumber + 1) {
-                  a_Image_write(Image, DicEntry->v_imgbuf,
-                                DicEntry->linebuf, i, FALSE);
+                  a_Image_write(Image, i);
                }
                if (!a_Bitvec_get_bit(DicEntry->BitVec, (int)i))
                   a_Bitvec_clear_bit(Image->BitVec, (int)i);
@@ -301,129 +439,6 @@
 /* ------------------------------------------------------------------------- */
 
 /*
- * Set image's width, height & type
- * (By now, we'll use the image information despite the html tags --Jcid)
- */
-void a_Dicache_set_parms(DilloUrl *url, int version, DilloImage *Image,
-                         uint_t width, uint_t height, DilloImgType type)
-{
-   DICacheEntry *DicEntry;
-
-   dReturn_if_fail ( Image != NULL && width && height );
-   /* Find the DicEntry for this Image */
-   DicEntry = Dicache_get_entry_version(url, version);
-   dReturn_if_fail ( DicEntry != NULL );
-   /* Parameters already set? */
-   dReturn_if_fail ( DicEntry->State < DIC_SetParms );
-
-   /* Initialize the DicEntry */
-   DicEntry->linebuf = dNew(uchar_t, width * 3);
-   dReturn_if_fail ( DicEntry->linebuf != NULL );
-
-   /* BUG: there's just one image-type now */
-   #define I_RGB 0
-   DicEntry->v_imgbuf = a_Image_imgbuf_new(Image->dw, I_RGB, width, height);
-
-   /* This extra reference activates the dicache ALWAYS.
-    * Extra code is necessary in Imgbuf to be able to free it */
-   //a_Image_imgbuf_ref(DicEntry->v_imgbuf);
-
-   DicEntry->TotalSize = width * height * 3;
-   DicEntry->width = width;
-   DicEntry->height = height;
-   DicEntry->type = type;
-   DicEntry->BitVec = a_Bitvec_new((int)height);
-   DicEntry->State = DIC_SetParms;
-
-   dicache_size_total += DicEntry->TotalSize;
-
-   /* Allocate and initialize this image */
-   a_Image_set_parms(Image, DicEntry->v_imgbuf, url, version,
-                     width, height, type);
-}
-
-/*
- * Implement the set_cmap method for the Image
- */
-void a_Dicache_set_cmap(DilloUrl *url, int version, DilloImage *Image,
-                        const uchar_t *cmap, uint_t num_colors,
-                        int num_colors_max, int bg_index)
-{
-   DICacheEntry *DicEntry = Dicache_get_entry_version(url, version);
-
-   dReturn_if_fail ( DicEntry != NULL );
-
-   dFree(DicEntry->cmap);
-   DicEntry->cmap = dNew0(uchar_t, 3 * num_colors_max);
-   memcpy(DicEntry->cmap, cmap, 3 * num_colors);
-   if (bg_index >= 0 && (uint_t)bg_index < num_colors) {
-      DicEntry->cmap[bg_index * 3]     = (Image->bg_color >> 16) & 0xff;
-      DicEntry->cmap[bg_index * 3 + 1] = (Image->bg_color >> 8) & 0xff;
-      DicEntry->cmap[bg_index * 3 + 2] = (Image->bg_color) & 0xff;
-   }
-
-   a_Image_set_cmap(Image, DicEntry->cmap);
-   DicEntry->State = DIC_SetCmap;
-}
-
-/*
- * Reset for a new scan from a multiple-scan image.
- */
-void a_Dicache_new_scan(DilloImage *image, const DilloUrl *url, int version)
-{
-   DICacheEntry *DicEntry;
-
-   dReturn_if_fail ( url != NULL );
-   DicEntry = Dicache_get_entry_version(url, version);
-   dReturn_if_fail ( DicEntry != NULL );
-
-   a_Bitvec_clear(DicEntry->BitVec);
-   DicEntry->ScanNumber++;
-   a_Image_new_scan(image, DicEntry->v_imgbuf);
-}
-
-/*
- * Implement the write method
- * (Write a scan line into the Dicache entry)
- * buf: row buffer
- * Y  : row number
- */
-void a_Dicache_write(DilloImage *Image, DilloUrl *url, int version,
-                     const uchar_t *buf, uint_t Y)
-{
-   DICacheEntry *DicEntry;
-
-   dReturn_if_fail ( Image != NULL );
-   DicEntry = Dicache_get_entry_version(url, version);
-   dReturn_if_fail ( DicEntry != NULL );
-   dReturn_if_fail ( DicEntry->width > 0 && DicEntry->height > 0 );
-
-   a_Image_write(Image, DicEntry->v_imgbuf, buf, Y, TRUE);
-   DicEntry->Y = Y;
-   a_Bitvec_set_bit(DicEntry->BitVec, (int)Y);
-   DicEntry->State = DIC_Write;
-}
-
-/*
- * Implement the close method of the decoding process
- */
-void a_Dicache_close(DilloUrl *url, int version, CacheClient_t *Client)
-{
-   DilloWeb *Web = Client->Web;
-   DICacheEntry *DicEntry = Dicache_get_entry_version(url, version);
-
-   dReturn_if_fail ( DicEntry != NULL );
-
-   DicEntry->State = DIC_Close;
-   dFree(DicEntry->cmap);
-   DicEntry->cmap = NULL;
-   dFree(DicEntry->linebuf);
-   DicEntry->linebuf = NULL;
-   a_Image_close(Web->Image);
-   a_Bw_close_client(Web->bw, Client->Key);
-}
-
-/*
  * Free the imgbuf (RGB data) of unused entries.
  */
 void a_Dicache_cleanup(void)
@@ -432,12 +447,13 @@
    DICacheNode *node;
    DICacheEntry *entry;
 
+   _MSG("a_Dicache_cleanup\n");
    for (i = 0; i < dList_length(CachedIMGs); ++i) {
       node = dList_nth_data(CachedIMGs, i);
       /* iterate each entry of this node */
       for (entry = node->first; entry; entry = entry->next) {
          if (entry->v_imgbuf &&
-             a_Image_imgbuf_last_reference(entry->v_imgbuf)) {
+             a_Imgbuf_last_reference(entry->v_imgbuf)) {
             /* free this unused entry */
             if (entry->next) {
                Dicache_remove(node->url, entry->version);
@@ -467,9 +483,8 @@
       while ((entry = node->first)) {
          node->first = entry->next;
          dFree(entry->cmap);
-         dFree(entry->linebuf);
          a_Bitvec_free(entry->BitVec);
-         a_Image_imgbuf_unref(entry->v_imgbuf);
+         a_Imgbuf_unref(entry->v_imgbuf);
          dicache_size_total -= entry->TotalSize;
       }
       dList_remove(CachedIMGs, node);
--- a/src/dicache.h	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/dicache.h	Fri Jan 16 14:32:20 2009 -0300
@@ -10,6 +10,10 @@
 #include "image.hh"
 #include "cache.h"
 
+/* Symbolic name to request the last version of an image */
+#define DIC_Last  -1
+
+
 /* These will reflect the entry's "state" */
 typedef enum {
    DIC_Empty,      /* Just created the entry */
@@ -27,7 +31,6 @@
    uint_t width, height;   /* As taken from image data */
    DilloImgType type;      /* Image type */
    uchar_t *cmap;          /* Color map */
-   uchar_t *linebuf;       /* Decompressed RGB buffer for one line */
    void *v_imgbuf;         /* Void pointer to an Imgbuf object */
    uint_t TotalSize;       /* Amount of memory the image takes up */
    int Y;                  /* Current decoding row */
@@ -37,23 +40,29 @@
    int RefCount;           /* Reference Counter */
    int version;            /* Version number, used for different
                               versions of the same URL image */
+
+   CA_Callback_t Decoder;  /* Client function */
+   void *DecoderData;      /* Client function data */
+   uint_t DecodedSize;     /* Size of already decoded data */
+
    DICacheEntry *next;     /* Link to the next "newer" version */
 };
 
 
 void a_Dicache_init (void);
 
-DICacheEntry *a_Dicache_get_entry(const DilloUrl *Url);
+DICacheEntry *a_Dicache_get_entry(const DilloUrl *Url, int version);
 DICacheEntry *a_Dicache_add_entry(const DilloUrl *Url);
 
 void a_Dicache_callback(int Op, CacheClient_t *Client);
+void a_Dicache_callback2(int Op, CacheClient_t *Client);
 
 void a_Dicache_set_parms(DilloUrl *url, int version, DilloImage *Image,
                          uint_t width, uint_t height, DilloImgType type);
 void a_Dicache_set_cmap(DilloUrl *url, int version, DilloImage *Image,
                         const uchar_t *cmap, uint_t num_colors,
                         int num_colors_max, int bg_index);
-void a_Dicache_new_scan(DilloImage *image, const DilloUrl *url, int version);
+void a_Dicache_new_scan(const DilloUrl *url, int version);
 void a_Dicache_write(DilloImage *Image, DilloUrl *url, int version,
                      const uchar_t *buf, uint_t Y);
 void a_Dicache_close(DilloUrl *url, int version, CacheClient_t *Client);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/doctree.hh	Fri Jan 16 14:32:20 2009 -0300
@@ -0,0 +1,21 @@
+#ifndef __DOCTREE_HH__
+#define __DOCTREE_HH__
+
+class DoctreeNode {
+   public:
+      int num; // unique ascending id
+      int depth;
+      int element;
+      const char *klass;
+      const char *pseudo;
+      const char *id;
+};
+
+class Doctree {
+   public:
+      virtual ~Doctree () {};
+      virtual const DoctreeNode *top () = 0;
+      virtual const DoctreeNode *parent (const DoctreeNode *node) = 0;
+};
+
+#endif
--- a/src/form.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/form.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -294,7 +294,7 @@
    char *charset, *first;
    const char *attrbuf;
 
-   DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
+   DW2TB(html->dw)->addParbreak (9, html->styleEngine->wordStyle ());
 
    if (html->InFlags & IN_FORM) {
       BUG_MSG("nested forms\n");
@@ -558,10 +558,10 @@
       if (prefs.standard_widget_colors)
          bg = NULL;
       else
-         bg = Color::createShaded(HT2LT(html), S_TOP(html)->current_bg_color);
+         bg = Color::create (HT2LT(html), S_TOP(html)->current_bg_color);
       HTML_SET_TOP_ATTR(html, backgroundColor, bg);
 
-      DW2TB(html->dw)->addWidget (embed, S_TOP(html)->style);
+      DW2TB(html->dw)->addWidget (embed, html->styleEngine->style ());
    }
    dFree(type);
    dFree(name);
@@ -594,10 +594,10 @@
                  html->charset);
    html->InFlags |= IN_FORM;
 
-   DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
+   DW2TB(html->dw)->addParbreak (9, html->styleEngine->wordStyle ());
 
    if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "prompt")))
-      DW2TB(html->dw)->addText(attrbuf, S_TOP(html)->style);
+      DW2TB(html->dw)->addText(attrbuf, html->styleEngine->wordStyle ());
 
    ResourceFactory *factory = HT2LT(html)->getResourceFactory();
    EntryResource *entryResource = factory->createEntryResource (20,false,NULL);
@@ -608,9 +608,9 @@
    if (prefs.standard_widget_colors)
       bg = NULL;
    else
-      bg = Color::createShaded(HT2LT(html), S_TOP(html)->current_bg_color);
+      bg = Color::create (HT2LT(html), S_TOP(html)->current_bg_color);
    HTML_SET_TOP_ATTR(html, backgroundColor, bg);
-   DW2TB(html->dw)->addWidget (embed, S_TOP(html)->style);
+   DW2TB(html->dw)->addWidget (embed, html->styleEngine->style ());
 
    a_Url_free(action);
    html->InFlags &= ~IN_FORM;
@@ -676,10 +676,10 @@
    if (prefs.standard_widget_colors)
       bg = NULL;
    else
-      bg = Color::createShaded(HT2LT(html), S_TOP(html)->current_bg_color);
+      bg = Color::create (HT2LT(html), S_TOP(html)->current_bg_color);
    HTML_SET_TOP_ATTR(html, backgroundColor, bg);
 
-   DW2TB(html->dw)->addWidget (embed, S_TOP(html)->style);
+   DW2TB(html->dw)->addWidget (embed, html->styleEngine->style ());
    dFree(name);
 }
 
@@ -760,7 +760,7 @@
    }
    HTML_SET_TOP_ATTR(html, backgroundColor,
                      Color::createShaded (HT2LT(html), bg));
-   DW2TB(html->dw)->addWidget (embed, S_TOP(html)->style);
+   DW2TB(html->dw)->addWidget (embed, html->styleEngine->style ());
 
 // size = 0;
 // if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "size")))
@@ -879,12 +879,12 @@
       Embed *embed;
       char *name, *value;
 
-      style_attrs = *S_TOP(html)->style;
+      style_attrs = *html->styleEngine->style ();
       style_attrs.margin.setVal(0);
       style_attrs.borderWidth.setVal(0);
       style_attrs.padding.setVal(0);
       style_attrs.backgroundColor =
-               Color::createShaded(HT2LT(html), S_TOP(html)->current_bg_color);
+               Color::create (HT2LT(html), S_TOP(html)->current_bg_color);
       style = Style::create (HT2LT(html), &style_attrs);
 
       page = new Textblock (prefs.limit_text_width);
@@ -1945,14 +1945,11 @@
 
    if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "src")) &&
        (url = a_Html_url_new(html, attrbuf, NULL, 0))) {
-      style_attrs = *S_TOP(html)->style;
+      style_attrs = *html->styleEngine->style ();
       style_attrs.cursor = CURSOR_POINTER;
-      style_attrs.backgroundColor =
-        style::Color::createShaded(HT2LT(html), S_TOP(html)->current_bg_color);
 
       /* create new image and add it to the button */
-      if ((Image = a_Html_add_new_image(html, tag, tagsize, url, &style_attrs,
-                                        false))) {
+      if ((Image = a_Html_add_new_image(html, tag, tagsize, url, false))) {
          Style *style = Style::create (HT2LT(html), &style_attrs);
          IM2DW(Image)->setStyle (style);
          ResourceFactory *factory = HT2LT(html)->getResourceFactory();
--- a/src/gif.c	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/gif.c	Fri Jan 16 14:32:20 2009 -0300
@@ -157,7 +157,8 @@
 
 /*
  * MIME handler for "image/gif" type
- * (Sets Gif_callback as cache-client)
+ * Sets a_Dicache_callback as the cache-client,
+ * and Gif_callback as the image decoder.
  */
 void *a_Gif_image(const char *Type, void *Ptr, CA_Callback_t *Call,
                   void **Data)
@@ -172,20 +173,20 @@
    /* Add an extra reference to the Image (for dicache usage) */
    a_Image_ref(web->Image);
 
-   DicEntry = a_Dicache_get_entry(web->url);
+   DicEntry = a_Dicache_get_entry(web->url, DIC_Last);
    if (!DicEntry) {
       /* Let's create an entry for this image... */
       DicEntry = a_Dicache_add_entry(web->url);
-
-      /* ... and let the decoder feed it! */
-      *Data = Gif_new(web->Image, DicEntry->url, DicEntry->version);
-      *Call = (CA_Callback_t) Gif_callback;
+      DicEntry->DecoderData =
+         Gif_new(web->Image, DicEntry->url, DicEntry->version);
    } else {
-      /* Let's feed our client from the dicache */
+      /* Repeated image */
       a_Dicache_ref(DicEntry->url, DicEntry->version);
-      *Data = web->Image;
-      *Call = (CA_Callback_t) a_Dicache_callback;
    }
+   DicEntry->Decoder = Gif_callback;
+   *Data = DicEntry->DecoderData;
+   *Call = (CA_Callback_t) a_Dicache_callback;
+
    return (web->Image->dw);
 }
 
@@ -261,7 +262,7 @@
 {
    int i;
 
-   _MSG("destroy gif %p\n", gif);
+   _MSG("Gif_close: destroy gif %p\n", gif);
 
    a_Dicache_close(gif->url, gif->version, Client);
 
--- a/src/html.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/html.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -106,14 +106,10 @@
                                   int tagsize,
                                   const char *attrname,
                                   int tag_parsing_flags);
-static void Html_add_widget(DilloHtml *html, Widget *widget,
-                            char *width_str, char *height_str,
-                            StyleAttrs *style_attrs);
 static int Html_write_raw(DilloHtml *html, char *buf, int bufsize, int Eof);
 static void Html_load_image(BrowserWindow *bw, DilloUrl *url,
                             DilloImage *image);
 static void Html_callback(int Op, CacheClient_t *Client);
-static int Html_tag_index(const char *tag);
 static void Html_tag_cleanup_at_close(DilloHtml *html, int TagIdx);
 
 /*-----------------------------------------------------------------------------
@@ -312,52 +308,30 @@
 }
 
 /*
- * Set the font at the top of the stack. BImask specifies which
- * attributes in BI should be changed.
- */
-void a_Html_set_top_font(DilloHtml *html, const char *name, int size,
-                         int BI, int BImask)
-{
-   FontAttrs font_attrs;
-
-   font_attrs = *S_TOP(html)->style->font;
-   if (name)
-      font_attrs.name = name;
-   if (size)
-      font_attrs.size = size;
-   if (BImask & 1)
-      font_attrs.weight = (BI & 1) ? 700 : 400;
-   if (BImask & 2)
-      font_attrs.style = (BI & 2) ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL;
-
-   HTML_SET_TOP_ATTR (html, font,
-                      Font::create (HT2LT(html), &font_attrs));
-}
-
-/*
  * Evaluates the ALIGN attribute (left|center|right|justify) and
  * sets the style at the top of the stack.
  */
 void a_Html_tag_set_align_attr(DilloHtml *html,
+                               CssPropertyList *props,        
                                const char *tag, int tagsize)
 {
-   const char *align, *charattr;
+   const char *align;
 
    if ((align = a_Html_get_attr(html, tag, tagsize, "align"))) {
-      Style *old_style = S_TOP(html)->style;
-      StyleAttrs style_attrs = *old_style;
+      TextAlignType textAlignType = TEXT_ALIGN_LEFT;
 
       if (dStrcasecmp (align, "left") == 0)
-         style_attrs.textAlign = TEXT_ALIGN_LEFT;
+         textAlignType = TEXT_ALIGN_LEFT;
       else if (dStrcasecmp (align, "right") == 0)
-         style_attrs.textAlign = TEXT_ALIGN_RIGHT;
+         textAlignType = TEXT_ALIGN_RIGHT;
       else if (dStrcasecmp (align, "center") == 0)
-         style_attrs.textAlign = TEXT_ALIGN_CENTER;
+         textAlignType = TEXT_ALIGN_CENTER;
       else if (dStrcasecmp (align, "justify") == 0)
-         style_attrs.textAlign = TEXT_ALIGN_JUSTIFY;
+         textAlignType = TEXT_ALIGN_JUSTIFY;
+#if 0
       else if (dStrcasecmp (align, "char") == 0) {
          /* TODO: Actually not supported for <p> etc. */
-         style_attrs.textAlign = TEXT_ALIGN_STRING;
+         v.textAlign = TEXT_ALIGN_STRING;
          if ((charattr = a_Html_get_attr(html, tag, tagsize, "char"))) {
             if (charattr[0] == 0)
                /* TODO: ALIGN=" ", and even ALIGN="&32;" will reult in
@@ -371,8 +345,8 @@
             /* TODO: Examine LANG attr of <html>. */
             style_attrs.textAlignChar = '.';
       }
-      S_TOP(html)->style = Style::create (HT2LT(html), &style_attrs);
-      old_style->unref ();
+#endif
+      props->set (CssProperty::CSS_PROPERTY_TEXT_ALIGN, textAlignType);
    }
 }
 
@@ -381,19 +355,22 @@
  * sets the style in style_attrs. Returns true when set.
  */
 bool a_Html_tag_set_valign_attr(DilloHtml *html, const char *tag,
-                                int tagsize, StyleAttrs *style_attrs)
+                                int tagsize, CssPropertyList *props)
 {
    const char *attr;
+   VAlignType valign;
 
    if ((attr = a_Html_get_attr(html, tag, tagsize, "valign"))) {
       if (dStrcasecmp (attr, "top") == 0)
-         style_attrs->valign = VALIGN_TOP;
+         valign = VALIGN_TOP;
       else if (dStrcasecmp (attr, "bottom") == 0)
-         style_attrs->valign = VALIGN_BOTTOM;
+         valign = VALIGN_BOTTOM;
       else if (dStrcasecmp (attr, "baseline") == 0)
-         style_attrs->valign = VALIGN_BASELINE;
+         valign = VALIGN_BASELINE;
       else
-         style_attrs->valign = VALIGN_MIDDLE;
+         valign = VALIGN_MIDDLE;
+
+      props->set (CssProperty::CSS_PROPERTY_VERTICAL_ALIGN, valign);
       return true;
    } else
       return false;
@@ -401,87 +378,23 @@
 
 
 /*
- * Add a new DwPage into the current DwPage, for indentation.
- * left and right are the horizontal indentation amounts, space is the
- * vertical space around the block.
+ * Create and add a new Textblock to the current Textblock
  */
-static void Html_add_indented_widget(DilloHtml *html, Widget *textblock,
-                                     int left, int right, int space)
+static void Html_add_textblock(DilloHtml *html, int space)
 {
-   StyleAttrs style_attrs;
-   Style *style;
-
-   style_attrs = *S_TOP(html)->style;
-
-   style_attrs.margin.setVal (0);
-   style_attrs.borderWidth.setVal (0);
-   style_attrs.padding.setVal(0);
-
-   /* Activate this for debugging */
-#if 0
-   style_attrs.borderWidth.setVal (1);
-   style_attrs.setBorderColor (
-      Color::createShaded (HT2LT(html), style_attrs.color->getColor());
-   style_attrs.setBorderStyle (BORDER_DASHED);
-#endif
-
-   style_attrs.margin.left = left;
-   style_attrs.margin.right = right;
-   style = Style::create (HT2LT(html), &style_attrs);
-
-   DW2TB(html->dw)->addParbreak (space, style);
-   DW2TB(html->dw)->addWidget (textblock, style);
-   DW2TB(html->dw)->addParbreak (space, style);
+   Textblock *textblock = new Textblock (prefs.limit_text_width);
+
+   DW2TB(html->dw)->addParbreak (space, html->styleEngine->wordStyle ());
+   DW2TB(html->dw)->addWidget (textblock, html->styleEngine->style ());
+   DW2TB(html->dw)->addParbreak (space, html->styleEngine->wordStyle ());
    S_TOP(html)->textblock = html->dw = textblock;
    S_TOP(html)->hand_over_break = true;
-   style->unref ();
 
    /* Handle it when the user clicks on a link */
    html->connectSignals(textblock);
 }
 
 /*
- * Create and add a new indented DwPage to the current DwPage
- */
-static void Html_add_indented(DilloHtml *html, int left, int right, int space)
-{
-   Textblock *textblock = new Textblock (prefs.limit_text_width);
-   Html_add_indented_widget (html, textblock, left, right, space);
-}
-
-/*
- * Given a font_size, this will return the correct 'level'.
- * (or the closest, if the exact level isn't found).
- */
-static int Html_fontsize_to_level(int fontsize)
-{
-   int i, level;
-   double normalized_size = fontsize / prefs.font_factor,
-          approximation   = FontSizes[FontSizesNum-1] + 1;
-
-   for (i = level = 0; i < FontSizesNum; i++)
-      if (approximation >= fabs(normalized_size - FontSizes[i])) {
-         approximation = fabs(normalized_size - FontSizes[i]);
-         level = i;
-      } else {
-         break;
-      }
-
-   return level;
-}
-
-/*
- * Given a level of a font, this will return the correct 'size'.
- */
-static int Html_level_to_fontsize(int level)
-{
-   level = MAX(0, level);
-   level = MIN(FontSizesNum - 1, level);
-
-   return (int)rint(FontSizes[level]*prefs.font_factor);
-}
-
-/*
  * Create and initialize a new DilloHtml class
  */
 DilloHtml::DilloHtml(BrowserWindow *p_bw, const DilloUrl *url,
@@ -510,6 +423,7 @@
    a_Misc_parse_content_type(content_type, NULL, NULL, &charset);
 
    stop_parser = false;
+   repush_after_head = false;
 
    CurrTagOfs = 0;
    OldTagOfs = 0;
@@ -520,8 +434,7 @@
 
    stack = new misc::SimpleVector <DilloHtmlState> (16);
    stack->increase();
-   stack->getRef(0)->style = NULL;
-   stack->getRef(0)->table_cell_style = NULL;
+   stack->getRef(0)->table_cell_props = NULL;
    stack->getRef(0)->parse_mode = DILLO_HTML_PARSE_MODE_INIT;
    stack->getRef(0)->table_mode = DILLO_HTML_TABLE_MODE_NONE;
    stack->getRef(0)->cell_text_align_set = false;
@@ -534,6 +447,8 @@
    stack->getRef(0)->current_bg_color = prefs.bg_color;
    stack->getRef(0)->hand_over_break = false;
 
+   styleEngine = new StyleEngine (HT2LT (this));
+
    InFlags = IN_NONE;
 
    Stash = dStr_new("");
@@ -561,8 +476,8 @@
    images = new misc::SimpleVector <DilloLinkImage*> (16);
    //a_Dw_image_map_list_init(&maps);
 
-   link_color = prefs.link_color;
-   visited_color = prefs.visited_color;
+   link_color = -1;
+   visited_color = -1;
 
    /* Initialize the main widget */
    initDw();
@@ -575,26 +490,12 @@
  */
 void DilloHtml::initDw()
 {
-   StyleAttrs style_attrs;
-   FontAttrs font_attrs;
-
    dReturn_if_fail (dw == NULL);
 
    /* Create the main widget */
    dw = stack->getRef(0)->textblock = new Textblock (prefs.limit_text_width);
 
-   /* Create a dummy font, attribute, and tag for the bottom of the stack. */
-   font_attrs.name = prefs.vw_fontname;
-   font_attrs.size = Html_level_to_fontsize(FontSizesBase);
-   font_attrs.weight = 400;
-   font_attrs.style = FONT_STYLE_NORMAL;
-
-   style_attrs.initValues ();
-   style_attrs.font = Font::create (HT2LT(this), &font_attrs);
-   style_attrs.color = Color::createSimple (HT2LT(this), prefs.text_color);
-   stack->getRef(0)->style = Style::create (HT2LT(this), &style_attrs);
-
-   stack->getRef(0)->table_cell_style = NULL;
+   stack->getRef(0)->table_cell_props = NULL;
 
    /* Handle it when the user clicks on a link */
    connectSignals(dw);
@@ -640,6 +541,8 @@
    }
    delete (images);
 
+   delete styleEngine;
+
    //a_Dw_image_map_list_free(&maps);
 }
 
@@ -661,7 +564,15 @@
    char *buf = Buf + Start_Ofs;
    int bufsize = BufSize - Start_Ofs;
 
+   _MSG("DilloHtml::write BufSize=%d Start_Ofs=%d\n", BufSize, Start_Ofs);
+#if 0
+   char *aux = dStrndup(Buf, BufSize);
+   MSG(" {%s}\n", aux);
+   dFree(aux);
+#endif
+
    dReturn_if_fail (dw != NULL);
+   dReturn_if_fail (stop_parser == FALSE);
 
    Start_Buf = Buf;
    token_start = Html_write_raw(this, buf, bufsize, Eof);
@@ -694,7 +605,6 @@
  */
 void DilloHtml::freeParseData()
 {
-   (stack->getRef(0)->style)->unref ();  /* template style */
    delete(stack);
 
    dStr_free(Stash, TRUE);
@@ -1150,11 +1060,11 @@
 
             if (spaceCnt) {
                spc = dStrnfill(spaceCnt, ' ');
-               DW2TB(html->dw)->addText (spc, S_TOP(html)->style);
+               DW2TB(html->dw)->addText (spc, html->styleEngine->wordStyle ());
                dFree(spc);
                spaceCnt = 0;
             }
-            DW2TB(html->dw)->addLinebreak (S_TOP(html)->style);
+            DW2TB(html->dw)->addLinebreak (html->styleEngine->wordStyle ());
             html->pre_column = 0;
          }
          html->PreFirstChar = false;
@@ -1182,7 +1092,7 @@
 
       if (spaceCnt) {
          spc = dStrnfill(spaceCnt, ' ');
-         DW2TB(html->dw)->addText (spc, S_TOP(html)->style);
+         DW2TB(html->dw)->addText (spc, html->styleEngine->wordStyle ());
          dFree(spc);
       }
 
@@ -1190,7 +1100,7 @@
       if (SGML_SPCDEL) {
          /* SGML_SPCDEL ignores white space inmediately after an open tag */
       } else if (!html->PrevWasSPC) {
-         DW2TB(html->dw)->addSpace(S_TOP(html)->style);
+         DW2TB(html->dw)->addSpace(html->styleEngine->wordStyle ());
          html->PrevWasSPC = true;
       }
 
@@ -1243,7 +1153,7 @@
             while (Pword[++i] && !isspace(Pword[i])) ;
             ch = Pword[i];
             Pword[i] = 0;
-            DW2TB(html->dw)->addText(Pword, S_TOP(html)->style);
+            DW2TB(html->dw)->addText(Pword, html->styleEngine->wordStyle ());
             Pword[i] = ch;
             html->pre_column += i - start;
             html->PreFirstChar = false;
@@ -1253,7 +1163,7 @@
    } else {
       if (!memchr(word,'&', size)) {
          /* No entities */
-         DW2TB(html->dw)->addText(word, S_TOP(html)->style);
+         DW2TB(html->dw)->addText(word, html->styleEngine->wordStyle ());
       } else {
          /* Collapse white-space entities inside the word (except &nbsp;) */
          Pword = a_Html_parse_entities(html, word, size);
@@ -1261,7 +1171,7 @@
             if (strchr("\t\f\n\r", Pword[i]))
                for (j = i; (Pword[j] = Pword[j+1]); ++j) ;
    
-         DW2TB(html->dw)->addText(Pword, S_TOP(html)->style);
+         DW2TB(html->dw)->addText(Pword, html->styleEngine->wordStyle ());
          dFree(Pword);
       }
    }
@@ -1297,7 +1207,7 @@
 {
    if (html->dw != S_TOP(html)->textblock) {
       if (hand_over_break)
-         DW2TB(html->dw)->handOverBreak (S_TOP(html)->style);
+         DW2TB(html->dw)->handOverBreak (html->styleEngine->style ());
       DW2TB(html->dw)->flush ();
       html->dw = S_TOP(html)->textblock;
    }
@@ -1316,10 +1226,8 @@
     * instead of copying all fields except for tag.  --Jcid */
    *html->stack->getRef(n_items) = *html->stack->getRef(n_items - 1);
    html->stack->getRef(n_items)->tag_idx = tag_idx;
-   /* proper memory management, may be unref'd later */
-   (S_TOP(html)->style)->ref ();
-   if (S_TOP(html)->table_cell_style)
-      (S_TOP(html)->table_cell_style)->ref ();
+   if (S_TOP(html)->table_cell_props)
+      S_TOP(html)->table_cell_props->ref ();
    html->dw = S_TOP(html)->textblock;
 }
 
@@ -1329,6 +1237,7 @@
  */
 static void Html_force_push_tag(DilloHtml *html, int tag_idx)
 {
+   html->styleEngine->startElement (tag_idx);
    Html_push_tag(html, tag_idx);
 }
 
@@ -1339,9 +1248,9 @@
 {
    bool hand_over_break;
 
-   (S_TOP(html)->style)->unref ();
-   if (S_TOP(html)->table_cell_style)
-      (S_TOP(html)->table_cell_style)->unref ();
+   html->styleEngine->endElement (S_TOP(html)->tag_idx);
+   if (S_TOP(html)->table_cell_props)
+      S_TOP(html)->table_cell_props->unref ();
    hand_over_break = S_TOP(html)->hand_over_break;
    html->stack->setSize (html->stack->size() - 1);
    Html_eventually_pop_dw(html, hand_over_break);
@@ -1416,10 +1325,10 @@
 /*
  * Used by a_Html_parse_length
  */
-static Length Html_parse_length_or_multi_length (const char *attr,
-                                                 char **endptr)
+static CssLength Html_parse_length_or_multi_length (const char *attr,
+                                                    char **endptr)
 {
-   Length l;
+   CssLength l;
    double v;
    char *end;
 
@@ -1427,12 +1336,12 @@
    switch (*end) {
    case '%':
       end++;
-      l = createPerLength (v / 100);
+      l = CSS_CREATE_LENGTH (v / 100, CSS_LENGTH_TYPE_PERCENTAGE);
       break;
 
    case '*':
       end++;
-      l = createRelLength (v);
+      l = CSS_CREATE_LENGTH (v, CSS_LENGTH_TYPE_RELATIVE);
       break;
 /*
    The "px" suffix seems not allowed by HTML4.01 SPEC.
@@ -1441,7 +1350,7 @@
          end += 2;
 */
    default:
-      l = createAbsLength ((int)v);
+      l = CSS_CREATE_LENGTH (v, CSS_LENGTH_TYPE_PX);
       break;
    }
 
@@ -1455,24 +1364,24 @@
  * Returns a length or a percentage, or UNDEF_LENGTH in case
  * of an error, or if attr is NULL.
  */
-Length a_Html_parse_length (DilloHtml *html, const char *attr)
+CssLength a_Html_parse_length (DilloHtml *html, const char *attr)
 {
-   Length l;
+   CssLength l;
    char *end;
 
    l = Html_parse_length_or_multi_length (attr, &end);
-   if (isRelLength (l))
+   if (CSS_LENGTH_TYPE (l) == CSS_LENGTH_TYPE_RELATIVE)
       /* not allowed as &Length; */
-      return LENGTH_AUTO;
+      l = CSS_CREATE_LENGTH(0.0, CSS_LENGTH_TYPE_AUTO);
    else {
       /* allow only whitespaces */
       if (*end && !isspace (*end)) {
          BUG_MSG("Garbage after length: %s\n", attr);
-         return LENGTH_AUTO;
+         l = CSS_CREATE_LENGTH(0.0, CSS_LENGTH_TYPE_AUTO);
       }
    }
 
-   _MSG("a_Html_parse_length: \"%s\" %d\n", attr, absLengthVal(l));
+   _MSG("a_Html_parse_length: \"%s\" %d\n", attr, CSS_LENGTH_VALUE(l));
    return l;
 }
 
@@ -1649,14 +1558,23 @@
  * Handle close HEAD element
  * Note: as a side effect of Html_test_section() this function is called
  *       twice when the head element is closed implicitly.
+ * Note2: HEAD is parsed once completely got. This asserts that a
+ *        linked stylesheet will always arrive after HEAD contents.
  */
 static void Html_tag_close_head(DilloHtml *html, int TagIdx)
 {
    if (html->InFlags & IN_HEAD) {
+      _MSG("Closing HEAD section\n");
       if (html->Num_TITLE == 0)
          BUG_MSG("HEAD section lacks the TITLE element\n");
-   
+
       html->InFlags &= ~IN_HEAD;
+
+      if (html->repush_after_head) {
+         html->stop_parser = true;
+         MSG(" [html->stop_parser = true]\n");
+         a_Nav_repush(html->bw);
+      }
    }
 }
 
@@ -1706,11 +1624,27 @@
 
 /*
  * Handle open STYLE
- * store the contents to the stash where (in the future) the style
- * sheet interpreter can get it.
+ * Store contents in the stash where the style sheet interpreter can get it.
  */
 static void Html_tag_open_style(DilloHtml *html, const char *tag, int tagsize)
 {
+   const char *attrbuf;
+
+   if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "type"))) {
+      BUG_MSG("type attribute is required for <style>\n");
+   } else if (dStrcasecmp(attrbuf, "text/css")) {
+      MSG("Shouldn't be applying <style type=\"%s\">\n", attrbuf);
+      /* We need to inform close_style() */
+   }
+   if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "media")) &&
+       dStrcasecmp(attrbuf, "all") && !dStristr(attrbuf, "screen")) {
+      /* HTML 4.01 sec. 6.13 says that media descriptors are case-sensitive,
+       * but sec. 14.2.3 says that the attribute is case-insensitive.
+       * TODO can be a comma-separated list.
+       * TODO handheld.
+       */
+      MSG("Shouldn't be applying <style media=\"%s\">\n", attrbuf);
+   }
    a_Html_stash_init(html);
    S_TOP(html)->parse_mode = DILLO_HTML_PARSE_MODE_VERBATIM;
 }
@@ -1720,7 +1654,8 @@
  */
 static void Html_tag_close_style(DilloHtml *html, int TagIdx)
 {
-   /* eventually the stash will be sent to an interpreter for parsing */
+   html->styleEngine->parse(html->Stash->str, html->Stash->len,
+                            0, CSS_ORIGIN_AUTHOR);
 }
 
 /*
@@ -1730,8 +1665,7 @@
 {
    const char *attrbuf;
    Textblock *textblock;
-   StyleAttrs style_attrs;
-   Style *style;
+   CssPropertyList props;
    int32_t color;
 
    if (!(html->InFlags & IN_BODY))
@@ -1749,43 +1683,37 @@
 
    textblock = DW2TB(html->dw);
 
-   if (!prefs.force_my_colors) {
-      if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "bgcolor"))) {
-         color = a_Html_color_parse(html, attrbuf, prefs.bg_color);
-         if (color == 0xffffff && !prefs.allow_white_bg)
-            color = prefs.bg_color;
-
-         style_attrs = *html->dw->getStyle ();
-         style_attrs.backgroundColor = Color::createShaded(HT2LT(html), color);
-         style = Style::create (HT2LT(html), &style_attrs);
-         html->dw->setStyle (style);
-         style->unref ();
-         S_TOP(html)->current_bg_color = color;
-      }
-
-      if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "text"))) {
-         color = a_Html_color_parse(html, attrbuf, prefs.text_color);
-         HTML_SET_TOP_ATTR (html, color,
-                            Color::createSimple (HT2LT(html),color));
-      }
-
-      if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "link")))
-         html->link_color = a_Html_color_parse(html,attrbuf,prefs.link_color);
-
-      if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "vlink")))
-         html->visited_color = a_Html_color_parse(html, attrbuf,
-                                                  prefs.visited_color);
-
-      if (prefs.contrast_visited_color) {
-         /* get a color that has a "safe distance" from text, link and bg */
-         html->visited_color =
+   if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "bgcolor"))) {
+      color = a_Html_color_parse(html, attrbuf, prefs.bg_color);
+      if (color == 0xffffff && !prefs.allow_white_bg)
+         color = prefs.bg_color;
+      S_TOP(html)->current_bg_color = color;
+      props.set (CssProperty::CSS_PROPERTY_BACKGROUND_COLOR, color);
+   }
+
+   if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "text"))) {
+      color = a_Html_color_parse(html, attrbuf, prefs.text_color);
+      props.set (CssProperty::CSS_PROPERTY_COLOR, color);
+   }
+
+   if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "link")))
+      html->link_color = a_Html_color_parse(html, attrbuf, -1);
+
+   if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "vlink")))
+      html->visited_color = a_Html_color_parse(html, attrbuf, -1);
+
+   if (prefs.contrast_visited_color) {
+      /* get a color that has a "safe distance" from text, link and bg */
+      html->visited_color =
             a_Color_vc(html->visited_color,
-                       S_TOP(html)->style->color->getColor(),
+                       html->styleEngine->style ()->color->getColor(),
                        html->link_color,
                        S_TOP(html)->current_bg_color);
-      }
    }
 
+   html->styleEngine->setNonCssHints (&props);
+   html->dw->setStyle (html->styleEngine->style ());
+
    S_TOP(html)->parse_mode = DILLO_HTML_PARSE_MODE_BODY;
 }
 
@@ -1807,13 +1735,16 @@
  */
 static void Html_tag_open_p(DilloHtml *html, const char *tag, int tagsize)
 {
+   CssPropertyList props;
+
    if ((html->InFlags & IN_LI) && !html->WordAfterLI) {
       /* ignore first parbreak after an empty <LI> */
       html->WordAfterLI = true;
    } else {
-      DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
+      DW2TB(html->dw)->addParbreak (9, html->styleEngine->wordStyle ());
    }
-   a_Html_tag_set_align_attr (html, tag, tagsize);
+   a_Html_tag_set_align_attr (html, &props, tag, tagsize);
+   html->styleEngine->setNonCssHints (&props);
 }
 
 /*
@@ -1827,9 +1758,8 @@
    char *src;
    DilloUrl *url;
    Textblock *textblock;
-   StyleAttrs style_attrs;
-   Style *link_style;
    Widget *bullet;
+   CssPropertyList props;
 
    textblock = DW2TB(html->dw);
 
@@ -1841,46 +1771,41 @@
 
    src = dStrdup(attrbuf);
 
-   style_attrs = *(S_TOP(html)->style);
-
    if (a_Capi_get_flags(url) & CAPI_IsCached) { /* visited frame */
-      style_attrs.color =
-         Color::createSimple (HT2LT(html), html->visited_color);
+      html->styleEngine->setPseudoVisited ();
    } else {                                    /* unvisited frame */
-      style_attrs.color = Color::createSimple (HT2LT(html), html->link_color);
+      html->styleEngine->setPseudoLink ();
    }
-   style_attrs.textDecoration |= TEXT_DECORATION_UNDERLINE;
-   style_attrs.x_link = Html_set_new_link(html, &url);
-   style_attrs.cursor = CURSOR_POINTER;
-   link_style = Style::create (HT2LT(html), &style_attrs);
-
-   textblock->addParbreak (5, S_TOP(html)->style);
+
+   props.set (CssProperty::PROPERTY_X_LINK, Html_set_new_link(html, &url));
+   html->styleEngine->setNonCssHints (&props);
+
+   textblock->addParbreak (5, html->styleEngine->wordStyle ());
 
    /* The bullet will be assigned the current list style, which should
     * be "disc" by default, but may in very weird pages be different.
     * Anyway, there should be no harm. */
    bullet = new Bullet();
-   textblock->addWidget(bullet, S_TOP(html)->style);
-   textblock->addSpace(S_TOP(html)->style);
+   textblock->addWidget(bullet, html->styleEngine->style ());
+   textblock->addSpace(html->styleEngine->wordStyle ());
 
    if (tolower(tag[1]) == 'i') {
       /* IFRAME usually comes with very long advertising/spying URLS,
        * to not break rendering we will force name="IFRAME" */
-      textblock->addText ("IFRAME", link_style);
+      textblock->addText ("IFRAME", html->styleEngine->wordStyle ());
 
    } else {
       /* FRAME:
        * If 'name' tag is present use it, if not use 'src' value */
       if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "name"))) {
-         textblock->addText (src, link_style);
+         textblock->addText (src, html->styleEngine->wordStyle ());
       } else {
-         textblock->addText (attrbuf, link_style);
+         textblock->addText (attrbuf, html->styleEngine->wordStyle ());
       }
    }
 
-   textblock->addParbreak (5, S_TOP(html)->style);
-
-   link_style->unref ();
+   textblock->addParbreak (5, html->styleEngine->wordStyle ());
+
    dFree(src);
 }
 
@@ -1892,9 +1817,9 @@
 static void Html_tag_open_frameset (DilloHtml *html,
                                     const char *tag, int tagsize)
 {
-   DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
-   DW2TB(html->dw)->addText("--FRAME--", S_TOP(html)->style);
-   Html_add_indented(html, 40, 0, 5);
+   DW2TB(html->dw)->addParbreak (9, html->styleEngine->wordStyle ());
+   DW2TB(html->dw)->addText("--FRAME--", html->styleEngine->wordStyle ());
+   Html_add_textblock(html, 5);
 }
 
 /*
@@ -1902,18 +1827,19 @@
  */
 static void Html_tag_open_h(DilloHtml *html, const char *tag, int tagsize)
 {
-   DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
-
-   /* TODO: combining these two would be slightly faster */
-   a_Html_set_top_font(html, prefs.vw_fontname,
-                       Html_level_to_fontsize(FontSizesNum - (tag[2] - '0')),
-                       1, 3);
-   a_Html_tag_set_align_attr (html, tag, tagsize);
+   CssPropertyList props;
+
+
+   html->styleEngine->inheritBackgroundColor ();
+   a_Html_tag_set_align_attr (html, &props, tag, tagsize);
+   html->styleEngine->setNonCssHints (&props);
+
+   DW2TB(html->dw)->addParbreak (9, html->styleEngine->wordStyle ());
 
    /* First finalize unclosed H tags (we test if already named anyway) */
    a_Menu_pagemarks_set_text(html->bw, html->Stash->str);
    a_Menu_pagemarks_add(html->bw, DW2TB(html->dw),
-                        S_TOP(html)->style, (tag[2] - '0'));
+                        html->styleEngine->style (), (tag[2] - '0'));
    a_Html_stash_init(html);
    S_TOP(html)->parse_mode =
       DILLO_HTML_PARSE_MODE_STASH_AND_BODY;
@@ -1925,29 +1851,22 @@
 static void Html_tag_close_h(DilloHtml *html, int TagIdx)
 {
    a_Menu_pagemarks_set_text(html->bw, html->Stash->str);
-   DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
+   DW2TB(html->dw)->addParbreak (9, html->styleEngine->wordStyle ());
 }
 
-/*
- * <BIG> | <SMALL>
- */
-static void Html_tag_open_big_small(DilloHtml *html,
-                                    const char *tag, int tagsize)
+static void Html_tag_open_span(DilloHtml *html,
+                               const char *tag, int tagsize)
 {
-   int level;
-
-   level =
-      Html_fontsize_to_level(S_TOP(html)->style->font->size) +
-      ((dStrncasecmp(tag+1, "big", 3)) ? -1 : 1);
-   a_Html_set_top_font(html, NULL, Html_level_to_fontsize(level), 0, 0);
+   html->styleEngine->inheritBackgroundColor();
 }
 
+
 /*
  * <BR>
  */
 static void Html_tag_open_br(DilloHtml *html, const char *tag, int tagsize)
 {
-   DW2TB(html->dw)->addLinebreak (S_TOP(html)->style);
+   DW2TB(html->dw)->addLinebreak (html->styleEngine->wordStyle ());
 }
 
 /*
@@ -1955,39 +1874,27 @@
  */
 static void Html_tag_open_font(DilloHtml *html, const char *tag, int tagsize)
 {
-   StyleAttrs style_attrs;
-   Style *old_style;
    /*Font font;*/
    const char *attrbuf;
    int32_t color;
-
-   if (!prefs.force_my_colors) {
-      old_style = S_TOP(html)->style;
-      style_attrs = *old_style;
-
-      if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "color"))) {
-         if (prefs.contrast_visited_color && html->InVisitedLink) {
-            color = html->visited_color;
-         } else { 
-            /* use the tag-specified color */
-            color = a_Html_color_parse(html, attrbuf,
-                                       style_attrs.color->getColor());
-            style_attrs.color = Color::createSimple (HT2LT(html), color);
-         }
+   CssPropertyList props;
+
+   if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "color"))) {
+      if (prefs.contrast_visited_color && html->InVisitedLink) {
+         color = html->visited_color;
+      } else { 
+         /* use the tag-specified color */
+         color = a_Html_color_parse(html, attrbuf, -1);
       }
-
-#if 0
-    //if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "face"))) {
-    //   font = *( style_attrs.font );
-    //   font.name = attrbuf;
-    //   style_attrs.font = a_Dw_style_font_new_from_list (&font);
-    //}
-#endif
-
-      S_TOP(html)->style =
-         Style::create (HT2LT(html), &style_attrs);
-      old_style->unref ();
+      if (color != -1)
+         props.set (CssProperty::CSS_PROPERTY_COLOR, color);
    }
+
+// \todo reenable font face handling when font selection is implemented
+//   if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "face")))
+//      props.set (CssProperty::CSS_PROPERTY_FONT_FAMILY, attrbuf);
+
+   html->styleEngine->setNonCssHints (&props);
 }
 
 /*
@@ -2005,52 +1912,11 @@
 }
 
 /*
- * <B>
- */
-static void Html_tag_open_b(DilloHtml *html, const char *tag, int tagsize)
-{
-   a_Html_set_top_font(html, NULL, 0, 1, 1);
-}
-
-/*
- * <STRONG>
- */
-static void Html_tag_open_strong(DilloHtml *html, const char *tag, int tagsize)
-{
-   a_Html_set_top_font(html, NULL, 0, 1, 1);
-}
-
-/*
- * <I>
- */
-static void Html_tag_open_i(DilloHtml *html, const char *tag, int tagsize)
-{
-   a_Html_set_top_font(html, NULL, 0, 2, 2);
-}
-
-/*
- * <EM>
- */
-static void Html_tag_open_em(DilloHtml *html, const char *tag, int tagsize)
-{
-   a_Html_set_top_font(html, NULL, 0, 2, 2);
-}
-
-/*
- * <CITE>
- */
-static void Html_tag_open_cite(DilloHtml *html, const char *tag, int tagsize)
-{
-   a_Html_set_top_font(html, NULL, 0, 2, 2);
-}
-
-/*
  * <CENTER>
  */
 static void Html_tag_open_center(DilloHtml *html, const char *tag, int tagsize)
 {
-   DW2TB(html->dw)->addParbreak (0, S_TOP(html)->style);
-   HTML_SET_TOP_ATTR(html, textAlign, TEXT_ALIGN_CENTER);
+   DW2TB(html->dw)->addParbreak (0, html->styleEngine->wordStyle ());
 }
 
 /*
@@ -2059,16 +1925,7 @@
 static void Html_tag_open_address(DilloHtml *html,
                                   const char *tag, int tagsize)
 {
-   DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
-   a_Html_set_top_font(html, NULL, 0, 2, 2);
-}
-
-/*
- * <TT>
- */
-static void Html_tag_open_tt(DilloHtml *html, const char *tag, int tagsize)
-{
-   a_Html_set_top_font(html, prefs.fw_fontname, 0, 0, 0);
+   DW2TB(html->dw)->addParbreak (9, html->styleEngine->wordStyle ());
 }
 
 /*
@@ -2077,7 +1934,6 @@
  */
 DilloImage *a_Html_add_new_image(DilloHtml *html, const char *tag,
                                  int tagsize, DilloUrl *url,
-                                 dw::core::style::StyleAttrs *style_attrs,
                                  bool add)
 {
    const int MAX_W = 6000, MAX_H = 6000;
@@ -2085,9 +1941,11 @@
    DilloImage *Image;
    char *width_ptr, *height_ptr, *alt_ptr;
    const char *attrbuf;
-   Length l_w, l_h;
-   int space, w = 0, h = 0;
+   Length l_w  = CSS_CREATE_LENGTH(0.0, CSS_LENGTH_TYPE_AUTO);
+   Length l_h  = CSS_CREATE_LENGTH(0.0, CSS_LENGTH_TYPE_AUTO);
+   int space, border, w = 0, h = 0;
    bool load_now;
+   CssPropertyList props;
 
 // if (prefs.show_tooltip &&
 //     (attrbuf = a_Html_get_attr(html, tag, tagsize, "title")))
@@ -2104,17 +1962,24 @@
    // TODO: the same for percentage and relative lengths.
    if (width_ptr) {
       l_w = a_Html_parse_length (html, width_ptr);
-      w = isAbsLength(l_w) ? absLengthVal(l_w) : 0;
+      w = (int) (CSS_LENGTH_TYPE(l_w) == CSS_LENGTH_TYPE_PX ?
+                 CSS_LENGTH_VALUE(l_w) : 0);
    }
    if (height_ptr) {
       l_h = a_Html_parse_length (html, height_ptr);
-      h = isAbsLength(l_h) ? absLengthVal(l_h) : 0;
+      h = (int) (CSS_LENGTH_TYPE(l_h) == CSS_LENGTH_TYPE_PX ?
+                 CSS_LENGTH_VALUE(l_h) : 0);
    }
    if (w < 0 || h < 0 || abs(w*h) > MAX_W * MAX_H) {
       dFree(width_ptr);
       dFree(height_ptr);
       width_ptr = height_ptr = NULL;
       MSG("a_Html_add_new_image: suspicious image size request %dx%d\n", w, h);
+   } else {
+      if (CSS_LENGTH_TYPE(l_w) != CSS_LENGTH_TYPE_AUTO)
+         props.set (CssProperty::CSS_PROPERTY_WIDTH, l_w);
+      if (CSS_LENGTH_TYPE(l_h) != CSS_LENGTH_TYPE_AUTO)
+         props.set (CssProperty::CSS_PROPERTY_HEIGHT, l_h);
    }
 
    /* TODO: we should scale the image respecting its ratio.
@@ -2127,27 +1992,55 @@
    /* Spacing to the left and right */
    if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "hspace"))) {
       space = strtol(attrbuf, NULL, 10);
-      if (space > 0)
-         style_attrs->margin.left = style_attrs->margin.right = space;
+      if (space > 0) {
+         space = CSS_CREATE_LENGTH(space, CSS_LENGTH_TYPE_PX);
+         props.set (CssProperty::CSS_PROPERTY_MARGIN_LEFT, space);
+         props.set (CssProperty::CSS_PROPERTY_MARGIN_RIGHT, 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)
-         style_attrs->margin.top = style_attrs->margin.bottom = space;
+      if (space > 0) {
+         space = CSS_CREATE_LENGTH(space, CSS_LENGTH_TYPE_PX);
+         props.set (CssProperty::CSS_PROPERTY_MARGIN_TOP, space);
+         props.set (CssProperty::CSS_PROPERTY_MARGIN_BOTTOM, 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);
+         props.set (CssProperty::CSS_PROPERTY_BORDER_TOP_WIDTH, border);
+         props.set (CssProperty::CSS_PROPERTY_BORDER_BOTTOM_WIDTH, border);
+         props.set (CssProperty::CSS_PROPERTY_BORDER_LEFT_WIDTH, border);
+         props.set (CssProperty::CSS_PROPERTY_BORDER_RIGHT_WIDTH, border);
+
+         props.set (CssProperty::CSS_PROPERTY_BORDER_TOP_STYLE, BORDER_SOLID);
+         props.set (CssProperty::CSS_PROPERTY_BORDER_BOTTOM_STYLE,
+                    BORDER_SOLID);
+         props.set (CssProperty::CSS_PROPERTY_BORDER_LEFT_STYLE, BORDER_SOLID);
+         props.set (CssProperty::CSS_PROPERTY_BORDER_RIGHT_STYLE,BORDER_SOLID);
+      }
    }
 
    /* x_img is an index to a list of {url,image} pairs.
     * We know Html_add_new_linkimage() will use size() as its next index */
-   style_attrs->x_img = html->images->size();
+   props.set (CssProperty::PROPERTY_X_IMG, html->images->size());
+
+   html->styleEngine->setNonCssHints(&props);
 
    /* Add a new image widget to this page */
-   Image = a_Image_new(0, 0, alt_ptr, S_TOP(html)->current_bg_color);
+   Image = a_Image_new(0, 0, alt_ptr, 0);
    if (add) {
-      Html_add_widget(html, (Widget*)Image->dw, width_ptr, height_ptr,
-                      style_attrs);
+      DW2TB(html->dw)->addWidget((Widget*)Image->dw,
+                                 html->styleEngine->style());
    }
+   if (DW2TB(html->dw)->getBgColor())
+      Image->bg_color = DW2TB(html->dw)->getBgColor()->getColor();
 
    load_now = a_UIcmd_get_images_enabled(html->bw) ||
               (a_Capi_get_flags(url) & CAPI_IsCached);
@@ -2191,9 +2084,7 @@
    DilloImage *Image;
    DilloUrl *url, *usemap_url;
    Textblock *textblock;
-   StyleAttrs style_attrs;
    const char *attrbuf;
-   int border;
 
    /* This avoids loading images. Useful for viewing suspicious HTML email. */
    if (URL_FLAGS(html->base_url) & URL_SpamSafe)
@@ -2210,34 +2101,13 @@
       /* TODO: usemap URLs outside of the document are not used. */
       usemap_url = a_Html_url_new(html, attrbuf, NULL, 0);
 
-   /* Set the style attributes for this image */
-   style_attrs = *S_TOP(html)->style;
-   if (S_TOP(html)->style->x_link != -1 ||
-       usemap_url != NULL) {
-      /* Images within links */
-      border = 1;
-      if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "border")))
-         border = strtol (attrbuf, NULL, 10);
-
-      if (S_TOP(html)->style->x_link != -1) {
-         /* In this case we can use the text color */
-         style_attrs.setBorderColor (
-            Color::createShaded (HT2LT(html), style_attrs.color->getColor()));
-      } else {
-         style_attrs.setBorderColor (
-            Color::createShaded (HT2LT(html), html->link_color));
-      }
-      style_attrs.setBorderStyle (BORDER_SOLID);
-      style_attrs.borderWidth.setVal (border);
-   }
-
-   Image = a_Html_add_new_image(html, tag, tagsize, url, &style_attrs, true);
+   Image = a_Html_add_new_image(html, tag, tagsize, url, true);
 
    /* Image maps */
    if (a_Html_get_attr(html, tag, tagsize, "ismap")) {
       ((::dw::Image*)Image->dw)->setIsMap();
       _MSG("  Html_tag_open_img: server-side map (ISMAP)\n");
-   } else if (S_TOP(html)->style->x_link != -1 &&
+   } else if (html->styleEngine->style ()->x_link != -1 &&
               usemap_url == NULL) {
       /* For simple links, we have to suppress the "image_pressed" signal.
        * This is overridden for USEMAP images. */
@@ -2404,10 +2274,9 @@
  */
 static void Html_tag_open_object(DilloHtml *html, const char *tag, int tagsize)
 {
-   StyleAttrs style_attrs;
-   Style *style;
    DilloUrl *url, *base_url = NULL;
    const char *attrbuf;
+   CssPropertyList props;
 
    if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "codebase"))) {
       base_url = a_Html_url_new(html, attrbuf, NULL, 0);
@@ -2418,31 +2287,16 @@
                            URL_STR(base_url), (base_url != NULL));
       dReturn_if_fail ( url != NULL );
 
-      style_attrs = *S_TOP(html)->style;
-
       if (a_Capi_get_flags(url) & CAPI_IsCached) {
-         style_attrs.color = Color::createSimple (
-            HT2LT(html),
-            html->visited_color
-/*
-            a_Color_vc(html->visited_color,
-                       S_TOP(html)->style->color->getColor(),
-                       html->link_color,
-                       S_TOP(html)->style->backgroundColor->getColor()),
-*/
-            );
+         html->styleEngine->setPseudoVisited ();
       } else {
-         style_attrs.color = Color::createSimple(HT2LT(html),
-                                                 html->link_color);
+         html->styleEngine->setPseudoLink ();
       }
-
-      style_attrs.textDecoration |= TEXT_DECORATION_UNDERLINE;
-      style_attrs.x_link = Html_set_new_link(html, &url);
-      style_attrs.cursor = CURSOR_POINTER;
-
-      style = Style::create (HT2LT(html), &style_attrs);
-      DW2TB(html->dw)->addText("[OBJECT]", style);
-      style->unref ();
+   
+      props.set(CssProperty::PROPERTY_X_LINK, Html_set_new_link(html, &url));
+      html->styleEngine->setNonCssHints (&props);
+
+      DW2TB(html->dw)->addText("[OBJECT]", html->styleEngine->wordStyle ());
    }
    a_Url_free(base_url);
 }
@@ -2476,7 +2330,7 @@
 static void Html_add_anchor(DilloHtml *html, const char *name)
 {
    _MSG("Registering ANCHOR: %s\n", name);
-   if (!DW2TB(html->dw)->addAnchor (name, S_TOP(html)->style))
+   if (!DW2TB(html->dw)->addAnchor (name, html->styleEngine->style ()))
       BUG_MSG("Anchor names must be unique within the document\n");
    /*
     * According to Sec. 12.2.1 of the HTML 4.01 spec, "anchor names that
@@ -2493,9 +2347,8 @@
  */
 static void Html_tag_open_a(DilloHtml *html, const char *tag, int tagsize)
 {
-   StyleAttrs style_attrs;
-   Style *old_style;
    DilloUrl *url;
+   CssPropertyList props;
    const char *attrbuf;
 
    /* TODO: add support for MAP with A HREF */
@@ -2510,38 +2363,24 @@
       url = a_Html_url_new(html, attrbuf, NULL, 0);
       dReturn_if_fail ( url != NULL );
 
-      old_style = S_TOP(html)->style;
-      style_attrs = *old_style;
-
       if (a_Capi_get_flags(url) & CAPI_IsCached) {
          html->InVisitedLink = true;
-         style_attrs.color = Color::createSimple (
-            HT2LT(html),
-            html->visited_color
-/*
-            a_Color_vc(html->visited_color,
-                       S_TOP(html)->style->color->getColor(),
-                       html->link_color,
-                       S_TOP(html)->current_bg_color),
-*/
-            );
+         html->styleEngine->setPseudoVisited ();
+         if (html->visited_color != -1)
+            props.set (CssProperty::CSS_PROPERTY_COLOR, html->visited_color);
       } else {
-         style_attrs.color = Color::createSimple(HT2LT(html),
-                                                 html->link_color);
+         html->styleEngine->setPseudoLink ();
+         if (html->link_color != -1)
+            props.set (CssProperty::CSS_PROPERTY_COLOR, html->link_color);
       }
 
-//    if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "title")))
-//       style_attrs.x_tooltip = a_Dw_tooltip_new_no_ref(attrbuf);
-
-      style_attrs.textDecoration |= TEXT_DECORATION_UNDERLINE;
-      style_attrs.x_link = Html_set_new_link(html, &url);
-      style_attrs.cursor = CURSOR_POINTER;
-
-      S_TOP(html)->style =
-         Style::create (HT2LT(html), &style_attrs);
-      old_style->unref ();
+      props.set (CssProperty::PROPERTY_X_LINK, Html_set_new_link(html, &url));
+
+      html->styleEngine->setNonCssHints (&props);
    }
 
+   html->styleEngine->inheritBackgroundColor ();
+
    if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "name"))) {
       if (prefs.show_extra_warnings)
          Html_check_name_val(html, attrbuf, "name");
@@ -2560,45 +2399,13 @@
 }
 
 /*
- * Insert underlined text in the page.
- */
-static void Html_tag_open_u(DilloHtml *html, const char *tag, int tagsize)
-{
-   Style *style;
-   StyleAttrs style_attrs;
-
-   style = S_TOP(html)->style;
-   style_attrs = *style;
-   style_attrs.textDecoration |= TEXT_DECORATION_UNDERLINE;
-   S_TOP(html)->style =
-      Style::create (HT2LT(html), &style_attrs);
-   style->unref ();
-}
-
-/*
- * Insert strike-through text. Used by <S>, <STRIKE> and <DEL>.
- */
-static void Html_tag_open_strike(DilloHtml *html, const char *tag, int tagsize)
-{
-   Style *style;
-   StyleAttrs style_attrs;
-
-   style = S_TOP(html)->style;
-   style_attrs = *style;
-   style_attrs.textDecoration |= TEXT_DECORATION_LINE_THROUGH;
-   S_TOP(html)->style =
-      Style::create (HT2LT(html), &style_attrs);
-   style->unref ();
-}
-
-/*
  * <BLOCKQUOTE>
  */
 static void Html_tag_open_blockquote(DilloHtml *html, 
                                      const char *tag, int tagsize)
 {
-   DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
-   Html_add_indented(html, 40, 40, 9);
+   DW2TB(html->dw)->addParbreak (9, html->styleEngine->wordStyle ());
+   Html_add_textblock(html, 9);
 }
 
 /*
@@ -2612,7 +2419,7 @@
      */
     const char *U201C = "\xe2\x80\x9c";
 
-    DW2TB(html->dw)->addText (U201C, S_TOP(html)->style);
+    DW2TB(html->dw)->addText (U201C, html->styleEngine->wordStyle ());
 }
 
 /*
@@ -2623,7 +2430,7 @@
    /* Right Double Quotation Mark */
    const char *U201D = "\xe2\x80\x9d";
 
-   DW2TB(html->dw)->addText (U201D, S_TOP(html)->style);
+   DW2TB(html->dw)->addText (U201D, html->styleEngine->wordStyle ());
 }
 
 /*
@@ -2634,10 +2441,9 @@
    const char *attrbuf;
    ListStyleType list_style_type;
 
-   DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
-   Html_add_indented(html, 40, 0, 9);
-
    if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "type"))) {
+      CssPropertyList props;
+
       /* list_style_type explicitly defined */
       if (dStrncasecmp(attrbuf, "disc", 4) == 0)
          list_style_type = LIST_STYLE_TYPE_DISC;
@@ -2648,33 +2454,15 @@
       else
          /* invalid value */
          list_style_type = LIST_STYLE_TYPE_DISC;
-   } else {
-      if (S_TOP(html)->list_type == HTML_LIST_UNORDERED) {
-         /* Nested <UL>'s. */
-         /* --EG :: I changed the behavior here : types are cycling instead of
-          * being forced to square. It's easier for mixed lists level counting.
-          */
-         switch (S_TOP(html)->style->listStyleType) {
-         case LIST_STYLE_TYPE_DISC:
-            list_style_type = LIST_STYLE_TYPE_CIRCLE;
-            break;
-         case LIST_STYLE_TYPE_CIRCLE:
-            list_style_type = LIST_STYLE_TYPE_SQUARE;
-            break;
-         case LIST_STYLE_TYPE_SQUARE:
-         default: /* this is actually a bug */
-            list_style_type = LIST_STYLE_TYPE_DISC;
-            break;
-         }
-      } else {
-         /* Either first <UL>, or a <OL> before. */
-         list_style_type = LIST_STYLE_TYPE_DISC;
-      }
-   }
-
-   HTML_SET_TOP_ATTR(html, listStyleType, list_style_type);
+
+      props.set(CssProperty::CSS_PROPERTY_LIST_STYLE_TYPE, list_style_type);
+      html->styleEngine->setNonCssHints (&props);
+   } 
+
+   DW2TB(html->dw)->addParbreak (9, html->styleEngine->wordStyle ());
+   Html_add_textblock(html, 9);
+
    S_TOP(html)->list_type = HTML_LIST_UNORDERED;
-
    S_TOP(html)->list_number = 0;
    S_TOP(html)->ref_list_item = NULL;
 }
@@ -2685,11 +2473,8 @@
  */
 static void Html_tag_open_dir(DilloHtml *html, const char *tag, int tagsize)
 {
-   ListStyleType list_style_type = LIST_STYLE_TYPE_DISC;
-
-   DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
-   Html_add_indented(html, 40, 0, 9);
-   HTML_SET_TOP_ATTR(html, listStyleType, list_style_type);
+   DW2TB(html->dw)->addParbreak (9, html->styleEngine->wordStyle ());
+
    S_TOP(html)->list_type = HTML_LIST_UNORDERED;
    S_TOP(html)->list_number = 0;
    S_TOP(html)->ref_list_item = NULL;
@@ -2712,28 +2497,30 @@
 static void Html_tag_open_ol(DilloHtml *html, const char *tag, int tagsize)
 {
    const char *attrbuf;
-   ListStyleType list_style_type;
    int n = 1;
 
-   DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
-   Html_add_indented(html, 40, 0, 9);
-
-   list_style_type = LIST_STYLE_TYPE_DECIMAL;
-
    if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "type"))) {
+      CssPropertyList props;
+      ListStyleType listStyleType = LIST_STYLE_TYPE_DECIMAL;
+
       if (*attrbuf == '1')
-         list_style_type = LIST_STYLE_TYPE_DECIMAL;
+         listStyleType = LIST_STYLE_TYPE_DECIMAL;
       else if (*attrbuf == 'a')
-         list_style_type = LIST_STYLE_TYPE_LOWER_ALPHA;
+         listStyleType = LIST_STYLE_TYPE_LOWER_ALPHA;
       else if (*attrbuf == 'A')
-         list_style_type = LIST_STYLE_TYPE_UPPER_ALPHA;
+         listStyleType = LIST_STYLE_TYPE_UPPER_ALPHA;
       else if (*attrbuf == 'i')
-         list_style_type = LIST_STYLE_TYPE_LOWER_ROMAN;
+         listStyleType = LIST_STYLE_TYPE_LOWER_ROMAN;
       else if (*attrbuf == 'I')
-         list_style_type = LIST_STYLE_TYPE_UPPER_ROMAN;
+         listStyleType = LIST_STYLE_TYPE_UPPER_ROMAN;
+
+      props.set (CssProperty::CSS_PROPERTY_LIST_STYLE_TYPE, listStyleType);
+      html->styleEngine->setNonCssHints (&props);
    }
 
-   HTML_SET_TOP_ATTR(html, listStyleType, list_style_type);
+   DW2TB(html->dw)->addParbreak (9, html->styleEngine->wordStyle ());
+   Html_add_textblock(html, 9);
+
    S_TOP(html)->list_type = HTML_LIST_ORDERED;
 
    if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "start")) &&
@@ -2750,13 +2537,16 @@
  */
 static void Html_tag_open_li(DilloHtml *html, const char *tag, int tagsize)
 {
-   StyleAttrs style_attrs;
-   Style *item_style, *word_style;
+   Style *style = html->styleEngine->style ();
+   Style *wordStyle = html->styleEngine->wordStyle ();
    Widget **ref_list_item;
    ListItem *list_item;
    int *list_number;
    const char *attrbuf;
    char buf[16];
+   
+   if (S_TOP(html)->list_type == HTML_LIST_NONE)
+      BUG_MSG("<li> outside <ul> or <ol>\n");
 
    html->InFlags |= IN_LI;
    html->WordAfterLI = false;
@@ -2765,44 +2555,33 @@
    list_number = &html->stack->getRef(html->stack->size()-2)->list_number;
    ref_list_item = &html->stack->getRef(html->stack->size()-2)->ref_list_item;
 
-   /* set the item style */
-   word_style = S_TOP(html)->style;
-   style_attrs = *word_style;
- //style_attrs.backgroundColor = Color::createShaded (HT2LT(html), 0xffff40);
- //style_attrs.setBorderColor (Color::createSimple (HT2LT(html), 0x000000));
- //style_attrs.setBorderStyle (BORDER_SOLID);
- //style_attrs.borderWidth.setVal (1);
-   item_style = Style::create (HT2LT(html), &style_attrs);
-
-   DW2TB(html->dw)->addParbreak (2, word_style);
+   DW2TB(html->dw)->addParbreak (0, wordStyle);
 
    list_item = new ListItem ((ListItem*)*ref_list_item,prefs.limit_text_width);
-   DW2TB(html->dw)->addWidget (list_item, item_style);
-   DW2TB(html->dw)->addParbreak (2, word_style);
+   DW2TB(html->dw)->addWidget (list_item, style);
+   DW2TB(html->dw)->addParbreak (0, wordStyle);
    *ref_list_item = list_item;
    S_TOP(html)->textblock = html->dw = list_item;
-   item_style->unref();
    /* Handle it when the user clicks on a link */
    html->connectSignals(list_item);
 
-   switch (S_TOP(html)->list_type) {
-   case HTML_LIST_ORDERED:
+   if (style->listStyleType == LIST_STYLE_TYPE_NONE) {
+      // none
+   } else if (style->listStyleType >= LIST_STYLE_TYPE_DECIMAL) {
+      // ordered
       if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "value")) &&
           (*list_number = strtol(attrbuf, NULL, 10)) < 0) {
          BUG_MSG("illegal negative LIST VALUE attribute; Starting from 0\n");
          *list_number = 0;
       }
-      numtostr((*list_number)++, buf, 16, S_TOP(html)->style->listStyleType);
-      list_item->initWithText (dStrdup(buf), word_style);
-      list_item->addSpace (word_style);
+      numtostr((*list_number)++, buf, 16, style->listStyleType);
+      list_item->initWithText (dStrdup(buf), wordStyle);
+      list_item->addSpace (wordStyle);
       html->PrevWasSPC = true;
-      break;
-   case HTML_LIST_NONE:
-      BUG_MSG("<li> outside <ul> or <ol>\n");
-   default:
-      list_item->initWithWidget (new Bullet(), word_style);
-      list_item->addSpace (word_style);
-      break;
+   } else {
+      // unordered
+      list_item->initWithWidget (new Bullet(), wordStyle);
+      list_item->addSpace (wordStyle);
    }
 }
 
@@ -2822,58 +2601,50 @@
 static void Html_tag_open_hr(DilloHtml *html, const char *tag, int tagsize)
 {
    Widget *hruler;
-   StyleAttrs style_attrs;
-   Style *style;
+   CssPropertyList props;
    char *width_ptr;
    const char *attrbuf;
    int32_t size = 0;
   
-   style_attrs = *S_TOP(html)->style;
-
-   width_ptr = a_Html_get_attr_wdef(html, tag, tagsize, "width", "100%");
-   style_attrs.width = a_Html_parse_length (html, width_ptr);
-   dFree(width_ptr);
+   width_ptr = a_Html_get_attr_wdef(html, tag, tagsize, "width", NULL);
+   if (width_ptr) {
+      props.set (CssProperty::CSS_PROPERTY_WIDTH, 
+         a_Html_parse_length (html, width_ptr));
+      dFree(width_ptr);
+   }
 
    if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "size")))
       size = strtol(attrbuf, NULL, 10);
-  
-   if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "align"))) {
-      if (dStrcasecmp (attrbuf, "left") == 0)
-         style_attrs.textAlign = TEXT_ALIGN_LEFT;
-      else if (dStrcasecmp (attrbuf, "right") == 0)
-         style_attrs.textAlign = TEXT_ALIGN_RIGHT;
-      else if (dStrcasecmp (attrbuf, "center") == 0)
-         style_attrs.textAlign = TEXT_ALIGN_CENTER;
-   }
+ 
+   a_Html_tag_set_align_attr(html, &props, tag, tagsize); 
   
    /* TODO: evaluate attribute */
    if (a_Html_get_attr(html, tag, tagsize, "noshade")) {
-      style_attrs.setBorderStyle (BORDER_SOLID);
-      style_attrs.setBorderColor (
-         Color::createShaded (HT2LT(html), style_attrs.color->getColor()));
-      if (size < 1)
+      props.set (CssProperty::CSS_PROPERTY_BORDER_TOP_STYLE, BORDER_SOLID);
+      props.set (CssProperty::CSS_PROPERTY_BORDER_BOTTOM_STYLE, BORDER_SOLID);
+      props.set (CssProperty::CSS_PROPERTY_BORDER_LEFT_STYLE, BORDER_SOLID);
+      props.set (CssProperty::CSS_PROPERTY_BORDER_RIGHT_STYLE, BORDER_SOLID);
+
+      if (size <= 0)
          size = 1;
-   } else {
-      style_attrs.setBorderStyle (BORDER_INSET);
-      style_attrs.setBorderColor
-         (Color::createShaded (HT2LT(html),
-                               S_TOP(html)->current_bg_color));
-      if (size < 2)
-         size = 2;
    }
-  
-   style_attrs.borderWidth.top =
-      style_attrs.borderWidth.left = (size + 1) / 2;
-   style_attrs.borderWidth.bottom =
-      style_attrs.borderWidth.right = size / 2;
-   style = Style::create (HT2LT(html), &style_attrs);
-
-   DW2TB(html->dw)->addParbreak (5, S_TOP(html)->style);
+ 
+   if (size > 0) { 
+      CssLength size_top = CSS_CREATE_LENGTH ((size+1)/2, CSS_LENGTH_TYPE_PX);
+      CssLength size_bottom = CSS_CREATE_LENGTH (size / 2, CSS_LENGTH_TYPE_PX);
+      props.set (CssProperty::CSS_PROPERTY_BORDER_TOP_WIDTH, size_top);
+      props.set (CssProperty::CSS_PROPERTY_BORDER_LEFT_WIDTH, size_top);
+      props.set (CssProperty::CSS_PROPERTY_BORDER_BOTTOM_WIDTH, size_bottom);
+      props.set (CssProperty::CSS_PROPERTY_BORDER_RIGHT_WIDTH, size_bottom);
+   }
+
+   DW2TB(html->dw)->addParbreak (5, html->styleEngine->wordStyle ());
+
+   html->styleEngine->setNonCssHints (&props);
    hruler = new Ruler();
-   hruler->setStyle (style);
-   DW2TB(html->dw)->addWidget (hruler, style);
-   style->unref ();
-   DW2TB(html->dw)->addParbreak (5, S_TOP(html)->style);
+   hruler->setStyle (html->styleEngine->style ());
+   DW2TB(html->dw)->addWidget (hruler, html->styleEngine->style ());
+   DW2TB(html->dw)->addParbreak (5, html->styleEngine->wordStyle ());
 }
 
 /*
@@ -2882,7 +2653,7 @@
 static void Html_tag_open_dl(DilloHtml *html, const char *tag, int tagsize)
 {
    /* may want to actually do some stuff here. */
-   DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
+   DW2TB(html->dw)->addParbreak (9, html->styleEngine->wordStyle ());
 }
 
 /*
@@ -2890,8 +2661,7 @@
  */
 static void Html_tag_open_dt(DilloHtml *html, const char *tag, int tagsize)
 {
-   DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
-   a_Html_set_top_font(html, NULL, 0, 1, 1);
+   DW2TB(html->dw)->addParbreak (9, html->styleEngine->wordStyle ());
 }
 
 /*
@@ -2899,8 +2669,8 @@
  */
 static void Html_tag_open_dd(DilloHtml *html, const char *tag, int tagsize)
 {
-   DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
-   Html_add_indented(html, 40, 40, 9);
+   DW2TB(html->dw)->addParbreak (9, html->styleEngine->wordStyle ());
+   Html_add_textblock(html, 9);
 }
 
 /*
@@ -2908,12 +2678,10 @@
  */
 static void Html_tag_open_pre(DilloHtml *html, const char *tag, int tagsize)
 {
-   DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
-   a_Html_set_top_font(html, prefs.fw_fontname, 0, 0, 0);
+   DW2TB(html->dw)->addParbreak (9, html->styleEngine->wordStyle ());
 
    /* Is the placement of this statement right? */
    S_TOP(html)->parse_mode = DILLO_HTML_PARSE_MODE_PRE;
-   HTML_SET_TOP_ATTR (html, whiteSpace, WHITE_SPACE_PRE);
    html->pre_column = 0;
    html->PreFirstChar = true;
    html->InFlags |= IN_PRE;
@@ -2925,7 +2693,7 @@
 static void Html_tag_close_pre(DilloHtml *html, int TagIdx)
 {
    html->InFlags &= ~IN_PRE;
-   DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
+   DW2TB(html->dw)->addParbreak (9, html->styleEngine->wordStyle ());
 }
 
 /*
@@ -2941,7 +2709,7 @@
    /* initialize array */
    if (!ei_set[0])
       for (i = 0; es_set[i]; ++i)
-         ei_set[i] = Html_tag_index(es_set[i]);
+         ei_set[i] = a_Html_tag_index(es_set[i]);
 
    for (i = 0; ei_set[i]; ++i)
       if (tag_idx == ei_set[i])
@@ -3015,15 +2783,13 @@
       } else if (!dStrcasecmp(equiv, "content-type") &&
                  (content = a_Html_get_attr(html, tag, tagsize, "content"))) {
          if (a_Misc_content_type_cmp(html->content_type, content)) {
-            const bool_t force = FALSE;
             const char *new_content =
-               a_Capi_set_content_type(html->page_url, content, force);
+               a_Capi_set_content_type(html->page_url, content);
             /* Cannot ask cache whether the content type was changed, as
              * this code in another bw might have already changed it for us.
              */
             if (a_Misc_content_type_cmp(html->content_type, new_content)) {
-               a_Nav_repush(html->bw);
-               html->stop_parser = true;
+               html->repush_after_head = true;
             }
          }
       }   
@@ -3031,6 +2797,97 @@
 }
 
 /*
+ * Called by the network engine when a stylesheet has new data.
+ */
+static void Html_css_load_callback(int Op, CacheClient_t *Client)
+{
+   _MSG("Css_callback: Op=%d\n", Op);
+   if (Op) { /* EOF */
+      BrowserWindow *bw = ((DilloWeb *)Client->Web)->bw;
+      /* Repush when we've got them all */
+      if (--bw->NumPendingStyleSheets == 0)
+         a_Nav_repush(bw);
+   }
+}
+
+/*
+ * Tell cache to retrieve a stylesheet
+ */
+static void Html_load_stylesheet(DilloHtml *html, DilloUrl *url)
+{
+   char *data;
+   int len;
+   if (a_Nav_get_buf(url, &data, &len)) {
+      /* Haven't looked into what origin_count is */
+      if (a_Capi_get_flags(url) & CAPI_Completed)
+         html->styleEngine->parse(data, len, 0, CSS_ORIGIN_AUTHOR);
+      a_Nav_unref_buf(url);
+   } else if (!html->repush_after_head) {
+      /* Fill a Web structure for the cache query */
+      int ClientKey;
+      DilloWeb *Web = a_Web_new(url);
+      Web->bw = html->bw;
+      //Web->flags |= WEB_Stylesheet;
+      if ((ClientKey = a_Capi_open_url(Web, Html_css_load_callback, NULL))) {
+         ++html->bw->NumPendingStyleSheets;
+         a_Bw_add_client(html->bw, ClientKey, 0);
+         a_Bw_add_url(html->bw, url);
+         MSG("Html_load_stylesheet: NumPendingStyleSheets=%d\n",
+             html->bw->NumPendingStyleSheets);
+      }
+   }
+}
+
+/*
+ * Parse the LINK element (Only CSS stylesheets by now).
+ * (If it either hits or misses, is not relevant here; that's up to the
+ *  cache functions)
+ */
+static void Html_tag_open_link(DilloHtml *html, const char *tag, int tagsize)
+{
+   DilloUrl *url;
+   const char *attrbuf;
+
+   //char *tag_str = dStrndup(tag, tagsize);
+   //MSG("Html_tag_open_link(): %s\n", tag_str);
+   //dFree(tag_str);
+
+   /* When viewing suspicious HTML email, don't load LINK */
+   if (URL_FLAGS(html->base_url) & URL_SpamSafe)
+      return;
+   /* Ignore LINK outside HEAD */
+   if (!(html->InFlags & IN_HEAD)) {
+      BUG_MSG("the LINK element must be inside the HEAD section\n");
+      return;
+   }
+
+   /* TODO: How will we know when to use "handheld"? Ask the html->bw->ui for
+      screen dimensions, or a dillorc preference. */
+
+   if (!prefs.load_stylesheets)
+      return;
+
+   /* CSS stylesheet link */
+   if ((!(attrbuf = a_Html_get_attr(html, tag, tagsize, "rel")) ||
+        dStrcasecmp(attrbuf, "stylesheet")) ||
+       (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "href")) ||
+        !(url = a_Html_url_new(html, attrbuf, NULL, 0))))
+      return;
+   /* IMPLIED attributes? */
+   if (((attrbuf = a_Html_get_attr(html, tag, tagsize, "type")) &&
+        dStrcasecmp(attrbuf, "text/css")) ||
+       ((attrbuf = a_Html_get_attr(html, tag, tagsize, "media")) &&
+        !dStristr(attrbuf, "screen") && dStrcasecmp(attrbuf, "all")))
+      return;
+
+   MSG("  Html_tag_open_link(): URL=%s\n", URL_STR(url));
+   _MSG("    repush after HEAD=%d\n", html->repush_after_head);
+
+   Html_load_stylesheet(html, url);
+   a_Url_free(url);
+}
+
+/*
  * Set the history of the menu to be consistent with the active menuitem.
  */
 //static void Html_select_set_history(DilloHtmlInput *input)
@@ -3073,60 +2930,8 @@
    }
 }
 
-/*
- * <CODE>
- */
-static void Html_tag_open_code(DilloHtml *html, const char *tag, int tagsize)
-{
-   a_Html_set_top_font(html, prefs.fw_fontname, 0, 0, 0);
-}
-
-/*
- * <DFN>
- */
-static void Html_tag_open_dfn(DilloHtml *html, const char *tag, int tagsize)
-{
-   a_Html_set_top_font(html, NULL, 0, 2, 3);
-}
-
-/*
- * <KBD>
- */
-static void Html_tag_open_kbd(DilloHtml *html, const char *tag, int tagsize)
+static void Html_tag_open_default(DilloHtml *html,const char *tag,int tagsize)
 {
-   a_Html_set_top_font(html, prefs.fw_fontname, 0, 0, 0);
-}
-
-/*
- * <SAMP>
- */
-static void Html_tag_open_samp(DilloHtml *html, const char *tag, int tagsize)
-{
-   a_Html_set_top_font(html, prefs.fw_fontname, 0, 0, 0);
-}
-
-/*
- * <VAR>
- */
-static void Html_tag_open_var(DilloHtml *html, const char *tag, int tagsize)
-{
-   a_Html_set_top_font(html, NULL, 0, 2, 2);
-}
-
-/*
- * <SUB>
- */
-static void Html_tag_open_sub(DilloHtml *html, const char *tag, int tagsize)
-{
-   HTML_SET_TOP_ATTR (html, valign, VALIGN_SUB);
-}
-
-/*
- * <SUP>
- */
-static void Html_tag_open_sup(DilloHtml *html, const char *tag, int tagsize)
-{
-   HTML_SET_TOP_ATTR (html, valign, VALIGN_SUPER);
 }
 
 /*
@@ -3134,8 +2939,11 @@
  */
 static void Html_tag_open_div(DilloHtml *html, const char *tag, int tagsize)
 {
-   DW2TB(html->dw)->addParbreak (0, S_TOP(html)->style);
-   a_Html_tag_set_align_attr (html, tag, tagsize);
+   CssPropertyList props;
+
+   a_Html_tag_set_align_attr (html, &props, tag, tagsize);
+   html->styleEngine->setNonCssHints (&props);
+   Html_add_textblock(html, 0);
 }
 
 /*
@@ -3143,7 +2951,7 @@
  */
 static void Html_tag_close_div(DilloHtml *html, int TagIdx)
 {
-   DW2TB(html->dw)->addParbreak (0, S_TOP(html)->style);
+   DW2TB(html->dw)->addParbreak (0, html->styleEngine->wordStyle ());
 }
 
 /*
@@ -3158,7 +2966,7 @@
  */
 static void Html_tag_close_par(DilloHtml *html, int TagIdx)
 {
-   DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
+   DW2TB(html->dw)->addParbreak (9, html->styleEngine->wordStyle ());
 }
 
 
@@ -3197,30 +3005,30 @@
  /* acronym 010101 */
  {"address", B8(010110),'R',2, Html_tag_open_address, Html_tag_close_par},
  {"area", B8(010001),'F',0, Html_tag_open_area, Html_tag_close_default},
- {"b", B8(010101),'R',2, Html_tag_open_b, Html_tag_close_default},
+ {"b", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
  {"base", B8(100001),'F',0, Html_tag_open_base, Html_tag_close_default},
  /* basefont 010001 */
  /* bdo 010101 */
- {"big", B8(010101),'R',2, Html_tag_open_big_small, Html_tag_close_default},
+ {"big", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
  {"blockquote", B8(011110),'R',2,Html_tag_open_blockquote,Html_tag_close_par},
  {"body", B8(011110),'O',1, Html_tag_open_body, Html_tag_close_body},
  {"br", B8(010001),'F',0, Html_tag_open_br, Html_tag_close_default},
  {"button", B8(011101),'R',2, Html_tag_open_button, Html_tag_close_button},
  /* caption */
  {"center", B8(011110),'R',2, Html_tag_open_center, Html_tag_close_div},
- {"cite", B8(010101),'R',2, Html_tag_open_cite, Html_tag_close_default},
- {"code", B8(010101),'R',2, Html_tag_open_code, Html_tag_close_default},
+ {"cite", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
+ {"code", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
  /* col 010010 'F' */
  /* colgroup */
  {"dd", B8(011110),'O',1, Html_tag_open_dd, Html_tag_close_par},
- {"del", B8(011101),'R',2, Html_tag_open_strike, Html_tag_close_default},
- {"dfn", B8(010101),'R',2, Html_tag_open_dfn, Html_tag_close_default},
+ {"del", B8(011101),'R',2, Html_tag_open_default, Html_tag_close_default},
+ {"dfn", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
  {"dir", B8(011010),'R',2, Html_tag_open_dir, Html_tag_close_par},
  /* TODO: complete <div> support! */
  {"div", B8(011110),'R',2, Html_tag_open_div, Html_tag_close_div},
  {"dl", B8(011010),'R',2, Html_tag_open_dl, Html_tag_close_par},
  {"dt", B8(010110),'O',1, Html_tag_open_dt, Html_tag_close_par},
- {"em", B8(010101),'R',2, Html_tag_open_em, Html_tag_close_default},
+ {"em", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
  /* fieldset */
  {"font", B8(010101),'R',2, Html_tag_open_font, Html_tag_close_default},
  {"form", B8(011110),'R',2, Html_tag_open_form, Html_tag_close_form},
@@ -3235,17 +3043,17 @@
  {"head", B8(101101),'O',1, Html_tag_open_head, Html_tag_close_head},
  {"hr", B8(010010),'F',0, Html_tag_open_hr, Html_tag_close_default},
  {"html", B8(001110),'O',1, Html_tag_open_html, Html_tag_close_html},
- {"i", B8(010101),'R',2, Html_tag_open_i, Html_tag_close_default},
+ {"i", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
  {"iframe", B8(011110),'R',2, Html_tag_open_frame, Html_tag_close_default},
  {"img", B8(010001),'F',0, Html_tag_open_img, Html_tag_close_default},
  {"input", B8(010001),'F',0, Html_tag_open_input, Html_tag_close_default},
  /* ins */
  {"isindex", B8(110001),'F',0, Html_tag_open_isindex, Html_tag_close_default},
- {"kbd", B8(010101),'R',2, Html_tag_open_kbd, Html_tag_close_default},
+ {"kbd", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
  /* label 010101 */
  /* legend 01?? */
  {"li", B8(011110),'O',1, Html_tag_open_li, Html_tag_close_li},
- /* link 100000 'F' */
+ {"link", B8(100001),'F',0, Html_tag_open_link, Html_tag_close_default},
  {"map", B8(011001),'R',2, Html_tag_open_map, Html_tag_close_map},
  /* menu 1010 -- TODO: not exactly 1010, it can contain LI and inline */
  {"menu", B8(011010),'R',2, Html_tag_open_menu, Html_tag_close_par},
@@ -3260,17 +3068,17 @@
  /* param 010001 'F' */
  {"pre", B8(010110),'R',2, Html_tag_open_pre, Html_tag_close_pre},
  {"q", B8(010101),'R',2, Html_tag_open_q, Html_tag_close_q},
- {"s", B8(010101),'R',2, Html_tag_open_strike, Html_tag_close_default},
- {"samp", B8(010101),'R',2, Html_tag_open_samp, Html_tag_close_default},
+ {"s", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
+ {"samp", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
  {"script", B8(111001),'R',2, Html_tag_open_script, Html_tag_close_script},
  {"select", B8(010101),'R',2, Html_tag_open_select, Html_tag_close_select},
- {"small", B8(010101),'R',2, Html_tag_open_big_small, Html_tag_close_default},
- /* span 0101 */
- {"strike", B8(010101),'R',2, Html_tag_open_strike, Html_tag_close_default},
- {"strong", B8(010101),'R',2, Html_tag_open_strong, Html_tag_close_default},
+ {"small", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
+ {"span", B8(010101),'R',2, Html_tag_open_span, Html_tag_close_default},
+ {"strike", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
+ {"strong", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
  {"style", B8(100101),'R',2, Html_tag_open_style, Html_tag_close_style},
- {"sub", B8(010101),'R',2, Html_tag_open_sub, Html_tag_close_default},
- {"sup", B8(010101),'R',2, Html_tag_open_sup, Html_tag_close_default},
+ {"sub", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
+ {"sup", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
  {"table", B8(011010),'R',5, Html_tag_open_table, Html_tag_close_div},
  /* tbody */
  {"td", B8(011110),'O',3, Html_tag_open_td, Html_tag_close_default},
@@ -3280,10 +3088,10 @@
  /* thead */
  {"title", B8(100101),'R',2, Html_tag_open_title, Html_tag_close_title},
  {"tr", B8(011010),'O',4, Html_tag_open_tr, Html_tag_close_default},
- {"tt", B8(010101),'R',2, Html_tag_open_tt, Html_tag_close_default},
- {"u", B8(010101),'R',2, Html_tag_open_u, Html_tag_close_default},
+ {"tt", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
+ {"u", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
  {"ul", B8(011010),'R',2, Html_tag_open_ul, Html_tag_close_par},
- {"var", B8(010101),'R',2, Html_tag_open_var, Html_tag_close_default}
+ {"var", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}
 
 };
 #define NTAGS (sizeof(Tags)/sizeof(Tags[0]))
@@ -3309,7 +3117,7 @@
  * Get 'tag' index
  * return -1 if tag is not handled yet
  */
-static int Html_tag_index(const char *tag)
+int a_Html_tag_index(const char *tag)
 {
    int low, high, mid, cond;
 
@@ -3340,17 +3148,17 @@
 
    if (i_P == -1) {
     /* initialize the indexes of elements with optional close */
-    i_P  = Html_tag_index("p"),
-    i_LI = Html_tag_index("li"),
-    i_TD = Html_tag_index("td"),
-    i_TR = Html_tag_index("tr"),
-    i_TH = Html_tag_index("th"),
-    i_DD = Html_tag_index("dd"),
-    i_DT = Html_tag_index("dt"),
-    i_OPTION = Html_tag_index("option");
-    // i_THEAD = Html_tag_index("thead");
-    // i_TFOOT = Html_tag_index("tfoot");
-    // i_COLGROUP = Html_tag_index("colgroup");
+    i_P  = a_Html_tag_index("p"),
+    i_LI = a_Html_tag_index("li"),
+    i_TD = a_Html_tag_index("td"),
+    i_TR = a_Html_tag_index("tr"),
+    i_TH = a_Html_tag_index("th"),
+    i_DD = a_Html_tag_index("dd"),
+    i_DT = a_Html_tag_index("dt"),
+    i_OPTION = a_Html_tag_index("option");
+    // i_THEAD = a_Html_tag_index("thead");
+    // i_TFOOT = a_Html_tag_index("tfoot");
+    // i_COLGROUP = a_Html_tag_index("colgroup");
    }
 
    if (old_idx == i_P || old_idx == i_DT) {
@@ -3447,7 +3255,7 @@
 
    if (!(html->InFlags & IN_HTML)) {
       tag = "<html>";
-      tag_idx = Html_tag_index(tag + 1);
+      tag_idx = a_Html_tag_index(tag + 1);
       if (tag_idx != new_idx || IsCloseTag) {
          /* implicit open */
          Html_force_push_tag(html, tag_idx);
@@ -3460,7 +3268,7 @@
       /* head element */
       if (!(html->InFlags & IN_HEAD)) {
          tag = "<head>";
-         tag_idx = Html_tag_index(tag + 1);
+         tag_idx = a_Html_tag_index(tag + 1);
          if (tag_idx != new_idx || IsCloseTag) {
             /* implicit open of the head element */
             Html_force_push_tag(html, tag_idx);
@@ -3473,11 +3281,11 @@
       /* body element */
       if (html->InFlags & IN_HEAD) {
          tag = "</head>";
-         tag_idx = Html_tag_index(tag + 2);
+         tag_idx = a_Html_tag_index(tag + 2);
          Html_tag_cleanup_at_close(html, tag_idx);
       }
       tag = "<body>";
-      tag_idx = Html_tag_index(tag + 1);
+      tag_idx = a_Html_tag_index(tag + 1);
       if (tag_idx != new_idx || IsCloseTag) {
          /* implicit open */
          Html_force_push_tag(html, tag_idx);
@@ -3499,7 +3307,9 @@
    char *start = tag + 1; /* discard the '<' */
    int IsCloseTag = (*start == '/');
 
-   ni = Html_tag_index(start + IsCloseTag);
+   dReturn_if_fail ( html->stop_parser == false );
+
+   ni = a_Html_tag_index(start + IsCloseTag);
    if (ni == -1) {
       /* TODO: doctype parsing is a bit fuzzy, but enough for the time being */
       if (!(html->InFlags & IN_HTML)) {
@@ -3533,11 +3343,8 @@
       /* Push the tag into the stack */
       Html_push_tag(html, ni);
 
-      /* Call the open function for this tag */
+      html->styleEngine->startElement (ni);
       _MSG("Open : %*s%s\n", html->stack->size(), " ", Tags[ni].name);
-      Tags[ni].open (html, tag, tagsize);
-      if (html->stop_parser)
-         break;
 
       /* Now parse attributes that can appear on any tag */
       if (tagsize >= 8 &&        /* length of "<t id=i>" */
@@ -3549,6 +3356,9 @@
           * spec states in Sec. 7.5.2 that anchor ids are case-sensitive.
           * So we don't do it and hope for better specs in the future ...
           */
+         if (attrbuf)
+            html->styleEngine->setId (attrbuf);
+
          Html_check_name_val(html, attrbuf, "id");
          /* We compare the "id" value with the url-decoded "name" value */
          if (!html->NameVal || strcmp(html->NameVal, attrbuf)) {
@@ -3564,6 +3374,24 @@
          html->NameVal = NULL;
       }
 
+      if (tagsize >= 10) {       /* length of "<t class=i>" */
+          attrbuf = Html_get_attr2(html, tag, tagsize, "class",
+                                   HTML_LeftTrim | HTML_RightTrim);
+          if (attrbuf)
+            html->styleEngine->setClass (attrbuf);
+      }
+
+      if (tagsize >= 11) {       /* length of "<t style=i>" */
+          attrbuf = Html_get_attr2(html, tag, tagsize, "style",
+                                   HTML_LeftTrim | HTML_RightTrim);
+          if (attrbuf)
+            html->styleEngine->setStyle (attrbuf);
+      }
+
+      /* Call the open function for this tag */
+      _MSG("Open : %s\n", Tags[ni].name);
+      Tags[ni].open (html, tag, tagsize);
+
       /* Request inmediate close for elements with forbidden close tag. */
       /* TODO: XHTML always requires close tags. A simple implementation
        * of the commented clause below will make it work. */
@@ -3582,6 +3410,7 @@
            (strchr(" \"'", tag[tagsize-3]) ||                   /* [ "']/> */
             (size_t)tagsize == strlen(Tags[ni].name) + 3))) {   /*  <x/>   */
    
+         _MSG("Close: %s\n", Tags[ni].name);
          Html_tag_cleanup_at_close(html, ni);
          /* This was a close tag */
          html->ReqTagClose = false;
@@ -3726,29 +3555,6 @@
 }
 
 /*
- * Add a widget to the page.
- */
-static void Html_add_widget(DilloHtml *html,
-                            Widget *widget,
-                            char *width_str,
-                            char *height_str,
-                            StyleAttrs *style_attrs)
-{
-   StyleAttrs new_style_attrs;
-   Style *style;
-
-   new_style_attrs = *style_attrs;
-   new_style_attrs.width = width_str ?
-      a_Html_parse_length (html, width_str) : LENGTH_AUTO;
-   new_style_attrs.height = height_str ?
-      a_Html_parse_length (html, height_str) : LENGTH_AUTO;
-   style = Style::create (HT2LT(html), &new_style_attrs);
-   DW2TB(html->dw)->addWidget (widget, style);
-   style->unref ();
-}
-
-
-/*
  * Dispatch the apropriate function for 'Op'
  * This function is a Cache client and gets called whenever new data arrives
  *  Op      : operation to perform.
--- a/src/html_common.hh	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/html_common.hh	Fri Jan 16 14:32:20 2009 -0300
@@ -13,6 +13,8 @@
 
 #include "form.hh"
 
+#include "styleengine.hh"
+
 /*
  * Macros 
  */
@@ -36,6 +38,7 @@
  * Change one toplevel attribute. var should be an identifier. val is
  * only evaluated once, so you can safely use a function call for it.
  */
+#if 0
 #define HTML_SET_TOP_ATTR(html, var, val) \
    do { \
       StyleAttrs style_attrs; \
@@ -48,7 +51,9 @@
          Style::create (HT2LT(html), &style_attrs); \
       old_style->unref (); \
    } while (FALSE)
-
+#else
+#define HTML_SET_TOP_ATTR(html, var, val) 
+#endif
 /*
  * Typedefs 
  */
@@ -109,7 +114,7 @@
 };
 
 struct _DilloHtmlState {
-   dw::core::style::Style *style, *table_cell_style;
+   CssPropertyList *table_cell_props;
    DilloHtmlParseMode parse_mode;
    DilloHtmlTableMode table_mode;
    bool cell_text_align_set;
@@ -167,6 +172,8 @@
    char *content_type, *charset;
    bool stop_parser;
 
+   bool repush_after_head;
+
    size_t CurrTagOfs;
    size_t OldTagOfs, OldTagLine;
 
@@ -174,6 +181,7 @@
    float DocTypeVersion;          /* HTML or XHTML version number */
 
    lout::misc::SimpleVector<DilloHtmlState> *stack;
+   StyleEngine *styleEngine;
 
    int InFlags; /* tracks which elements we are in */
 
@@ -232,6 +240,8 @@
  * Parser functions 
  */
 
+int a_Html_tag_index(const char *tag);
+
 const char *a_Html_get_attr(DilloHtml *html,
                             const char *tag,
                             int tagsize,
@@ -249,7 +259,6 @@
 
 DilloImage *a_Html_add_new_image(DilloHtml *html, const char *tag,
                                  int tagsize, DilloUrl *url,
-                                 dw::core::style::StyleAttrs *style_attrs,
                                  bool add);
 
 char *a_Html_parse_entities(DilloHtml *html, const char *token, int toksize);
@@ -259,12 +268,10 @@
                            const char *subtag, int32_t default_color);
 dw::core::style::Length a_Html_parse_length (DilloHtml *html,
                                              const char *attr);
-void a_Html_tag_set_align_attr(DilloHtml *html,
+void a_Html_tag_set_align_attr(DilloHtml *html, CssPropertyList *props,
                                const char *tag, int tagsize);
 bool a_Html_tag_set_valign_attr(DilloHtml *html,
                                 const char *tag, int tagsize,
-                                dw::core::style::StyleAttrs *style_attrs);
-void a_Html_set_top_font(DilloHtml *html, const char *name, int size,
-                         int BI, int BImask);
+                                CssPropertyList *props);
 
 #endif /* __HTML_COMMON_HH__ */
--- a/src/image.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/image.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -27,14 +27,7 @@
 using namespace dw::core;
 
 // Image to Object-Image macro
-#define OI(Image)  ((dw::Image*)(Image->dw))
-
-
-/*
- * Local data
- */
-static size_t linebuf_size = 0;
-static uchar_t *linebuf = NULL;
+#define I2DW(Image)  ((dw::Image*)(Image->dw))
 
 
 /*
@@ -51,8 +44,6 @@
    Image->dw = (void*) new dw::Image(alt_text);
    Image->width = 0;
    Image->height = 0;
-   Image->cmap = NULL;
-   Image->in_type = DILLO_IMG_TYPE_NOTSET;
    Image->bg_color = bg_color;
    Image->ScanNumber = 0;
    Image->BitVec = NULL;
@@ -92,37 +83,6 @@
 }
 
 /*
- * Decode 'buf' (an image line) into RGB format.
- */
-static uchar_t *
- Image_line(DilloImage *Image, const uchar_t *buf, const uchar_t *cmap, int y)
-{
-   uint_t x;
-
-   switch (Image->in_type) {
-   case DILLO_IMG_TYPE_INDEXED:
-      if (cmap) {
-         for (x = 0; x < Image->width; x++)
-            memcpy(linebuf + x * 3, cmap + buf[x] * 3, 3);
-      } else {
-         MSG("Gif:: WARNING, image lacks a color map\n");
-      }
-      break;
-   case DILLO_IMG_TYPE_GRAY:
-      for (x = 0; x < Image->width; x++)
-         memset(linebuf + x * 3, buf[x], 3);
-      break;
-   case DILLO_IMG_TYPE_RGB:
-      /* avoid a memcpy here!  --Jcid */
-      return (uchar_t *)buf;
-   case DILLO_IMG_TYPE_NOTSET:
-      MSG_ERR("Image_line: type not set...\n");
-      break;
-   }
-   return linebuf;
-}
-
-/*
  * Set initial parameters of the image
  */
 void a_Image_set_parms(DilloImage *Image, void *v_imgbuf, DilloUrl *url,
@@ -132,17 +92,12 @@
    _MSG("a_Image_set_parms: width=%d height=%d\n", width, height);
 
    bool resize = (Image->width != width || Image->height != height);
-   OI(Image)->setBuffer((Imgbuf*)v_imgbuf, resize);
+   I2DW(Image)->setBuffer((Imgbuf*)v_imgbuf, resize);
 
    if (!Image->BitVec)
       Image->BitVec = a_Bitvec_new(height);
-   Image->in_type = type;
    Image->width = width;
    Image->height = height;
-   if (3 * width > linebuf_size) {
-      linebuf_size = 3 * width;
-      linebuf = (uchar_t*) dRealloc(linebuf, linebuf_size);
-   }
    Image->State = IMG_SetParms;
 }
 
@@ -151,7 +106,7 @@
  */
 void a_Image_set_cmap(DilloImage *Image, const uchar_t *cmap)
 {
-   Image->cmap = cmap;
+   _MSG("a_Image_set_cmap\n");
    Image->State = IMG_SetCmap;
 }
 
@@ -160,6 +115,7 @@
  */
 void a_Image_new_scan(DilloImage *Image, void *v_imgbuf)
 {
+   _MSG("a_Image_new_scan\n");
    a_Bitvec_clear(Image->BitVec);
    Image->ScanNumber++;
    ((Imgbuf*)v_imgbuf)->newScan();
@@ -168,23 +124,15 @@
 /*
  * Implement the write method
  */
-void a_Image_write(DilloImage *Image, void *v_imgbuf,
-                   const uchar_t *buf, uint_t y, int decode)
+void a_Image_write(DilloImage *Image, uint_t y)
 {
-   const uchar_t *newbuf;
-
+   _MSG("a_Image_write\n");
    dReturn_if_fail ( y < Image->height );
 
-   if (decode) {
-      /* Decode 'buf' and copy it into the DicEntry buffer */
-      newbuf = Image_line(Image, buf, Image->cmap, y);
-      ((Imgbuf*)v_imgbuf)->copyRow(y, (byte *)newbuf);
-   }
+   /* Update the row in DwImage */
+   I2DW(Image)->drawRow(y);
    a_Bitvec_set_bit(Image->BitVec, y);
    Image->State = IMG_Write;
-
-   /* Update the row in DwImage */
-   OI(Image)->drawRow(y);
 }
 
 /*
@@ -192,46 +140,7 @@
  */
 void a_Image_close(DilloImage *Image)
 {
+   _MSG("a_Image_close\n");
    a_Image_unref(Image);
 }
 
-
-// Wrappers for Imgbuf -------------------------------------------------------
-
-/*
- * Increment reference count for an Imgbuf
- */
-void a_Image_imgbuf_ref(void *v_imgbuf)
-{
-   ((Imgbuf*)v_imgbuf)->ref();
-}
-
-/*
- * Decrement reference count for an Imgbuf
- */
-void a_Image_imgbuf_unref(void *v_imgbuf)
-{
-   ((Imgbuf*)v_imgbuf)->unref();
-}
-
-/*
- * Create a new Imgbuf
- */
-void *a_Image_imgbuf_new(void *v_dw, int img_type, int width, int height)
-{
-   Layout *layout = ((Widget*)v_dw)->getLayout();
-   if (!layout) {
-      MSG_ERR("a_Image_imgbuf_new: layout is NULL.\n");
-      exit(1);
-   }
-   return (void*)layout->createImgbuf(Imgbuf::RGB, width, height);
-}
-
-/*
- * Last reference for this Imgbuf?
- */
-int a_Image_imgbuf_last_reference(void *v_imgbuf)
-{
-   return ((Imgbuf*)v_imgbuf)->lastReference () ? 1 : 0;
-}
-
--- a/src/image.hh	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/image.hh	Fri Jan 16 14:32:20 2009 -0300
@@ -38,10 +38,7 @@
    uint_t width;
    uint_t height;
 
-   const uchar_t *cmap;     /* Color map (only for indexed) */
-   DilloImgType in_type;    /* Image Type */
    int32_t bg_color;        /* Background color */
-
    bitvec_t *BitVec;        /* Bit vector for decoded rows */
    uint_t ScanNumber;       /* Current decoding scan */
    ImageState State;        /* Processing status */
@@ -63,14 +60,9 @@
                        DilloImgType type);
 void a_Image_set_cmap(DilloImage *Image, const uchar_t *cmap);
 void a_Image_new_scan(DilloImage *image, void *v_imgbuf);
-void a_Image_write(DilloImage *Image, void *v_imgbuf,
-                   const uchar_t *buf, uint_t y, int decode);
+void a_Image_write(DilloImage *Image, uint_t y);
 void a_Image_close(DilloImage *Image);
 
-void a_Image_imgbuf_ref(void *v_imgbuf);
-void a_Image_imgbuf_unref(void *v_imgbuf);
-void *a_Image_imgbuf_new(void *v_dw, int img_type, int width, int height) ;
-int a_Image_imgbuf_last_reference(void *v_imgbuf);
 
 #ifdef __cplusplus
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imgbuf.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -0,0 +1,117 @@
+/*
+ * File: imgbuf.cc
+ *
+ * Copyright (C) 2008 Jorge Arellano Cid <jcid@dillo.org>,
+ *
+ * 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
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "msg.h"
+#include "imgbuf.hh"
+#include "dw/core.hh"
+#include "dw/image.hh"
+
+using namespace dw::core;
+
+/*
+ * Local data
+ */
+static size_t linebuf_size = 0;
+static uchar_t *linebuf = NULL;
+
+
+/*
+ * Decode 'buf' (an image line) into RGB format.
+ */
+static uchar_t *Imgbuf_rgb_line(const uchar_t *buf,
+                                DilloImgType type, uchar_t *cmap,
+                                uint_t width, uint_t y)
+{
+   uint_t x;
+
+   switch (type) {
+   case DILLO_IMG_TYPE_INDEXED:
+      if (cmap) {
+         for (x = 0; x < width; x++)
+            memcpy(linebuf + x * 3, cmap + buf[x] * 3, 3);
+      } else {
+         MSG("Gif:: WARNING, image lacks a color map\n");
+      }
+      break;
+   case DILLO_IMG_TYPE_GRAY:
+      for (x = 0; x < width; x++)
+         memset(linebuf + x * 3, buf[x], 3);
+      break;
+   case DILLO_IMG_TYPE_RGB:
+      /* avoid a memcpy here!  --Jcid */
+      return (uchar_t *)buf;
+   case DILLO_IMG_TYPE_NOTSET:
+      MSG_ERR("Imgbuf_rgb_line: type not set...\n");
+      break;
+   }
+   return linebuf;
+}
+
+// Wrappers for Imgbuf -------------------------------------------------------
+
+/*
+ * Increment reference count for an Imgbuf
+ */
+void a_Imgbuf_ref(void *v_imgbuf)
+{
+   ((Imgbuf*)v_imgbuf)->ref();
+}
+
+/*
+ * Decrement reference count for an Imgbuf
+ */
+void a_Imgbuf_unref(void *v_imgbuf)
+{
+   if (v_imgbuf)
+      ((Imgbuf*)v_imgbuf)->unref();
+}
+
+/*
+ * Create a new Imgbuf
+ */
+void *a_Imgbuf_new(void *v_dw, int img_type, uint_t width, uint_t height)
+{
+   Layout *layout = ((Widget*)v_dw)->getLayout();
+   if (!layout) {
+      MSG_ERR("a_Imgbuf_new: layout is NULL.\n");
+      exit(1);
+   }
+   // Assert linebuf is wide enough.
+   if (3 * width > linebuf_size) {
+      linebuf_size = 3 * width;
+      linebuf = (uchar_t*) dRealloc(linebuf, linebuf_size);
+   }
+
+   return (void*)layout->createImgbuf(Imgbuf::RGB, width, height);
+}
+
+/*
+ * Last reference for this Imgbuf?
+ */
+int a_Imgbuf_last_reference(void *v_imgbuf)
+{
+   return ((Imgbuf*)v_imgbuf)->lastReference () ? 1 : 0;
+}
+
+/*
+ * Update the root buffer of an imgbuf.
+ */
+void a_Imgbuf_update(void *v_imgbuf, const uchar_t *buf, DilloImgType type,
+                     uchar_t *cmap, uint_t width, uint_t height, uint_t y)
+
+{
+   dReturn_if_fail ( y < height );
+
+   /* Decode 'buf' and copy it into the imgbuf */
+   uchar_t *newbuf = Imgbuf_rgb_line(buf, type, cmap, width, y);
+   ((Imgbuf*)v_imgbuf)->copyRow(y, (byte *)newbuf);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imgbuf.hh	Fri Jan 16 14:32:20 2009 -0300
@@ -0,0 +1,30 @@
+#ifndef __IMGBUF_HH__
+#define __IMGBUF_HH__
+
+// Imgbuf wrappers
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#include "image.hh"
+
+/*
+ * Function prototypes
+ */
+void a_Imgbuf_ref(void *v_imgbuf);
+void a_Imgbuf_unref(void *v_imgbuf);
+void *a_Imgbuf_new(void *v_dw, int img_type, uint_t width, uint_t height);
+int a_Imgbuf_last_reference(void *v_imgbuf);
+void a_Imgbuf_update(void *v_imgbuf, const uchar_t *buf, DilloImgType type,
+                     uchar_t *cmap, uint_t width, uint_t height, uint_t y);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __IMGBUF_HH__ */
+
--- a/src/jpeg.c	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/jpeg.c	Fri Jan 16 14:32:20 2009 -0300
@@ -84,7 +84,6 @@
 static DilloJpeg *Jpeg_new(DilloImage *Image, DilloUrl *url, int version);
 static void Jpeg_callback(int Op, CacheClient_t *Client);
 static void Jpeg_write(DilloJpeg *jpeg, void *Buf, uint_t BufSize);
-static void Jpeg_close(DilloJpeg *jpeg, CacheClient_t *Client);
 METHODDEF(void) Jpeg_errorexit (j_common_ptr cinfo);
 
 /* exported function */
@@ -103,7 +102,8 @@
 
 /*
  * MIME handler for "image/jpeg" type
- * (Sets Jpeg_callback or a_Dicache_callback as the cache-client)
+ * Sets a_Dicache_callback as the cache-client,
+ * and Jpeg_callback as the image decoder.
  */
 void *a_Jpeg_image(const char *Type, void *P, CA_Callback_t *Call,
                    void **Data)
@@ -117,20 +117,20 @@
    /* Add an extra reference to the Image (for dicache usage) */
    a_Image_ref(web->Image);
 
-   DicEntry = a_Dicache_get_entry(web->url);
+   DicEntry = a_Dicache_get_entry(web->url, DIC_Last);
    if (!DicEntry) {
       /* Let's create an entry for this image... */
       DicEntry = a_Dicache_add_entry(web->url);
-
-      /* ... and let the decoder feed it! */
-      *Data = Jpeg_new(web->Image, DicEntry->url, DicEntry->version);
-      *Call = (CA_Callback_t) Jpeg_callback;
+      DicEntry->DecoderData =
+         Jpeg_new(web->Image, DicEntry->url, DicEntry->version);
    } else {
-      /* Let's feed our client from the dicache */
+      /* Repeated image */
       a_Dicache_ref(DicEntry->url, DicEntry->version);
-      *Data = web->Image;
-      *Call = (CA_Callback_t) a_Dicache_callback;
    }
+   DicEntry->Decoder = Jpeg_callback;
+   *Data = DicEntry->DecoderData;
+   *Call = (CA_Callback_t) a_Dicache_callback;
+
    return (web->Image->dw);
 }
 
@@ -139,6 +139,7 @@
  */
 static void Jpeg_close(DilloJpeg *jpeg, CacheClient_t *Client)
 {
+   _MSG("Jpeg_close\n");
    a_Dicache_close(jpeg->url, jpeg->version, Client);
    jpeg_destroy_decompress(&(jpeg->cinfo));
    dFree(jpeg);
@@ -330,7 +331,7 @@
 
    if (jpeg->state == DILLO_JPEG_READ_BEGIN_SCAN) {
       if (jpeg_start_output(&jpeg->cinfo, jpeg->cinfo.input_scan_number)) {
-         a_Dicache_new_scan(jpeg->Image, jpeg->url, jpeg->version);
+         a_Dicache_new_scan(jpeg->url, jpeg->version);
          jpeg->state = DILLO_JPEG_READ_IN_SCAN;
       }
    }
@@ -389,7 +390,7 @@
                   /* out of input */
                   break;
                }
-               a_Dicache_new_scan(jpeg->Image, jpeg->url, jpeg->version);
+               a_Dicache_new_scan(jpeg->url, jpeg->version);
                jpeg->state = DILLO_JPEG_READ_IN_SCAN;
             }
          }
--- a/src/nav.c	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/nav.c	Fri Jan 16 14:32:20 2009 -0300
@@ -378,10 +378,14 @@
  * Repush current URL: not an end-to-end reload but from cache.
  * - Currently used to switch to a charset decoder given by the META element.
  * - Delayed to let dillo finish the call flow into a known state.
+ *
+ * There's no need to stop the parser before calling this function:
+ * When the timeout activates, a_Bw_stop_clients will stop the data feed.
  */
 void a_Nav_repush(BrowserWindow *bw)
 {
    dReturn_if_fail (bw != NULL);
+   MSG(">>> a_Nav_repush <<<<\n");
    a_Timeout_add(0.0, Nav_repush_callback, (void*)bw);
 }
 
--- a/src/plain.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/plain.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -108,9 +108,9 @@
    styleAttrs.initValues ();
    styleAttrs.margin.setVal (5);
    styleAttrs.font = style::Font::create (layout, &fontAttrs);
-   styleAttrs.color = style::Color::createSimple (layout, prefs.text_color);
+   styleAttrs.color = style::Color::create (layout, prefs.text_color);
    styleAttrs.backgroundColor = 
-      style::Color::createSimple (layout, prefs.bg_color);
+      style::Color::create (layout, prefs.bg_color);
    widgetStyle = style::Style::create (layout, &styleAttrs);
 
    /* The context menu */
--- a/src/png.c	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/png.c	Fri Jan 16 14:32:20 2009 -0300
@@ -231,8 +231,9 @@
 
    png_progressive_combine_row(png_ptr, png->row_pointers[row_num], new_row);
 
+   _MSG("png: row_num=%u previous_row=%u\n", row_num, png->previous_row);
    if (row_num < png->previous_row) {
-      a_Dicache_new_scan(png->Image, png->url, png->version);
+      a_Dicache_new_scan(png->url, png->version);
    }
    png->previous_row = row_num;
 
@@ -303,12 +304,14 @@
  */
 static void Png_close(DilloPng *png, CacheClient_t *Client)
 {
+   _MSG("Png_close\n");
+   /* Let dicache know decoding is over */
+   a_Dicache_close(png->url, png->version, Client);
+
    /* Free up the resources for this image */
-   a_Dicache_close(png->url, png->version, Client);
    dFree(png->image_data);
    dFree(png->row_pointers);
    dFree(png->linebuf);
-
    if (setjmp(png->jmpbuf))
       MSG_WARN("PNG: can't destroy read structure\n");
    else if (png->png_ptr)
@@ -443,8 +446,9 @@
 }
 
 /*
- * MIME handler for "image/png" type
- * (Sets Png_callback or a_Dicache_callback as the cache-client)
+ * MIME handler for "image/png" type.
+ * Sets a_Dicache_callback as the cache-client,
+ * and Png_callback as the image decoder.
  *
  * Parameters:
  *   Type: MIME type
@@ -464,20 +468,20 @@
    /* Add an extra reference to the Image (for dicache usage) */
    a_Image_ref(web->Image);
 
-   DicEntry = a_Dicache_get_entry(web->url);
+   DicEntry = a_Dicache_get_entry(web->url, DIC_Last);
    if (!DicEntry) {
       /* Let's create an entry for this image... */
       DicEntry = a_Dicache_add_entry(web->url);
-
-      /* ... and let the decoder feed it! */
-      *Data = Png_new(web->Image, DicEntry->url, DicEntry->version);
-      *Call = (CA_Callback_t) Png_callback;
+      DicEntry->DecoderData =
+         Png_new(web->Image, DicEntry->url, DicEntry->version);
    } else {
-      /* Let's feed our client from the dicache */
+      /* Repeated image */
       a_Dicache_ref(DicEntry->url, DicEntry->version);
-      *Data = web->Image;
-      *Call = (CA_Callback_t) a_Dicache_callback;
    }
+   DicEntry->Decoder = Png_callback;
+   *Data = DicEntry->DecoderData;
+   *Call = (CA_Callback_t) a_Dicache_callback;
+
    return (web->Image->dw);
 }
 
--- a/src/prefs.c	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/prefs.c	Fri Jan 16 14:32:20 2009 -0300
@@ -74,6 +74,7 @@
    DRC_TOKEN_LIMIT_TEXT_WIDTH,
    DRC_TOKEN_LINK_COLOR,
    DRC_TOKEN_LOAD_IMAGES,
+   DRC_TOKEN_LOAD_STYLESHEETS,
    DRC_TOKEN_BUFFERED_DRAWING,
    DRC_TOKEN_MIDDLE_CLICK_OPENS_NEW_TAB,
    DRC_TOKEN_NOPROXY,
@@ -140,6 +141,7 @@
    { "limit_text_width", DRC_TOKEN_LIMIT_TEXT_WIDTH },
    { "link_color", DRC_TOKEN_LINK_COLOR },
    { "load_images", DRC_TOKEN_LOAD_IMAGES },
+   { "load_stylesheets", DRC_TOKEN_LOAD_STYLESHEETS },
    { "middle_click_drags_page", DRC_TOKEN_MIDDLE_CLICK_DRAGS_PAGE },
    { "middle_click_opens_new_tab", DRC_TOKEN_MIDDLE_CLICK_OPENS_NEW_TAB },
    { "no_proxy", DRC_TOKEN_NOPROXY },
@@ -330,6 +332,9 @@
    case DRC_TOKEN_LOAD_IMAGES:
       prefs.load_images = (strcmp(value, "YES") == 0);
       break;
+   case DRC_TOKEN_LOAD_STYLESHEETS:
+      prefs.load_stylesheets = (strcmp(value, "YES") == 0);
+      break;
    case DRC_TOKEN_BUFFERED_DRAWING:
       prefs.buffered_drawing = atoi(value);
       break;
@@ -457,6 +462,7 @@
    prefs.show_progress_box=TRUE;
    prefs.fullwindow_start=FALSE;
    prefs.load_images=TRUE;
+   prefs.load_stylesheets=TRUE;
    prefs.buffered_drawing=1;
    prefs.vw_fontname = dStrdup(D_VW_FONTNAME);
    prefs.fw_fontname = dStrdup(D_FW_FONTNAME);
--- a/src/prefs.h	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/prefs.h	Fri Jan 16 14:32:20 2009 -0300
@@ -58,6 +58,7 @@
    bool_t show_progress_box;
    bool_t fullwindow_start;
    bool_t load_images;
+   bool_t load_stylesheets;
    int32_t buffered_drawing;
    char *vw_fontname;
    char *fw_fontname;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/styleengine.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -0,0 +1,432 @@
+/*
+ * File: styleengine.cc
+ *
+ * Copyright 2008 Jorge Arellano Cid <jcid@dillo.org>
+ *
+ * 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
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include "../dlib/dlib.h"
+#include "prefs.h"
+#include "styleengine.hh"
+
+using namespace dw::core::style;
+
+StyleEngine::StyleEngine (dw::core::Layout *layout) {
+   StyleAttrs style_attrs;
+   FontAttrs font_attrs;
+
+   stack = new lout::misc::SimpleVector <Node> (1);
+   cssContext = new CssContext ();
+   this->layout = layout;
+   num = 0;
+
+   stack->increase ();
+   Node *n =  stack->getRef (stack->size () - 1);
+
+   /* Create a dummy font, attribute, and tag for the bottom of the stack. */
+   font_attrs.name = "helvetica";
+   font_attrs.size = (int) (12 * prefs.font_factor + 0.5);
+   font_attrs.weight = CssProperty::CSS_FONT_WEIGHT_NORMAL;
+   font_attrs.style = FONT_STYLE_NORMAL;
+ 
+   style_attrs.initValues ();
+   style_attrs.font = Font::create (layout, &font_attrs);
+   style_attrs.color = Color::create (layout, 0);
+   style_attrs.backgroundColor = Color::create (layout, 0xffffff);
+
+   n->num = num++;
+   n->style = Style::create (layout, &style_attrs);
+   n->wordStyle = NULL;
+   n->pseudo = NULL;
+   n->styleAttribute = NULL;
+   n->inheritBackgroundColor = false;
+}
+
+StyleEngine::~StyleEngine () {
+   /* \todo clear stack if not empty */
+   delete stack;
+   delete cssContext;
+}
+
+/**
+ * \brief tell the styleEngine that a new html element has started.
+ */
+void StyleEngine::startElement (int element) {
+//   fprintf(stderr, "===> START %d\n", element);
+
+   if (stack->getRef (stack->size () - 1)->style == NULL)
+      style0 ();
+
+   stack->increase ();
+   Node *n =  stack->getRef (stack->size () - 1);
+   n->num = num++;
+   n->style = NULL;
+   n->wordStyle = NULL;
+   n->depth = stack->size () - 1;
+   n->element = element;
+   n->id = NULL;
+   n->klass = NULL;
+   n->pseudo = NULL;
+   n->styleAttribute = NULL;
+   n->inheritBackgroundColor = false;
+}
+
+void StyleEngine::setId (const char *id) {
+   Node *n =  stack->getRef (stack->size () - 1);
+   assert (n->id == NULL);
+   n->id = dStrdup (id);
+};
+
+void StyleEngine::setClass (const char *klass) {
+   Node *n =  stack->getRef (stack->size () - 1);
+   assert (n->klass == NULL);
+   n->klass = dStrdup (klass);
+};
+
+void StyleEngine::setStyle (const char *style) {
+   Node *n =  stack->getRef (stack->size () - 1);
+   assert (n->styleAttribute == NULL);
+   n->styleAttribute = dStrdup (style);
+};
+
+/**
+ * \brief set properties that were definded using (mostly deprecated) HTML
+ *    attributes (e.g. bgColor).
+ */
+void StyleEngine::setNonCssHints (CssPropertyList *nonCssHints) {
+   if (stack->getRef (stack->size () - 1)->style)
+      stack->getRef (stack->size () - 1)->style->unref ();
+   style0 (nonCssHints); // evaluate now, so caller can free nonCssHints
+}
+
+/**
+ * \brief Use of the background color of the parent style as default.
+ *   This is only used in table code to allow for colors specified for
+ *   table rows as table rows are currently no widgets and therefore
+ *   don't draw any background.
+ */
+void StyleEngine::inheritBackgroundColor () {
+   stack->getRef (stack->size () - 1)->inheritBackgroundColor = true;
+}
+
+/**
+ * \brief set the CSS pseudo class :link.
+ */
+void StyleEngine::setPseudoLink () {
+   Node *n =  stack->getRef (stack->size () - 1);
+   n->pseudo = "link";
+}
+
+/**
+ * \brief set the CSS pseudo class :visited.
+ */
+void StyleEngine::setPseudoVisited () {
+   Node *n =  stack->getRef (stack->size () - 1);
+   n->pseudo = "visited";
+}
+
+/**
+ * \brief tell the styleEngine that a html element has ended.
+ */
+void StyleEngine::endElement (int element) {
+//   fprintf(stderr, "===> END %d\n", element);
+   assert (stack->size () > 1);
+   assert (element == stack->getRef (stack->size () - 1)->element);
+
+   Node *n =  stack->getRef (stack->size () - 1);
+
+   if (n->style)
+      n->style->unref ();
+   if (n->wordStyle)
+      n->wordStyle->unref ();
+   if (n->id)
+      dFree ((void*) n->id); 
+   if (n->klass)
+      dFree ((void*) n->klass); 
+   if (n->styleAttribute)
+      dFree ((void*) n->styleAttribute); 
+
+   stack->setSize (stack->size () - 1);
+}
+
+/**
+ * \brief Make changes to StyleAttrs attrs according to CssPropertyList props.
+ */
+void StyleEngine::apply (StyleAttrs *attrs, CssPropertyList *props) {
+   FontAttrs fontAttrs = *attrs->font;
+   Font *parentFont;
+
+   /* Determine font first so it can be used to resolve relative lenths.
+    * \todo Things should be rearranged so that just one pass is necessary.
+    */
+   for (int i = 0; i < props->size (); i++) {
+      CssProperty *p = props->getRef (i);
+      
+      switch (p->name) {
+         case CssProperty::CSS_PROPERTY_FONT_FAMILY:
+            fontAttrs.name = p->value.strVal;
+            break;
+         case CssProperty::CSS_PROPERTY_FONT_SIZE:
+            parentFont = stack->get (stack->size () - 2).style->font;
+            computeValue (&fontAttrs.size, p->value.intVal, parentFont,
+               parentFont->size);
+            break;
+         case CssProperty::CSS_PROPERTY_FONT_STYLE:
+            fontAttrs.style = (FontStyle) p->value.intVal;
+            break;
+         case CssProperty::CSS_PROPERTY_FONT_WEIGHT:
+            switch (p->value.intVal) {
+               case CssProperty::CSS_FONT_WEIGHT_LIGHTER:
+                  fontAttrs.weight -= CssProperty::CSS_FONT_WEIGHT_STEP;
+                  break;
+               case CssProperty::CSS_FONT_WEIGHT_BOLDER:
+                  fontAttrs.weight += CssProperty::CSS_FONT_WEIGHT_STEP;
+                  break;
+               default:
+                  fontAttrs.weight = p->value.intVal;
+                  break;
+            }
+            if (fontAttrs.weight < CssProperty::CSS_FONT_WEIGHT_MIN)
+               fontAttrs.weight = CssProperty::CSS_FONT_WEIGHT_MIN;
+            if (fontAttrs.weight > CssProperty::CSS_FONT_WEIGHT_MAX)
+               fontAttrs.weight = CssProperty::CSS_FONT_WEIGHT_MAX;
+            break;
+         default:
+            break;
+      }
+   }
+
+   attrs->font = Font::create (layout, &fontAttrs);
+
+   for (int i = 0; i < props->size (); i++) {
+      CssProperty *p = props->getRef (i);
+      
+      switch (p->name) {
+         /* \todo missing cases */
+         case CssProperty::CSS_PROPERTY_BACKGROUND_COLOR:
+            attrs->backgroundColor =
+               Color::create (layout, p->value.intVal);
+            break; 
+         case CssProperty::CSS_PROPERTY_BORDER_TOP_COLOR:
+            attrs->borderColor.top =
+              Color::create (layout, p->value.intVal);
+            break; 
+         case CssProperty::CSS_PROPERTY_BORDER_BOTTOM_COLOR:
+            attrs->borderColor.bottom =
+              Color::create (layout, p->value.intVal);
+            break; 
+         case CssProperty::CSS_PROPERTY_BORDER_LEFT_COLOR:
+            attrs->borderColor.left =
+              Color::create (layout, p->value.intVal);
+            break; 
+         case CssProperty::CSS_PROPERTY_BORDER_RIGHT_COLOR:
+            attrs->borderColor.right =
+              Color::create (layout, p->value.intVal);
+            break; 
+         case CssProperty::CSS_PROPERTY_BORDER_BOTTOM_STYLE:
+            attrs->borderStyle.bottom = (BorderStyle) p->value.intVal;
+            break;
+         case CssProperty::CSS_PROPERTY_BORDER_LEFT_STYLE:
+            attrs->borderStyle.left = (BorderStyle) p->value.intVal;
+            break;
+         case CssProperty::CSS_PROPERTY_BORDER_RIGHT_STYLE:
+            attrs->borderStyle.right = (BorderStyle) p->value.intVal;
+            break;
+         case CssProperty::CSS_PROPERTY_BORDER_TOP_STYLE:
+            attrs->borderStyle.top = (BorderStyle) p->value.intVal;
+            break;
+         case CssProperty::CSS_PROPERTY_BORDER_BOTTOM_WIDTH:
+            computeValue (&attrs->borderWidth.bottom, p->value.intVal, attrs->font);
+            break;
+         case CssProperty::CSS_PROPERTY_BORDER_LEFT_WIDTH:
+            computeValue (&attrs->borderWidth.left, p->value.intVal, attrs->font);
+            break;
+         case CssProperty::CSS_PROPERTY_BORDER_RIGHT_WIDTH:
+            computeValue (&attrs->borderWidth.right, p->value.intVal, attrs->font);
+            break;
+         case CssProperty::CSS_PROPERTY_BORDER_TOP_WIDTH:
+            computeValue (&attrs->borderWidth.top, p->value.intVal, attrs->font);
+            break;
+         case CssProperty::CSS_PROPERTY_BORDER_SPACING:
+            computeValue (&attrs->hBorderSpacing, p->value.intVal, attrs->font);
+            computeValue (&attrs->vBorderSpacing, p->value.intVal, attrs->font);
+            break;
+         case CssProperty::CSS_PROPERTY_COLOR:
+            attrs->color = Color::create (layout, p->value.intVal);
+            break; 
+         case CssProperty::CSS_PROPERTY_CURSOR:
+            attrs->cursor = (Cursor) p->value.intVal;
+            break; 
+         case CssProperty::CSS_PROPERTY_LIST_STYLE_TYPE:
+            attrs->listStyleType = (ListStyleType) p->value.intVal;
+            break;
+         case CssProperty::CSS_PROPERTY_MARGIN_BOTTOM:
+            computeValue (&attrs->margin.bottom, p->value.intVal, attrs->font);
+            break;
+         case CssProperty::CSS_PROPERTY_MARGIN_LEFT:
+            computeValue (&attrs->margin.left, p->value.intVal, attrs->font);
+            break;
+         case CssProperty::CSS_PROPERTY_MARGIN_RIGHT:
+            computeValue (&attrs->margin.right, p->value.intVal, attrs->font);
+            break;
+         case CssProperty::CSS_PROPERTY_MARGIN_TOP:
+            computeValue (&attrs->margin.top, p->value.intVal, attrs->font);
+            break;
+         case CssProperty::CSS_PROPERTY_PADDING_TOP:
+            computeValue (&attrs->padding.top, p->value.intVal, attrs->font);
+            break;
+         case CssProperty::CSS_PROPERTY_PADDING_BOTTOM:
+            computeValue (&attrs->padding.bottom, p->value.intVal, attrs->font);
+            break;
+         case CssProperty::CSS_PROPERTY_PADDING_LEFT:
+            computeValue (&attrs->padding.left, p->value.intVal, attrs->font);
+            break;
+         case CssProperty::CSS_PROPERTY_PADDING_RIGHT:
+            computeValue (&attrs->padding.right, p->value.intVal, attrs->font);
+            break;
+         case CssProperty::CSS_PROPERTY_TEXT_ALIGN:
+            attrs->textAlign = (TextAlignType) p->value.intVal;
+            break;
+         case CssProperty::CSS_PROPERTY_TEXT_DECORATION:
+            attrs->textDecoration |= p->value.intVal;
+            break;
+         case CssProperty::CSS_PROPERTY_VERTICAL_ALIGN:
+            attrs->valign = (VAlignType) p->value.intVal;
+            break;
+         case CssProperty::CSS_PROPERTY_WHITE_SPACE:
+            attrs->whiteSpace = (WhiteSpace) p->value.intVal;
+            break;
+         case CssProperty::CSS_PROPERTY_WIDTH:
+            computeLength (&attrs->width, p->value.intVal, attrs->font);
+            break;
+         case CssProperty::CSS_PROPERTY_HEIGHT:
+            computeLength (&attrs->height, p->value.intVal, attrs->font);
+            break;
+         case CssProperty::PROPERTY_X_LINK:
+            attrs->x_link = p->value.intVal;
+            break;
+         case CssProperty::PROPERTY_X_IMG:
+            attrs->x_img = p->value.intVal;
+            break;
+
+         default:
+            break;
+      }
+   }
+
+   /* make sure border colors are set */
+   if (attrs->borderColor.top == NULL) 
+      attrs->borderColor.top = attrs->color;
+   if (attrs->borderColor.bottom == NULL) 
+      attrs->borderColor.bottom = attrs->color;
+   if (attrs->borderColor.left == NULL) 
+      attrs->borderColor.left = attrs->color;
+   if (attrs->borderColor.right == NULL) 
+      attrs->borderColor.right = attrs->color;
+   
+}
+
+/**
+ * \brief Resolve relative lengths to absolute values.
+ */
+bool StyleEngine::computeValue (int *dest, CssLength value, Font *font) {
+   static float dpmm;
+
+   if (dpmm == 0.0)
+      dpmm = layout->dpiX () / 25.4; /* assume dpiX == dpiY */
+
+   switch (CSS_LENGTH_TYPE (value)) {
+      case CSS_LENGTH_TYPE_PX:
+         *dest = (int) CSS_LENGTH_VALUE (value);
+         return true;
+      case CSS_LENGTH_TYPE_MM:
+         *dest = (int) (CSS_LENGTH_VALUE (value) * dpmm + 0.5);
+        return true;
+      case CSS_LENGTH_TYPE_EM:
+         *dest = (int) (CSS_LENGTH_VALUE (value) * font->size + 0.5);
+        return true;
+      case CSS_LENGTH_TYPE_EX:
+         *dest = (int) (CSS_LENGTH_VALUE(value) * font->xHeight + 0.5);
+        return true;
+      default:
+         break;
+   }
+
+   return false;
+}
+
+bool StyleEngine::computeValue (int *dest, CssLength value, Font *font,
+                                int percentageBase) {
+   if (CSS_LENGTH_TYPE (value) == CSS_LENGTH_TYPE_PERCENTAGE) {
+      *dest = (int) (CSS_LENGTH_VALUE (value) * percentageBase + 0.5);
+      return true;
+   } else
+      return computeValue (dest, value, font);
+}
+
+bool StyleEngine::computeLength (dw::core::style::Length *dest,
+                                 CssLength value, Font *font) {
+   int v;
+
+   if (CSS_LENGTH_TYPE (value) == CSS_LENGTH_TYPE_PERCENTAGE) {
+      *dest = createPerLength (CSS_LENGTH_VALUE (value));
+      return true;
+    } else if (computeValue (&v, value, font)) {
+       *dest = createAbsLength (v);
+       return true;
+    }
+
+   return false;
+}
+
+/**
+ * \brief Create a new style object based on the previously opened / closed
+ *    HTML elements and the nonCssProperties that have been set.
+ *    This method is private. Call style() to get a current style object.
+ */
+Style * StyleEngine::style0 (CssPropertyList *nonCssProperties) {
+   CssPropertyList props;
+   CssPropertyList *tagStyleProps = NULL; /** \todo implementation */
+
+   // get previous style from the stack
+   StyleAttrs attrs = *stack->getRef (stack->size () - 2)->style;
+   // reset values that are not inherited according to CSS
+   attrs.resetValues ();
+
+   if (stack->getRef (stack->size () - 2)->inheritBackgroundColor)
+      attrs.backgroundColor =
+         stack->getRef (stack->size () - 2)->style->backgroundColor;
+  
+   cssContext->apply (&props, this, tagStyleProps, nonCssProperties);
+
+   apply (&attrs, &props);
+
+   stack->getRef (stack->size () - 1)->style = Style::create (layout, &attrs);
+   
+   return stack->getRef (stack->size () - 1)->style;
+}
+
+Style * StyleEngine::wordStyle0 (CssPropertyList *nonCssProperties) {
+   StyleAttrs attrs = *style ();
+   attrs.resetValues ();
+
+   if (stack->getRef (stack->size () - 1)->inheritBackgroundColor)
+      attrs.backgroundColor = style ()->backgroundColor;
+
+   attrs.valign = style ()->valign;
+
+   stack->getRef (stack->size () - 1)->wordStyle = Style::create (layout, &attrs);
+   return stack->getRef (stack->size () - 1)->wordStyle;
+}
+
+void StyleEngine::parse (const char *buf, int buflen,
+                         int order_count, CssOrigin origin) {
+
+   a_Css_parse (cssContext, buf, buflen, order_count, origin);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/styleengine.hh	Fri Jan 16 14:32:20 2009 -0300
@@ -0,0 +1,76 @@
+#ifndef __STYLEENGINE_HH__
+#define __STYLEENGINE_HH__
+
+#include "dw/core.hh"
+#include "doctree.hh"
+#include "css.hh"
+#include "cssparser.hh"
+
+class StyleEngine : public Doctree {
+   private:
+      class Node : public DoctreeNode {
+         public:
+            dw::core::style::Style *style;
+            dw::core::style::Style *wordStyle;
+            const char *styleAttribute;
+            bool inheritBackgroundColor;
+      };
+
+      dw::core::Layout *layout;
+      lout::misc::SimpleVector <Node> *stack;
+      CssContext *cssContext;
+      int num;
+
+      dw::core::style::Style *style0 (CssPropertyList *nonCssHints = NULL);
+      dw::core::style::Style *wordStyle0 (CssPropertyList *nonCssHints = NULL);
+      void apply (dw::core::style::StyleAttrs *attrs, CssPropertyList *props);
+      bool computeValue (int *dest, CssLength value, dw::core::style::Font *font);
+      bool computeValue (int *dest, CssLength value, dw::core::style::Font *font,
+         int percentageBase);
+      bool computeLength (dw::core::style::Length *dest, CssLength value, dw::core::style::Font *font);
+
+   public:
+      StyleEngine (dw::core::Layout *layout);
+      ~StyleEngine ();
+   
+      /* Doctree interface */
+      inline const DoctreeNode *top () {
+         return stack->getRef (stack->size () - 1);
+      };
+
+      inline const DoctreeNode *parent (const DoctreeNode *n) {
+         if (n->depth > 1)
+            return stack->getRef (n->depth - 1);
+         else
+            return NULL;
+      };
+
+      void parse (const char *buf, int buflen, int order_count, CssOrigin origin);
+      void startElement (int tag);
+      void setId (const char *id);
+      void setClass (const char *klass);
+      void setStyle (const char *style);
+      void endElement (int tag);
+      void setPseudoLink ();
+      void setPseudoVisited ();
+      void setNonCssHints (CssPropertyList *nonCssHints);
+      void inheritBackgroundColor (); /* \todo get rid of this somehow */
+
+      inline dw::core::style::Style *style () {
+         dw::core::style::Style *s = stack->getRef (stack->size () - 1)->style;
+         if (s)
+            return s;
+         else
+            return style0 ();
+      };
+      inline dw::core::style::Style *wordStyle () {
+         dw::core::style::Style *s = stack->getRef (stack->size () - 1)->wordStyle;
+         if (s)
+            return s;
+         else
+            return wordStyle0 ();
+      };
+
+};
+
+#endif
--- a/src/table.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/table.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -18,12 +18,11 @@
 
 #include "prefs.h"
 #include "msg.h"
+#include "css.hh"
 
 /* Undefine if you want to unroll tables. For instance for PDAs */
 #define USE_TABLES
 
-#define dillo_dbg_rendering 0
-
 using namespace dw;
 using namespace dw::core;
 using namespace dw::core::style;
@@ -43,13 +42,13 @@
 {
 #ifdef USE_TABLES
    dw::core::Widget *table;
-   dw::core::style::StyleAttrs style_attrs;
-   dw::core::style::Style *cell_style, *old_style;
+   CssPropertyList props, *table_cell_props;
    const char *attrbuf;
-   int32_t border = 0, cellspacing = 1, cellpadding = 2, bgcolor;
+   int32_t border = -1, cellspacing = -1, cellpadding = -1, bgcolor = -1;
+   int cssLength;
 #endif
 
-   DW2TB(html->dw)->addParbreak (0, S_TOP(html)->style);
+   DW2TB(html->dw)->addParbreak (0, html->styleEngine->wordStyle ());
 
 #ifdef USE_TABLES
    if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "border")))
@@ -59,68 +58,70 @@
    if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "cellpadding")))
       cellpadding = strtol (attrbuf, NULL, 10);
 
-   /* The style for the table */
-   style_attrs = *S_TOP(html)->style;
+   if (border != -1) {
+      cssLength = CSS_CREATE_LENGTH (border, CSS_LENGTH_TYPE_PX);
+      props.set (CssProperty::CSS_PROPERTY_BORDER_TOP_WIDTH, cssLength);
+      props.set (CssProperty::CSS_PROPERTY_BORDER_BOTTOM_WIDTH, cssLength);
+      props.set (CssProperty::CSS_PROPERTY_BORDER_LEFT_WIDTH, cssLength);
+      props.set (CssProperty::CSS_PROPERTY_BORDER_RIGHT_WIDTH, cssLength);
+   }
 
-   /* When dillo was started with the --debug-rendering option, there
-    * is always a border around the table. */
-   if (dillo_dbg_rendering)
-      style_attrs.borderWidth.setVal (MIN (border, 1));
-   else
-      style_attrs.borderWidth.setVal (border);
-
-   style_attrs.setBorderColor (
-      Color::createShaded(HT2LT(html), S_TOP(html)->current_bg_color));
-   style_attrs.setBorderStyle (BORDER_OUTSET);
-   style_attrs.hBorderSpacing = cellspacing;
-   style_attrs.vBorderSpacing = cellspacing;
+   if (cellspacing != -1) {
+      cssLength = CSS_CREATE_LENGTH (cellspacing, CSS_LENGTH_TYPE_PX);
+      props.set (CssProperty::CSS_PROPERTY_BORDER_SPACING, cssLength);
+   }
 
    if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "width")))
-      style_attrs.width = a_Html_parse_length (html, attrbuf);
+      props.set (CssProperty::CSS_PROPERTY_WIDTH,
+         a_Html_parse_length (html, attrbuf));
 
    if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "align"))) {
       if (dStrcasecmp (attrbuf, "left") == 0)
-         style_attrs.textAlign = dw::core::style::TEXT_ALIGN_LEFT;
+         props.set (CssProperty::CSS_PROPERTY_TEXT_ALIGN, TEXT_ALIGN_LEFT);
       else if (dStrcasecmp (attrbuf, "right") == 0)
-         style_attrs.textAlign = dw::core::style::TEXT_ALIGN_RIGHT;
+         props.set (CssProperty::CSS_PROPERTY_TEXT_ALIGN, TEXT_ALIGN_RIGHT);
       else if (dStrcasecmp (attrbuf, "center") == 0)
-         style_attrs.textAlign = dw::core::style::TEXT_ALIGN_CENTER;
+         props.set (CssProperty::CSS_PROPERTY_TEXT_ALIGN, TEXT_ALIGN_CENTER);
    }
 
-   if (!prefs.force_my_colors &&
-       (attrbuf = a_Html_get_attr(html, tag, tagsize, "bgcolor"))) {
+   if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "bgcolor"))) {
       bgcolor = a_Html_color_parse(html, attrbuf, -1);
       if (bgcolor != -1) {
          if (bgcolor == 0xffffff && !prefs.allow_white_bg)
             bgcolor = prefs.bg_color;
          S_TOP(html)->current_bg_color = bgcolor;
-         style_attrs.backgroundColor =
-            Color::createShaded (HT2LT(html), bgcolor);
+         props.set (CssProperty::CSS_PROPERTY_BACKGROUND_COLOR, bgcolor);
       }
    }
 
+   html->styleEngine->setNonCssHints (&props);
+
    /* The style for the cells */
-   cell_style = Style::create (HT2LT(html), &style_attrs);
-   style_attrs = *S_TOP(html)->style;
-   /* When dillo was started with the --debug-rendering option, there
-    * is always a border around the cells. */
-   if (dillo_dbg_rendering)
-      style_attrs.borderWidth.setVal (1);
-   else
-      style_attrs.borderWidth.setVal (border ? 1 : 0);
-   style_attrs.padding.setVal(cellpadding);
-   style_attrs.setBorderColor (cell_style->borderColor.top);
-   style_attrs.setBorderStyle (BORDER_INSET);
+   table_cell_props = new CssPropertyList ();
+   if (border > 0) {
+      cssLength = CSS_CREATE_LENGTH (1, CSS_LENGTH_TYPE_PX);
+      table_cell_props->set (CssProperty::CSS_PROPERTY_BORDER_TOP_WIDTH, cssLength);
+      table_cell_props->set (CssProperty::CSS_PROPERTY_BORDER_BOTTOM_WIDTH, cssLength);
+      table_cell_props->set (CssProperty::CSS_PROPERTY_BORDER_LEFT_WIDTH, cssLength);
+      table_cell_props->set (CssProperty::CSS_PROPERTY_BORDER_RIGHT_WIDTH, cssLength);
+   }
 
-   old_style = S_TOP(html)->table_cell_style;
-   S_TOP(html)->table_cell_style =
-      Style::create (HT2LT(html), &style_attrs);
-   if (old_style)
-      old_style->unref ();
+   if (cellpadding != -1) {
+      cssLength = CSS_CREATE_LENGTH (cellpadding, CSS_LENGTH_TYPE_PX);
+      table_cell_props->set (CssProperty::CSS_PROPERTY_PADDING_TOP, cssLength);
+      table_cell_props->set (CssProperty::CSS_PROPERTY_PADDING_BOTTOM, cssLength);
+      table_cell_props->set (CssProperty::CSS_PROPERTY_PADDING_LEFT, cssLength);
+      table_cell_props->set (CssProperty::CSS_PROPERTY_PADDING_RIGHT, cssLength);
+   }
+
+   if (S_TOP(html)->table_cell_props)
+      S_TOP(html)->table_cell_props->unref ();
+
+   S_TOP(html)->table_cell_props = table_cell_props;
+   S_TOP(html)->table_cell_props->ref ();
 
    table = new dw::Table(prefs.limit_text_width);
-   DW2TB(html->dw)->addWidget (table, cell_style);
-   cell_style->unref ();
+   DW2TB(html->dw)->addWidget (table, html->styleEngine->style ());
 
    S_TOP(html)->table_mode = DILLO_HTML_TABLE_MODE_TOP;
    S_TOP(html)->cell_text_align_set = FALSE;
@@ -134,10 +135,9 @@
 void Html_tag_open_tr(DilloHtml *html, const char *tag, int tagsize)
 {
    const char *attrbuf;
-   dw::core::style::StyleAttrs style_attrs;
-   dw::core::style::Style *style, *old_style;
    int32_t bgcolor = -1;
    bool new_style = false;
+   CssPropertyList props, *table_cell_props;
 
 #ifdef USE_TABLES
    switch (S_TOP(html)->table_mode) {
@@ -148,44 +148,41 @@
    case DILLO_HTML_TABLE_MODE_TOP:
    case DILLO_HTML_TABLE_MODE_TR:
    case DILLO_HTML_TABLE_MODE_TD:
-      style = NULL;
 
-      if (!prefs.force_my_colors &&
-          (attrbuf = a_Html_get_attr(html, tag, tagsize, "bgcolor"))) {
+      if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "bgcolor"))) {
          bgcolor = a_Html_color_parse(html, attrbuf, -1);
          if (bgcolor != -1) {
             if (bgcolor == 0xffffff && !prefs.allow_white_bg)
                bgcolor = prefs.bg_color;
-
-            style_attrs = *S_TOP(html)->style;
-            style_attrs.backgroundColor =
-               Color::createShaded (HT2LT(html), bgcolor);
-            style = Style::create (HT2LT(html), &style_attrs);
+            props.set (CssProperty::CSS_PROPERTY_BACKGROUND_COLOR, bgcolor);
             S_TOP(html)->current_bg_color = bgcolor;
          }
       }
 
-      ((dw::Table*)S_TOP(html)->table)->addRow (style);
-      if (style)
-         style->unref ();
+      html->styleEngine->inheritBackgroundColor ();
+      html->styleEngine->setNonCssHints (&props);
+
+      ((dw::Table*)S_TOP(html)->table)->addRow (html->styleEngine->style ());
 
       if (a_Html_get_attr (html, tag, tagsize, "align")) {
          S_TOP(html)->cell_text_align_set = TRUE;
-         a_Html_tag_set_align_attr (html, tag, tagsize);
+         a_Html_tag_set_align_attr (html, &props, tag, tagsize);
+         html->styleEngine->setNonCssHints (&props);
       }
 
-      style_attrs = *S_TOP(html)->table_cell_style;
+      table_cell_props = new CssPropertyList (*S_TOP(html)->table_cell_props);
       if (bgcolor != -1) {
-         style_attrs.backgroundColor =Color::createShaded(HT2LT(html),bgcolor);
+         table_cell_props->set (CssProperty::CSS_PROPERTY_BACKGROUND_COLOR, bgcolor);
          new_style = true;
       }
-      if (a_Html_tag_set_valign_attr (html, tag, tagsize, &style_attrs))
+      if (a_Html_tag_set_valign_attr (html, tag, tagsize, table_cell_props))
          new_style = true;
       if (new_style) {
-         old_style = S_TOP(html)->table_cell_style;
-         S_TOP(html)->table_cell_style =
-            Style::create (HT2LT(html), &style_attrs);
-         old_style->unref ();
+         S_TOP(html)->table_cell_props->unref ();
+         S_TOP(html)->table_cell_props = table_cell_props;
+         S_TOP(html)->table_cell_props->ref ();
+      } else {
+         delete table_cell_props;
       }
       break;
    default:
@@ -194,7 +191,7 @@
 
    S_TOP(html)->table_mode = DILLO_HTML_TABLE_MODE_TR;
 #else
-   DW2TB(html->dw)->addParbreak (0, S_TOP(html)->style);
+   DW2TB(html->dw)->addParbreak (0, html->styleEngine->wordStyle ());
 #endif
 }
 
@@ -212,7 +209,6 @@
  */
 void Html_tag_open_th(DilloHtml *html, const char *tag, int tagsize)
 {
-   a_Html_set_top_font(html, NULL, 0, 1, 1);
    Html_tag_open_table_cell (html, tag, tagsize,
                              dw::core::style::TEXT_ALIGN_CENTER);
 }
@@ -232,10 +228,15 @@
    Widget *col_tb;
    int colspan = 1, rowspan = 1;
    const char *attrbuf;
-   dw::core::style::StyleAttrs style_attrs;
-   dw::core::style::Style *style, *old_style;
    int32_t bgcolor;
    bool_t new_style;
+   CssPropertyList *props;
+
+   // \todo any shorter way to do this?
+   if (S_TOP(html)->table_cell_props != NULL)
+      props = new CssPropertyList (*S_TOP(html)->table_cell_props);
+   else
+      props = new CssPropertyList ();
 
    switch (S_TOP(html)->table_mode) {
    case DILLO_HTML_TABLE_MODE_NONE:
@@ -259,47 +260,39 @@
          rowspan = MAX(1, strtol (attrbuf, NULL, 10));
 
       /* text style */
-      old_style = S_TOP(html)->style;
-      style_attrs = *old_style;
-      if (!S_TOP(html)->cell_text_align_set)
-         style_attrs.textAlign = text_align;
+      if (!S_TOP(html)->cell_text_align_set) {
+         props->set (CssProperty::CSS_PROPERTY_TEXT_ALIGN, text_align);
+      }
       if (a_Html_get_attr(html, tag, tagsize, "nowrap"))
-         style_attrs.whiteSpace = WHITE_SPACE_NOWRAP;
+         props->set (CssProperty::CSS_PROPERTY_WHITE_SPACE, WHITE_SPACE_NOWRAP);
       else
-         style_attrs.whiteSpace = WHITE_SPACE_NORMAL;
+         props->set (CssProperty::CSS_PROPERTY_WHITE_SPACE, WHITE_SPACE_NORMAL);
 
-      S_TOP(html)->style =
-         Style::create (HT2LT(html), &style_attrs);
-      old_style->unref ();
-      a_Html_tag_set_align_attr (html, tag, tagsize);
-
-      /* cell style */
-      style_attrs = *S_TOP(html)->table_cell_style;
-      new_style = FALSE;
+      a_Html_tag_set_align_attr (html, props, tag, tagsize);
 
       if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "width"))) {
-         style_attrs.width = a_Html_parse_length (html, attrbuf);
-         new_style = TRUE;
+         props->set (CssProperty::CSS_PROPERTY_WIDTH,
+            a_Html_parse_length (html, attrbuf));
       }
 
-      if (a_Html_tag_set_valign_attr (html, tag, tagsize, &style_attrs))
+      if (a_Html_tag_set_valign_attr (html, tag, tagsize, props))
          new_style = TRUE;
 
-      if (!prefs.force_my_colors &&
-          (attrbuf = a_Html_get_attr(html, tag, tagsize, "bgcolor"))) {
+      if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "bgcolor"))) {
          bgcolor = a_Html_color_parse(html, attrbuf, -1);
          if (bgcolor != -1) {
             if (bgcolor == 0xffffff && !prefs.allow_white_bg)
                bgcolor = prefs.bg_color;
 
-            new_style = TRUE;
-            style_attrs.backgroundColor =
-               Color::createShaded (HT2LT(html), bgcolor);
+            props->set (CssProperty::CSS_PROPERTY_BACKGROUND_COLOR, bgcolor);
             S_TOP(html)->current_bg_color = bgcolor;
          }
       }
 
-      if (S_TOP(html)->style->textAlign
+      html->styleEngine->setNonCssHints (props);
+      delete props;
+
+      if (html->styleEngine->style ()->textAlign
           == TEXT_ALIGN_STRING)
          col_tb = new dw::TableCell (
                      ((dw::Table*)S_TOP(html)->table)->getCellRef (),
@@ -307,18 +300,14 @@
       else
          col_tb = new Textblock (prefs.limit_text_width);
 
-      if (new_style) {
-         style = dw::core::style::Style::create (HT2LT(html), &style_attrs);
-         col_tb->setStyle (style);
-         style->unref ();
-      } else
-         col_tb->setStyle (S_TOP(html)->table_cell_style);
+      col_tb->setStyle (html->styleEngine->style ());
 
       ((dw::Table*)S_TOP(html)->table)->addCell (col_tb, colspan, rowspan);
       S_TOP(html)->textblock = html->dw = col_tb;
 
       /* Handle it when the user clicks on a link */
       html->connectSignals(col_tb);
+
       break;
 
    default:
--- a/src/web.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/src/web.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -80,9 +80,9 @@
       styleAttrs.initValues ();
       styleAttrs.margin.setVal (5);
       styleAttrs.font = style::Font::create (layout, &fontAttrs);
-      styleAttrs.color = style::Color::createSimple (layout, 0xff0000);
+      styleAttrs.color = style::Color::create (layout, 0xff0000);
       styleAttrs.backgroundColor = 
-         style::Color::createSimple (layout, prefs.bg_color);
+         style::Color::create (layout, prefs.bg_color);
       widgetStyle = style::Style::create (layout, &styleAttrs);
       dw->setStyle (widgetStyle);
       widgetStyle->unref ();
--- a/test/dw_anchors_test.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/test/dw_anchors_test.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -126,8 +126,8 @@
    styleAttrs.initValues ();
    styleAttrs.font = Font::create (layout, &fontAttrs);
    styleAttrs.margin.setVal (5);
-   styleAttrs.color = Color::createSimple (layout, 0x000000);
-   styleAttrs.backgroundColor = Color::createSimple (layout, 0xffffff);
+   styleAttrs.color = Color::create (layout, 0x000000);
+   styleAttrs.backgroundColor = Color::create (layout, 0xffffff);
    topWidgetStyle = Style::create (layout, &styleAttrs);
 
    styleAttrs.margin.left = 20;
--- a/test/dw_border_test.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/test/dw_border_test.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -49,7 +49,7 @@
    styleAttrs.initValues ();
    styleAttrs.margin.setVal (5);
    styleAttrs.borderWidth.setVal (2);
-   styleAttrs.setBorderColor (Color::createShaded (layout, 0xffffff));
+   styleAttrs.setBorderColor (Color::create (layout, 0xffffff));
    styleAttrs.setBorderStyle (BORDER_INSET);
    styleAttrs.padding.setVal (5);
 
@@ -60,15 +60,15 @@
    fontAttrs.style = FONT_STYLE_NORMAL;
    styleAttrs.font = Font::create (layout, &fontAttrs);
 
-   styleAttrs.color = Color::createSimple (layout, 0x000000);
-   styleAttrs.backgroundColor = Color::createSimple (layout, 0xffffff);
+   styleAttrs.color = Color::create (layout, 0x000000);
+   styleAttrs.backgroundColor = Color::create (layout, 0xffffff);
 
    Style *widgetStyle1 = Style::create (layout, &styleAttrs);
 
-   styleAttrs.backgroundColor = Color::createSimple (layout, 0xffff80);
+   styleAttrs.backgroundColor = Color::create (layout, 0xffff80);
    styleAttrs.margin.setVal (0);
    styleAttrs.borderWidth.setVal (1);
-   styleAttrs.setBorderColor (Color::createSimple (layout, 0x4040ff));
+   styleAttrs.setBorderColor (Color::create (layout, 0x4040ff));
    styleAttrs.setBorderStyle (BORDER_SOLID);
    styleAttrs.padding.setVal (1);
 
--- a/test/dw_example.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/test/dw_example.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -53,9 +53,9 @@
    styleAttrs.font = dw::core::style::Font::create (layout, &fontAttrs);
 
    styleAttrs.color =
-      dw::core::style::Color::createSimple (layout, 0x000000);
+      dw::core::style::Color::create (layout, 0x000000);
    styleAttrs.backgroundColor =
-      dw::core::style::Color::createSimple (layout, 0xffffff);
+      dw::core::style::Color::create (layout, 0xffffff);
 
    dw::core::style::Style *widgetStyle = 
       dw::core::style::Style::create (layout, &styleAttrs);
--- a/test/dw_find_test.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/test/dw_find_test.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -99,8 +99,8 @@
    styleAttrs.initValues ();
    styleAttrs.font = Font::create (layout, &fontAttrs);
    styleAttrs.margin.setVal (10);
-   styleAttrs.color = Color::createSimple (layout, 0x000000);
-   styleAttrs.backgroundColor = Color::createSimple (layout, 0xffffff);
+   styleAttrs.color = Color::create (layout, 0x000000);
+   styleAttrs.backgroundColor = Color::create (layout, 0xffffff);
    Style *topWidgetStyle = Style::create (layout, &styleAttrs);
 
    styleAttrs.margin.setVal (0);
--- a/test/dw_images_scaled.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/test/dw_images_scaled.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -115,8 +115,8 @@
    fontAttrs.style = FONT_STYLE_NORMAL;
    styleAttrs.font = Font::create (layout, &fontAttrs);
 
-   styleAttrs.color = Color::createSimple (layout, 0x000000);
-   styleAttrs.backgroundColor = Color::createSimple (layout, 0xffffff);
+   styleAttrs.color = Color::create (layout, 0x000000);
+   styleAttrs.backgroundColor = Color::create (layout, 0xffffff);
 
    Style *widgetStyle = Style::create (layout, &styleAttrs);
 
--- a/test/dw_images_scaled2.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/test/dw_images_scaled2.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -90,8 +90,8 @@
    fontAttrs.style = FONT_STYLE_NORMAL;
    styleAttrs.font = Font::create (layout, &fontAttrs);
 
-   styleAttrs.color = Color::createSimple (layout, 0x000000);
-   styleAttrs.backgroundColor = Color::createSimple (layout, 0xffffff);
+   styleAttrs.color = Color::create (layout, 0x000000);
+   styleAttrs.backgroundColor = Color::create (layout, 0xffffff);
 
    Style *widgetStyle = Style::create (layout, &styleAttrs);
 
@@ -109,7 +109,7 @@
    Style *wordStyle = Style::create (layout, &styleAttrs);
 
    styleAttrs.borderWidth.setVal (1);
-   styleAttrs.setBorderColor (Color::createShaded (layout, 0x000080));
+   styleAttrs.setBorderColor (Color::create (layout, 0x000080));
    styleAttrs.setBorderStyle (BORDER_SOLID);
    styleAttrs.padding.setVal (1);
    styleAttrs.backgroundColor = NULL;
--- a/test/dw_images_simple.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/test/dw_images_simple.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -113,8 +113,8 @@
    fontAttrs.style = FONT_STYLE_NORMAL;
    styleAttrs.font = Font::create (layout, &fontAttrs);
 
-   styleAttrs.color = Color::createSimple (layout, 0x000000);
-   styleAttrs.backgroundColor = Color::createSimple (layout, 0xffffff);
+   styleAttrs.color = Color::create (layout, 0x000000);
+   styleAttrs.backgroundColor = Color::create (layout, 0xffffff);
 
    Style *widgetStyle = Style::create (layout, &styleAttrs);
 
--- a/test/dw_links.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/test/dw_links.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -91,8 +91,8 @@
    fontAttrs.style = FONT_STYLE_NORMAL;
    styleAttrs.font = Font::create (layout, &fontAttrs);
 
-   styleAttrs.color = Color::createSimple (layout, 0x000000);
-   styleAttrs.backgroundColor = Color::createSimple (layout, 0xffffff);
+   styleAttrs.color = Color::create (layout, 0x000000);
+   styleAttrs.backgroundColor = Color::create (layout, 0xffffff);
 
    Style *widgetStyle = Style::create (layout, &styleAttrs);
 
@@ -110,7 +110,7 @@
 
    Style *wordStyle = Style::create (layout, &styleAttrs);
 
-   styleAttrs.color = Color::createSimple (layout, 0x0000ff);
+   styleAttrs.color = Color::create (layout, 0x0000ff);
    styleAttrs.textDecoration = TEXT_DECORATION_UNDERLINE;
    styleAttrs.cursor = CURSOR_POINTER;
    
--- a/test/dw_links2.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/test/dw_links2.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -119,8 +119,8 @@
    fontAttrs.style = FONT_STYLE_NORMAL;
    styleAttrs.font = Font::create (layout, &fontAttrs);
 
-   styleAttrs.color = Color::createSimple (layout, 0x000000);
-   styleAttrs.backgroundColor = Color::createSimple (layout, 0xffffff);
+   styleAttrs.color = Color::create (layout, 0x000000);
+   styleAttrs.backgroundColor = Color::create (layout, 0xffffff);
 
    Style *widgetStyle = Style::create (layout, &styleAttrs);
 
@@ -138,7 +138,7 @@
 
    Style *wordStyle = Style::create (layout, &styleAttrs);
 
-   styleAttrs.color = Color::createSimple (layout, 0x0000ff);
+   styleAttrs.color = Color::create (layout, 0x0000ff);
    styleAttrs.textDecoration = TEXT_DECORATION_UNDERLINE;
    styleAttrs.cursor = CURSOR_POINTER;
    
--- a/test/dw_lists.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/test/dw_lists.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -56,8 +56,8 @@
    fontAttrs.style = FONT_STYLE_NORMAL;
    styleAttrs.font = Font::create (layout, &fontAttrs);
 
-   styleAttrs.color = Color::createSimple (layout, 0x000000);
-   styleAttrs.backgroundColor = Color::createSimple (layout, 0xffffff);
+   styleAttrs.color = Color::create (layout, 0x000000);
+   styleAttrs.backgroundColor = Color::create (layout, 0xffffff);
 
    Style *widgetStyle = Style::create (layout, &styleAttrs);
 
@@ -75,8 +75,8 @@
 
    styleAttrs.margin.setVal (5);
    styleAttrs.padding.setVal (5);
-   styleAttrs.backgroundColor = Color::createSimple (layout, 0xffff40);
-   styleAttrs.setBorderColor (Color::createSimple (layout, 0x000000));
+   styleAttrs.backgroundColor = Color::create (layout, 0xffff40);
+   styleAttrs.setBorderColor (Color::create (layout, 0x000000));
    styleAttrs.setBorderStyle (BORDER_SOLID);
    styleAttrs.borderWidth.setVal (1);
 
--- a/test/dw_resource_test.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/test/dw_resource_test.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -57,8 +57,8 @@
    fontAttrs.style = FONT_STYLE_NORMAL;
    styleAttrs.font = Font::create (layout, &fontAttrs);
 
-   styleAttrs.color = Color::createSimple (layout, 0x000000);
-   styleAttrs.backgroundColor = Color::createSimple (layout, 0xffffff);
+   styleAttrs.color = Color::create (layout, 0x000000);
+   styleAttrs.backgroundColor = Color::create (layout, 0xffffff);
 
    Style *widgetStyle = Style::create (layout, &styleAttrs);
 
--- a/test/dw_table.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/test/dw_table.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -51,9 +51,9 @@
    styleAttrs.padding.setVal (0);
    styleAttrs.borderWidth.setVal (1);
    styleAttrs.setBorderStyle (BORDER_OUTSET);
-   styleAttrs.setBorderColor (Color::createShaded (layout, 0xffffff));
-   styleAttrs.color = Color::createSimple (layout, 0x000000);
-   styleAttrs.backgroundColor = Color::createSimple (layout, 0xffffff);
+   styleAttrs.setBorderColor (Color::create (layout, 0xffffff));
+   styleAttrs.color = Color::create (layout, 0x000000);
+   styleAttrs.backgroundColor = Color::create (layout, 0xffffff);
    styleAttrs.hBorderSpacing = 5;
    styleAttrs.vBorderSpacing = 5;
 
--- a/test/dw_table_aligned.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/test/dw_table_aligned.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -50,7 +50,7 @@
    styleAttrs.margin.setVal (5);
    styleAttrs.borderWidth.setVal (1);
    styleAttrs.setBorderStyle (BORDER_OUTSET);
-   styleAttrs.setBorderColor (Color::createShaded (layout, 0x808080));
+   styleAttrs.setBorderColor (Color::create (layout, 0x808080));
 
    FontAttrs fontAttrs;
    fontAttrs.name = "Bitstream Charter";
@@ -59,8 +59,8 @@
    fontAttrs.style = FONT_STYLE_NORMAL;
    styleAttrs.font = Font::create (layout, &fontAttrs);
 
-   styleAttrs.color = Color::createSimple (layout, 0x000000);
-   styleAttrs.backgroundColor = Color::createSimple (layout, 0xa0a0a0);
+   styleAttrs.color = Color::create (layout, 0x000000);
+   styleAttrs.backgroundColor = Color::create (layout, 0xa0a0a0);
    styleAttrs.hBorderSpacing = 5;
    styleAttrs.vBorderSpacing = 5;
 
--- a/test/dw_ui_test.cc	Fri Jan 16 14:20:49 2009 -0300
+++ b/test/dw_ui_test.cc	Fri Jan 16 14:32:20 2009 -0300
@@ -53,8 +53,8 @@
    StyleAttrs styleAttrs;
    styleAttrs.initValues ();
    styleAttrs.margin.setVal (5);
-   styleAttrs.color = Color::createSimple (layout, 0x000000);
-   styleAttrs.backgroundColor = Color::createSimple (layout, 0xffffff);
+   styleAttrs.color = Color::create (layout, 0x000000);
+   styleAttrs.backgroundColor = Color::create (layout, 0xffffff);
 
    FontAttrs fontAttrs;
    fontAttrs.name = "Helvetica";