Update current version of litehtml. Fix a crash when document contains no fonts
authorMichael Rasmussen <mir@datanom.net>
Sat, 1 Dec 2018 17:36:46 +0000 (18:36 +0100)
committerAndrej Kacian <ticho@claws-mail.org>
Tue, 12 Feb 2019 18:38:09 +0000 (19:38 +0100)
Signed-off-by: Michael Rasmussen <mir@datanom.net>
84 files changed:
src/plugins/litehtml_viewer/container_linux.cpp
src/plugins/litehtml_viewer/lh_viewer.c
src/plugins/litehtml_viewer/lh_widget.cpp
src/plugins/litehtml_viewer/lh_widget_wrapped.h
src/plugins/litehtml_viewer/litehtml/attributes.h
src/plugins/litehtml_viewer/litehtml/background.cpp
src/plugins/litehtml_viewer/litehtml/background.h
src/plugins/litehtml_viewer/litehtml/borders.h
src/plugins/litehtml_viewer/litehtml/box.cpp
src/plugins/litehtml_viewer/litehtml/box.h
src/plugins/litehtml_viewer/litehtml/context.cpp
src/plugins/litehtml_viewer/litehtml/context.h
src/plugins/litehtml_viewer/litehtml/css_length.cpp
src/plugins/litehtml_viewer/litehtml/css_length.h
src/plugins/litehtml_viewer/litehtml/css_margins.h
src/plugins/litehtml_viewer/litehtml/css_offsets.h
src/plugins/litehtml_viewer/litehtml/css_position.h
src/plugins/litehtml_viewer/litehtml/css_selector.cpp
src/plugins/litehtml_viewer/litehtml/css_selector.h
src/plugins/litehtml_viewer/litehtml/document.cpp
src/plugins/litehtml_viewer/litehtml/document.h
src/plugins/litehtml_viewer/litehtml/el_anchor.cpp
src/plugins/litehtml_viewer/litehtml/el_anchor.h
src/plugins/litehtml_viewer/litehtml/el_base.cpp
src/plugins/litehtml_viewer/litehtml/el_base.h
src/plugins/litehtml_viewer/litehtml/el_before_after.cpp
src/plugins/litehtml_viewer/litehtml/el_before_after.h
src/plugins/litehtml_viewer/litehtml/el_body.cpp
src/plugins/litehtml_viewer/litehtml/el_body.h
src/plugins/litehtml_viewer/litehtml/el_break.cpp
src/plugins/litehtml_viewer/litehtml/el_break.h
src/plugins/litehtml_viewer/litehtml/el_cdata.cpp
src/plugins/litehtml_viewer/litehtml/el_cdata.h
src/plugins/litehtml_viewer/litehtml/el_comment.cpp
src/plugins/litehtml_viewer/litehtml/el_comment.h
src/plugins/litehtml_viewer/litehtml/el_div.cpp
src/plugins/litehtml_viewer/litehtml/el_div.h
src/plugins/litehtml_viewer/litehtml/el_font.cpp
src/plugins/litehtml_viewer/litehtml/el_font.h
src/plugins/litehtml_viewer/litehtml/el_image.cpp
src/plugins/litehtml_viewer/litehtml/el_image.h
src/plugins/litehtml_viewer/litehtml/el_link.cpp
src/plugins/litehtml_viewer/litehtml/el_link.h
src/plugins/litehtml_viewer/litehtml/el_para.cpp
src/plugins/litehtml_viewer/litehtml/el_para.h
src/plugins/litehtml_viewer/litehtml/el_script.cpp
src/plugins/litehtml_viewer/litehtml/el_script.h
src/plugins/litehtml_viewer/litehtml/el_space.cpp
src/plugins/litehtml_viewer/litehtml/el_space.h
src/plugins/litehtml_viewer/litehtml/el_style.cpp
src/plugins/litehtml_viewer/litehtml/el_style.h
src/plugins/litehtml_viewer/litehtml/el_table.cpp
src/plugins/litehtml_viewer/litehtml/el_table.h
src/plugins/litehtml_viewer/litehtml/el_td.cpp
src/plugins/litehtml_viewer/litehtml/el_td.h
src/plugins/litehtml_viewer/litehtml/el_text.cpp
src/plugins/litehtml_viewer/litehtml/el_text.h
src/plugins/litehtml_viewer/litehtml/el_title.cpp
src/plugins/litehtml_viewer/litehtml/el_title.h
src/plugins/litehtml_viewer/litehtml/el_tr.cpp
src/plugins/litehtml_viewer/litehtml/el_tr.h
src/plugins/litehtml_viewer/litehtml/element.cpp
src/plugins/litehtml_viewer/litehtml/element.h
src/plugins/litehtml_viewer/litehtml/html.cpp
src/plugins/litehtml_viewer/litehtml/html.h
src/plugins/litehtml_viewer/litehtml/html_tag.cpp
src/plugins/litehtml_viewer/litehtml/html_tag.h
src/plugins/litehtml_viewer/litehtml/iterators.cpp
src/plugins/litehtml_viewer/litehtml/iterators.h
src/plugins/litehtml_viewer/litehtml/litehtml.h
src/plugins/litehtml_viewer/litehtml/media_query.cpp
src/plugins/litehtml_viewer/litehtml/media_query.h
src/plugins/litehtml_viewer/litehtml/os_types.h
src/plugins/litehtml_viewer/litehtml/style.cpp
src/plugins/litehtml_viewer/litehtml/style.h
src/plugins/litehtml_viewer/litehtml/stylesheet.cpp
src/plugins/litehtml_viewer/litehtml/stylesheet.h
src/plugins/litehtml_viewer/litehtml/table.cpp
src/plugins/litehtml_viewer/litehtml/table.h
src/plugins/litehtml_viewer/litehtml/types.h
src/plugins/litehtml_viewer/litehtml/utf8_strings.cpp
src/plugins/litehtml_viewer/litehtml/utf8_strings.h
src/plugins/litehtml_viewer/litehtml/web_color.cpp
src/plugins/litehtml_viewer/litehtml/web_color.h

index 2341da5..c34df5f 100644 (file)
@@ -50,7 +50,9 @@ litehtml::uint_ptr container_linux::create_font( const litehtml::tchar_t* faceNa
 {
        litehtml::string_vector fonts;
        litehtml::split_string(faceName, fonts, ",");
-       litehtml::trim(fonts[0]);
+       if (! fonts.empty()) {
+           litehtml::trim(fonts[0]);
+       }
 
        cairo_font_face_t* fnt = 0;
 
@@ -140,8 +142,10 @@ int container_linux::text_width( const litehtml::tchar_t* text, litehtml::uint_p
 
        cairo_save(m_temp_cr);
 
-       cairo_set_font_size(m_temp_cr, fnt->size);
-       cairo_set_font_face(m_temp_cr, fnt->font);
+       if (fnt) {
+           cairo_set_font_size(m_temp_cr, fnt->size);
+           cairo_set_font_face(m_temp_cr, fnt->font);
+       }
        cairo_text_extents_t ext;
        cairo_text_extents(m_temp_cr, text, &ext);
 
@@ -158,8 +162,10 @@ void container_linux::draw_text( litehtml::uint_ptr hdc, const litehtml::tchar_t
 
        apply_clip(cr);
 
-       cairo_set_font_face(cr, fnt->font);
-       cairo_set_font_size(cr, fnt->size);
+       if (fnt) {
+           cairo_set_font_face(cr, fnt->font);
+           cairo_set_font_size(cr, fnt->size);
+       }
        cairo_font_extents_t ext;
        cairo_font_extents(cr, &ext);
 
@@ -173,20 +179,21 @@ void container_linux::draw_text( litehtml::uint_ptr hdc, const litehtml::tchar_t
 
        int tw = 0;
 
-       if(fnt->underline || fnt->strikeout)
-       {
+       if (fnt) {
+           if(fnt->underline || fnt->strikeout)
+           {
                tw = text_width(text, hFont);
-       }
+           }
 
-       if(fnt->underline)
-       {
+           if(fnt->underline)
+           {
                cairo_set_line_width(cr, 1);
                cairo_move_to(cr, x, y + 1.5);
                cairo_line_to(cr, x + tw, y + 1.5);
                cairo_stroke(cr);
-       }
-       if(fnt->strikeout)
-       {
+           }
+           if(fnt->strikeout)
+           {
                cairo_text_extents_t tex;
                cairo_text_extents(cr, "x", &tex);
 
@@ -196,7 +203,8 @@ void container_linux::draw_text( litehtml::uint_ptr hdc, const litehtml::tchar_t
                cairo_move_to(cr, x, (double) ln_y - 0.5);
                cairo_line_to(cr, x + tw, (double) ln_y - 0.5);
                cairo_stroke(cr);
-       }
+           }
+       }   
 
        cairo_restore(cr);
 }
index f127917..fe5727f 100644 (file)
@@ -171,11 +171,10 @@ MimeViewer *lh_viewer_create()
        return (MimeViewer *)viewer;
 }
 
-void lh_widget_statusbar_push(gchar* msg)
+void lh_widget_statusbar_push(const gchar* msg)
 {
        MainWindow *mainwin = mainwindow_get_mainwindow();
        STATUSBAR_PUSH(mainwin, msg);
-        g_free(msg);
 }
 
 void lh_widget_statusbar_pop()
index a4528c0..42b96dc 100644 (file)
@@ -149,7 +149,9 @@ GdkPixbuf *lh_widget::get_image(const litehtml::tchar_t* url, bool redraw_on_rea
        GdkPixbuf *pixbuf = NULL;
 
        g_log(NULL, G_LOG_LEVEL_MESSAGE, "Loading... %s", url);
-        lh_widget_statusbar_push(g_strconcat("Loading ", url, " ...", NULL));
+       gchar *msg = g_strdup_printf("Loading %s ...", url);
+        lh_widget_statusbar_push(msg);
+       g_free(msg);
        
        http http_loader;
        GInputStream *image = http_loader.load_url(url, &error);
@@ -183,7 +185,7 @@ statusbar_pop:
 
 void lh_widget::open_html(const gchar *contents)
 {
-       lh_widget_statusbar_push(g_strconcat("Loading HTML part", " ...", NULL));
+       lh_widget_statusbar_push("Loading HTML part ...");
        m_html = litehtml::document::createFromString(contents, this, &m_context);
        m_rendered_width = 0;
        if (m_html != NULL) {
@@ -314,9 +316,13 @@ void lh_widget::update_cursor()
     }
     if(cursType == GDK_ARROW)
     {
+       lh_widget_statusbar_pop();
         gdk_window_set_cursor(gtk_widget_get_window(m_drawing_area), NULL);
     } else
     {
+       if (!m_clicked_url.empty()) {
+           lh_widget_statusbar_push(m_clicked_url.c_str());
+       }
         gdk_window_set_cursor(gtk_widget_get_window(m_drawing_area), gdk_cursor_new(cursType));
     }
 }
@@ -380,6 +386,7 @@ static gboolean motion_notify_event(GtkWidget *widget, GdkEventButton *event,
 
     if(w->m_html)
     {    
+       //if(m_cursor == _t("pointer"))
         if(w->m_html->on_mouse_over((int) event->x, (int) event->y, (int) event->x, (int) event->y, redraw_boxes))
         {
             for (auto& pos : redraw_boxes)
@@ -405,7 +412,7 @@ static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event,
        if(w->m_html)
        {
            w->m_clicked_url.clear();
-        if(w->m_html->on_lbutton_up((int) event->x, (int) event->y, (int) event->x, (int) event->y, redraw_boxes))
+           if(w->m_html->on_lbutton_up((int) event->x, (int) event->y, (int) event->x, (int) event->y, redraw_boxes))
         {
             for (auto& pos : redraw_boxes)
             {
index 64085fa..24dcb57 100644 (file)
@@ -12,7 +12,7 @@ GtkWidget *lh_widget_get_widget(lh_widget_wrapped *w);
 void lh_widget_open_html(lh_widget_wrapped *w, const gchar *path);
 void lh_widget_clear(lh_widget_wrapped *w);
 void lh_widget_destroy(lh_widget_wrapped *w);
-void lh_widget_statusbar_push(gchar* msg);
+void lh_widget_statusbar_push(const gchar* msg);
 void lh_widget_statusbar_pop();
 void lh_widget_print(lh_widget_wrapped *w);
 
index ca1c9a7..98487f0 100644 (file)
@@ -1,32 +1,35 @@
-#pragma once\r
-\r
-namespace litehtml\r
-{\r
-       struct attr_color\r
-       {\r
-               unsigned char    rgbBlue;\r
-               unsigned char    rgbGreen;\r
-               unsigned char    rgbRed;\r
-               unsigned char    rgbAlpha;\r
-               attr_color()\r
-               {\r
-                       rgbAlpha        = 255;\r
-                       rgbBlue         = 0;\r
-                       rgbGreen        = 0;\r
-                       rgbRed          = 0;\r
-               }\r
-       };\r
-\r
-       struct attr_border\r
-       {\r
-               style_border    border;\r
-               int                             width;\r
-               attr_color              color;\r
-\r
-               attr_border()\r
-               {\r
-                       border  = borderNone;\r
-                       width   = 0;\r
-               }\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_ATTRIBUTES_H
+#define LH_ATTRIBUTES_H
+
+namespace litehtml
+{
+       struct attr_color
+       {
+               unsigned char    rgbBlue;
+               unsigned char    rgbGreen;
+               unsigned char    rgbRed;
+               unsigned char    rgbAlpha;
+               attr_color()
+               {
+                       rgbAlpha        = 255;
+                       rgbBlue         = 0;
+                       rgbGreen        = 0;
+                       rgbRed          = 0;
+               }
+       };
+
+       struct attr_border
+       {
+               style_border    border;
+               int                             width;
+               attr_color              color;
+
+               attr_border()
+               {
+                       border  = borderNone;
+                       width   = 0;
+               }
+       };
+}
+
+#endif  // LH_ATTRIBUTES_H
index 87ce59e..1c65e30 100644 (file)
@@ -1,79 +1,79 @@
-#include "html.h"\r
-#include "background.h"\r
-\r
-litehtml::background::background(void)\r
-{\r
-       m_attachment    = background_attachment_scroll;\r
-       m_repeat                = background_repeat_repeat;\r
-       m_clip                  = background_box_border;\r
-       m_origin                = background_box_padding;\r
-       m_color.alpha   = 0;\r
-       m_color.red             = 0;\r
-       m_color.green   = 0;\r
-       m_color.blue    = 0;\r
-}\r
-\r
-litehtml::background::background( const background& val )\r
-{\r
-       m_image                 = val.m_image;\r
-       m_baseurl               = val.m_baseurl;\r
-       m_color                 = val.m_color;\r
-       m_attachment    = val.m_attachment;\r
-       m_position              = val.m_position;\r
-       m_repeat                = val.m_repeat;\r
-       m_clip                  = val.m_clip;\r
-       m_origin                = val.m_origin;\r
-}\r
-\r
-litehtml::background::~background(void)\r
-{\r
-}\r
-\r
-litehtml::background& litehtml::background::operator=( const background& val )\r
-{\r
-       m_image                 = val.m_image;\r
-       m_baseurl               = val.m_baseurl;\r
-       m_color                 = val.m_color;\r
-       m_attachment    = val.m_attachment;\r
-       m_position              = val.m_position;\r
-       m_repeat                = val.m_repeat;\r
-       m_clip                  = val.m_clip;\r
-       m_origin                = val.m_origin;\r
-       return *this;\r
-}\r
-\r
-\r
-litehtml::background_paint::background_paint() : color(0, 0, 0, 0)\r
-{\r
-       position_x              = 0;\r
-       position_y              = 0;\r
-       attachment              = background_attachment_scroll;\r
-       repeat                  = background_repeat_repeat;\r
-       is_root                 = false;\r
-}\r
-\r
-litehtml::background_paint::background_paint( const background_paint& val )\r
-{\r
-       image                   = val.image;\r
-       baseurl                 = val.baseurl;\r
-       attachment              = val.attachment;\r
-       repeat                  = val.repeat;\r
-       color                   = val.color;\r
-       clip_box                = val.clip_box;\r
-       origin_box              = val.origin_box;\r
-       border_box              = val.border_box;\r
-       border_radius   = val.border_radius;\r
-       image_size              = val.image_size;\r
-       position_x              = val.position_x;\r
-       position_y              = val.position_y;\r
-       is_root                 = val.is_root;\r
-}\r
-\r
-void litehtml::background_paint::operator=( const background& val )\r
-{\r
-       attachment      = val.m_attachment;\r
-       baseurl         = val.m_baseurl;\r
-       image           = val.m_image;\r
-       repeat          = val.m_repeat;\r
-       color           = val.m_color;\r
-}\r
+#include "html.h"
+#include "background.h"
+
+litehtml::background::background(void)
+{
+       m_attachment    = background_attachment_scroll;
+       m_repeat                = background_repeat_repeat;
+       m_clip                  = background_box_border;
+       m_origin                = background_box_padding;
+       m_color.alpha   = 0;
+       m_color.red             = 0;
+       m_color.green   = 0;
+       m_color.blue    = 0;
+}
+
+litehtml::background::background( const background& val )
+{
+       m_image                 = val.m_image;
+       m_baseurl               = val.m_baseurl;
+       m_color                 = val.m_color;
+       m_attachment    = val.m_attachment;
+       m_position              = val.m_position;
+       m_repeat                = val.m_repeat;
+       m_clip                  = val.m_clip;
+       m_origin                = val.m_origin;
+}
+
+litehtml::background::~background(void)
+{
+}
+
+litehtml::background& litehtml::background::operator=( const background& val )
+{
+       m_image                 = val.m_image;
+       m_baseurl               = val.m_baseurl;
+       m_color                 = val.m_color;
+       m_attachment    = val.m_attachment;
+       m_position              = val.m_position;
+       m_repeat                = val.m_repeat;
+       m_clip                  = val.m_clip;
+       m_origin                = val.m_origin;
+       return *this;
+}
+
+
+litehtml::background_paint::background_paint() : color(0, 0, 0, 0)
+{
+       position_x              = 0;
+       position_y              = 0;
+       attachment              = background_attachment_scroll;
+       repeat                  = background_repeat_repeat;
+       is_root                 = false;
+}
+
+litehtml::background_paint::background_paint( const background_paint& val )
+{
+       image                   = val.image;
+       baseurl                 = val.baseurl;
+       attachment              = val.attachment;
+       repeat                  = val.repeat;
+       color                   = val.color;
+       clip_box                = val.clip_box;
+       origin_box              = val.origin_box;
+       border_box              = val.border_box;
+       border_radius   = val.border_radius;
+       image_size              = val.image_size;
+       position_x              = val.position_x;
+       position_y              = val.position_y;
+       is_root                 = val.is_root;
+}
+
+void litehtml::background_paint::operator=( const background& val )
+{
+       attachment      = val.m_attachment;
+       baseurl         = val.m_baseurl;
+       image           = val.m_image;
+       repeat          = val.m_repeat;
+       color           = val.m_color;
+}
index e3fc2f6..ce0b69a 100644 (file)
@@ -1,54 +1,58 @@
-#pragma once\r
-#include "types.h"\r
-#include "attributes.h"\r
-#include "css_length.h"\r
-#include "css_position.h"\r
-#include "web_color.h"\r
-#include "borders.h"\r
-\r
-namespace litehtml\r
-{\r
-       class background\r
-       {\r
-       public:\r
-               tstring                                 m_image;\r
-               tstring                                 m_baseurl;\r
-               web_color                               m_color;\r
-               background_attachment   m_attachment;\r
-               css_position                    m_position;\r
-               background_repeat               m_repeat;\r
-               background_box                  m_clip;\r
-               background_box                  m_origin;\r
-               css_border_radius               m_radius;\r
-\r
-       public:\r
-               background(void);\r
-               background(const background& val);\r
-               ~background(void);\r
-\r
-               background& operator=(const background& val);\r
-       };\r
-\r
-       class background_paint\r
-       {\r
-       public:\r
-               tstring                                 image;\r
-               tstring                                 baseurl;\r
-               background_attachment   attachment;\r
-               background_repeat               repeat;\r
-               web_color                               color;\r
-               position                                clip_box;\r
-               position                                origin_box;\r
-               position                                border_box;\r
-               border_radiuses                 border_radius;\r
-               size                                    image_size;\r
-               int                                             position_x;\r
-               int                                             position_y;\r
-               bool                                    is_root;\r
-       public:\r
-               background_paint();\r
-               background_paint(const background_paint& val);\r
-               void operator=(const background& val);\r
-       };\r
-\r
-}
\ No newline at end of file
+#ifndef LH_BACKGROUND_H
+#define LH_BACKGROUND_H
+
+#include "types.h"
+#include "attributes.h"
+#include "css_length.h"
+#include "css_position.h"
+#include "web_color.h"
+#include "borders.h"
+
+namespace litehtml
+{
+       class background
+       {
+       public:
+               tstring                                 m_image;
+               tstring                                 m_baseurl;
+               web_color                               m_color;
+               background_attachment   m_attachment;
+               css_position                    m_position;
+               background_repeat               m_repeat;
+               background_box                  m_clip;
+               background_box                  m_origin;
+               css_border_radius               m_radius;
+
+       public:
+               background(void);
+               background(const background& val);
+               ~background(void);
+
+               background& operator=(const background& val);
+       };
+
+       class background_paint
+       {
+       public:
+               tstring                                 image;
+               tstring                                 baseurl;
+               background_attachment   attachment;
+               background_repeat               repeat;
+               web_color                               color;
+               position                                clip_box;
+               position                                origin_box;
+               position                                border_box;
+               border_radiuses                 border_radius;
+               size                                    image_size;
+               int                                             position_x;
+               int                                             position_y;
+               bool                                    is_root;
+       public:
+               background_paint();
+               background_paint(const background_paint& val);
+               void operator=(const background& val);
+       };
+
+}
+
+#endif  // LH_BACKGROUND_H
index a46a9f8..859b852 100644 (file)
-#pragma once\r
-#include "css_length.h"\r
-#include "types.h"\r
-\r
-namespace litehtml\r
-{\r
-       struct css_border\r
-       {\r
-               css_length              width;\r
-               border_style    style;\r
-               web_color               color;\r
-\r
-               css_border()\r
-               {\r
-                       style = border_style_none;\r
-               }\r
-\r
-               css_border(const css_border& val)\r
-               {\r
-                       width   = val.width;\r
-                       style   = val.style;\r
-                       color   = val.color;\r
-               }\r
-\r
-               css_border& operator=(const css_border& val)\r
-               {\r
-                       width   = val.width;\r
-                       style   = val.style;\r
-                       color   = val.color;\r
-                       return *this;\r
-               }\r
-       };\r
-\r
-       struct border\r
-       {\r
-               int                             width;\r
-               border_style    style;\r
-               web_color               color;\r
-\r
-               border()\r
-               {\r
-                       width = 0;\r
-               }\r
-               border(const border& val)\r
-               {\r
-                       width = val.width;\r
-                       style = val.style;\r
-                       color = val.color;\r
-               }\r
-               border(const css_border& val)\r
-               {\r
-                       width = (int) val.width.val();\r
-                       style = val.style;\r
-                       color = val.color;\r
-               }\r
-               border& operator=(const border& val)\r
-               {\r
-                       width = val.width;\r
-                       style = val.style;\r
-                       color = val.color;\r
-                       return *this;\r
-               }\r
-               border& operator=(const css_border& val)\r
-               {\r
-                       width = (int) val.width.val();\r
-                       style = val.style;\r
-                       color = val.color;\r
-                       return *this;\r
-               }\r
-       };\r
-\r
-       struct border_radiuses\r
-       {\r
-               int     top_left_x;\r
-               int     top_left_y;\r
-\r
-               int     top_right_x;\r
-               int     top_right_y;\r
-\r
-               int     bottom_right_x;\r
-               int     bottom_right_y;\r
-\r
-               int     bottom_left_x;\r
-               int     bottom_left_y;\r
-\r
-               border_radiuses()\r
-               {\r
-                       top_left_x = 0;\r
-                       top_left_y = 0;\r
-                       top_right_x = 0;\r
-                       top_right_y = 0;\r
-                       bottom_right_x = 0;\r
-                       bottom_right_y = 0;\r
-                       bottom_left_x = 0;\r
-                       bottom_left_y = 0;\r
-               }\r
-               border_radiuses(const border_radiuses& val)\r
-               {\r
-                       top_left_x = val.top_left_x;\r
-                       top_left_y = val.top_left_y;\r
-                       top_right_x = val.top_right_x;\r
-                       top_right_y = val.top_right_y;\r
-                       bottom_right_x = val.bottom_right_x;\r
-                       bottom_right_y = val.bottom_right_y;\r
-                       bottom_left_x = val.bottom_left_x;\r
-                       bottom_left_y = val.bottom_left_y;\r
-               }\r
-               border_radiuses& operator = (const border_radiuses& val)\r
-               {\r
-                       top_left_x = val.top_left_x;\r
-                       top_left_y = val.top_left_y;\r
-                       top_right_x = val.top_right_x;\r
-                       top_right_y = val.top_right_y;\r
-                       bottom_right_x = val.bottom_right_x;\r
-                       bottom_right_y = val.bottom_right_y;\r
-                       bottom_left_x = val.bottom_left_x;\r
-                       bottom_left_y = val.bottom_left_y;\r
-                       return *this;\r
-               }\r
-               void operator += (const margins& mg)\r
-               {\r
-                       top_left_x += mg.left;\r
-                       top_left_y += mg.top;\r
-                       top_right_x += mg.right;\r
-                       top_right_y += mg.top;\r
-                       bottom_right_x += mg.right;\r
-                       bottom_right_y += mg.bottom;\r
-                       bottom_left_x += mg.left;\r
-                       bottom_left_y += mg.bottom;\r
-                       fix_values();\r
-               }\r
-               void operator -= (const margins& mg)\r
-               {\r
-                       top_left_x -= mg.left;\r
-                       top_left_y -= mg.top;\r
-                       top_right_x -= mg.right;\r
-                       top_right_y -= mg.top;\r
-                       bottom_right_x -= mg.right;\r
-                       bottom_right_y -= mg.bottom;\r
-                       bottom_left_x -= mg.left;\r
-                       bottom_left_y -= mg.bottom;\r
-                       fix_values();\r
-               }\r
-               void fix_values()\r
-               {\r
-                       if (top_left_x < 0)     top_left_x = 0;\r
-                       if (top_left_y < 0)     top_left_y = 0;\r
-                       if (top_right_x < 0) top_right_x = 0;\r
-                       if (bottom_right_x < 0) bottom_right_x = 0;\r
-                       if (bottom_right_y < 0) bottom_right_y = 0;\r
-                       if (bottom_left_x < 0) bottom_left_x = 0;\r
-                       if (bottom_left_y < 0) bottom_left_y = 0;\r
-               }\r
-       };\r
-\r
-       struct css_border_radius\r
-       {\r
-               css_length      top_left_x;\r
-               css_length      top_left_y;\r
-\r
-               css_length      top_right_x;\r
-               css_length      top_right_y;\r
-\r
-               css_length      bottom_right_x;\r
-               css_length      bottom_right_y;\r
-\r
-               css_length      bottom_left_x;\r
-               css_length      bottom_left_y;\r
-\r
-               css_border_radius()\r
-               {\r
-\r
-               }\r
-\r
-               css_border_radius(const css_border_radius& val)\r
-               {\r
-                       top_left_x              = val.top_left_x;\r
-                       top_left_y              = val.top_left_y;\r
-                       top_right_x             = val.top_right_x;\r
-                       top_right_y             = val.top_right_y;\r
-                       bottom_left_x   = val.bottom_left_x;\r
-                       bottom_left_y   = val.bottom_left_y;\r
-                       bottom_right_x  = val.bottom_right_x;\r
-                       bottom_right_y  = val.bottom_right_y;\r
-               }\r
-\r
-               css_border_radius& operator=(const css_border_radius& val)\r
-               {\r
-                       top_left_x              = val.top_left_x;\r
-                       top_left_y              = val.top_left_y;\r
-                       top_right_x             = val.top_right_x;\r
-                       top_right_y             = val.top_right_y;\r
-                       bottom_left_x   = val.bottom_left_x;\r
-                       bottom_left_y   = val.bottom_left_y;\r
-                       bottom_right_x  = val.bottom_right_x;\r
-                       bottom_right_y  = val.bottom_right_y;\r
-                       return *this;\r
-               }\r
-               border_radiuses calc_percents(int width, int height)\r
-               {\r
-                       border_radiuses ret;\r
-                       ret.bottom_left_x = bottom_left_x.calc_percent(width);\r
-                       ret.bottom_left_y = bottom_left_y.calc_percent(height);\r
-                       ret.top_left_x = top_left_x.calc_percent(width);\r
-                       ret.top_left_y = top_left_y.calc_percent(height);\r
-                       ret.top_right_x = top_right_x.calc_percent(width);\r
-                       ret.top_right_y = top_right_y.calc_percent(height);\r
-                       ret.bottom_right_x = bottom_right_x.calc_percent(width);\r
-                       ret.bottom_right_y = bottom_right_y.calc_percent(height);\r
-                       return ret;\r
-               }\r
-       };\r
-\r
-       struct css_borders\r
-       {\r
-               css_border                      left;\r
-               css_border                      top;\r
-               css_border                      right;\r
-               css_border                      bottom;\r
-               css_border_radius       radius;\r
-\r
-               css_borders()\r
-               {\r
-\r
-               }\r
-\r
-               css_borders(const css_borders& val)\r
-               {\r
-                       left    = val.left;\r
-                       right   = val.right;\r
-                       top             = val.top;\r
-                       bottom  = val.bottom;\r
-                       radius  = val.radius;\r
-               }\r
-\r
-               css_borders& operator=(const css_borders& val)\r
-               {\r
-                       left    = val.left;\r
-                       right   = val.right;\r
-                       top             = val.top;\r
-                       bottom  = val.bottom;\r
-                       radius  = val.radius;\r
-                       return *this;\r
-               }\r
-       };\r
-\r
-       struct borders\r
-       {\r
-               border                  left;\r
-               border                  top;\r
-               border                  right;\r
-               border                  bottom;\r
-               border_radiuses radius;\r
-\r
-               borders()\r
-               {\r
-\r
-               }\r
-\r
-               borders(const borders& val)\r
-               {\r
-                       left = val.left;\r
-                       right = val.right;\r
-                       top = val.top;\r
-                       bottom = val.bottom;\r
-                       radius = val.radius;\r
-               }\r
-\r
-               borders(const css_borders& val)\r
-               {\r
-                       left = val.left;\r
-                       right = val.right;\r
-                       top = val.top;\r
-                       bottom = val.bottom;\r
-               }\r
-\r
-               borders& operator=(const borders& val)\r
-               {\r
-                       left = val.left;\r
-                       right = val.right;\r
-                       top = val.top;\r
-                       bottom = val.bottom;\r
-                       radius = val.radius;\r
-                       return *this;\r
-               }\r
-\r
-               borders& operator=(const css_borders& val)\r
-               {\r
-                       left = val.left;\r
-                       right = val.right;\r
-                       top = val.top;\r
-                       bottom = val.bottom;\r
-                       return *this;\r
-               }\r
-       };\r
-}\r
+#ifndef LH_BORDERS_H
+#define LH_BORDERS_H
+
+#include "css_length.h"
+#include "types.h"
+
+namespace litehtml
+{
+       struct css_border
+       {
+               css_length              width;
+               border_style    style;
+               web_color               color;
+
+               css_border()
+               {
+                       style = border_style_none;
+               }
+
+               css_border(const css_border& val)
+               {
+                       width   = val.width;
+                       style   = val.style;
+                       color   = val.color;
+               }
+
+               css_border& operator=(const css_border& val)
+               {
+                       width   = val.width;
+                       style   = val.style;
+                       color   = val.color;
+                       return *this;
+               }
+       };
+
+       struct border
+       {
+               int                             width;
+               border_style    style;
+               web_color               color;
+
+               border()
+               {
+                       width = 0;
+               }
+               border(const border& val)
+               {
+                       width = val.width;
+                       style = val.style;
+                       color = val.color;
+               }
+               border(const css_border& val)
+               {
+                       width = (int) val.width.val();
+                       style = val.style;
+                       color = val.color;
+               }
+               border& operator=(const border& val)
+               {
+                       width = val.width;
+                       style = val.style;
+                       color = val.color;
+                       return *this;
+               }
+               border& operator=(const css_border& val)
+               {
+                       width = (int) val.width.val();
+                       style = val.style;
+                       color = val.color;
+                       return *this;
+               }
+       };
+
+       struct border_radiuses
+       {
+               int     top_left_x;
+               int     top_left_y;
+
+               int     top_right_x;
+               int     top_right_y;
+
+               int     bottom_right_x;
+               int     bottom_right_y;
+
+               int     bottom_left_x;
+               int     bottom_left_y;
+
+               border_radiuses()
+               {
+                       top_left_x = 0;
+                       top_left_y = 0;
+                       top_right_x = 0;
+                       top_right_y = 0;
+                       bottom_right_x = 0;
+                       bottom_right_y = 0;
+                       bottom_left_x = 0;
+                       bottom_left_y = 0;
+               }
+               border_radiuses(const border_radiuses& val)
+               {
+                       top_left_x = val.top_left_x;
+                       top_left_y = val.top_left_y;
+                       top_right_x = val.top_right_x;
+                       top_right_y = val.top_right_y;
+                       bottom_right_x = val.bottom_right_x;
+                       bottom_right_y = val.bottom_right_y;
+                       bottom_left_x = val.bottom_left_x;
+                       bottom_left_y = val.bottom_left_y;
+               }
+               border_radiuses& operator = (const border_radiuses& val)
+               {
+                       top_left_x = val.top_left_x;
+                       top_left_y = val.top_left_y;
+                       top_right_x = val.top_right_x;
+                       top_right_y = val.top_right_y;
+                       bottom_right_x = val.bottom_right_x;
+                       bottom_right_y = val.bottom_right_y;
+                       bottom_left_x = val.bottom_left_x;
+                       bottom_left_y = val.bottom_left_y;
+                       return *this;
+               }
+               void operator += (const margins& mg)
+               {
+                       top_left_x += mg.left;
+                       top_left_y += mg.top;
+                       top_right_x += mg.right;
+                       top_right_y += mg.top;
+                       bottom_right_x += mg.right;
+                       bottom_right_y += mg.bottom;
+                       bottom_left_x += mg.left;
+                       bottom_left_y += mg.bottom;
+                       fix_values();
+               }
+               void operator -= (const margins& mg)
+               {
+                       top_left_x -= mg.left;
+                       top_left_y -= mg.top;
+                       top_right_x -= mg.right;
+                       top_right_y -= mg.top;
+                       bottom_right_x -= mg.right;
+                       bottom_right_y -= mg.bottom;
+                       bottom_left_x -= mg.left;
+                       bottom_left_y -= mg.bottom;
+                       fix_values();
+               }
+               void fix_values()
+               {
+                       if (top_left_x < 0)     top_left_x = 0;
+                       if (top_left_y < 0)     top_left_y = 0;
+                       if (top_right_x < 0) top_right_x = 0;
+                       if (bottom_right_x < 0) bottom_right_x = 0;
+                       if (bottom_right_y < 0) bottom_right_y = 0;
+                       if (bottom_left_x < 0) bottom_left_x = 0;
+                       if (bottom_left_y < 0) bottom_left_y = 0;
+               }
+       };
+
+       struct css_border_radius
+       {
+               css_length      top_left_x;
+               css_length      top_left_y;
+
+               css_length      top_right_x;
+               css_length      top_right_y;
+
+               css_length      bottom_right_x;
+               css_length      bottom_right_y;
+
+               css_length      bottom_left_x;
+               css_length      bottom_left_y;
+
+               css_border_radius()
+               {
+
+               }
+
+               css_border_radius(const css_border_radius& val)
+               {
+                       top_left_x              = val.top_left_x;
+                       top_left_y              = val.top_left_y;
+                       top_right_x             = val.top_right_x;
+                       top_right_y             = val.top_right_y;
+                       bottom_left_x   = val.bottom_left_x;
+                       bottom_left_y   = val.bottom_left_y;
+                       bottom_right_x  = val.bottom_right_x;
+                       bottom_right_y  = val.bottom_right_y;
+               }
+
+               css_border_radius& operator=(const css_border_radius& val)
+               {
+                       top_left_x              = val.top_left_x;
+                       top_left_y              = val.top_left_y;
+                       top_right_x             = val.top_right_x;
+                       top_right_y             = val.top_right_y;
+                       bottom_left_x   = val.bottom_left_x;
+                       bottom_left_y   = val.bottom_left_y;
+                       bottom_right_x  = val.bottom_right_x;
+                       bottom_right_y  = val.bottom_right_y;
+                       return *this;
+               }
+               border_radiuses calc_percents(int width, int height)
+               {
+                       border_radiuses ret;
+                       ret.bottom_left_x = bottom_left_x.calc_percent(width);
+                       ret.bottom_left_y = bottom_left_y.calc_percent(height);
+                       ret.top_left_x = top_left_x.calc_percent(width);
+                       ret.top_left_y = top_left_y.calc_percent(height);
+                       ret.top_right_x = top_right_x.calc_percent(width);
+                       ret.top_right_y = top_right_y.calc_percent(height);
+                       ret.bottom_right_x = bottom_right_x.calc_percent(width);
+                       ret.bottom_right_y = bottom_right_y.calc_percent(height);
+                       return ret;
+               }
+       };
+
+       struct css_borders
+       {
+               css_border                      left;
+               css_border                      top;
+               css_border                      right;
+               css_border                      bottom;
+               css_border_radius       radius;
+
+               css_borders()
+               {
+
+               }
+
+               css_borders(const css_borders& val)
+               {
+                       left    = val.left;
+                       right   = val.right;
+                       top             = val.top;
+                       bottom  = val.bottom;
+                       radius  = val.radius;
+               }
+
+               css_borders& operator=(const css_borders& val)
+               {
+                       left    = val.left;
+                       right   = val.right;
+                       top             = val.top;
+                       bottom  = val.bottom;
+                       radius  = val.radius;
+                       return *this;
+               }
+       };
+
+       struct borders
+       {
+               border                  left;
+               border                  top;
+               border                  right;
+               border                  bottom;
+               border_radiuses radius;
+
+               borders()
+               {
+
+               }
+
+               borders(const borders& val)
+               {
+                       left = val.left;
+                       right = val.right;
+                       top = val.top;
+                       bottom = val.bottom;
+                       radius = val.radius;
+               }
+
+               borders(const css_borders& val)
+               {
+                       left = val.left;
+                       right = val.right;
+                       top = val.top;
+                       bottom = val.bottom;
+               }
+
+               borders& operator=(const borders& val)
+               {
+                       left = val.left;
+                       right = val.right;
+                       top = val.top;
+                       bottom = val.bottom;
+                       radius = val.radius;
+                       return *this;
+               }
+
+               borders& operator=(const css_borders& val)
+               {
+                       left = val.left;
+                       right = val.right;
+                       top = val.top;
+                       bottom = val.bottom;
+                       return *this;
+               }
+       };
+}
+
+#endif  // LH_BORDERS_H
index 023d15c..4ad23c5 100644 (file)
-#include "html.h"\r
-#include "box.h"\r
-#include "html_tag.h"\r
-\r
-\r
-litehtml::box_type litehtml::block_box::get_type()\r
-{\r
-       return box_block;\r
-}\r
-\r
-int litehtml::block_box::height()\r
-{\r
-       return m_element->height();\r
-}\r
-\r
-int litehtml::block_box::width()\r
-{\r
-       return m_element->width();\r
-}\r
-\r
-void litehtml::block_box::add_element(const element::ptr &el)\r
-{\r
-       m_element = el;\r
-       el->m_box = this;\r
-}\r
-\r
-void litehtml::block_box::finish(bool last_box)\r
-{\r
-       if(!m_element) return;\r
-       m_element->apply_relative_shift(m_box_right - m_box_left);\r
-}\r
-\r
-bool litehtml::block_box::can_hold(const element::ptr &el, white_space ws)\r
-{\r
-       if(m_element || el->is_inline_box())\r
-       {\r
-               return false;\r
-       }\r
-       return true;\r
-}\r
-\r
-bool litehtml::block_box::is_empty()\r
-{\r
-       if(m_element)\r
-       {\r
-               return false;\r
-       }\r
-       return true;\r
-}\r
-\r
-int litehtml::block_box::baseline()\r
-{\r
-       if(m_element)\r
-       {\r
-               return m_element->get_base_line();\r
-       }\r
-       return 0;\r
-}\r
-\r
-void litehtml::block_box::get_elements( elements_vector& els )\r
-{\r
-       els.push_back(m_element);\r
-}\r
-\r
-int litehtml::block_box::top_margin()\r
-{\r
-       if(m_element && m_element->collapse_top_margin())\r
-       {\r
-               return m_element->m_margins.top;\r
-       }\r
-       return 0;\r
-}\r
-\r
-int litehtml::block_box::bottom_margin()\r
-{\r
-       if(m_element && m_element->collapse_bottom_margin())\r
-       {\r
-               return m_element->m_margins.bottom;\r
-       }\r
-       return 0;\r
-}\r
-\r
-void litehtml::block_box::y_shift( int shift )\r
-{\r
-       m_box_top += shift;\r
-       if(m_element)\r
-       {\r
-               m_element->m_pos.y += shift;\r
-       }\r
-}\r
-\r
-void litehtml::block_box::new_width( int left, int right, elements_vector& els )\r
-{\r
-\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////////\r
-\r
-litehtml::box_type litehtml::line_box::get_type()\r
-{\r
-       return box_line;\r
-}\r
-\r
-int litehtml::line_box::height()\r
-{\r
-       return m_height;\r
-}\r
-\r
-int litehtml::line_box::width()\r
-{\r
-       return m_width;\r
-}\r
-\r
-void litehtml::line_box::add_element(const element::ptr &el)\r
-{\r
-       el->m_skip      = false;\r
-       el->m_box       = 0;\r
-       bool add        = true;\r
-       if( (m_items.empty() && el->is_white_space()) || el->is_break() )\r
-       {\r
-               el->m_skip = true;\r
-       } else if(el->is_white_space())\r
-       {\r
-               if (have_last_space())\r
-               {\r
-                       add = false;\r
-                       el->m_skip = true;\r
-               }\r
-       }\r
-\r
-       if(add)\r
-       {\r
-               el->m_box = this;\r
-               m_items.push_back(el);\r
-\r
-               if(!el->m_skip)\r
-               {\r
-                       int el_shift_left       = el->get_inline_shift_left();\r
-                       int el_shift_right      = el->get_inline_shift_right();\r
-\r
-                       el->m_pos.x     = m_box_left + m_width + el_shift_left + el->content_margins_left();\r
-                       el->m_pos.y     = m_box_top + el->content_margins_top();\r
-                       m_width         += el->width() + el_shift_left + el_shift_right;\r
-               }\r
-       }\r
-}\r
-\r
-void litehtml::line_box::finish(bool last_box)\r
-{\r
-       if( is_empty() || (!is_empty() && last_box && is_break_only()) )\r
-       {\r
-               m_height = 0;\r
-               return;\r
-       }\r
-\r
-       for(auto i = m_items.rbegin(); i != m_items.rend(); i++)\r
-       {\r
-               if((*i)->is_white_space() || (*i)->is_break())\r
-               {\r
-                       if(!(*i)->m_skip)\r
-                       {\r
-                               (*i)->m_skip = true;\r
-                               m_width -= (*i)->width();\r
-                       }\r
-               } else\r
-               {\r
-                       break;\r
-               }\r
-       }\r
-\r
-       int base_line   = m_font_metrics.base_line();\r
-       int line_height = m_line_height;\r
-\r
-       int add_x = 0;\r
-       switch(m_text_align)\r
-       {\r
-       case text_align_right:\r
-               if(m_width < (m_box_right - m_box_left))\r
-               {\r
-                       add_x = (m_box_right - m_box_left) - m_width;\r
-               }\r
-               break;\r
-       case text_align_center:\r
-               if(m_width < (m_box_right - m_box_left))\r
-               {\r
-                       add_x = ((m_box_right - m_box_left) - m_width) / 2;\r
-               }\r
-               break;\r
-       default:\r
-               add_x = 0;\r
-       }\r
-\r
-       m_height = 0;\r
-       // find line box baseline and line-height\r
-       for(const auto& el : m_items)\r
-       {\r
-               if(el->get_display() == display_inline_text)\r
-               {\r
-                       font_metrics fm;\r
-                       el->get_font(&fm);\r
-                       base_line       = std::max(base_line,   fm.base_line());\r
-                       line_height = std::max(line_height, el->line_height());\r
-                       m_height = std::max(m_height, fm.height);\r
-               }\r
-               el->m_pos.x += add_x;\r
-       }\r
-\r
-       if(m_height)\r
-       {\r
-               base_line += (line_height - m_height) / 2;\r
-       }\r
-\r
-       m_height = line_height;\r
-\r
-       int y1  = 0;\r
-       int y2  = m_height;\r
-\r
-       for (const auto& el : m_items)\r
-       {\r
-               if(el->get_display() == display_inline_text)\r
-               {\r
-                       font_metrics fm;\r
-                       el->get_font(&fm);\r
-                       el->m_pos.y = m_height - base_line - fm.ascent;\r
-               } else\r
-               {\r
-                       switch(el->get_vertical_align())\r
-                       {\r
-                       case va_super:\r
-                       case va_sub:\r
-                       case va_baseline:\r
-                               el->m_pos.y = m_height - base_line - el->height() + el->get_base_line() + el->content_margins_top();\r
-                               break;\r
-                       case va_top:\r
-                               el->m_pos.y = y1 + el->content_margins_top();\r
-                               break;\r
-                       case va_text_top:\r
-                               el->m_pos.y = m_height - base_line - m_font_metrics.ascent + el->content_margins_top();\r
-                               break;\r
-                       case va_middle:\r
-                               el->m_pos.y = m_height - base_line - m_font_metrics.x_height / 2 - el->height() / 2 + el->content_margins_top();\r
-                               break;\r
-                       case va_bottom:\r
-                               el->m_pos.y = y2 - el->height() + el->content_margins_top();\r
-                               break;\r
-                       case va_text_bottom:\r
-                               el->m_pos.y = m_height - base_line + m_font_metrics.descent - el->height() + el->content_margins_top();\r
-                               break;\r
-                       }\r
-                       y1 = std::min(y1, el->top());\r
-                       y2 = std::max(y2, el->bottom());\r
-               }\r
-       }\r
-\r
-       css_offsets offsets;\r
-\r
-       for (const auto& el : m_items)\r
-       {\r
-               el->m_pos.y -= y1;\r
-               el->m_pos.y += m_box_top;\r
-               if(el->get_display() != display_inline_text)\r
-               {\r
-                       switch(el->get_vertical_align())\r
-                       {\r
-                       case va_top:\r
-                               el->m_pos.y = m_box_top + el->content_margins_top();\r
-                               break;\r
-                       case va_bottom:\r
-                               el->m_pos.y = m_box_top + (y2 - y1) - el->height() + el->content_margins_top();\r
-                               break;\r
-                       case va_baseline:\r
-                               //TODO: process vertical align "baseline"\r
-                               break;\r
-                       case va_middle:\r
-                               //TODO: process vertical align "middle"\r
-                               break;\r
-                       case va_sub:\r
-                               //TODO: process vertical align "sub"\r
-                               break;\r
-                       case va_super:\r
-                               //TODO: process vertical align "super"\r
-                               break;\r
-                       case va_text_bottom:\r
-                               //TODO: process vertical align "text-bottom"\r
-                               break;\r
-                       case va_text_top:\r
-                               //TODO: process vertical align "text-top"\r
-                               break;\r
-                       }\r
-               }\r
-\r
-               el->apply_relative_shift(m_box_right - m_box_left);\r
-       }\r
-       m_height = y2 - y1;\r
-       m_baseline = (base_line - y1) - (m_height - line_height);\r
-}\r
-\r
-bool litehtml::line_box::can_hold(const element::ptr &el, white_space ws)\r
-{\r
-       if(!el->is_inline_box()) return false;\r
-\r
-       if(el->is_break())\r
-       {\r
-               return false;\r
-       }\r
-\r
-       if(ws == white_space_nowrap || ws == white_space_pre)\r
-       {\r
-               return true;\r
-       }\r
-\r
-       if(m_box_left + m_width + el->width() + el->get_inline_shift_left() + el->get_inline_shift_right() > m_box_right)\r
-       {\r
-               return false;\r
-       }\r
-\r
-       return true;\r
-}\r
-\r
-bool litehtml::line_box::have_last_space()\r
-{\r
-       bool ret = false;\r
-       for (auto i = m_items.rbegin(); i != m_items.rend() && !ret; i++)\r
-       {\r
-               if((*i)->is_white_space() || (*i)->is_break())\r
-               {\r
-                       ret = true;\r
-               } else\r
-               {\r
-                       break;\r
-               }\r
-       }\r
-       return ret;\r
-}\r
-\r
-bool litehtml::line_box::is_empty()\r
-{\r
-       if(m_items.empty()) return true;\r
-       for (auto i = m_items.rbegin(); i != m_items.rend(); i++)\r
-       {\r
-               if(!(*i)->m_skip || (*i)->is_break())\r
-               {\r
-                       return false;\r
-               }\r
-       }\r
-       return true;\r
-}\r
-\r
-int litehtml::line_box::baseline()\r
-{\r
-       return m_baseline;\r
-}\r
-\r
-void litehtml::line_box::get_elements( elements_vector& els )\r
-{\r
-       els.insert(els.begin(), m_items.begin(), m_items.end());\r
-}\r
-\r
-int litehtml::line_box::top_margin()\r
-{\r
-       return 0;\r
-}\r
-\r
-int litehtml::line_box::bottom_margin()\r
-{\r
-       return 0;\r
-}\r
-\r
-void litehtml::line_box::y_shift( int shift )\r
-{\r
-       m_box_top += shift;\r
-       for (auto& el : m_items)\r
-       {\r
-               el->m_pos.y += shift;\r
-       }\r
-}\r
-\r
-bool litehtml::line_box::is_break_only()\r
-{\r
-       if(m_items.empty()) return true;\r
-\r
-       if(m_items.front()->is_break())\r
-       {\r
-               for (auto& el : m_items)\r
-               {\r
-                       if(!el->m_skip)\r
-                       {\r
-                               return false;\r
-                       }\r
-               }\r
-               return true;\r
-       }\r
-       return false;\r
-}\r
-\r
-void litehtml::line_box::new_width( int left, int right, elements_vector& els )\r
-{\r
-       int add = left - m_box_left;\r
-       if(add)\r
-       {\r
-               m_box_left      = left;\r
-               m_box_right     = right;\r
-               m_width = 0;\r
-               auto remove_begin = m_items.end();\r
-               for (auto i = m_items.begin() + 1; i != m_items.end(); i++)\r
-               {\r
-                       element::ptr el = (*i);\r
-\r
-                       if(!el->m_skip)\r
-                       {\r
-                               if(m_box_left + m_width + el->width() + el->get_inline_shift_right() + el->get_inline_shift_left() > m_box_right)\r
-                               {\r
-                                       remove_begin = i;\r
-                                       break;\r
-                               } else\r
-                               {\r
-                                       el->m_pos.x += add;\r
-                                       m_width += el->width() + el->get_inline_shift_right() + el->get_inline_shift_left();\r
-                               }\r
-                       }\r
-               }\r
-               if(remove_begin != m_items.end())\r
-               {\r
-                       els.insert(els.begin(), remove_begin, m_items.end());\r
-                       m_items.erase(remove_begin, m_items.end());\r
-\r
-                       for(const auto& el : els)\r
-                       {\r
-                               el->m_box = 0;\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
+#include "html.h"
+#include "box.h"
+#include "html_tag.h"
+
+
+litehtml::box_type litehtml::block_box::get_type()
+{
+       return box_block;
+}
+
+int litehtml::block_box::height()
+{
+       return m_element->height();
+}
+
+int litehtml::block_box::width()
+{
+       return m_element->width();
+}
+
+void litehtml::block_box::add_element(const element::ptr &el)
+{
+       m_element = el;
+       el->m_box = this;
+}
+
+void litehtml::block_box::finish(bool last_box)
+{
+       if(!m_element) return;
+       m_element->apply_relative_shift(m_box_right - m_box_left);
+}
+
+bool litehtml::block_box::can_hold(const element::ptr &el, white_space ws)
+{
+       if(m_element || el->is_inline_box())
+       {
+               return false;
+       }
+       return true;
+}
+
+bool litehtml::block_box::is_empty()
+{
+       if(m_element)
+       {
+               return false;
+       }
+       return true;
+}
+
+int litehtml::block_box::baseline()
+{
+       if(m_element)
+       {
+               return m_element->get_base_line();
+       }
+       return 0;
+}
+
+void litehtml::block_box::get_elements( elements_vector& els )
+{
+       els.push_back(m_element);
+}
+
+int litehtml::block_box::top_margin()
+{
+       if(m_element && m_element->collapse_top_margin())
+       {
+               return m_element->m_margins.top;
+       }
+       return 0;
+}
+
+int litehtml::block_box::bottom_margin()
+{
+       if(m_element && m_element->collapse_bottom_margin())
+       {
+               return m_element->m_margins.bottom;
+       }
+       return 0;
+}
+
+void litehtml::block_box::y_shift( int shift )
+{
+       m_box_top += shift;
+       if(m_element)
+       {
+               m_element->m_pos.y += shift;
+       }
+}
+
+void litehtml::block_box::new_width( int left, int right, elements_vector& els )
+{
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+litehtml::box_type litehtml::line_box::get_type()
+{
+       return box_line;
+}
+
+int litehtml::line_box::height()
+{
+       return m_height;
+}
+
+int litehtml::line_box::width()
+{
+       return m_width;
+}
+
+void litehtml::line_box::add_element(const element::ptr &el)
+{
+       el->m_skip      = false;
+       el->m_box       = 0;
+       bool add        = true;
+       if( (m_items.empty() && el->is_white_space()) || el->is_break() )
+       {
+               el->m_skip = true;
+       } else if(el->is_white_space())
+       {
+               if (have_last_space())
+               {
+                       add = false;
+                       el->m_skip = true;
+               }
+       }
+
+       if(add)
+       {
+               el->m_box = this;
+               m_items.push_back(el);
+
+               if(!el->m_skip)
+               {
+                       int el_shift_left       = el->get_inline_shift_left();
+                       int el_shift_right      = el->get_inline_shift_right();
+
+                       el->m_pos.x     = m_box_left + m_width + el_shift_left + el->content_margins_left();
+                       el->m_pos.y     = m_box_top + el->content_margins_top();
+                       m_width         += el->width() + el_shift_left + el_shift_right;
+               }
+       }
+}
+
+void litehtml::line_box::finish(bool last_box)
+{
+       if( is_empty() || (!is_empty() && last_box && is_break_only()) )
+       {
+               m_height = 0;
+               return;
+       }
+
+       for(auto i = m_items.rbegin(); i != m_items.rend(); i++)
+       {
+               if((*i)->is_white_space() || (*i)->is_break())
+               {
+                       if(!(*i)->m_skip)
+                       {
+                               (*i)->m_skip = true;
+                               m_width -= (*i)->width();
+                       }
+               } else
+               {
+                       break;
+               }
+       }
+
+       int base_line   = m_font_metrics.base_line();
+       int line_height = m_line_height;
+
+       int add_x = 0;
+       switch(m_text_align)
+       {
+       case text_align_right:
+               if(m_width < (m_box_right - m_box_left))
+               {
+                       add_x = (m_box_right - m_box_left) - m_width;
+               }
+               break;
+       case text_align_center:
+               if(m_width < (m_box_right - m_box_left))
+               {
+                       add_x = ((m_box_right - m_box_left) - m_width) / 2;
+               }
+               break;
+       default:
+               add_x = 0;
+       }
+
+       m_height = 0;
+       // find line box baseline and line-height
+       for(const auto& el : m_items)
+       {
+               if(el->get_display() == display_inline_text)
+               {
+                       font_metrics fm;
+                       el->get_font(&fm);
+                       base_line       = std::max(base_line,   fm.base_line());
+                       line_height = std::max(line_height, el->line_height());
+                       m_height = std::max(m_height, fm.height);
+               }
+               el->m_pos.x += add_x;
+       }
+
+       if(m_height)
+       {
+               base_line += (line_height - m_height) / 2;
+       }
+
+       m_height = line_height;
+
+       int y1  = 0;
+       int y2  = m_height;
+
+       for (const auto& el : m_items)
+       {
+               if(el->get_display() == display_inline_text)
+               {
+                       font_metrics fm;
+                       el->get_font(&fm);
+                       el->m_pos.y = m_height - base_line - fm.ascent;
+               } else
+               {
+                       switch(el->get_vertical_align())
+                       {
+                       case va_super:
+                       case va_sub:
+                       case va_baseline:
+                               el->m_pos.y = m_height - base_line - el->height() + el->get_base_line() + el->content_margins_top();
+                               break;
+                       case va_top:
+                               el->m_pos.y = y1 + el->content_margins_top();
+                               break;
+                       case va_text_top:
+                               el->m_pos.y = m_height - base_line - m_font_metrics.ascent + el->content_margins_top();
+                               break;
+                       case va_middle:
+                               el->m_pos.y = m_height - base_line - m_font_metrics.x_height / 2 - el->height() / 2 + el->content_margins_top();
+                               break;
+                       case va_bottom:
+                               el->m_pos.y = y2 - el->height() + el->content_margins_top();
+                               break;
+                       case va_text_bottom:
+                               el->m_pos.y = m_height - base_line + m_font_metrics.descent - el->height() + el->content_margins_top();
+                               break;
+                       }
+                       y1 = std::min(y1, el->top());
+                       y2 = std::max(y2, el->bottom());
+               }
+       }
+
+       css_offsets offsets;
+
+       for (const auto& el : m_items)
+       {
+               el->m_pos.y -= y1;
+               el->m_pos.y += m_box_top;
+               if(el->get_display() != display_inline_text)
+               {
+                       switch(el->get_vertical_align())
+                       {
+                       case va_top:
+                               el->m_pos.y = m_box_top + el->content_margins_top();
+                               break;
+                       case va_bottom:
+                               el->m_pos.y = m_box_top + (y2 - y1) - el->height() + el->content_margins_top();
+                               break;
+                       case va_baseline:
+                               //TODO: process vertical align "baseline"
+                               break;
+                       case va_middle:
+                               //TODO: process vertical align "middle"
+                               break;
+                       case va_sub:
+                               //TODO: process vertical align "sub"
+                               break;
+                       case va_super:
+                               //TODO: process vertical align "super"
+                               break;
+                       case va_text_bottom:
+                               //TODO: process vertical align "text-bottom"
+                               break;
+                       case va_text_top:
+                               //TODO: process vertical align "text-top"
+                               break;
+                       }
+               }
+
+               el->apply_relative_shift(m_box_right - m_box_left);
+       }
+       m_height = y2 - y1;
+       m_baseline = (base_line - y1) - (m_height - line_height);
+}
+
+bool litehtml::line_box::can_hold(const element::ptr &el, white_space ws)
+{
+       if(!el->is_inline_box()) return false;
+
+       if(el->is_break())
+       {
+               return false;
+       }
+
+       if(ws == white_space_nowrap || ws == white_space_pre)
+       {
+               return true;
+       }
+
+       if(m_box_left + m_width + el->width() + el->get_inline_shift_left() + el->get_inline_shift_right() > m_box_right)
+       {
+               return false;
+       }
+
+       return true;
+}
+
+bool litehtml::line_box::have_last_space()
+{
+       bool ret = false;
+       for (auto i = m_items.rbegin(); i != m_items.rend() && !ret; i++)
+       {
+               if((*i)->is_white_space() || (*i)->is_break())
+               {
+                       ret = true;
+               } else
+               {
+                       break;
+               }
+       }
+       return ret;
+}
+
+bool litehtml::line_box::is_empty()
+{
+       if(m_items.empty()) return true;
+       for (auto i = m_items.rbegin(); i != m_items.rend(); i++)
+       {
+               if(!(*i)->m_skip || (*i)->is_break())
+               {
+                       return false;
+               }
+       }
+       return true;
+}
+
+int litehtml::line_box::baseline()
+{
+       return m_baseline;
+}
+
+void litehtml::line_box::get_elements( elements_vector& els )
+{
+       els.insert(els.begin(), m_items.begin(), m_items.end());
+}
+
+int litehtml::line_box::top_margin()
+{
+       return 0;
+}
+
+int litehtml::line_box::bottom_margin()
+{
+       return 0;
+}
+
+void litehtml::line_box::y_shift( int shift )
+{
+       m_box_top += shift;
+       for (auto& el : m_items)
+       {
+               el->m_pos.y += shift;
+       }
+}
+
+bool litehtml::line_box::is_break_only()
+{
+       if(m_items.empty()) return true;
+
+       if(m_items.front()->is_break())
+       {
+               for (auto& el : m_items)
+               {
+                       if(!el->m_skip)
+                       {
+                               return false;
+                       }
+               }
+               return true;
+       }
+       return false;
+}
+
+void litehtml::line_box::new_width( int left, int right, elements_vector& els )
+{
+       int add = left - m_box_left;
+       if(add)
+       {
+               m_box_left      = left;
+               m_box_right     = right;
+               m_width = 0;
+               auto remove_begin = m_items.end();
+               for (auto i = m_items.begin() + 1; i != m_items.end(); i++)
+               {
+                       element::ptr el = (*i);
+
+                       if(!el->m_skip)
+                       {
+                               if(m_box_left + m_width + el->width() + el->get_inline_shift_right() + el->get_inline_shift_left() > m_box_right)
+                               {
+                                       remove_begin = i;
+                                       break;
+                               } else
+                               {
+                                       el->m_pos.x += add;
+                                       m_width += el->width() + el->get_inline_shift_right() + el->get_inline_shift_left();
+                               }
+                       }
+               }
+               if(remove_begin != m_items.end())
+               {
+                       els.insert(els.begin(), remove_begin, m_items.end());
+                       m_items.erase(remove_begin, m_items.end());
+
+                       for(const auto& el : els)
+                       {
+                               el->m_box = 0;
+                       }
+               }
+       }
+}
+
index d15a528..eeeea51 100644 (file)
-#pragma once\r
-\r
-namespace litehtml\r
-{\r
-       class html_tag;\r
-\r
-       enum box_type\r
-       {\r
-               box_block,\r
-               box_line\r
-       };\r
-\r
-       class box\r
-       {\r
-       public:\r
-               typedef std::unique_ptr<litehtml::box>  ptr;\r
-               typedef std::vector< box::ptr >                 vector;\r
-       protected:\r
-               int             m_box_top;\r
-               int             m_box_left;\r
-               int             m_box_right;\r
-       public:\r
-               box(int top, int left, int right)\r
-               {\r
-                       m_box_top       = top;\r
-                       m_box_left      = left;\r
-                       m_box_right     = right;\r
-               }\r
-               virtual ~box() {}\r
-\r
-               int             bottom()        { return m_box_top + height();  }\r
-               int             top()           { return m_box_top;                             }\r
-               int             right()         { return m_box_left + width();  }\r
-               int             left()          { return m_box_left;                    }\r
-\r
-               virtual litehtml::box_type      get_type() = 0;\r
-               virtual int                                     height() = 0;\r
-               virtual int                                     width() = 0;\r
-               virtual void                            add_element(const element::ptr &el) = 0;\r
-               virtual bool                            can_hold(const element::ptr &el, white_space ws) = 0;\r
-               virtual void                            finish(bool last_box = false) = 0;\r
-               virtual bool                            is_empty() = 0;\r
-               virtual int                                     baseline() = 0;\r
-               virtual void                            get_elements(elements_vector& els) = 0;\r
-               virtual int                                     top_margin() = 0;\r
-               virtual int                                     bottom_margin() = 0;\r
-               virtual void                            y_shift(int shift) = 0;\r
-               virtual void                            new_width(int left, int right, elements_vector& els) = 0;\r
-       };\r
-\r
-       //////////////////////////////////////////////////////////////////////////\r
-\r
-       class block_box : public box\r
-       {\r
-               element::ptr m_element;\r
-       public:\r
-               block_box(int top, int left, int right) : box(top, left, right)\r
-               {\r
-                       m_element = 0;\r
-               }\r
-\r
-               virtual litehtml::box_type      get_type();\r
-               virtual int                                     height();\r
-               virtual int                                     width();\r
-               virtual void                            add_element(const element::ptr &el);\r
-               virtual bool                            can_hold(const element::ptr &el, white_space ws);\r
-               virtual void                            finish(bool last_box = false);\r
-               virtual bool                            is_empty();\r
-               virtual int                                     baseline();\r
-               virtual void                            get_elements(elements_vector& els);\r
-               virtual int                                     top_margin();\r
-               virtual int                                     bottom_margin();\r
-               virtual void                            y_shift(int shift);\r
-               virtual void                            new_width(int left, int right, elements_vector& els);\r
-       };\r
-\r
-       //////////////////////////////////////////////////////////////////////////\r
-\r
-       class line_box : public box\r
-       {\r
-               elements_vector                 m_items;\r
-               int                                             m_height;\r
-               int                                             m_width;\r
-               int                                             m_line_height;\r
-               font_metrics                    m_font_metrics;\r
-               int                                             m_baseline;\r
-               text_align                              m_text_align;\r
-       public:\r
-               line_box(int top, int left, int right, int line_height, font_metrics& fm, text_align align) : box(top, left, right)\r
-               {\r
-                       m_height                = 0;\r
-                       m_width                 = 0;\r
-                       m_font_metrics  = fm;\r
-                       m_line_height   = line_height;\r
-                       m_baseline              = 0;\r
-                       m_text_align    = align;\r
-               }\r
-\r
-               virtual litehtml::box_type      get_type();\r
-               virtual int                                     height();\r
-               virtual int                                     width();\r
-               virtual void                            add_element(const element::ptr &el);\r
-               virtual bool                            can_hold(const element::ptr &el, white_space ws);\r
-               virtual void                            finish(bool last_box = false);\r
-               virtual bool                            is_empty();\r
-               virtual int                                     baseline();\r
-               virtual void                            get_elements(elements_vector& els);\r
-               virtual int                                     top_margin();\r
-               virtual int                                     bottom_margin();\r
-               virtual void                            y_shift(int shift);\r
-               virtual void                            new_width(int left, int right, elements_vector& els);\r
-\r
-       private:\r
-               bool                                            have_last_space();\r
-               bool                                            is_break_only();\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_BOX_H
+#define LH_BOX_H
+
+namespace litehtml
+{
+       class html_tag;
+
+       enum box_type
+       {
+               box_block,
+               box_line
+       };
+
+       class box
+       {
+       public:
+               typedef std::unique_ptr<litehtml::box>  ptr;
+               typedef std::vector< box::ptr >                 vector;
+       protected:
+               int             m_box_top;
+               int             m_box_left;
+               int             m_box_right;
+       public:
+               box(int top, int left, int right)
+               {
+                       m_box_top       = top;
+                       m_box_left      = left;
+                       m_box_right     = right;
+               }
+               virtual ~box() {}
+
+               int             bottom()        { return m_box_top + height();  }
+               int             top()           { return m_box_top;                             }
+               int             right()         { return m_box_left + width();  }
+               int             left()          { return m_box_left;                    }
+
+               virtual litehtml::box_type      get_type() = 0;
+               virtual int                                     height() = 0;
+               virtual int                                     width() = 0;
+               virtual void                            add_element(const element::ptr &el) = 0;
+               virtual bool                            can_hold(const element::ptr &el, white_space ws) = 0;
+               virtual void                            finish(bool last_box = false) = 0;
+               virtual bool                            is_empty() = 0;
+               virtual int                                     baseline() = 0;
+               virtual void                            get_elements(elements_vector& els) = 0;
+               virtual int                                     top_margin() = 0;
+               virtual int                                     bottom_margin() = 0;
+               virtual void                            y_shift(int shift) = 0;
+               virtual void                            new_width(int left, int right, elements_vector& els) = 0;
+       };
+
+       //////////////////////////////////////////////////////////////////////////
+
+       class block_box : public box
+       {
+               element::ptr m_element;
+       public:
+               block_box(int top, int left, int right) : box(top, left, right)
+               {
+                       m_element = 0;
+               }
+
+               virtual litehtml::box_type      get_type();
+               virtual int                                     height();
+               virtual int                                     width();
+               virtual void                            add_element(const element::ptr &el);
+               virtual bool                            can_hold(const element::ptr &el, white_space ws);
+               virtual void                            finish(bool last_box = false);
+               virtual bool                            is_empty();
+               virtual int                                     baseline();
+               virtual void                            get_elements(elements_vector& els);
+               virtual int                                     top_margin();
+               virtual int                                     bottom_margin();
+               virtual void                            y_shift(int shift);
+               virtual void                            new_width(int left, int right, elements_vector& els);
+       };
+
+       //////////////////////////////////////////////////////////////////////////
+
+       class line_box : public box
+       {
+               elements_vector                 m_items;
+               int                                             m_height;
+               int                                             m_width;
+               int                                             m_line_height;
+               font_metrics                    m_font_metrics;
+               int                                             m_baseline;
+               text_align                              m_text_align;
+       public:
+               line_box(int top, int left, int right, int line_height, font_metrics& fm, text_align align) : box(top, left, right)
+               {
+                       m_height                = 0;
+                       m_width                 = 0;
+                       m_font_metrics  = fm;
+                       m_line_height   = line_height;
+                       m_baseline              = 0;
+                       m_text_align    = align;
+               }
+
+               virtual litehtml::box_type      get_type();
+               virtual int                                     height();
+               virtual int                                     width();
+               virtual void                            add_element(const element::ptr &el);
+               virtual bool                            can_hold(const element::ptr &el, white_space ws);
+               virtual void                            finish(bool last_box = false);
+               virtual bool                            is_empty();
+               virtual int                                     baseline();
+               virtual void                            get_elements(elements_vector& els);
+               virtual int                                     top_margin();
+               virtual int                                     bottom_margin();
+               virtual void                            y_shift(int shift);
+               virtual void                            new_width(int left, int right, elements_vector& els);
+
+       private:
+               bool                                            have_last_space();
+               bool                                            is_break_only();
+       };
+}
+
+#endif  // LH_BOX_H
index 5f26269..4cea5d3 100644 (file)
@@ -1,12 +1,12 @@
-#include "html.h"\r
-#include "context.h"\r
-#include "stylesheet.h"\r
-\r
-\r
-void litehtml::context::load_master_stylesheet( const tchar_t* str )\r
-{\r
-       media_query_list::ptr media;\r
-\r
-       m_master_css.parse_stylesheet(str, 0, std::shared_ptr<litehtml::document>(), media_query_list::ptr());\r
-       m_master_css.sort_selectors();\r
-}\r
+#include "html.h"
+#include "context.h"
+#include "stylesheet.h"
+
+
+void litehtml::context::load_master_stylesheet( const tchar_t* str )
+{
+       media_query_list::ptr media;
+
+       m_master_css.parse_stylesheet(str, 0, std::shared_ptr<litehtml::document>(), media_query_list::ptr());
+       m_master_css.sort_selectors();
+}
index ce62991..b6450f8 100644 (file)
@@ -1,16 +1,20 @@
-#pragma once\r
-#include "stylesheet.h"\r
-\r
-namespace litehtml\r
-{\r
-       class context\r
-       {\r
-               litehtml::css   m_master_css;\r
-       public:\r
-               void                    load_master_stylesheet(const tchar_t* str);\r
-               litehtml::css&  master_css()\r
-               {\r
-                       return m_master_css;\r
-               }\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_CONTEXT_H
+#define LH_CONTEXT_H
+
+#include "stylesheet.h"
+
+namespace litehtml
+{
+       class context
+       {
+               litehtml::css   m_master_css;
+       public:
+               void                    load_master_stylesheet(const tchar_t* str);
+               litehtml::css&  master_css()
+               {
+                       return m_master_css;
+               }
+       };
+}
+
+#endif  // LH_CONTEXT_H
index 06d5580..472cd54 100644 (file)
@@ -1,54 +1,54 @@
-#include "html.h"\r
-#include "css_length.h"\r
-\r
-void litehtml::css_length::fromString( const tstring& str, const tstring& predefs, int defValue )\r
-{\r
-       // TODO: Make support for calc\r
-       if(str.substr(0, 4) == _t("calc"))\r
-       {\r
-               m_is_predefined = true;\r
-               m_predef                = 0;\r
-               return;\r
-       }\r
-\r
-       int predef = value_index(str.c_str(), predefs.c_str(), -1);\r
-       if(predef >= 0)\r
-       {\r
-               m_is_predefined = true;\r
-               m_predef                = predef;\r
-       } else\r
-       {\r
-               m_is_predefined = false;\r
-\r
-               tstring num;\r
-               tstring un;\r
-               bool is_unit = false;\r
-               for(tstring::const_iterator chr = str.begin(); chr != str.end(); chr++)\r
-               {\r
-                       if(!is_unit)\r
-                       {\r
-                               if(t_isdigit(*chr) || *chr == _t('.') || *chr == _t('+') || *chr == _t('-'))\r
-                               {\r
-                                       num += *chr;\r
-                               } else\r
-                               {\r
-                                       is_unit = true;\r
-                               }\r
-                       }\r
-                       if(is_unit)\r
-                       {\r
-                               un += *chr;\r
-                       }\r
-               }\r
-               if(!num.empty())\r
-               {\r
-                       m_value = (float) t_strtod(num.c_str(), 0);\r
-                       m_units = (css_units) value_index(un.c_str(), css_units_strings, css_units_none);\r
-               } else\r
-               {\r
-                       // not a number so it is predefined\r
-                       m_is_predefined = true;\r
-                       m_predef = defValue;\r
-               }\r
-       }\r
-}\r
+#include "html.h"
+#include "css_length.h"
+
+void litehtml::css_length::fromString( const tstring& str, const tstring& predefs, int defValue )
+{
+       // TODO: Make support for calc
+       if(str.substr(0, 4) == _t("calc"))
+       {
+               m_is_predefined = true;
+               m_predef                = 0;
+               return;
+       }
+
+       int predef = value_index(str.c_str(), predefs.c_str(), -1);
+       if(predef >= 0)
+       {
+               m_is_predefined = true;
+               m_predef                = predef;
+       } else
+       {
+               m_is_predefined = false;
+
+               tstring num;
+               tstring un;
+               bool is_unit = false;
+               for(tstring::const_iterator chr = str.begin(); chr != str.end(); chr++)
+               {
+                       if(!is_unit)
+                       {
+                               if(t_isdigit(*chr) || *chr == _t('.') || *chr == _t('+') || *chr == _t('-'))
+                               {
+                                       num += *chr;
+                               } else
+                               {
+                                       is_unit = true;
+                               }
+                       }
+                       if(is_unit)
+                       {
+                               un += *chr;
+                       }
+               }
+               if(!num.empty())
+               {
+                       m_value = (float) t_strtod(num.c_str(), 0);
+                       m_units = (css_units) value_index(un.c_str(), css_units_strings, css_units_none);
+               } else
+               {
+                       // not a number so it is predefined
+                       m_is_predefined = true;
+                       m_predef = defValue;
+               }
+       }
+}
index 078f9dd..13a3d77 100644 (file)
-#pragma once\r
-#include "types.h"\r
-\r
-namespace litehtml\r
-{\r
-       class css_length\r
-       {\r
-               union\r
-               {\r
-                       float   m_value;\r
-                       int             m_predef;\r
-               };\r
-               css_units       m_units;\r
-               bool            m_is_predefined;\r
-       public:\r
-               css_length();\r
-               css_length(const css_length& val);\r
-\r
-               css_length&     operator=(const css_length& val);\r
-               css_length&     operator=(float val);\r
-               bool            is_predefined() const;\r
-               void            predef(int val);\r
-               int                     predef() const;\r
-               void            set_value(float val, css_units units);\r
-               float           val() const;\r
-               css_units       units() const;\r
-               int                     calc_percent(int width) const;\r
-               void            fromString(const tstring& str, const tstring& predefs = _t(""), int defValue = 0);\r
-       };\r
-\r
-       // css_length inlines\r
-\r
-       inline css_length::css_length()\r
-       {\r
-               m_value                 = 0;\r
-               m_predef                = 0;\r
-               m_units                 = css_units_none;\r
-               m_is_predefined = false;\r
-       }\r
-\r
-       inline css_length::css_length(const css_length& val)\r
-       {\r
-               if(val.is_predefined())\r
-               {\r
-                       m_predef        = val.m_predef;\r
-               } else\r
-               {\r
-                       m_value         = val.m_value;\r
-               }\r
-               m_units                 = val.m_units;\r
-               m_is_predefined = val.m_is_predefined;\r
-       }\r
-\r
-       inline css_length&      css_length::operator=(const css_length& val)\r
-       {\r
-               if(val.is_predefined())\r
-               {\r
-                       m_predef        = val.m_predef;\r
-               } else\r
-               {\r
-                       m_value         = val.m_value;\r
-               }\r
-               m_units                 = val.m_units;\r
-               m_is_predefined = val.m_is_predefined;\r
-               return *this;\r
-       }\r
-\r
-       inline css_length&      css_length::operator=(float val)\r
-       {\r
-               m_value = val;\r
-               m_units = css_units_px;\r
-               m_is_predefined = false;\r
-               return *this;\r
-       }\r
-\r
-       inline bool css_length::is_predefined() const\r
-       { \r
-               return m_is_predefined;                                 \r
-       }\r
-\r
-       inline void css_length::predef(int val)         \r
-       { \r
-               m_predef                = val; \r
-               m_is_predefined = true; \r
-       }\r
-\r
-       inline int css_length::predef() const\r
-       { \r
-               if(m_is_predefined)\r
-               {\r
-                       return m_predef; \r
-               }\r
-               return 0;\r
-       }\r
-\r
-       inline void css_length::set_value(float val, css_units units)           \r
-       { \r
-               m_value                 = val; \r
-               m_is_predefined = false;        \r
-               m_units                 = units;\r
-       }\r
-\r
-       inline float css_length::val() const\r
-       {\r
-               if(!m_is_predefined)\r
-               {\r
-                       return m_value;\r
-               }\r
-               return 0;\r
-       }\r
-\r
-       inline css_units css_length::units() const\r
-       {\r
-               return m_units;\r
-       }\r
-\r
-       inline int css_length::calc_percent(int width) const\r
-       {\r
-               if(!is_predefined())\r
-               {\r
-                       if(units() == css_units_percentage)\r
-                       {\r
-                               return (int) ((double) width * (double) m_value / 100.0);\r
-                       } else\r
-                       {\r
-                               return (int) val();\r
-                       }\r
-               }\r
-               return 0;\r
-       }\r
-}
\ No newline at end of file
+#ifndef LH_CSS_LENGTH_H
+#define LH_CSS_LENGTH_H
+
+#include "types.h"
+
+namespace litehtml
+{
+       class css_length
+       {
+               union
+               {
+                       float   m_value;
+                       int             m_predef;
+               };
+               css_units       m_units;
+               bool            m_is_predefined;
+       public:
+               css_length();
+               css_length(const css_length& val);
+
+               css_length&     operator=(const css_length& val);
+               css_length&     operator=(float val);
+               bool            is_predefined() const;
+               void            predef(int val);
+               int                     predef() const;
+               void            set_value(float val, css_units units);
+               float           val() const;
+               css_units       units() const;
+               int                     calc_percent(int width) const;
+               void            fromString(const tstring& str, const tstring& predefs = _t(""), int defValue = 0);
+       };
+
+       // css_length inlines
+
+       inline css_length::css_length()
+       {
+               m_value                 = 0;
+               m_predef                = 0;
+               m_units                 = css_units_none;
+               m_is_predefined = false;
+       }
+
+       inline css_length::css_length(const css_length& val)
+       {
+               if(val.is_predefined())
+               {
+                       m_predef        = val.m_predef;
+               } else
+               {
+                       m_value         = val.m_value;
+               }
+               m_units                 = val.m_units;
+               m_is_predefined = val.m_is_predefined;
+       }
+
+       inline css_length&      css_length::operator=(const css_length& val)
+       {
+               if(val.is_predefined())
+               {
+                       m_predef        = val.m_predef;
+               } else
+               {
+                       m_value         = val.m_value;
+               }
+               m_units                 = val.m_units;
+               m_is_predefined = val.m_is_predefined;
+               return *this;
+       }
+
+       inline css_length&      css_length::operator=(float val)
+       {
+               m_value = val;
+               m_units = css_units_px;
+               m_is_predefined = false;
+               return *this;
+       }
+
+       inline bool css_length::is_predefined() const
+       { 
+               return m_is_predefined;                                 
+       }
+
+       inline void css_length::predef(int val)         
+       { 
+               m_predef                = val; 
+               m_is_predefined = true; 
+       }
+
+       inline int css_length::predef() const
+       { 
+               if(m_is_predefined)
+               {
+                       return m_predef; 
+               }
+               return 0;
+       }
+
+       inline void css_length::set_value(float val, css_units units)           
+       { 
+               m_value                 = val; 
+               m_is_predefined = false;        
+               m_units                 = units;
+       }
+
+       inline float css_length::val() const
+       {
+               if(!m_is_predefined)
+               {
+                       return m_value;
+               }
+               return 0;
+       }
+
+       inline css_units css_length::units() const
+       {
+               return m_units;
+       }
+
+       inline int css_length::calc_percent(int width) const
+       {
+               if(!is_predefined())
+               {
+                       if(units() == css_units_percentage)
+                       {
+                               return (int) ((double) width * (double) m_value / 100.0);
+                       } else
+                       {
+                               return (int) val();
+                       }
+               }
+               return 0;
+       }
+}
+
+#endif  // LH_CSS_LENGTH_H
index fbe1d40..5c99a8b 100644 (file)
@@ -1,35 +1,39 @@
-#pragma once\r
-#include "css_length.h"\r
-\r
-namespace litehtml\r
-{\r
-       struct css_margins\r
-       {\r
-               css_length      left;\r
-               css_length      right;\r
-               css_length      top;\r
-               css_length      bottom;\r
-\r
-               css_margins()\r
-               {\r
-\r
-               }\r
-\r
-               css_margins(const css_margins& val)\r
-               {\r
-                       left    = val.left;\r
-                       right   = val.right;\r
-                       top             = val.top;\r
-                       bottom  = val.bottom;\r
-               }\r
-\r
-               css_margins& operator=(const css_margins& val)\r
-               {\r
-                       left    = val.left;\r
-                       right   = val.right;\r
-                       top             = val.top;\r
-                       bottom  = val.bottom;\r
-                       return *this;\r
-               }\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_CSS_MARGINS_H
+#define LH_CSS_MARGINS_H
+
+#include "css_length.h"
+
+namespace litehtml
+{
+       struct css_margins
+       {
+               css_length      left;
+               css_length      right;
+               css_length      top;
+               css_length      bottom;
+
+               css_margins()
+               {
+
+               }
+
+               css_margins(const css_margins& val)
+               {
+                       left    = val.left;
+                       right   = val.right;
+                       top             = val.top;
+                       bottom  = val.bottom;
+               }
+
+               css_margins& operator=(const css_margins& val)
+               {
+                       left    = val.left;
+                       right   = val.right;
+                       top             = val.top;
+                       bottom  = val.bottom;
+                       return *this;
+               }
+       };
+}
+
+#endif  // LH_CSS_MARGINS_H
index e4ca723..18d7f26 100644 (file)
@@ -1,35 +1,39 @@
-#pragma once\r
-#include "css_length.h"\r
-\r
-namespace litehtml\r
-{\r
-       struct css_offsets\r
-       {\r
-               css_length      left;\r
-               css_length      top;\r
-               css_length      right;\r
-               css_length      bottom;\r
-\r
-               css_offsets()\r
-               {\r
-\r
-               }\r
-\r
-               css_offsets(const css_offsets& val)\r
-               {\r
-                       left    = val.left;\r
-                       top             = val.top;\r
-                       right   = val.right;\r
-                       bottom  = val.bottom;\r
-               }\r
-\r
-               css_offsets& operator=(const css_offsets& val)\r
-               {\r
-                       left    = val.left;\r
-                       top             = val.top;\r
-                       right   = val.right;\r
-                       bottom  = val.bottom;\r
-                       return *this;\r
-               }\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_CSS_OFFSETS_H
+#define LH_CSS_OFFSETS_H
+
+#include "css_length.h"
+
+namespace litehtml
+{
+       struct css_offsets
+       {
+               css_length      left;
+               css_length      top;
+               css_length      right;
+               css_length      bottom;
+
+               css_offsets()
+               {
+
+               }
+
+               css_offsets(const css_offsets& val)
+               {
+                       left    = val.left;
+                       top             = val.top;
+                       right   = val.right;
+                       bottom  = val.bottom;
+               }
+
+               css_offsets& operator=(const css_offsets& val)
+               {
+                       left    = val.left;
+                       top             = val.top;
+                       right   = val.right;
+                       bottom  = val.bottom;
+                       return *this;
+               }
+       };
+}
+
+#endif  // LH_CSS_OFFSETS_H
index 05f046d..308a14f 100644 (file)
@@ -1,35 +1,39 @@
-#pragma once\r
-#include "css_length.h"\r
-\r
-namespace litehtml\r
-{\r
-       struct css_position\r
-       {\r
-               css_length      x;\r
-               css_length      y;\r
-               css_length      width;\r
-               css_length      height;\r
-\r
-               css_position()\r
-               {\r
-\r
-               }\r
-\r
-               css_position(const css_position& val)\r
-               {\r
-                       x               = val.x;\r
-                       y               = val.y;\r
-                       width   = val.width;\r
-                       height  = val.height;\r
-               }\r
-\r
-               css_position& operator=(const css_position& val)\r
-               {\r
-                       x               = val.x;\r
-                       y               = val.y;\r
-                       width   = val.width;\r
-                       height  = val.height;\r
-                       return *this;\r
-               }\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_CSS_POSITION_H
+#define LH_CSS_POSITION_H
+
+#include "css_length.h"
+
+namespace litehtml
+{
+       struct css_position
+       {
+               css_length      x;
+               css_length      y;
+               css_length      width;
+               css_length      height;
+
+               css_position()
+               {
+
+               }
+
+               css_position(const css_position& val)
+               {
+                       x               = val.x;
+                       y               = val.y;
+                       width   = val.width;
+                       height  = val.height;
+               }
+
+               css_position& operator=(const css_position& val)
+               {
+                       x               = val.x;
+                       y               = val.y;
+                       width   = val.width;
+                       height  = val.height;
+                       return *this;
+               }
+       };
+}
+
+#endif  // LH_CSS_POSITION_H
index a8e5f41..dc40088 100644 (file)
-#include "html.h"\r
-#include "css_selector.h"\r
-#include "document.h"\r
-\r
-void litehtml::css_element_selector::parse( const tstring& txt )\r
-{\r
-       tstring::size_type el_end = txt.find_first_of(_t(".#[:"));\r
-       m_tag = txt.substr(0, el_end);\r
-       litehtml::lcase(m_tag);\r
-       while(el_end != tstring::npos)\r
-       {\r
-               if(txt[el_end] == _t('.'))\r
-               {\r
-                       css_attribute_selector attribute;\r
-\r
-                       tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);\r
-                       attribute.val           = txt.substr(el_end + 1, pos - el_end - 1);\r
-                       split_string( attribute.val, attribute.class_val, _t(" ") );\r
-                       attribute.condition     = select_equal;\r
-                       attribute.attribute     = _t("class");\r
-                       m_attrs.push_back(attribute);\r
-                       el_end = pos;\r
-               } else if(txt[el_end] == _t(':'))\r
-               {\r
-                       css_attribute_selector attribute;\r
-\r
-                       if(txt[el_end + 1] == _t(':'))\r
-                       {\r
-                               tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 2);\r
-                               attribute.val           = txt.substr(el_end + 2, pos - el_end - 2);\r
-                               attribute.condition     = select_pseudo_element;\r
-                               litehtml::lcase(attribute.val);\r
-                               attribute.attribute     = _t("pseudo-el");\r
-                               m_attrs.push_back(attribute);\r
-                               el_end = pos;\r
-                       } else\r
-                       {\r
-                               tstring::size_type pos = txt.find_first_of(_t(".#[:("), el_end + 1);\r
-                               if(pos != tstring::npos && txt.at(pos) == _t('('))\r
-                               {\r
-                                       pos = find_close_bracket(txt, pos);\r
-                                       if(pos != tstring::npos)\r
-                                       {\r
-                                               pos++;\r
-                                       } else\r
-                                       {\r
-                                               int iii = 0;\r
-                                               iii++;\r
-                                       }\r
-                               }\r
-                               if(pos != tstring::npos)\r
-                               {\r
-                                       attribute.val           = txt.substr(el_end + 1, pos - el_end - 1);\r
-                               } else\r
-                               {\r
-                                       attribute.val           = txt.substr(el_end + 1);\r
-                               }\r
-                               litehtml::lcase(attribute.val);\r
-                               if(attribute.val == _t("after") || attribute.val == _t("before"))\r
-                               {\r
-                                       attribute.condition     = select_pseudo_element;\r
-                               } else\r
-                               {\r
-                                       attribute.condition     = select_pseudo_class;\r
-                               }\r
-                               attribute.attribute     = _t("pseudo");\r
-                               m_attrs.push_back(attribute);\r
-                               el_end = pos;\r
-                       }\r
-               } else if(txt[el_end] == _t('#'))\r
-               {\r
-                       css_attribute_selector attribute;\r
-\r
-                       tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);\r
-                       attribute.val           = txt.substr(el_end + 1, pos - el_end - 1);\r
-                       attribute.condition     = select_equal;\r
-                       attribute.attribute     = _t("id");\r
-                       m_attrs.push_back(attribute);\r
-                       el_end = pos;\r
-               } else if(txt[el_end] == _t('['))\r
-               {\r
-                       css_attribute_selector attribute;\r
-\r
-                       tstring::size_type pos = txt.find_first_of(_t("]~=|$*^"), el_end + 1);\r
-                       tstring attr = txt.substr(el_end + 1, pos - el_end - 1);\r
-                       trim(attr);\r
-                       litehtml::lcase(attr);\r
-                       if(pos != tstring::npos)\r
-                       {\r
-                               if(txt[pos] == _t(']'))\r
-                               {\r
-                                       attribute.condition = select_exists;\r
-                               } else if(txt[pos] == _t('='))\r
-                               {\r
-                                       attribute.condition = select_equal;\r
-                                       pos++;\r
-                               } else if(txt.substr(pos, 2) == _t("~="))\r
-                               {\r
-                                       attribute.condition = select_contain_str;\r
-                                       pos += 2;\r
-                               } else if(txt.substr(pos, 2) == _t("|="))\r
-                               {\r
-                                       attribute.condition = select_start_str;\r
-                                       pos += 2;\r
-                               } else if(txt.substr(pos, 2) == _t("^="))\r
-                               {\r
-                                       attribute.condition = select_start_str;\r
-                                       pos += 2;\r
-                               } else if(txt.substr(pos, 2) == _t("$="))\r
-                               {\r
-                                       attribute.condition = select_end_str;\r
-                                       pos += 2;\r
-                               } else if(txt.substr(pos, 2) == _t("*="))\r
-                               {\r
-                                       attribute.condition = select_contain_str;\r
-                                       pos += 2;\r
-                               } else\r
-                               {\r
-                                       attribute.condition = select_exists;\r
-                                       pos += 1;\r
-                               }\r
-                               pos = txt.find_first_not_of(_t(" \t"), pos);\r
-                               if(pos != tstring::npos)\r
-                               {\r
-                                       if(txt[pos] == _t('"'))\r
-                                       {\r
-                                               tstring::size_type pos2 = txt.find_first_of(_t("\""), pos + 1);\r
-                                               attribute.val = txt.substr(pos + 1, pos2 == tstring::npos ? pos2 : (pos2 - pos - 1));\r
-                                               pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);\r
-                                       } else if(txt[pos] == _t(']'))\r
-                                       {\r
-                                               pos ++;\r
-                                       } else\r
-                                       {\r
-                                               tstring::size_type pos2 = txt.find_first_of(_t("]"), pos + 1);\r
-                                               attribute.val = txt.substr(pos, pos2 == tstring::npos ? pos2 : (pos2 - pos));\r
-                                               trim(attribute.val);\r
-                                               pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);\r
-                                       }\r
-                               }\r
-                       } else\r
-                       {\r
-                               attribute.condition = select_exists;\r
-                       }\r
-                       attribute.attribute     = attr;\r
-                       m_attrs.push_back(attribute);\r
-                       el_end = pos;\r
-               } else\r
-               {\r
-                       el_end++;\r
-               }\r
-               el_end = txt.find_first_of(_t(".#[:"), el_end);\r
-       }\r
-}\r
-\r
-\r
-bool litehtml::css_selector::parse( const tstring& text )\r
-{\r
-       if(text.empty())\r
-       {\r
-               return false;\r
-       }\r
-       string_vector tokens;\r
-       split_string(text, tokens, _t(""), _t(" \t>+~"), _t("(["));\r
-\r
-       if(tokens.empty())\r
-       {\r
-               return false;\r
-       }\r
-\r
-       tstring left;\r
-       tstring right = tokens.back();\r
-       tchar_t combinator = 0;\r
-\r
-       tokens.pop_back();\r
-       while(!tokens.empty() && (tokens.back() == _t(" ") || tokens.back() == _t("\t") || tokens.back() == _t("+") || tokens.back() == _t("~") || tokens.back() == _t(">")))\r
-       {\r
-               if(combinator == _t(' ') || combinator == 0)\r
-               {\r
-                       combinator = tokens.back()[0];\r
-               }\r
-               tokens.pop_back();\r
-       }\r
-\r
-       for(string_vector::const_iterator i = tokens.begin(); i != tokens.end(); i++)\r
-       {\r
-               left += *i;\r
-       }\r
-\r
-       trim(left);\r
-       trim(right);\r
-\r
-       if(right.empty())\r
-       {\r
-               return false;\r
-       }\r
-\r
-       m_right.parse(right);\r
-\r
-       switch(combinator)\r
-       {\r
-       case _t('>'):\r
-               m_combinator    = combinator_child;\r
-               break;\r
-       case _t('+'):\r
-               m_combinator    = combinator_adjacent_sibling;\r
-               break;\r
-       case _t('~'):\r
-               m_combinator    = combinator_general_sibling;\r
-               break;\r
-       default:\r
-               m_combinator    = combinator_descendant;\r
-               break;\r
-       }\r
-\r
-       m_left = 0;\r
-\r
-       if(!left.empty())\r
-       {\r
-               m_left = std::make_shared<css_selector>(media_query_list::ptr(0));\r
-               if(!m_left->parse(left))\r
-               {\r
-                       return false;\r
-               }\r
-       }\r
-\r
-       return true;\r
-}\r
-\r
-void litehtml::css_selector::calc_specificity()\r
-{\r
-       if(!m_right.m_tag.empty() && m_right.m_tag != _t("*"))\r
-       {\r
-               m_specificity.d = 1;\r
-       }\r
-       for(css_attribute_selector::vector::iterator i = m_right.m_attrs.begin(); i != m_right.m_attrs.end(); i++)\r
-       {\r
-               if(i->attribute == _t("id"))\r
-               {\r
-                       m_specificity.b++;\r
-               } else\r
-               {\r
-                       if(i->attribute == _t("class"))\r
-                       {\r
-                               m_specificity.c += (int) i->class_val.size();\r
-                       } else\r
-                       {\r
-                               m_specificity.c++;\r
-                       }\r
-               }       \r
-       }\r
-       if(m_left)\r
-       {\r
-               m_left->calc_specificity();\r
-               m_specificity += m_left->m_specificity;\r
-       }\r
-}\r
-\r
-void litehtml::css_selector::add_media_to_doc( document* doc ) const\r
-{\r
-       if(m_media_query && doc)\r
-       {\r
-               doc->add_media_list(m_media_query);\r
-       }\r
-}\r
-\r
+#include "html.h"
+#include "css_selector.h"
+#include "document.h"
+
+void litehtml::css_element_selector::parse( const tstring& txt )
+{
+       tstring::size_type el_end = txt.find_first_of(_t(".#[:"));
+       m_tag = txt.substr(0, el_end);
+       litehtml::lcase(m_tag);
+       while(el_end != tstring::npos)
+       {
+               if(txt[el_end] == _t('.'))
+               {
+                       css_attribute_selector attribute;
+
+                       tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);
+                       attribute.val           = txt.substr(el_end + 1, pos - el_end - 1);
+                       split_string( attribute.val, attribute.class_val, _t(" ") );
+                       attribute.condition     = select_equal;
+                       attribute.attribute     = _t("class");
+                       m_attrs.push_back(attribute);
+                       el_end = pos;
+               } else if(txt[el_end] == _t(':'))
+               {
+                       css_attribute_selector attribute;
+
+                       if(txt[el_end + 1] == _t(':'))
+                       {
+                               tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 2);
+                               attribute.val           = txt.substr(el_end + 2, pos - el_end - 2);
+                               attribute.condition     = select_pseudo_element;
+                               litehtml::lcase(attribute.val);
+                               attribute.attribute     = _t("pseudo-el");
+                               m_attrs.push_back(attribute);
+                               el_end = pos;
+                       } else
+                       {
+                               tstring::size_type pos = txt.find_first_of(_t(".#[:("), el_end + 1);
+                               if(pos != tstring::npos && txt.at(pos) == _t('('))
+                               {
+                                       pos = find_close_bracket(txt, pos);
+                                       if(pos != tstring::npos)
+                                       {
+                                               pos++;
+                                       } else
+                                       {
+                                               int iii = 0;
+                                               iii++;
+                                       }
+                               }
+                               if(pos != tstring::npos)
+                               {
+                                       attribute.val           = txt.substr(el_end + 1, pos - el_end - 1);
+                               } else
+                               {
+                                       attribute.val           = txt.substr(el_end + 1);
+                               }
+                               litehtml::lcase(attribute.val);
+                               if(attribute.val == _t("after") || attribute.val == _t("before"))
+                               {
+                                       attribute.condition     = select_pseudo_element;
+                               } else
+                               {
+                                       attribute.condition     = select_pseudo_class;
+                               }
+                               attribute.attribute     = _t("pseudo");
+                               m_attrs.push_back(attribute);
+                               el_end = pos;
+                       }
+               } else if(txt[el_end] == _t('#'))
+               {
+                       css_attribute_selector attribute;
+
+                       tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);
+                       attribute.val           = txt.substr(el_end + 1, pos - el_end - 1);
+                       attribute.condition     = select_equal;
+                       attribute.attribute     = _t("id");
+                       m_attrs.push_back(attribute);
+                       el_end = pos;
+               } else if(txt[el_end] == _t('['))
+               {
+                       css_attribute_selector attribute;
+
+                       tstring::size_type pos = txt.find_first_of(_t("]~=|$*^"), el_end + 1);
+                       tstring attr = txt.substr(el_end + 1, pos - el_end - 1);
+                       trim(attr);
+                       litehtml::lcase(attr);
+                       if(pos != tstring::npos)
+                       {
+                               if(txt[pos] == _t(']'))
+                               {
+                                       attribute.condition = select_exists;
+                               } else if(txt[pos] == _t('='))
+                               {
+                                       attribute.condition = select_equal;
+                                       pos++;
+                               } else if(txt.substr(pos, 2) == _t("~="))
+                               {
+                                       attribute.condition = select_contain_str;
+                                       pos += 2;
+                               } else if(txt.substr(pos, 2) == _t("|="))
+                               {
+                                       attribute.condition = select_start_str;
+                                       pos += 2;
+                               } else if(txt.substr(pos, 2) == _t("^="))
+                               {
+                                       attribute.condition = select_start_str;
+                                       pos += 2;
+                               } else if(txt.substr(pos, 2) == _t("$="))
+                               {
+                                       attribute.condition = select_end_str;
+                                       pos += 2;
+                               } else if(txt.substr(pos, 2) == _t("*="))
+                               {
+                                       attribute.condition = select_contain_str;
+                                       pos += 2;
+                               } else
+                               {
+                                       attribute.condition = select_exists;
+                                       pos += 1;
+                               }
+                               pos = txt.find_first_not_of(_t(" \t"), pos);
+                               if(pos != tstring::npos)
+                               {
+                                       if(txt[pos] == _t('"'))
+                                       {
+                                               tstring::size_type pos2 = txt.find_first_of(_t("\""), pos + 1);
+                                               attribute.val = txt.substr(pos + 1, pos2 == tstring::npos ? pos2 : (pos2 - pos - 1));
+                                               pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);
+                                       } else if(txt[pos] == _t(']'))
+                                       {
+                                               pos ++;
+                                       } else
+                                       {
+                                               tstring::size_type pos2 = txt.find_first_of(_t("]"), pos + 1);
+                                               attribute.val = txt.substr(pos, pos2 == tstring::npos ? pos2 : (pos2 - pos));
+                                               trim(attribute.val);
+                                               pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);
+                                       }
+                               }
+                       } else
+                       {
+                               attribute.condition = select_exists;
+                       }
+                       attribute.attribute     = attr;
+                       m_attrs.push_back(attribute);
+                       el_end = pos;
+               } else
+               {
+                       el_end++;
+               }
+               el_end = txt.find_first_of(_t(".#[:"), el_end);
+       }
+}
+
+
+bool litehtml::css_selector::parse( const tstring& text )
+{
+       if(text.empty())
+       {
+               return false;
+       }
+       string_vector tokens;
+       split_string(text, tokens, _t(""), _t(" \t>+~"), _t("(["));
+
+       if(tokens.empty())
+       {
+               return false;
+       }
+
+       tstring left;
+       tstring right = tokens.back();
+       tchar_t combinator = 0;
+
+       tokens.pop_back();
+       while(!tokens.empty() && (tokens.back() == _t(" ") || tokens.back() == _t("\t") || tokens.back() == _t("+") || tokens.back() == _t("~") || tokens.back() == _t(">")))
+       {
+               if(combinator == _t(' ') || combinator == 0)
+               {
+                       combinator = tokens.back()[0];
+               }
+               tokens.pop_back();
+       }
+
+       for(string_vector::const_iterator i = tokens.begin(); i != tokens.end(); i++)
+       {
+               left += *i;
+       }
+
+       trim(left);
+       trim(right);
+
+       if(right.empty())
+       {
+               return false;
+       }
+
+       m_right.parse(right);
+
+       switch(combinator)
+       {
+       case _t('>'):
+               m_combinator    = combinator_child;
+               break;
+       case _t('+'):
+               m_combinator    = combinator_adjacent_sibling;
+               break;
+       case _t('~'):
+               m_combinator    = combinator_general_sibling;
+               break;
+       default:
+               m_combinator    = combinator_descendant;
+               break;
+       }
+
+       m_left = 0;
+
+       if(!left.empty())
+       {
+               m_left = std::make_shared<css_selector>(media_query_list::ptr(0));
+               if(!m_left->parse(left))
+               {
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+void litehtml::css_selector::calc_specificity()
+{
+       if(!m_right.m_tag.empty() && m_right.m_tag != _t("*"))
+       {
+               m_specificity.d = 1;
+       }
+       for(css_attribute_selector::vector::iterator i = m_right.m_attrs.begin(); i != m_right.m_attrs.end(); i++)
+       {
+               if(i->attribute == _t("id"))
+               {
+                       m_specificity.b++;
+               } else
+               {
+                       if(i->attribute == _t("class"))
+                       {
+                               m_specificity.c += (int) i->class_val.size();
+                       } else
+                       {
+                               m_specificity.c++;
+                       }
+               }       
+       }
+       if(m_left)
+       {
+               m_left->calc_specificity();
+               m_specificity += m_left->m_specificity;
+       }
+}
+
+void litehtml::css_selector::add_media_to_doc( document* doc ) const
+{
+       if(m_media_query && doc)
+       {
+               doc->add_media_list(m_media_query);
+       }
+}
+
index ae8f9c9..d9a0274 100644 (file)
-#pragma once\r
-#include "style.h"\r
-#include "media_query.h"\r
-\r
-namespace litehtml\r
-{\r
-       //////////////////////////////////////////////////////////////////////////\r
-\r
-       struct selector_specificity\r
-       {\r
-               int             a;\r
-               int             b;\r
-               int             c;\r
-               int             d;\r
-\r
-               selector_specificity(int va = 0, int vb = 0, int vc = 0, int vd = 0)\r
-               {\r
-                       a       = va;\r
-                       b       = vb;\r
-                       c       = vc;\r
-                       d       = vd;\r
-               }\r
-\r
-               void operator += (const selector_specificity& val)\r
-               {\r
-                       a       += val.a;\r
-                       b       += val.b;\r
-                       c       += val.c;\r
-                       d       += val.d;\r
-               }\r
-\r
-               bool operator==(const selector_specificity& val) const\r
-               {\r
-                       if(a == val.a && b == val.b && c == val.c && d == val.d)\r
-                       {\r
-                               return true;\r
-                       }\r
-                       return false;\r
-               }\r
-\r
-               bool operator!=(const selector_specificity& val) const\r
-               {\r
-                       if(a != val.a || b != val.b || c != val.c || d != val.d)\r
-                       {\r
-                               return true;\r
-                       }\r
-                       return false;\r
-               }\r
-\r
-               bool operator > (const selector_specificity& val) const\r
-               {\r
-                       if(a > val.a)\r
-                       {\r
-                               return true;\r
-                       } else if(a < val.a)\r
-                       {\r
-                               return false;\r
-                       } else\r
-                       {\r
-                               if(b > val.b)\r
-                               {\r
-                                       return true;\r
-                               } else if(b < val.b)\r
-                               {\r
-                                       return false;\r
-                               } else\r
-                               {\r
-                                       if(c > val.c)\r
-                                       {\r
-                                               return true;\r
-                                       } else if(c < val.c)\r
-                                       {\r
-                                               return false;\r
-                                       } else\r
-                                       {\r
-                                               if(d > val.d)\r
-                                               {\r
-                                                       return true;\r
-                                               } else if(d < val.d)\r
-                                               {\r
-                                                       return false;\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-                       return false;\r
-               }\r
-\r
-               bool operator >= (const selector_specificity& val) const\r
-               {\r
-                       if((*this) == val) return true;\r
-                       if((*this) > val) return true;\r
-                       return false;\r
-               }\r
-\r
-               bool operator <= (const selector_specificity& val) const\r
-               {\r
-                       if((*this) > val)\r
-                       {\r
-                               return false;\r
-                       }\r
-                       return true;\r
-               }\r
-\r
-               bool operator < (const selector_specificity& val) const\r
-               {\r
-                       if((*this) <= val && (*this) != val)\r
-                       {\r
-                               return true;\r
-                       }\r
-                       return false;\r
-               }\r
-\r
-       };\r
-\r
-       //////////////////////////////////////////////////////////////////////////\r
-\r
-       enum attr_select_condition\r
-       {\r
-               select_exists,\r
-               select_equal,\r
-               select_contain_str,\r
-               select_start_str,\r
-               select_end_str,\r
-               select_pseudo_class,\r
-               select_pseudo_element,\r
-       };\r
-\r
-       //////////////////////////////////////////////////////////////////////////\r
-\r
-       struct css_attribute_selector\r
-       {\r
-               typedef std::vector<css_attribute_selector>     vector;\r
-\r
-               tstring                                 attribute;\r
-               tstring                                 val;\r
-               string_vector                   class_val;\r
-               attr_select_condition   condition;\r
-\r
-               css_attribute_selector()\r
-               {\r
-                       condition = select_exists;\r
-               }\r
-       };\r
-\r
-       //////////////////////////////////////////////////////////////////////////\r
-\r
-       class css_element_selector\r
-       {\r
-       public:\r
-               tstring                                                 m_tag;\r
-               css_attribute_selector::vector  m_attrs;\r
-       public:\r
-\r
-               void parse(const tstring& txt);\r
-       };\r
-\r
-       //////////////////////////////////////////////////////////////////////////\r
-\r
-       enum css_combinator\r
-       {\r
-               combinator_descendant,\r
-               combinator_child,\r
-               combinator_adjacent_sibling,\r
-               combinator_general_sibling\r
-       };\r
-\r
-       //////////////////////////////////////////////////////////////////////////\r
-\r
-       class css_selector\r
-       {\r
-       public:\r
-               typedef std::shared_ptr<css_selector>   ptr;\r
-               typedef std::vector<css_selector::ptr>  vector;\r
-       public:\r
-               selector_specificity    m_specificity;\r
-               css_element_selector    m_right;\r
-               css_selector::ptr               m_left;\r
-               css_combinator                  m_combinator;\r
-               style::ptr                              m_style;\r
-               int                                             m_order;\r
-               media_query_list::ptr   m_media_query;\r
-       public:\r
-               css_selector(media_query_list::ptr media)\r
-               {\r
-                       m_media_query   = media;\r
-                       m_combinator    = combinator_descendant;\r
-                       m_order                 = 0;\r
-               }\r
-\r
-               ~css_selector()\r
-               {\r
-               }\r
-\r
-               css_selector(const css_selector& val)\r
-               {\r
-                       m_right                 = val.m_right;\r
-                       if(val.m_left)\r
-                       {\r
-                               m_left                  = std::make_shared<css_selector>(*val.m_left);\r
-                       } else\r
-                       {\r
-                               m_left = 0;\r
-                       }\r
-                       m_combinator    = val.m_combinator;\r
-                       m_specificity   = val.m_specificity;\r
-                       m_order                 = val.m_order;\r
-                       m_media_query   = val.m_media_query;\r
-               }\r
-\r
-               bool parse(const tstring& text);\r
-               void calc_specificity();\r
-               bool is_media_valid() const;\r
-               void add_media_to_doc(document* doc) const;\r
-       };\r
-\r
-       inline bool css_selector::is_media_valid() const\r
-       {\r
-               if(!m_media_query)\r
-               {\r
-                       return true;\r
-               }\r
-               return m_media_query->is_used();\r
-       }\r
-\r
-\r
-       //////////////////////////////////////////////////////////////////////////\r
-\r
-       inline bool operator > (const css_selector& v1, const css_selector& v2)\r
-       {\r
-               if(v1.m_specificity == v2.m_specificity)\r
-               {\r
-                       return (v1.m_order > v2.m_order);\r
-               }\r
-               return (v1.m_specificity > v2.m_specificity);\r
-       }\r
-\r
-       inline bool operator < (const css_selector& v1, const css_selector& v2)\r
-       {\r
-               if(v1.m_specificity == v2.m_specificity)\r
-               {\r
-                       return (v1.m_order < v2.m_order);\r
-               }\r
-               return (v1.m_specificity < v2.m_specificity);\r
-       }\r
-\r
-       inline bool operator >(const css_selector::ptr& v1, const css_selector::ptr& v2)\r
-       {\r
-               return (*v1 > *v2);\r
-       }\r
-\r
-       inline bool operator < (const css_selector::ptr& v1, const css_selector::ptr& v2)\r
-       {\r
-               return (*v1 < *v2);\r
-       }\r
-\r
-       //////////////////////////////////////////////////////////////////////////\r
-\r
-       class used_selector\r
-       {\r
-       public:\r
-               typedef std::unique_ptr<used_selector>  ptr;\r
-               typedef std::vector<used_selector::ptr> vector;\r
-\r
-               css_selector::ptr       m_selector;\r
-               bool                            m_used;\r
-\r
-               used_selector(const css_selector::ptr& selector, bool used)\r
-               {\r
-                       m_used          = used;\r
-                       m_selector      = selector;\r
-               }\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_CSS_SELECTOR_H
+#define LH_CSS_SELECTOR_H
+
+#include "style.h"
+#include "media_query.h"
+
+namespace litehtml
+{
+       //////////////////////////////////////////////////////////////////////////
+
+       struct selector_specificity
+       {
+               int             a;
+               int             b;
+               int             c;
+               int             d;
+
+               selector_specificity(int va = 0, int vb = 0, int vc = 0, int vd = 0)
+               {
+                       a       = va;
+                       b       = vb;
+                       c       = vc;
+                       d       = vd;
+               }
+
+               void operator += (const selector_specificity& val)
+               {
+                       a       += val.a;
+                       b       += val.b;
+                       c       += val.c;
+                       d       += val.d;
+               }
+
+               bool operator==(const selector_specificity& val) const
+               {
+                       if(a == val.a && b == val.b && c == val.c && d == val.d)
+                       {
+                               return true;
+                       }
+                       return false;
+               }
+
+               bool operator!=(const selector_specificity& val) const
+               {
+                       if(a != val.a || b != val.b || c != val.c || d != val.d)
+                       {
+                               return true;
+                       }
+                       return false;
+               }
+
+               bool operator > (const selector_specificity& val) const
+               {
+                       if(a > val.a)
+                       {
+                               return true;
+                       } else if(a < val.a)
+                       {
+                               return false;
+                       } else
+                       {
+                               if(b > val.b)
+                               {
+                                       return true;
+                               } else if(b < val.b)
+                               {
+                                       return false;
+                               } else
+                               {
+                                       if(c > val.c)
+                                       {
+                                               return true;
+                                       } else if(c < val.c)
+                                       {
+                                               return false;
+                                       } else
+                                       {
+                                               if(d > val.d)
+                                               {
+                                                       return true;
+                                               } else if(d < val.d)
+                                               {
+                                                       return false;
+                                               }
+                                       }
+                               }
+                       }
+                       return false;
+               }
+
+               bool operator >= (const selector_specificity& val) const
+               {
+                       if((*this) == val) return true;
+                       if((*this) > val) return true;
+                       return false;
+               }
+
+               bool operator <= (const selector_specificity& val) const
+               {
+                       if((*this) > val)
+                       {
+                               return false;
+                       }
+                       return true;
+               }
+
+               bool operator < (const selector_specificity& val) const
+               {
+                       if((*this) <= val && (*this) != val)
+                       {
+                               return true;
+                       }
+                       return false;
+               }
+
+       };
+
+       //////////////////////////////////////////////////////////////////////////
+
+       enum attr_select_condition
+       {
+               select_exists,
+               select_equal,
+               select_contain_str,
+               select_start_str,
+               select_end_str,
+               select_pseudo_class,
+               select_pseudo_element,
+       };
+
+       //////////////////////////////////////////////////////////////////////////
+
+       struct css_attribute_selector
+       {
+               typedef std::vector<css_attribute_selector>     vector;
+
+               tstring                                 attribute;
+               tstring                                 val;
+               string_vector                   class_val;
+               attr_select_condition   condition;
+
+               css_attribute_selector()
+               {
+                       condition = select_exists;
+               }
+       };
+
+       //////////////////////////////////////////////////////////////////////////
+
+       class css_element_selector
+       {
+       public:
+               tstring                                                 m_tag;
+               css_attribute_selector::vector  m_attrs;
+       public:
+
+               void parse(const tstring& txt);
+       };
+
+       //////////////////////////////////////////////////////////////////////////
+
+       enum css_combinator
+       {
+               combinator_descendant,
+               combinator_child,
+               combinator_adjacent_sibling,
+               combinator_general_sibling
+       };
+
+       //////////////////////////////////////////////////////////////////////////
+
+       class css_selector
+       {
+       public:
+               typedef std::shared_ptr<css_selector>   ptr;
+               typedef std::vector<css_selector::ptr>  vector;
+       public:
+               selector_specificity    m_specificity;
+               css_element_selector    m_right;
+               css_selector::ptr               m_left;
+               css_combinator                  m_combinator;
+               style::ptr                              m_style;
+               int                                             m_order;
+               media_query_list::ptr   m_media_query;
+       public:
+               css_selector(media_query_list::ptr media)
+               {
+                       m_media_query   = media;
+                       m_combinator    = combinator_descendant;
+                       m_order                 = 0;
+               }
+
+               ~css_selector()
+               {
+               }
+
+               css_selector(const css_selector& val)
+               {
+                       m_right                 = val.m_right;
+                       if(val.m_left)
+                       {
+                               m_left                  = std::make_shared<css_selector>(*val.m_left);
+                       } else
+                       {
+                               m_left = 0;
+                       }
+                       m_combinator    = val.m_combinator;
+                       m_specificity   = val.m_specificity;
+                       m_order                 = val.m_order;
+                       m_media_query   = val.m_media_query;
+               }
+
+               bool parse(const tstring& text);
+               void calc_specificity();
+               bool is_media_valid() const;
+               void add_media_to_doc(document* doc) const;
+       };
+
+       inline bool css_selector::is_media_valid() const
+       {
+               if(!m_media_query)
+               {
+                       return true;
+               }
+               return m_media_query->is_used();
+       }
+
+
+       //////////////////////////////////////////////////////////////////////////
+
+       inline bool operator > (const css_selector& v1, const css_selector& v2)
+       {
+               if(v1.m_specificity == v2.m_specificity)
+               {
+                       return (v1.m_order > v2.m_order);
+               }
+               return (v1.m_specificity > v2.m_specificity);
+       }
+
+       inline bool operator < (const css_selector& v1, const css_selector& v2)
+       {
+               if(v1.m_specificity == v2.m_specificity)
+               {
+                       return (v1.m_order < v2.m_order);
+               }
+               return (v1.m_specificity < v2.m_specificity);
+       }
+
+       inline bool operator >(const css_selector::ptr& v1, const css_selector::ptr& v2)
+       {
+               return (*v1 > *v2);
+       }
+
+       inline bool operator < (const css_selector::ptr& v1, const css_selector::ptr& v2)
+       {
+               return (*v1 < *v2);
+       }
+
+       //////////////////////////////////////////////////////////////////////////
+
+       class used_selector
+       {
+       public:
+               typedef std::unique_ptr<used_selector>  ptr;
+               typedef std::vector<used_selector::ptr> vector;
+
+               css_selector::ptr       m_selector;
+               bool                            m_used;
+
+               used_selector(const css_selector::ptr& selector, bool used)
+               {
+                       m_used          = used;
+                       m_selector      = selector;
+               }
+       };
+}
+
+#endif  // LH_CSS_SELECTOR_H
index e9775aa..0be0ea7 100644 (file)
-#include "html.h"\r
-#include "document.h"\r
-#include "stylesheet.h"\r
-#include "html_tag.h"\r
-#include "el_text.h"\r
-#include "el_para.h"\r
-#include "el_space.h"\r
-#include "el_body.h"\r
-#include "el_image.h"\r
-#include "el_table.h"\r
-#include "el_td.h"\r
-#include "el_link.h"\r
-#include "el_title.h"\r
-#include "el_style.h"\r
-#include "el_script.h"\r
-#include "el_comment.h"\r
-#include "el_cdata.h"\r
-#include "el_base.h"\r
-#include "el_anchor.h"\r
-#include "el_break.h"\r
-#include "el_div.h"\r
-#include "el_font.h"\r
-#include "el_tr.h"\r
-#include <math.h>\r
-#include <stdio.h>\r
-#include <algorithm>\r
-#include "gumbo.h"\r
-#include "utf8_strings.h"\r
-\r
-litehtml::document::document(litehtml::document_container* objContainer, litehtml::context* ctx)\r
-{\r
-       m_container     = objContainer;\r
-       m_context       = ctx;\r
-}\r
-\r
-litehtml::document::~document()\r
-{\r
-       m_over_element = 0;\r
-       if(m_container)\r
-       {\r
-               for(fonts_map::iterator f = m_fonts.begin(); f != m_fonts.end(); f++)\r
-               {\r
-                       m_container->delete_font(f->second.font);\r
-               }\r
-       }\r
-}\r
-\r
-litehtml::document::ptr litehtml::document::createFromString( const tchar_t* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles)\r
-{\r
-       return createFromUTF8(litehtml_to_utf8(str), objPainter, ctx, user_styles);\r
-}\r
-\r
-litehtml::document::ptr litehtml::document::createFromUTF8(const char* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles)\r
-{\r
-       // parse document into GumboOutput\r
-       GumboOutput* output = gumbo_parse((const char*) str);\r
-\r
-       // Create litehtml::document\r
-       litehtml::document::ptr doc = std::make_shared<litehtml::document>(objPainter, ctx);\r
-\r
-       // Create litehtml::elements.\r
-       elements_vector root_elements;\r
-       doc->create_node(output->root, root_elements);\r
-       if (!root_elements.empty())\r
-       {\r
-               doc->m_root = root_elements.back();\r
-       }\r
-       // Destroy GumboOutput\r
-       gumbo_destroy_output(&kGumboDefaultOptions, output);\r
-\r
-       // Let's process created elements tree\r
-       if (doc->m_root)\r
-       {\r
-               doc->container()->get_media_features(doc->m_media);\r
-\r
-               // apply master CSS\r
-               doc->m_root->apply_stylesheet(ctx->master_css());\r
-\r
-               // parse elements attributes\r
-               doc->m_root->parse_attributes();\r
-\r
-               // parse style sheets linked in document\r
-               media_query_list::ptr media;\r
-               for (css_text::vector::iterator css = doc->m_css.begin(); css != doc->m_css.end(); css++)\r
-               {\r
-                       if (!css->media.empty())\r
-                       {\r
-                               media = media_query_list::create_from_string(css->media, doc);\r
-                       }\r
-                       else\r
-                       {\r
-                               media = 0;\r
-                       }\r
-                       doc->m_styles.parse_stylesheet(css->text.c_str(), css->baseurl.c_str(), doc, media);\r
-               }\r
-               // Sort css selectors using CSS rules.\r
-               doc->m_styles.sort_selectors();\r
-\r
-               // get current media features\r
-               if (!doc->m_media_lists.empty())\r
-               {\r
-                       doc->update_media_lists(doc->m_media);\r
-               }\r
-\r
-               // Apply parsed styles.\r
-               doc->m_root->apply_stylesheet(doc->m_styles);\r
-\r
-               // Apply user styles if any\r
-               if (user_styles)\r
-               {\r
-                       doc->m_root->apply_stylesheet(*user_styles);\r
-               }\r
-\r
-               // Parse applied styles in the elements\r
-               doc->m_root->parse_styles();\r
-\r
-               // Now the m_tabular_elements is filled with tabular elements.\r
-               // We have to check the tabular elements for missing table elements \r
-               // and create the anonymous boxes in visual table layout\r
-               doc->fix_tables_layout();\r
-\r
-               // Fanaly initialize elements\r
-               doc->m_root->init();\r
-       }\r
-\r
-       return doc;\r
-}\r
-\r
-litehtml::uint_ptr litehtml::document::add_font( const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm )\r
-{\r
-       uint_ptr ret = 0;\r
-\r
-       if( !name || (name && !t_strcasecmp(name, _t("inherit"))) )\r
-       {\r
-               name = m_container->get_default_font_name();\r
-       }\r
-\r
-       if(!size)\r
-       {\r
-               size = container()->get_default_font_size();\r
-       }\r
-\r
-       tchar_t strSize[20];\r
-       t_itoa(size, strSize, 20, 10);\r
-\r
-       tstring key = name;\r
-       key += _t(":");\r
-       key += strSize;\r
-       key += _t(":");\r
-       key += weight;\r
-       key += _t(":");\r
-       key += style;\r
-       key += _t(":");\r
-       key += decoration;\r
-\r
-       if(m_fonts.find(key) == m_fonts.end())\r
-       {\r
-               font_style fs = (font_style) value_index(style, font_style_strings, fontStyleNormal);\r
-               int     fw = value_index(weight, font_weight_strings, -1);\r
-               if(fw >= 0)\r
-               {\r
-                       switch(fw)\r
-                       {\r
-                       case litehtml::fontWeightBold:\r
-                               fw = 700;\r
-                               break;\r
-                       case litehtml::fontWeightBolder:\r
-                               fw = 600;\r
-                               break;\r
-                       case litehtml::fontWeightLighter:\r
-                               fw = 300;\r
-                               break;\r
-                       default:\r
-                               fw = 400;\r
-                               break;\r
-                       }\r
-               } else\r
-               {\r
-                       fw = t_atoi(weight);\r
-                       if(fw < 100)\r
-                       {\r
-                               fw = 400;\r
-                       }\r
-               }\r
-\r
-               unsigned int decor = 0;\r
-\r
-               if(decoration)\r
-               {\r
-                       std::vector<tstring> tokens;\r
-                       split_string(decoration, tokens, _t(" "));\r
-                       for(std::vector<tstring>::iterator i = tokens.begin(); i != tokens.end(); i++)\r
-                       {\r
-                               if(!t_strcasecmp(i->c_str(), _t("underline")))\r
-                               {\r
-                                       decor |= font_decoration_underline;\r
-                               } else if(!t_strcasecmp(i->c_str(), _t("line-through")))\r
-                               {\r
-                                       decor |= font_decoration_linethrough;\r
-                               } else if(!t_strcasecmp(i->c_str(), _t("overline")))\r
-                               {\r
-                                       decor |= font_decoration_overline;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               font_item fi= {0};\r
-\r
-               fi.font = m_container->create_font(name, size, fw, fs, decor, &fi.metrics);\r
-               m_fonts[key] = fi;\r
-               ret = fi.font;\r
-               if(fm)\r
-               {\r
-                       *fm = fi.metrics;\r
-               }\r
-       }\r
-       return ret;\r
-}\r
-\r
-litehtml::uint_ptr litehtml::document::get_font( const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm )\r
-{\r
-       if( !name || (name && !t_strcasecmp(name, _t("inherit"))) )\r
-       {\r
-               name = m_container->get_default_font_name();\r
-       }\r
-\r
-       if(!size)\r
-       {\r
-               size = container()->get_default_font_size();\r
-       }\r
-\r
-       tchar_t strSize[20];\r
-       t_itoa(size, strSize, 20, 10);\r
-\r
-       tstring key = name;\r
-       key += _t(":");\r
-       key += strSize;\r
-       key += _t(":");\r
-       key += weight;\r
-       key += _t(":");\r
-       key += style;\r
-       key += _t(":");\r
-       key += decoration;\r
-\r
-       fonts_map::iterator el = m_fonts.find(key);\r
-\r
-       if(el != m_fonts.end())\r
-       {\r
-               if(fm)\r
-               {\r
-                       *fm = el->second.metrics;\r
-               }\r
-               return el->second.font;\r
-       }\r
-       return add_font(name, size, weight, style, decoration, fm);\r
-}\r
-\r
-int litehtml::document::render( int max_width, render_type rt )\r
-{\r
-       int ret = 0;\r
-       if(m_root)\r
-       {\r
-               if(rt == render_fixed_only)\r
-               {\r
-                       m_fixed_boxes.clear();\r
-                       m_root->render_positioned(rt);\r
-               } else\r
-               {\r
-                       ret = m_root->render(0, 0, max_width);\r
-                       if(m_root->fetch_positioned())\r
-                       {\r
-                               m_fixed_boxes.clear();\r
-                               m_root->render_positioned(rt);\r
-                       }\r
-                       m_size.width    = 0;\r
-                       m_size.height   = 0;\r
-                       m_root->calc_document_size(m_size);\r
-               }\r
-       }\r
-       return ret;\r
-}\r
-\r
-void litehtml::document::draw( uint_ptr hdc, int x, int y, const position* clip )\r
-{\r
-       if(m_root)\r
-       {\r
-               m_root->draw(hdc, x, y, clip);\r
-               m_root->draw_stacking_context(hdc, x, y, clip, true);\r
-       }\r
-}\r
-\r
-int litehtml::document::cvt_units( const tchar_t* str, int fontSize, bool* is_percent/*= 0*/ ) const\r
-{\r
-       if(!str)        return 0;\r
-       \r
-       css_length val;\r
-       val.fromString(str);\r
-       if(is_percent && val.units() == css_units_percentage && !val.is_predefined())\r
-       {\r
-               *is_percent = true;\r
-       }\r
-       return cvt_units(val, fontSize);\r
-}\r
-\r
-int litehtml::document::cvt_units( css_length& val, int fontSize, int size ) const\r
-{\r
-       if(val.is_predefined())\r
-       {\r
-               return 0;\r
-       }\r
-       int ret = 0;\r
-       switch(val.units())\r
-       {\r
-       case css_units_percentage:\r
-               ret = val.calc_percent(size);\r
-               break;\r
-       case css_units_em:\r
-               ret = round_f(val.val() * fontSize);\r
-               val.set_value((float) ret, css_units_px);\r
-               break;\r
-       case css_units_pt:\r
-               ret = m_container->pt_to_px((int) val.val());\r
-               val.set_value((float) ret, css_units_px);\r
-               break;\r
-       case css_units_in:\r
-               ret = m_container->pt_to_px((int) (val.val() * 72));\r
-               val.set_value((float) ret, css_units_px);\r
-               break;\r
-       case css_units_cm:\r
-               ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72));\r
-               val.set_value((float) ret, css_units_px);\r
-               break;\r
-       case css_units_mm:\r
-               ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72) / 10);\r
-               val.set_value((float) ret, css_units_px);\r
-               break;\r
-       case css_units_vw:\r
-               ret = (int)((double)m_media.width * (double)val.val() / 100.0);\r
-               break;\r
-       case css_units_vh:\r
-               ret = (int)((double)m_media.height * (double)val.val() / 100.0);\r
-               break;\r
-       case css_units_vmin:\r
-               ret = (int)((double)std::min(m_media.height, m_media.width) * (double)val.val() / 100.0);\r
-               break;\r
-       case css_units_vmax:\r
-               ret = (int)((double)std::max(m_media.height, m_media.width) * (double)val.val() / 100.0);\r
-               break;\r
-       default:\r
-               ret = (int) val.val();\r
-               break;\r
-       }\r
-       return ret;\r
-}\r
-\r
-int litehtml::document::width() const\r
-{\r
-       return m_size.width;\r
-}\r
-\r
-int litehtml::document::height() const\r
-{\r
-       return m_size.height;\r
-}\r
-\r
-void litehtml::document::add_stylesheet( const tchar_t* str, const tchar_t* baseurl, const tchar_t* media )\r
-{\r
-       if(str && str[0])\r
-       {\r
-               m_css.push_back(css_text(str, baseurl, media));\r
-       }\r
-}\r
-\r
-bool litehtml::document::on_mouse_over( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )\r
-{\r
-       if(!m_root)\r
-       {\r
-               return false;\r
-       }\r
-\r
-       element::ptr over_el = m_root->get_element_by_point(x, y, client_x, client_y);\r
-\r
-       bool state_was_changed = false;\r
-\r
-       if(over_el != m_over_element)\r
-       {\r
-               if(m_over_element)\r
-               {\r
-                       if(m_over_element->on_mouse_leave())\r
-                       {\r
-                               state_was_changed = true;\r
-                       }\r
-               }\r
-               m_over_element = over_el;\r
-       }\r
-\r
-       const tchar_t* cursor = 0;\r
-\r
-       if(m_over_element)\r
-       {\r
-               if(m_over_element->on_mouse_over())\r
-               {\r
-                       state_was_changed = true;\r
-               }\r
-               cursor = m_over_element->get_cursor();\r
-       }\r
-       \r
-       m_container->set_cursor(cursor ? cursor : _t("auto"));\r
-       \r
-       if(state_was_changed)\r
-       {\r
-               return m_root->find_styles_changes(redraw_boxes, 0, 0);\r
-       }\r
-       return false;\r
-}\r
-\r
-bool litehtml::document::on_mouse_leave( position::vector& redraw_boxes )\r
-{\r
-       if(!m_root)\r
-       {\r
-               return false;\r
-       }\r
-       if(m_over_element)\r
-       {\r
-               if(m_over_element->on_mouse_leave())\r
-               {\r
-                       return m_root->find_styles_changes(redraw_boxes, 0, 0);\r
-               }\r
-       }\r
-       return false;\r
-}\r
-\r
-bool litehtml::document::on_lbutton_down( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )\r
-{\r
-       if(!m_root)\r
-       {\r
-               return false;\r
-       }\r
-\r
-       element::ptr over_el = m_root->get_element_by_point(x, y, client_x, client_y);\r
-\r
-       bool state_was_changed = false;\r
-\r
-       if(over_el != m_over_element)\r
-       {\r
-               if(m_over_element)\r
-               {\r
-                       if(m_over_element->on_mouse_leave())\r
-                       {\r
-                               state_was_changed = true;\r
-                       }\r
-               }\r
-               m_over_element = over_el;\r
-               if(m_over_element)\r
-               {\r
-                       if(m_over_element->on_mouse_over())\r
-                       {\r
-                               state_was_changed = true;\r
-                       }\r
-               }\r
-       }\r
-\r
-       const tchar_t* cursor = 0;\r
-\r
-       if(m_over_element)\r
-       {\r
-               if(m_over_element->on_lbutton_down())\r
-               {\r
-                       state_was_changed = true;\r
-               }\r
-               cursor = m_over_element->get_cursor();\r
-       }\r
-\r
-       m_container->set_cursor(cursor ? cursor : _t("auto"));\r
-\r
-       if(state_was_changed)\r
-       {\r
-               return m_root->find_styles_changes(redraw_boxes, 0, 0);\r
-       }\r
-\r
-       return false;\r
-}\r
-\r
-bool litehtml::document::on_lbutton_up( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )\r
-{\r
-       if(!m_root)\r
-       {\r
-               return false;\r
-       }\r
-       if(m_over_element)\r
-       {\r
-               if(m_over_element->on_lbutton_up())\r
-               {\r
-                       return m_root->find_styles_changes(redraw_boxes, 0, 0);\r
-               }\r
-       }\r
-       return false;\r
-}\r
-\r
-litehtml::element::ptr litehtml::document::create_element(const tchar_t* tag_name, const string_map& attributes)\r
-{\r
-       element::ptr newTag;\r
-       document::ptr this_doc = shared_from_this();\r
-       if(m_container)\r
-       {\r
-               newTag = m_container->create_element(tag_name, attributes, this_doc);\r
-       }\r
-       if(!newTag)\r
-       {\r
-               if(!t_strcmp(tag_name, _t("br")))\r
-               {\r
-                       newTag = std::make_shared<litehtml::el_break>(this_doc);\r
-               } else if(!t_strcmp(tag_name, _t("p")))\r
-               {\r
-                       newTag = std::make_shared<litehtml::el_para>(this_doc);\r
-               } else if(!t_strcmp(tag_name, _t("img")))\r
-               {\r
-                       newTag = std::make_shared<litehtml::el_image>(this_doc);\r
-               } else if(!t_strcmp(tag_name, _t("table")))\r
-               {\r
-                       newTag = std::make_shared<litehtml::el_table>(this_doc);\r
-               } else if(!t_strcmp(tag_name, _t("td")) || !t_strcmp(tag_name, _t("th")))\r
-               {\r
-                       newTag = std::make_shared<litehtml::el_td>(this_doc);\r
-               } else if(!t_strcmp(tag_name, _t("link")))\r
-               {\r
-                       newTag = std::make_shared<litehtml::el_link>(this_doc);\r
-               } else if(!t_strcmp(tag_name, _t("title")))\r
-               {\r
-                       newTag = std::make_shared<litehtml::el_title>(this_doc);\r
-               } else if(!t_strcmp(tag_name, _t("a")))\r
-               {\r
-                       newTag = std::make_shared<litehtml::el_anchor>(this_doc);\r
-               } else if(!t_strcmp(tag_name, _t("tr")))\r
-               {\r
-                       newTag = std::make_shared<litehtml::el_tr>(this_doc);\r
-               } else if(!t_strcmp(tag_name, _t("style")))\r
-               {\r
-                       newTag = std::make_shared<litehtml::el_style>(this_doc);\r
-               } else if(!t_strcmp(tag_name, _t("base")))\r
-               {\r
-                       newTag = std::make_shared<litehtml::el_base>(this_doc);\r
-               } else if(!t_strcmp(tag_name, _t("body")))\r
-               {\r
-                       newTag = std::make_shared<litehtml::el_body>(this_doc);\r
-               } else if(!t_strcmp(tag_name, _t("div")))\r
-               {\r
-                       newTag = std::make_shared<litehtml::el_div>(this_doc);\r
-               } else if(!t_strcmp(tag_name, _t("script")))\r
-               {\r
-                       newTag = std::make_shared<litehtml::el_script>(this_doc);\r
-               } else if(!t_strcmp(tag_name, _t("font")))\r
-               {\r
-                       newTag = std::make_shared<litehtml::el_font>(this_doc);\r
-               } else\r
-               {\r
-                       newTag = std::make_shared<litehtml::html_tag>(this_doc);\r
-               }\r
-       }\r
-\r
-       if(newTag)\r
-       {\r
-               newTag->set_tagName(tag_name);\r
-               for (string_map::const_iterator iter = attributes.begin(); iter != attributes.end(); iter++)\r
-               {\r
-                       newTag->set_attr(iter->first.c_str(), iter->second.c_str());\r
-               }\r
-       }\r
-\r
-       return newTag;\r
-}\r
-\r
-void litehtml::document::get_fixed_boxes( position::vector& fixed_boxes )\r
-{\r
-       fixed_boxes = m_fixed_boxes;\r
-}\r
-\r
-void litehtml::document::add_fixed_box( const position& pos )\r
-{\r
-       m_fixed_boxes.push_back(pos);\r
-}\r
-\r
-bool litehtml::document::media_changed()\r
-{\r
-       if(!m_media_lists.empty())\r
-       {\r
-               container()->get_media_features(m_media);\r
-               if (update_media_lists(m_media))\r
-               {\r
-                       m_root->refresh_styles();\r
-                       m_root->parse_styles();\r
-                       return true;\r
-               }\r
-       }\r
-       return false;\r
-}\r
-\r
-bool litehtml::document::lang_changed()\r
-{\r
-       if(!m_media_lists.empty())\r
-       {\r
-               tstring culture;\r
-               container()->get_language(m_lang, culture);\r
-               if(!culture.empty())\r
-               {\r
-                       m_culture = m_lang + _t('-') + culture;\r
-               }\r
-               else\r
-               {\r
-                       m_culture.clear();\r
-               }\r
-               m_root->refresh_styles();\r
-               m_root->parse_styles();\r
-               return true;\r
-       }\r
-       return false;\r
-}\r
-\r
-bool litehtml::document::update_media_lists(const media_features& features)\r
-{\r
-       bool update_styles = false;\r
-       for(media_query_list::vector::iterator iter = m_media_lists.begin(); iter != m_media_lists.end(); iter++)\r
-       {\r
-               if((*iter)->apply_media_features(features))\r
-               {\r
-                       update_styles = true;\r
-               }\r
-       }\r
-       return update_styles;\r
-}\r
-\r
-void litehtml::document::add_media_list( media_query_list::ptr list )\r
-{\r
-       if(list)\r
-       {\r
-               if(std::find(m_media_lists.begin(), m_media_lists.end(), list) == m_media_lists.end())\r
-               {\r
-                       m_media_lists.push_back(list);\r
-               }\r
-       }\r
-}\r
-\r
-void litehtml::document::create_node(GumboNode* node, elements_vector& elements)\r
-{\r
-       switch (node->type)\r
-       {\r
-       case GUMBO_NODE_ELEMENT:\r
-               {\r
-                       string_map attrs;\r
-                       GumboAttribute* attr;\r
-                       for (unsigned int i = 0; i < node->v.element.attributes.length; i++)\r
-                       {\r
-                               attr = (GumboAttribute*)node->v.element.attributes.data[i];\r
-                               attrs[tstring(litehtml_from_utf8(attr->name))] = litehtml_from_utf8(attr->value);\r
-                       }\r
-\r
-\r
-                       element::ptr ret;\r
-                       const char* tag = gumbo_normalized_tagname(node->v.element.tag);\r
-                       if (tag[0])\r
-                       {\r
-                               ret = create_element(litehtml_from_utf8(tag), attrs);\r
-                       }\r
-                       else\r
-                       {\r
-                               if (node->v.element.original_tag.data && node->v.element.original_tag.length)\r
-                               {\r
-                                       std::string strA;\r
-                                       gumbo_tag_from_original_text(&node->v.element.original_tag);\r
-                                       strA.append(node->v.element.original_tag.data, node->v.element.original_tag.length);\r
-                                       ret = create_element(litehtml_from_utf8(strA.c_str()), attrs);\r
-                               }\r
-                       }\r
-                       if (ret)\r
-                       {\r
-                               elements_vector child;\r
-                               for (unsigned int i = 0; i < node->v.element.children.length; i++)\r
-                               {\r
-                                       child.clear();\r
-                                       create_node(static_cast<GumboNode*> (node->v.element.children.data[i]), child);\r
-                                       std::for_each(child.begin(), child.end(), \r
-                                               [&ret](element::ptr& el)\r
-                                               {\r
-                                                       ret->appendChild(el);\r
-                                               }\r
-                                       );\r
-                               }\r
-                               elements.push_back(ret);\r
-                       }\r
-               }\r
-               break;\r
-       case GUMBO_NODE_TEXT:\r
-               {\r
-                       std::wstring str;\r
-                       std::wstring str_in = (const wchar_t*) (utf8_to_wchar(node->v.text.text));\r
-                       ucode_t c;\r
-                       for (size_t i = 0; i < str_in.length(); i++)\r
-                       {\r
-                               c = (ucode_t) str_in[i];\r
-                               if (c <= ' ' && (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f'))\r
-                               {\r
-                                       if (!str.empty())\r
-                                       {\r
-                                               elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));\r
-                                               str.clear();\r
-                                       }\r
-                                       str += c;\r
-                                       elements.push_back(std::make_shared<el_space>(litehtml_from_wchar(str.c_str()), shared_from_this()));\r
-                                       str.clear();\r
-                               }\r
-                               // CJK character range\r
-                               else if (c >= 0x4E00 && c <= 0x9FCC)\r
-                               {\r
-                                       if (!str.empty())\r
-                                       {\r
-                                               elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));\r
-                                               str.clear();\r
-                                       }\r
-                                       str += c;\r
-                                       elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));\r
-                                       str.clear();\r
-                               }\r
-                               else\r
-                               {\r
-                                       str += c;\r
-                               }\r
-                       }\r
-                       if (!str.empty())\r
-                       {\r
-                               elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));\r
-                       }\r
-               }\r
-               break;\r
-       case GUMBO_NODE_CDATA:\r
-               {\r
-                       element::ptr ret = std::make_shared<el_cdata>(shared_from_this());\r
-                       ret->set_data(litehtml_from_utf8(node->v.text.text));\r
-                       elements.push_back(ret);\r
-               }\r
-               break;\r
-       case GUMBO_NODE_COMMENT:\r
-               {\r
-                       element::ptr ret = std::make_shared<el_comment>(shared_from_this());\r
-                       ret->set_data(litehtml_from_utf8(node->v.text.text));\r
-                       elements.push_back(ret);\r
-               }\r
-               break;\r
-       case GUMBO_NODE_WHITESPACE:\r
-               {\r
-                       tstring str = litehtml_from_utf8(node->v.text.text);\r
-                       for (size_t i = 0; i < str.length(); i++)\r
-                       {\r
-                               elements.push_back(std::make_shared<el_space>(str.substr(i, 1).c_str(), shared_from_this()));\r
-                       }\r
-               }\r
-               break;\r
-       default:\r
-               break;\r
-       }\r
-}\r
-\r
-void litehtml::document::fix_tables_layout()\r
-{\r
-       size_t i = 0;\r
-       while (i < m_tabular_elements.size())\r
-       {\r
-               element::ptr el_ptr = m_tabular_elements[i];\r
-\r
-               switch (el_ptr->get_display())\r
-               {\r
-               case display_inline_table:\r
-               case display_table:\r
-                       fix_table_children(el_ptr, display_table_row_group, _t("table-row-group"));\r
-                       break;\r
-               case display_table_footer_group:\r
-               case display_table_row_group:\r
-               case display_table_header_group:\r
-                       fix_table_parent(el_ptr, display_table, _t("table"));\r
-                       fix_table_children(el_ptr, display_table_row, _t("table-row"));\r
-                       break;\r
-               case display_table_row:\r
-                       fix_table_parent(el_ptr, display_table_row_group, _t("table-row-group"));\r
-                       fix_table_children(el_ptr, display_table_cell, _t("table-cell"));\r
-                       break;\r
-               case display_table_cell:\r
-                       fix_table_parent(el_ptr, display_table_row, _t("table-row"));\r
-                       break;\r
-               // TODO: make table layout fix for table-caption, table-column etc. elements\r
-               case display_table_caption:\r
-               case display_table_column:\r
-               case display_table_column_group:\r
-               default:\r
-                       break;\r
-               }\r
-               i++;\r
-       }\r
-}\r
-\r
-void litehtml::document::fix_table_children(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str)\r
-{\r
-       elements_vector tmp;\r
-       elements_vector::iterator first_iter = el_ptr->m_children.begin();\r
-       elements_vector::iterator cur_iter = el_ptr->m_children.begin();\r
-\r
-       auto flush_elements = [&]()\r
-       {\r
-               element::ptr annon_tag = std::make_shared<html_tag>(shared_from_this());\r
-               style st;\r
-               st.add_property(_t("display"), disp_str, 0, false);\r
-               annon_tag->add_style(st);\r
-               annon_tag->parent(el_ptr);\r
-               annon_tag->parse_styles();\r
-               std::for_each(tmp.begin(), tmp.end(),\r
-                       [&annon_tag](element::ptr& el)\r
-                       {\r
-                               annon_tag->appendChild(el);\r
-                       }\r
-               );\r
-               first_iter = el_ptr->m_children.insert(first_iter, annon_tag);\r
-               cur_iter = first_iter + 1;\r
-               while (cur_iter != el_ptr->m_children.end() && (*cur_iter)->parent() != el_ptr)\r
-               {\r
-                       cur_iter = el_ptr->m_children.erase(cur_iter);\r
-               }\r
-               first_iter = cur_iter;\r
-               tmp.clear();\r
-       };\r
-\r
-       while (cur_iter != el_ptr->m_children.end())\r
-       {\r
-               if ((*cur_iter)->get_display() != disp)\r
-               {\r
-                       if (!(*cur_iter)->is_white_space() || ((*cur_iter)->is_white_space() && !tmp.empty()))\r
-                       {\r
-                               if (tmp.empty())\r
-                               {\r
-                                       first_iter = cur_iter;\r
-                               }\r
-                               tmp.push_back((*cur_iter));\r
-                       }\r
-                       cur_iter++;\r
-               }\r
-               else if (!tmp.empty())\r
-               {\r
-                       flush_elements();\r
-               }\r
-               else\r
-               {\r
-                       cur_iter++;\r
-               }\r
-       }\r
-       if (!tmp.empty())\r
-       {\r
-               flush_elements();\r
-       }\r
-}\r
-\r
-void litehtml::document::fix_table_parent(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str)\r
-{\r
-       element::ptr parent = el_ptr->parent();\r
-\r
-       if (parent->get_display() != disp)\r
-       {\r
-               elements_vector::iterator this_element = std::find_if(parent->m_children.begin(), parent->m_children.end(),\r
-                       [&](element::ptr& el)\r
-                       {\r
-                               if (el == el_ptr)\r
-                               {\r
-                                       return true;\r
-                               }\r
-                               return false;\r
-                       }\r
-               );\r
-               if (this_element != parent->m_children.end())\r
-               {\r
-                       style_display el_disp = el_ptr->get_display();\r
-                       elements_vector::iterator first = this_element;\r
-                       elements_vector::iterator last = this_element;\r
-                       elements_vector::iterator cur = this_element;\r
-\r
-                       // find first element with same display\r
-                       while (true)\r
-                       {\r
-                               if (cur == parent->m_children.begin()) break;\r
-                               cur--;\r
-                               if ((*cur)->is_white_space() || (*cur)->get_display() == el_disp)\r
-                               {\r
-                                       first = cur;\r
-                               }\r
-                               else\r
-                               {\r
-                                       break;\r
-                               }\r
-                       }\r
-\r
-                       // find last element with same display\r
-                       cur = this_element;\r
-                       while (true)\r
-                       {\r
-                               cur++;\r
-                               if (cur == parent->m_children.end()) break;\r
-\r
-                               if ((*cur)->is_white_space() || (*cur)->get_display() == el_disp)\r
-                               {\r
-                                       last = cur;\r
-                               }\r
-                               else\r
-                               {\r
-                                       break;\r
-                               }\r
-                       }\r
-\r
-                       // extract elements with the same display and wrap them with anonymous object\r
-                       element::ptr annon_tag = std::make_shared<html_tag>(shared_from_this());\r
-                       style st;\r
-                       st.add_property(_t("display"), disp_str, 0, false);\r
-                       annon_tag->add_style(st);\r
-                       annon_tag->parent(parent);\r
-                       annon_tag->parse_styles();\r
-                       std::for_each(first, last + 1,\r
-                               [&annon_tag](element::ptr& el)\r
-                               {\r
-                                       annon_tag->appendChild(el);\r
-                               }\r
-                       );\r
-                       first = parent->m_children.erase(first, last + 1);\r
-                       parent->m_children.insert(first, annon_tag);\r
-               }\r
-       }\r
-}\r
+#include "html.h"
+#include "document.h"
+#include "stylesheet.h"
+#include "html_tag.h"
+#include "el_text.h"
+#include "el_para.h"
+#include "el_space.h"
+#include "el_body.h"
+#include "el_image.h"
+#include "el_table.h"
+#include "el_td.h"
+#include "el_link.h"
+#include "el_title.h"
+#include "el_style.h"
+#include "el_script.h"
+#include "el_comment.h"
+#include "el_cdata.h"
+#include "el_base.h"
+#include "el_anchor.h"
+#include "el_break.h"
+#include "el_div.h"
+#include "el_font.h"
+#include "el_tr.h"
+#include <math.h>
+#include <stdio.h>
+#include <algorithm>
+#include "gumbo.h"
+#include "utf8_strings.h"
+
+litehtml::document::document(litehtml::document_container* objContainer, litehtml::context* ctx)
+{
+       m_container     = objContainer;
+       m_context       = ctx;
+}
+
+litehtml::document::~document()
+{
+       m_over_element = 0;
+       if(m_container)
+       {
+               for(fonts_map::iterator f = m_fonts.begin(); f != m_fonts.end(); f++)
+               {
+                       m_container->delete_font(f->second.font);
+               }
+       }
+}
+
+litehtml::document::ptr litehtml::document::createFromString( const tchar_t* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles)
+{
+       return createFromUTF8(litehtml_to_utf8(str), objPainter, ctx, user_styles);
+}
+
+litehtml::document::ptr litehtml::document::createFromUTF8(const char* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles)
+{
+       // parse document into GumboOutput
+       GumboOutput* output = gumbo_parse((const char*) str);
+
+       // Create litehtml::document
+       litehtml::document::ptr doc = std::make_shared<litehtml::document>(objPainter, ctx);
+
+       // Create litehtml::elements.
+       elements_vector root_elements;
+       doc->create_node(output->root, root_elements);
+       if (!root_elements.empty())
+       {
+               doc->m_root = root_elements.back();
+       }
+       // Destroy GumboOutput
+       gumbo_destroy_output(&kGumboDefaultOptions, output);
+
+       // Let's process created elements tree
+       if (doc->m_root)
+       {
+               doc->container()->get_media_features(doc->m_media);
+
+               // apply master CSS
+               doc->m_root->apply_stylesheet(ctx->master_css());
+
+               // parse elements attributes
+               doc->m_root->parse_attributes();
+
+               // parse style sheets linked in document
+               media_query_list::ptr media;
+               for (css_text::vector::iterator css = doc->m_css.begin(); css != doc->m_css.end(); css++)
+               {
+                       if (!css->media.empty())
+                       {
+                               media = media_query_list::create_from_string(css->media, doc);
+                       }
+                       else
+                       {
+                               media = 0;
+                       }
+                       doc->m_styles.parse_stylesheet(css->text.c_str(), css->baseurl.c_str(), doc, media);
+               }
+               // Sort css selectors using CSS rules.
+               doc->m_styles.sort_selectors();
+
+               // get current media features
+               if (!doc->m_media_lists.empty())
+               {
+                       doc->update_media_lists(doc->m_media);
+               }
+
+               // Apply parsed styles.
+               doc->m_root->apply_stylesheet(doc->m_styles);
+
+               // Apply user styles if any
+               if (user_styles)
+               {
+                       doc->m_root->apply_stylesheet(*user_styles);
+               }
+
+               // Parse applied styles in the elements
+               doc->m_root->parse_styles();
+
+               // Now the m_tabular_elements is filled with tabular elements.
+               // We have to check the tabular elements for missing table elements 
+               // and create the anonymous boxes in visual table layout
+               doc->fix_tables_layout();
+
+               // Fanaly initialize elements
+               doc->m_root->init();
+       }
+
+       return doc;
+}
+
+litehtml::uint_ptr litehtml::document::add_font( const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm )
+{
+       uint_ptr ret = 0;
+
+       if( !name || (name && !t_strcasecmp(name, _t("inherit"))) )
+       {
+               name = m_container->get_default_font_name();
+       }
+
+       if(!size)
+       {
+               size = container()->get_default_font_size();
+       }
+
+       tchar_t strSize[20];
+       t_itoa(size, strSize, 20, 10);
+
+       tstring key = name;
+       key += _t(":");
+       key += strSize;
+       key += _t(":");
+       key += weight;
+       key += _t(":");
+       key += style;
+       key += _t(":");
+       key += decoration;
+
+       if(m_fonts.find(key) == m_fonts.end())
+       {
+               font_style fs = (font_style) value_index(style, font_style_strings, fontStyleNormal);
+               int     fw = value_index(weight, font_weight_strings, -1);
+               if(fw >= 0)
+               {
+                       switch(fw)
+                       {
+                       case litehtml::fontWeightBold:
+                               fw = 700;
+                               break;
+                       case litehtml::fontWeightBolder:
+                               fw = 600;
+                               break;
+                       case litehtml::fontWeightLighter:
+                               fw = 300;
+                               break;
+                       default:
+                               fw = 400;
+                               break;
+                       }
+               } else
+               {
+                       fw = t_atoi(weight);
+                       if(fw < 100)
+                       {
+                               fw = 400;
+                       }
+               }
+
+               unsigned int decor = 0;
+
+               if(decoration)
+               {
+                       std::vector<tstring> tokens;
+                       split_string(decoration, tokens, _t(" "));
+                       for(std::vector<tstring>::iterator i = tokens.begin(); i != tokens.end(); i++)
+                       {
+                               if(!t_strcasecmp(i->c_str(), _t("underline")))
+                               {
+                                       decor |= font_decoration_underline;
+                               } else if(!t_strcasecmp(i->c_str(), _t("line-through")))
+                               {
+                                       decor |= font_decoration_linethrough;
+                               } else if(!t_strcasecmp(i->c_str(), _t("overline")))
+                               {
+                                       decor |= font_decoration_overline;
+                               }
+                       }
+               }
+
+               font_item fi= {0};
+
+               fi.font = m_container->create_font(name, size, fw, fs, decor, &fi.metrics);
+               m_fonts[key] = fi;
+               ret = fi.font;
+               if(fm)
+               {
+                       *fm = fi.metrics;
+               }
+       }
+       return ret;
+}
+
+litehtml::uint_ptr litehtml::document::get_font( const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm )
+{
+       if( !name || (name && !t_strcasecmp(name, _t("inherit"))) )
+       {
+               name = m_container->get_default_font_name();
+       }
+
+       if(!size)
+       {
+               size = container()->get_default_font_size();
+       }
+
+       tchar_t strSize[20];
+       t_itoa(size, strSize, 20, 10);
+
+       tstring key = name;
+       key += _t(":");
+       key += strSize;
+       key += _t(":");
+       key += weight;
+       key += _t(":");
+       key += style;
+       key += _t(":");
+       key += decoration;
+
+       fonts_map::iterator el = m_fonts.find(key);
+
+       if(el != m_fonts.end())
+       {
+               if(fm)
+               {
+                       *fm = el->second.metrics;
+               }
+               return el->second.font;
+       }
+       return add_font(name, size, weight, style, decoration, fm);
+}
+
+int litehtml::document::render( int max_width, render_type rt )
+{
+       int ret = 0;
+       if(m_root)
+       {
+               if(rt == render_fixed_only)
+               {
+                       m_fixed_boxes.clear();
+                       m_root->render_positioned(rt);
+               } else
+               {
+                       ret = m_root->render(0, 0, max_width);
+                       if(m_root->fetch_positioned())
+                       {
+                               m_fixed_boxes.clear();
+                               m_root->render_positioned(rt);
+                       }
+                       m_size.width    = 0;
+                       m_size.height   = 0;
+                       m_root->calc_document_size(m_size);
+               }
+       }
+       return ret;
+}
+
+void litehtml::document::draw( uint_ptr hdc, int x, int y, const position* clip )
+{
+       if(m_root)
+       {
+               m_root->draw(hdc, x, y, clip);
+               m_root->draw_stacking_context(hdc, x, y, clip, true);
+       }
+}
+
+int litehtml::document::cvt_units( const tchar_t* str, int fontSize, bool* is_percent/*= 0*/ ) const
+{
+       if(!str)        return 0;
+       
+       css_length val;
+       val.fromString(str);
+       if(is_percent && val.units() == css_units_percentage && !val.is_predefined())
+       {
+               *is_percent = true;
+       }
+       return cvt_units(val, fontSize);
+}
+
+int litehtml::document::cvt_units( css_length& val, int fontSize, int size ) const
+{
+       if(val.is_predefined())
+       {
+               return 0;
+       }
+       int ret = 0;
+       switch(val.units())
+       {
+       case css_units_percentage:
+               ret = val.calc_percent(size);
+               break;
+       case css_units_em:
+               ret = round_f(val.val() * fontSize);
+               val.set_value((float) ret, css_units_px);
+               break;
+       case css_units_pt:
+               ret = m_container->pt_to_px((int) val.val());
+               val.set_value((float) ret, css_units_px);
+               break;
+       case css_units_in:
+               ret = m_container->pt_to_px((int) (val.val() * 72));
+               val.set_value((float) ret, css_units_px);
+               break;
+       case css_units_cm:
+               ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72));
+               val.set_value((float) ret, css_units_px);
+               break;
+       case css_units_mm:
+               ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72) / 10);
+               val.set_value((float) ret, css_units_px);
+               break;
+       case css_units_vw:
+               ret = (int)((double)m_media.width * (double)val.val() / 100.0);
+               break;
+       case css_units_vh:
+               ret = (int)((double)m_media.height * (double)val.val() / 100.0);
+               break;
+       case css_units_vmin:
+               ret = (int)((double)std::min(m_media.height, m_media.width) * (double)val.val() / 100.0);
+               break;
+       case css_units_vmax:
+               ret = (int)((double)std::max(m_media.height, m_media.width) * (double)val.val() / 100.0);
+               break;
+       default:
+               ret = (int) val.val();
+               break;
+       }
+       return ret;
+}
+
+int litehtml::document::width() const
+{
+       return m_size.width;
+}
+
+int litehtml::document::height() const
+{
+       return m_size.height;
+}
+
+void litehtml::document::add_stylesheet( const tchar_t* str, const tchar_t* baseurl, const tchar_t* media )
+{
+       if(str && str[0])
+       {
+               m_css.push_back(css_text(str, baseurl, media));
+       }
+}
+
+bool litehtml::document::on_mouse_over( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )
+{
+       if(!m_root)
+       {
+               return false;
+       }
+
+       element::ptr over_el = m_root->get_element_by_point(x, y, client_x, client_y);
+
+       bool state_was_changed = false;
+
+       if(over_el != m_over_element)
+       {
+               if(m_over_element)
+               {
+                       if(m_over_element->on_mouse_leave())
+                       {
+                               state_was_changed = true;
+                       }
+               }
+               m_over_element = over_el;
+       }
+
+       const tchar_t* cursor = 0;
+
+       if(m_over_element)
+       {
+               if(m_over_element->on_mouse_over())
+               {
+                       state_was_changed = true;
+               }
+               cursor = m_over_element->get_cursor();
+       }
+       
+       m_container->set_cursor(cursor ? cursor : _t("auto"));
+       
+       if(state_was_changed)
+       {
+               return m_root->find_styles_changes(redraw_boxes, 0, 0);
+       }
+       return false;
+}
+
+bool litehtml::document::on_mouse_leave( position::vector& redraw_boxes )
+{
+       if(!m_root)
+       {
+               return false;
+       }
+       if(m_over_element)
+       {
+               if(m_over_element->on_mouse_leave())
+               {
+                       return m_root->find_styles_changes(redraw_boxes, 0, 0);
+               }
+       }
+       return false;
+}
+
+bool litehtml::document::on_lbutton_down( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )
+{
+       if(!m_root)
+       {
+               return false;
+       }
+
+       element::ptr over_el = m_root->get_element_by_point(x, y, client_x, client_y);
+
+       bool state_was_changed = false;
+
+       if(over_el != m_over_element)
+       {
+               if(m_over_element)
+               {
+                       if(m_over_element->on_mouse_leave())
+                       {
+                               state_was_changed = true;
+                       }
+               }
+               m_over_element = over_el;
+               if(m_over_element)
+               {
+                       if(m_over_element->on_mouse_over())
+                       {
+                               state_was_changed = true;
+                       }
+               }
+       }
+
+       const tchar_t* cursor = 0;
+
+       if(m_over_element)
+       {
+               if(m_over_element->on_lbutton_down())
+               {
+                       state_was_changed = true;
+               }
+               cursor = m_over_element->get_cursor();
+       }
+
+       m_container->set_cursor(cursor ? cursor : _t("auto"));
+
+       if(state_was_changed)
+       {
+               return m_root->find_styles_changes(redraw_boxes, 0, 0);
+       }
+
+       return false;
+}
+
+bool litehtml::document::on_lbutton_up( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )
+{
+       if(!m_root)
+       {
+               return false;
+       }
+       if(m_over_element)
+       {
+               if(m_over_element->on_lbutton_up())
+               {
+                       return m_root->find_styles_changes(redraw_boxes, 0, 0);
+               }
+       }
+       return false;
+}
+
+litehtml::element::ptr litehtml::document::create_element(const tchar_t* tag_name, const string_map& attributes)
+{
+       element::ptr newTag;
+       document::ptr this_doc = shared_from_this();
+       if(m_container)
+       {
+               newTag = m_container->create_element(tag_name, attributes, this_doc);
+       }
+       if(!newTag)
+       {
+               if(!t_strcmp(tag_name, _t("br")))
+               {
+                       newTag = std::make_shared<litehtml::el_break>(this_doc);
+               } else if(!t_strcmp(tag_name, _t("p")))
+               {
+                       newTag = std::make_shared<litehtml::el_para>(this_doc);
+               } else if(!t_strcmp(tag_name, _t("img")))
+               {
+                       newTag = std::make_shared<litehtml::el_image>(this_doc);
+               } else if(!t_strcmp(tag_name, _t("table")))
+               {
+                       newTag = std::make_shared<litehtml::el_table>(this_doc);
+               } else if(!t_strcmp(tag_name, _t("td")) || !t_strcmp(tag_name, _t("th")))
+               {
+                       newTag = std::make_shared<litehtml::el_td>(this_doc);
+               } else if(!t_strcmp(tag_name, _t("link")))
+               {
+                       newTag = std::make_shared<litehtml::el_link>(this_doc);
+               } else if(!t_strcmp(tag_name, _t("title")))
+               {
+                       newTag = std::make_shared<litehtml::el_title>(this_doc);
+               } else if(!t_strcmp(tag_name, _t("a")))
+               {
+                       newTag = std::make_shared<litehtml::el_anchor>(this_doc);
+               } else if(!t_strcmp(tag_name, _t("tr")))
+               {
+                       newTag = std::make_shared<litehtml::el_tr>(this_doc);
+               } else if(!t_strcmp(tag_name, _t("style")))
+               {
+                       newTag = std::make_shared<litehtml::el_style>(this_doc);
+               } else if(!t_strcmp(tag_name, _t("base")))
+               {
+                       newTag = std::make_shared<litehtml::el_base>(this_doc);
+               } else if(!t_strcmp(tag_name, _t("body")))
+               {
+                       newTag = std::make_shared<litehtml::el_body>(this_doc);
+               } else if(!t_strcmp(tag_name, _t("div")))
+               {
+                       newTag = std::make_shared<litehtml::el_div>(this_doc);
+               } else if(!t_strcmp(tag_name, _t("script")))
+               {
+                       newTag = std::make_shared<litehtml::el_script>(this_doc);
+               } else if(!t_strcmp(tag_name, _t("font")))
+               {
+                       newTag = std::make_shared<litehtml::el_font>(this_doc);
+               } else
+               {
+                       newTag = std::make_shared<litehtml::html_tag>(this_doc);
+               }
+       }
+
+       if(newTag)
+       {
+               newTag->set_tagName(tag_name);
+               for (string_map::const_iterator iter = attributes.begin(); iter != attributes.end(); iter++)
+               {
+                       newTag->set_attr(iter->first.c_str(), iter->second.c_str());
+               }
+       }
+
+       return newTag;
+}
+
+void litehtml::document::get_fixed_boxes( position::vector& fixed_boxes )
+{
+       fixed_boxes = m_fixed_boxes;
+}
+
+void litehtml::document::add_fixed_box( const position& pos )
+{
+       m_fixed_boxes.push_back(pos);
+}
+
+bool litehtml::document::media_changed()
+{
+       if(!m_media_lists.empty())
+       {
+               container()->get_media_features(m_media);
+               if (update_media_lists(m_media))
+               {
+                       m_root->refresh_styles();
+                       m_root->parse_styles();
+                       return true;
+               }
+       }
+       return false;
+}
+
+bool litehtml::document::lang_changed()
+{
+       if(!m_media_lists.empty())
+       {
+               tstring culture;
+               container()->get_language(m_lang, culture);
+               if(!culture.empty())
+               {
+                       m_culture = m_lang + _t('-') + culture;
+               }
+               else
+               {
+                       m_culture.clear();
+               }
+               m_root->refresh_styles();
+               m_root->parse_styles();
+               return true;
+       }
+       return false;
+}
+
+bool litehtml::document::update_media_lists(const media_features& features)
+{
+       bool update_styles = false;
+       for(media_query_list::vector::iterator iter = m_media_lists.begin(); iter != m_media_lists.end(); iter++)
+       {
+               if((*iter)->apply_media_features(features))
+               {
+                       update_styles = true;
+               }
+       }
+       return update_styles;
+}
+
+void litehtml::document::add_media_list( media_query_list::ptr list )
+{
+       if(list)
+       {
+               if(std::find(m_media_lists.begin(), m_media_lists.end(), list) == m_media_lists.end())
+               {
+                       m_media_lists.push_back(list);
+               }
+       }
+}
+
+void litehtml::document::create_node(GumboNode* node, elements_vector& elements)
+{
+       switch (node->type)
+       {
+       case GUMBO_NODE_ELEMENT:
+               {
+                       string_map attrs;
+                       GumboAttribute* attr;
+                       for (unsigned int i = 0; i < node->v.element.attributes.length; i++)
+                       {
+                               attr = (GumboAttribute*)node->v.element.attributes.data[i];
+                               attrs[tstring(litehtml_from_utf8(attr->name))] = litehtml_from_utf8(attr->value);
+                       }
+
+
+                       element::ptr ret;
+                       const char* tag = gumbo_normalized_tagname(node->v.element.tag);
+                       if (tag[0])
+                       {
+                               ret = create_element(litehtml_from_utf8(tag), attrs);
+                       }
+                       else
+                       {
+                               if (node->v.element.original_tag.data && node->v.element.original_tag.length)
+                               {
+                                       std::string strA;
+                                       gumbo_tag_from_original_text(&node->v.element.original_tag);
+                                       strA.append(node->v.element.original_tag.data, node->v.element.original_tag.length);
+                                       ret = create_element(litehtml_from_utf8(strA.c_str()), attrs);
+                               }
+                       }
+                       if (ret)
+                       {
+                               elements_vector child;
+                               for (unsigned int i = 0; i < node->v.element.children.length; i++)
+                               {
+                                       child.clear();
+                                       create_node(static_cast<GumboNode*> (node->v.element.children.data[i]), child);
+                                       std::for_each(child.begin(), child.end(), 
+                                               [&ret](element::ptr& el)
+                                               {
+                                                       ret->appendChild(el);
+                                               }
+                                       );
+                               }
+                               elements.push_back(ret);
+                       }
+               }
+               break;
+       case GUMBO_NODE_TEXT:
+               {
+                       std::wstring str;
+                       std::wstring str_in = (const wchar_t*) (utf8_to_wchar(node->v.text.text));
+                       ucode_t c;
+                       for (size_t i = 0; i < str_in.length(); i++)
+                       {
+                               c = (ucode_t) str_in[i];
+                               if (c <= ' ' && (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f'))
+                               {
+                                       if (!str.empty())
+                                       {
+                                               elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
+                                               str.clear();
+                                       }
+                                       str += c;
+                                       elements.push_back(std::make_shared<el_space>(litehtml_from_wchar(str.c_str()), shared_from_this()));
+                                       str.clear();
+                               }
+                               // CJK character range
+                               else if (c >= 0x4E00 && c <= 0x9FCC)
+                               {
+                                       if (!str.empty())
+                                       {
+                                               elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
+                                               str.clear();
+                                       }
+                                       str += c;
+                                       elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
+                                       str.clear();
+                               }
+                               else
+                               {
+                                       str += c;
+                               }
+                       }
+                       if (!str.empty())
+                       {
+                               elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
+                       }
+               }
+               break;
+       case GUMBO_NODE_CDATA:
+               {
+                       element::ptr ret = std::make_shared<el_cdata>(shared_from_this());
+                       ret->set_data(litehtml_from_utf8(node->v.text.text));
+                       elements.push_back(ret);
+               }
+               break;
+       case GUMBO_NODE_COMMENT:
+               {
+                       element::ptr ret = std::make_shared<el_comment>(shared_from_this());
+                       ret->set_data(litehtml_from_utf8(node->v.text.text));
+                       elements.push_back(ret);
+               }
+               break;
+       case GUMBO_NODE_WHITESPACE:
+               {
+                       tstring str = litehtml_from_utf8(node->v.text.text);
+                       for (size_t i = 0; i < str.length(); i++)
+                       {
+                               elements.push_back(std::make_shared<el_space>(str.substr(i, 1).c_str(), shared_from_this()));
+                       }
+               }
+               break;
+