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 2341da55e87101cf18e78d2c8f2dbcd3d4cac003..c34df5fbb339d7208f0dd67ad646433d5777b3a7 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 f1279173a777a2fe6b1fa1314887db5eb67e2a5d..fe5727f2bcc3dd54d8cebf243d9ed13a64787a91 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 a4528c07a3946970c5a3a918c1748b8c50ab8b72..42b96dce5180849d8f164e7c41fd2d5bec5f02ac 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 64085faf12bdb616ac969a9876d62878ced1abc1..24dcb57fea742459d46154f44090bbccc4bbcb14 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 ca1c9a7353876cd33ee57635bb1be500aa57c53c..98487f02e87fa995af09716cc8b0958883dedc7a 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 87ce59e20d9233d2c82284d277d5aa55923256a8..1c65e3042afebcd53c24894cf900d0ddce31d13d 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 e3fc2f69ef25c707cfc6055b521dc51a1393cb14..ce0b69a63d2307077fb34a50c0400b6c239af9f0 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 a46a9f888143c27915da0cb490605d5277a2d074..859b85249a2e71b216eda629568cf5d8b9fbc3c6 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 023d15c51800baaafad8149abb1127f13215babe..4ad23c5297865cf510eb5d9e5713b62ab5fe92ab 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 d15a528deeb23b9708213cb6750edc3edd835875..eeeea51c85ea02780f1b8d16a2cde8031a0c04ce 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 5f26269878be8bfabc77879fd5a84f23942f7983..4cea5d3d8c349c90a3ada4a3885fc9f8a3781a9c 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 ce629914d94301b862716007cd7ff332498f79f9..b6450f8f5517b0e52fe6b80fda312d671b9cd1fe 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 06d55806748ae97a3986e21ea26890cc4dfb99f7..472cd546b1a19055e108d37e864fa205fa7b2efa 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 078f9dd497c20517e64027381bcb0af120c74a2b..13a3d77b7a191883abf266afaadb73a57ae3ed66 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 fbe1d40c540616346c2cd70bb9c2dd3f44cd8a8d..5c99a8b26c2652fc3e63a85615f9b0ef0a409204 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 e4ca723ed7bfb41b0c217bb893366c7ecb96c5c4..18d7f2652fc955cc18251f6c2ac06c50bc900f25 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 05f046dcfa8448cb7202756517d68cb51839fe88..308a14fee7b995f7e7e14649cd68b2f57e362144 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 a8e5f41ed7581f08ef27b34a7a5e3c9fd83ffe00..dc400884e7f6eb608d29d5b86b17c053f32ae730 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 ae8f9c9177291b67c385350e4fef0a879c68c668..d9a0274640cbeb6b0e2041774b46daf294e775fc 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 e9775aa83d9977ee47b4c7a0c5ad7f89a3dbe26f..0be0ea7e7b82770feb3085d89324b09dcdc596c3 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;
+       default:
+               break;
+       }
+}
+
+void litehtml::document::fix_tables_layout()
+{
+       size_t i = 0;
+       while (i < m_tabular_elements.size())
+       {
+               element::ptr el_ptr = m_tabular_elements[i];
+
+               switch (el_ptr->get_display())
+               {
+               case display_inline_table:
+               case display_table:
+                       fix_table_children(el_ptr, display_table_row_group, _t("table-row-group"));
+                       break;
+               case display_table_footer_group:
+               case display_table_row_group:
+               case display_table_header_group:
+                       fix_table_parent(el_ptr, display_table, _t("table"));
+                       fix_table_children(el_ptr, display_table_row, _t("table-row"));
+                       break;
+               case display_table_row:
+                       fix_table_parent(el_ptr, display_table_row_group, _t("table-row-group"));
+                       fix_table_children(el_ptr, display_table_cell, _t("table-cell"));
+                       break;
+               case display_table_cell:
+                       fix_table_parent(el_ptr, display_table_row, _t("table-row"));
+                       break;
+               // TODO: make table layout fix for table-caption, table-column etc. elements
+               case display_table_caption:
+               case display_table_column:
+               case display_table_column_group:
+               default:
+                       break;
+               }
+               i++;
+       }
+}
+
+void litehtml::document::fix_table_children(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str)
+{
+       elements_vector tmp;
+       elements_vector::iterator first_iter = el_ptr->m_children.begin();
+       elements_vector::iterator cur_iter = el_ptr->m_children.begin();
+
+       auto flush_elements = [&]()
+       {
+               element::ptr annon_tag = std::make_shared<html_tag>(shared_from_this());
+               style st;
+               st.add_property(_t("display"), disp_str, 0, false);
+               annon_tag->add_style(st);
+               annon_tag->parent(el_ptr);
+               annon_tag->parse_styles();
+               std::for_each(tmp.begin(), tmp.end(),
+                       [&annon_tag](element::ptr& el)
+                       {
+                               annon_tag->appendChild(el);
+                       }
+               );
+               first_iter = el_ptr->m_children.insert(first_iter, annon_tag);
+               cur_iter = first_iter + 1;
+               while (cur_iter != el_ptr->m_children.end() && (*cur_iter)->parent() != el_ptr)
+               {
+                       cur_iter = el_ptr->m_children.erase(cur_iter);
+               }
+               first_iter = cur_iter;
+               tmp.clear();
+       };
+
+       while (cur_iter != el_ptr->m_children.end())
+       {
+               if ((*cur_iter)->get_display() != disp)
+               {
+                       if (!(*cur_iter)->is_white_space() || ((*cur_iter)->is_white_space() && !tmp.empty()))
+                       {
+                               if (tmp.empty())
+                               {
+                                       first_iter = cur_iter;
+                               }
+                               tmp.push_back((*cur_iter));
+                       }
+                       cur_iter++;
+               }
+               else if (!tmp.empty())
+               {
+                       flush_elements();
+               }
+               else
+               {
+                       cur_iter++;
+               }
+       }
+       if (!tmp.empty())
+       {
+               flush_elements();
+       }
+}
+
+void litehtml::document::fix_table_parent(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str)
+{
+       element::ptr parent = el_ptr->parent();
+
+       if (parent->get_display() != disp)
+       {
+               elements_vector::iterator this_element = std::find_if(parent->m_children.begin(), parent->m_children.end(),
+                       [&](element::ptr& el)
+                       {
+                               if (el == el_ptr)
+                               {
+                                       return true;
+                               }
+                               return false;
+                       }
+               );
+               if (this_element != parent->m_children.end())
+               {
+                       style_display el_disp = el_ptr->get_display();
+                       elements_vector::iterator first = this_element;
+                       elements_vector::iterator last = this_element;
+                       elements_vector::iterator cur = this_element;
+
+                       // find first element with same display
+                       while (true)
+                       {
+                               if (cur == parent->m_children.begin()) break;
+                               cur--;
+                               if ((*cur)->is_white_space() || (*cur)->get_display() == el_disp)
+                               {
+                                       first = cur;
+                               }
+                               else
+                               {
+                                       break;
+                               }
+                       }
+
+                       // find last element with same display
+                       cur = this_element;
+                       while (true)
+                       {
+                               cur++;
+                               if (cur == parent->m_children.end()) break;
+
+                               if ((*cur)->is_white_space() || (*cur)->get_display() == el_disp)
+                               {
+                                       last = cur;
+                               }
+                               else
+                               {
+                                       break;
+                               }
+                       }
+
+                       // extract elements with the same display and wrap them with anonymous object
+                       element::ptr annon_tag = std::make_shared<html_tag>(shared_from_this());
+                       style st;
+                       st.add_property(_t("display"), disp_str, 0, false);
+                       annon_tag->add_style(st);
+                       annon_tag->parent(parent);
+                       annon_tag->parse_styles();
+                       std::for_each(first, last + 1,
+                               [&annon_tag](element::ptr& el)
+                               {
+                                       annon_tag->appendChild(el);
+                               }
+                       );
+                       first = parent->m_children.erase(first, last + 1);
+                       parent->m_children.insert(first, annon_tag);
+               }
+       }
+}
index 33287f41c4e23ed6b08eca4a36f9db54374de97e..db307939d73c5790ced1badd2d523f9d56881678 100644 (file)
-#pragma once\r
-#include "style.h"\r
-#include "types.h"\r
-#include "context.h"\r
-#include "gumbo.h"\r
-\r
-namespace litehtml\r
-{\r
-       struct css_text\r
-       {\r
-               typedef std::vector<css_text>   vector;\r
-\r
-               tstring text;\r
-               tstring baseurl;\r
-               tstring media;\r
-               \r
-               css_text()\r
-               {\r
-               }\r
-\r
-               css_text(const tchar_t* txt, const tchar_t* url, const tchar_t* media_str)\r
-               {\r
-                       text    = txt ? txt : _t("");\r
-                       baseurl = url ? url : _t("");\r
-                       media   = media_str ? media_str : _t("");\r
-               }\r
-\r
-               css_text(const css_text& val)\r
-               {\r
-                       text    = val.text;\r
-                       baseurl = val.baseurl;\r
-                       media   = val.media;\r
-               }\r
-       };\r
-\r
-       struct stop_tags_t\r
-       {\r
-               const litehtml::tchar_t*        tags;\r
-               const litehtml::tchar_t*        stop_parent;\r
-       };\r
-\r
-       struct ommited_end_tags_t\r
-       {\r
-               const litehtml::tchar_t*        tag;\r
-               const litehtml::tchar_t*        followed_tags;\r
-       };\r
-\r
-       class html_tag;\r
-\r
-       class document : public std::enable_shared_from_this<document>\r
-       {\r
-       public:\r
-               typedef std::shared_ptr<document>       ptr;\r
-               typedef std::weak_ptr<document>         weak_ptr;\r
-       private:\r
-               std::shared_ptr<element>                        m_root;\r
-               document_container*                                     m_container;\r
-               fonts_map                                                       m_fonts;\r
-               css_text::vector                                        m_css;\r
-               litehtml::css                                           m_styles;\r
-               litehtml::web_color                                     m_def_color;\r
-               litehtml::context*                                      m_context;\r
-               litehtml::size                                          m_size;\r
-               position::vector                                        m_fixed_boxes;\r
-               media_query_list::vector                        m_media_lists;\r
-               element::ptr                                            m_over_element;\r
-               elements_vector                                         m_tabular_elements;\r
-               media_features                                          m_media;\r
-               tstring                             m_lang;\r
-               tstring                             m_culture;\r
-       public:\r
-               document(litehtml::document_container* objContainer, litehtml::context* ctx);\r
-               virtual ~document();\r
-\r
-               litehtml::document_container*   container()     { return m_container; }\r
-               uint_ptr                                                get_font(const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm);\r
-               int                                                             render(int max_width, render_type rt = render_all);\r
-               void                                                    draw(uint_ptr hdc, int x, int y, const position* clip);\r
-               web_color                                               get_def_color() { return m_def_color; }\r
-               int                                                             cvt_units(const tchar_t* str, int fontSize, bool* is_percent = 0) const;\r
-               int                                                             cvt_units(css_length& val, int fontSize, int size = 0) const;\r
-               int                                                             width() const;\r
-               int                                                             height() const;\r
-               void                                                    add_stylesheet(const tchar_t* str, const tchar_t* baseurl, const tchar_t* media);\r
-               bool                                                    on_mouse_over(int x, int y, int client_x, int client_y, position::vector& redraw_boxes);\r
-               bool                                                    on_lbutton_down(int x, int y, int client_x, int client_y, position::vector& redraw_boxes);\r
-               bool                                                    on_lbutton_up(int x, int y, int client_x, int client_y, position::vector& redraw_boxes);\r
-               bool                                                    on_mouse_leave(position::vector& redraw_boxes);\r
-               litehtml::element::ptr                  create_element(const tchar_t* tag_name, const string_map& attributes);\r
-               element::ptr                                    root();\r
-               void                                                    get_fixed_boxes(position::vector& fixed_boxes);\r
-               void                                                    add_fixed_box(const position& pos);\r
-               void                                                    add_media_list(media_query_list::ptr list);\r
-               bool                                                    media_changed();\r
-               bool                                                    lang_changed();\r
-               bool                            match_lang(const tstring & lang);\r
-               void                                                    add_tabular(const element::ptr& el);\r
-\r
-               static litehtml::document::ptr createFromString(const tchar_t* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles = 0);\r
-               static litehtml::document::ptr createFromUTF8(const char* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles = 0);\r
-       \r
-       private:\r
-               litehtml::uint_ptr      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
-               void create_node(GumboNode* node, elements_vector& elements);\r
-               bool update_media_lists(const media_features& features);\r
-               void fix_tables_layout();\r
-               void fix_table_children(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str);\r
-               void fix_table_parent(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str);\r
-       };\r
-\r
-       inline element::ptr document::root()\r
-       {\r
-               return m_root;\r
-       }\r
-       inline void document::add_tabular(const element::ptr& el)\r
-       {\r
-               m_tabular_elements.push_back(el);\r
-       }\r
-       inline bool document::match_lang(const tstring & lang)\r
-       {\r
-               return lang == m_lang || lang == m_culture;\r
-       }\r
-}\r
+#ifndef LH_DOCUMENT_H
+#define LH_DOCUMENT_H
+
+#include "style.h"
+#include "types.h"
+#include "context.h"
+#include "gumbo.h"
+
+namespace litehtml
+{
+       struct css_text
+       {
+               typedef std::vector<css_text>   vector;
+
+               tstring text;
+               tstring baseurl;
+               tstring media;
+               
+               css_text()
+               {
+               }
+
+               css_text(const tchar_t* txt, const tchar_t* url, const tchar_t* media_str)
+               {
+                       text    = txt ? txt : _t("");
+                       baseurl = url ? url : _t("");
+                       media   = media_str ? media_str : _t("");
+               }
+
+               css_text(const css_text& val)
+               {
+                       text    = val.text;
+                       baseurl = val.baseurl;
+                       media   = val.media;
+               }
+       };
+
+       struct stop_tags_t
+       {
+               const litehtml::tchar_t*        tags;
+               const litehtml::tchar_t*        stop_parent;
+       };
+
+       struct ommited_end_tags_t
+       {
+               const litehtml::tchar_t*        tag;
+               const litehtml::tchar_t*        followed_tags;
+       };
+
+       class html_tag;
+
+       class document : public std::enable_shared_from_this<document>
+       {
+       public:
+               typedef std::shared_ptr<document>       ptr;
+               typedef std::weak_ptr<document>         weak_ptr;
+       private:
+               std::shared_ptr<element>                        m_root;
+               document_container*                                     m_container;
+               fonts_map                                                       m_fonts;
+               css_text::vector                                        m_css;
+               litehtml::css                                           m_styles;
+               litehtml::web_color                                     m_def_color;
+               litehtml::context*                                      m_context;
+               litehtml::size                                          m_size;
+               position::vector                                        m_fixed_boxes;
+               media_query_list::vector                        m_media_lists;
+               element::ptr                                            m_over_element;
+               elements_vector                                         m_tabular_elements;
+               media_features                                          m_media;
+               tstring                             m_lang;
+               tstring                             m_culture;
+       public:
+               document(litehtml::document_container* objContainer, litehtml::context* ctx);
+               virtual ~document();
+
+               litehtml::document_container*   container()     { return m_container; }
+               uint_ptr                                                get_font(const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm);
+               int                                                             render(int max_width, render_type rt = render_all);
+               void                                                    draw(uint_ptr hdc, int x, int y, const position* clip);
+               web_color                                               get_def_color() { return m_def_color; }
+               int                                                             cvt_units(const tchar_t* str, int fontSize, bool* is_percent = 0) const;
+               int                                                             cvt_units(css_length& val, int fontSize, int size = 0) const;
+               int                                                             width() const;
+               int                                                             height() const;
+               void                                                    add_stylesheet(const tchar_t* str, const tchar_t* baseurl, const tchar_t* media);
+               bool                                                    on_mouse_over(int x, int y, int client_x, int client_y, position::vector& redraw_boxes);
+               bool                                                    on_lbutton_down(int x, int y, int client_x, int client_y, position::vector& redraw_boxes);
+               bool                                                    on_lbutton_up(int x, int y, int client_x, int client_y, position::vector& redraw_boxes);
+               bool                                                    on_mouse_leave(position::vector& redraw_boxes);
+               litehtml::element::ptr                  create_element(const tchar_t* tag_name, const string_map& attributes);
+               element::ptr                                    root();
+               void                                                    get_fixed_boxes(position::vector& fixed_boxes);
+               void                                                    add_fixed_box(const position& pos);
+               void                                                    add_media_list(media_query_list::ptr list);
+               bool                                                    media_changed();
+               bool                                                    lang_changed();
+               bool                            match_lang(const tstring & lang);
+               void                                                    add_tabular(const element::ptr& el);
+
+               static litehtml::document::ptr createFromString(const tchar_t* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles = 0);
+               static litehtml::document::ptr createFromUTF8(const char* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles = 0);
+       
+       private:
+               litehtml::uint_ptr      add_font(const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm);
+
+               void create_node(GumboNode* node, elements_vector& elements);
+               bool update_media_lists(const media_features& features);
+               void fix_tables_layout();
+               void fix_table_children(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str);
+               void fix_table_parent(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str);
+       };
+
+       inline element::ptr document::root()
+       {
+               return m_root;
+       }
+       inline void document::add_tabular(const element::ptr& el)
+       {
+               m_tabular_elements.push_back(el);
+       }
+       inline bool document::match_lang(const tstring & lang)
+       {
+               return lang == m_lang || lang == m_culture;
+       }
+}
+
+#endif  // LH_DOCUMENT_H
index b48b3f91d1bae99badb9fc3c930e48754e06579e..a120eb15d9f93d4c0d0e24c2df5bd23cdb965a5f 100644 (file)
@@ -1,31 +1,31 @@
-#include "html.h"\r
-#include "el_anchor.h"\r
-#include "document.h"\r
-\r
-litehtml::el_anchor::el_anchor(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)\r
-{\r
-}\r
-\r
-litehtml::el_anchor::~el_anchor()\r
-{\r
-\r
-}\r
-\r
-void litehtml::el_anchor::on_click()\r
-{\r
-       const tchar_t* href = get_attr(_t("href"));\r
-\r
-       if(href)\r
-       {\r
-               get_document()->container()->on_anchor_click(href, shared_from_this());\r
-       }\r
-}\r
-\r
-void litehtml::el_anchor::apply_stylesheet( const litehtml::css& stylesheet )\r
-{\r
-       if( get_attr(_t("href")) )\r
-       {\r
-               m_pseudo_classes.push_back(_t("link"));\r
-       }\r
-       html_tag::apply_stylesheet(stylesheet);\r
-}\r
+#include "html.h"
+#include "el_anchor.h"
+#include "document.h"
+
+litehtml::el_anchor::el_anchor(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+}
+
+litehtml::el_anchor::~el_anchor()
+{
+
+}
+
+void litehtml::el_anchor::on_click()
+{
+       const tchar_t* href = get_attr(_t("href"));
+
+       if(href)
+       {
+               get_document()->container()->on_anchor_click(href, shared_from_this());
+       }
+}
+
+void litehtml::el_anchor::apply_stylesheet( const litehtml::css& stylesheet )
+{
+       if( get_attr(_t("href")) )
+       {
+               m_pseudo_classes.push_back(_t("link"));
+       }
+       html_tag::apply_stylesheet(stylesheet);
+}
index 4e351ffa1ae72332684bb87f9aa3cb13c1d0672d..140d19508cdd05180e161376e21a9bc2b601f742 100644 (file)
@@ -1,15 +1,19 @@
-#pragma once\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-       class el_anchor : public html_tag\r
-       {\r
-       public:\r
-               el_anchor(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_anchor();\r
-\r
-               virtual void    on_click() override;\r
-               virtual void    apply_stylesheet(const litehtml::css& stylesheet) override;\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_EL_ANCHOR_H
+#define LH_EL_ANCHOR_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+       class el_anchor : public html_tag
+       {
+       public:
+               el_anchor(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_anchor();
+
+               virtual void    on_click() override;
+               virtual void    apply_stylesheet(const litehtml::css& stylesheet) override;
+       };
+}
+
+#endif  // LH_EL_ANCHOR_H
index 928bc2e5add0211cce34da7138b388a46f57b1ed..dffc6afd0511e58bf39abe753cc64e9f6064c61d 100644 (file)
@@ -1,18 +1,18 @@
-#include "html.h"\r
-#include "el_base.h"\r
-#include "document.h"\r
-\r
-litehtml::el_base::el_base(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)\r
-{\r
-       \r
-}\r
-\r
-litehtml::el_base::~el_base()\r
-{\r
-\r
-}\r
-\r
-void litehtml::el_base::parse_attributes()\r
-{\r
-       get_document()->container()->set_base_url(get_attr(_t("href")));\r
-}\r
+#include "html.h"
+#include "el_base.h"
+#include "document.h"
+
+litehtml::el_base::el_base(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+       
+}
+
+litehtml::el_base::~el_base()
+{
+
+}
+
+void litehtml::el_base::parse_attributes()
+{
+       get_document()->container()->set_base_url(get_attr(_t("href")));
+}
index c4c388f5419347a9b8587554682b6f1569bd4241..57ba87d4f1b959b724bfcc9138e6998f0b387b56 100644 (file)
@@ -1,14 +1,18 @@
-#pragma once\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-       class el_base : public html_tag\r
-       {\r
-       public:\r
-               el_base(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_base();\r
-\r
-               virtual void    parse_attributes() override;\r
-       };\r
-}\r
+#ifndef LH_EL_BASE_H
+#define LH_EL_BASE_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+       class el_base : public html_tag
+       {
+       public:
+               el_base(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_base();
+
+               virtual void    parse_attributes() override;
+       };
+}
+
+#endif  // LH_EL_BASE_H
index 5c9ca342fdd5ab02c65fdb5f377d8bb1cb31c90e..bf0127d2f59433628590a4d462a9b6f916f5c737 100644 (file)
-#include "html.h"\r
-#include "el_before_after.h"\r
-#include "el_text.h"\r
-#include "el_space.h"\r
-#include "el_image.h"\r
-\r
-litehtml::el_before_after_base::el_before_after_base(const std::shared_ptr<litehtml::document>& doc, bool before) : html_tag(doc)\r
-{\r
-       if(before)\r
-       {\r
-               set_tagName(_t("::before"));\r
-       } else\r
-       {\r
-               set_tagName(_t("::after"));\r
-       }\r
-}\r
-\r
-litehtml::el_before_after_base::~el_before_after_base()\r
-{\r
-\r
-}\r
-\r
-void litehtml::el_before_after_base::add_style(const litehtml::style& st)\r
-{\r
-       html_tag::add_style(st);\r
-\r
-       tstring content = get_style_property(_t("content"), false, _t(""));\r
-       if(!content.empty())\r
-       {\r
-               int idx = value_index(content.c_str(), content_property_string);\r
-               if(idx < 0)\r
-               {\r
-                       tstring fnc;\r
-                       tstring::size_type i = 0;\r
-                       while(i < content.length() && i != tstring::npos)\r
-                       {\r
-                               if(content.at(i) == _t('"'))\r
-                               {\r
-                                       fnc.clear();\r
-                                       i++;\r
-                                       tstring::size_type pos = content.find(_t('"'), i);\r
-                                       tstring txt;\r
-                                       if(pos == tstring::npos)\r
-                                       {\r
-                                               txt = content.substr(i);\r
-                                               i = tstring::npos;\r
-                                       } else\r
-                                       {\r
-                                               txt = content.substr(i, pos - i);\r
-                                               i = pos + 1;\r
-                                       }\r
-                                       add_text(txt);\r
-                               } else if(content.at(i) == _t('('))\r
-                               {\r
-                                       i++;\r
-                                       litehtml::trim(fnc);\r
-                                       litehtml::lcase(fnc);\r
-                                       tstring::size_type pos = content.find(_t(')'), i);\r
-                                       tstring params;\r
-                                       if(pos == tstring::npos)\r
-                                       {\r
-                                               params = content.substr(i);\r
-                                               i = tstring::npos;\r
-                                       } else\r
-                                       {\r
-                                               params = content.substr(i, pos - i);\r
-                                               i = pos + 1;\r
-                                       }\r
-                                       add_function(fnc, params);\r
-                                       fnc.clear();\r
-                               } else\r
-                               {\r
-                                       fnc += content.at(i);\r
-                                       i++;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-void litehtml::el_before_after_base::add_text( const tstring& txt )\r
-{\r
-       tstring word;\r
-       tstring esc;\r
-       for(tstring::size_type i = 0; i < txt.length(); i++)\r
-       {\r
-               if( (txt.at(i) == _t(' ')) || (txt.at(i) == _t('\t')) || (txt.at(i) == _t('\\') && !esc.empty()) )\r
-               {\r
-                       if(esc.empty())\r
-                       {\r
-                               if(!word.empty())\r
-                               {\r
-                                       element::ptr el = std::make_shared<el_text>(word.c_str(), get_document());\r
-                                       appendChild(el);\r
-                                       word.clear();\r
-                               }\r
-\r
-                               element::ptr el = std::make_shared<el_space>(txt.substr(i, 1).c_str(), get_document());\r
-                               appendChild(el);\r
-                       } else\r
-                       {\r
-                               word += convert_escape(esc.c_str() + 1);\r
-                               esc.clear();\r
-                               if(txt.at(i) == _t('\\'))\r
-                               {\r
-                                       esc += txt.at(i);\r
-                               }\r
-                       }\r
-               } else\r
-               {\r
-                       if(!esc.empty() || txt.at(i) == _t('\\'))\r
-                       {\r
-                               esc += txt.at(i);\r
-                       } else\r
-                       {\r
-                               word += txt.at(i);\r
-                       }\r
-               }\r
-       }\r
-\r
-       if(!esc.empty())\r
-       {\r
-               word += convert_escape(esc.c_str() + 1);\r
-       }\r
-       if(!word.empty())\r
-       {\r
-               element::ptr el = std::make_shared<el_text>(word.c_str(), get_document());\r
-               appendChild(el);\r
-               word.clear();\r
-       }\r
-}\r
-\r
-void litehtml::el_before_after_base::add_function( const tstring& fnc, const tstring& params )\r
-{\r
-       int idx = value_index(fnc.c_str(), _t("attr;counter;url"));\r
-       switch(idx)\r
-       {\r
-       // attr\r
-       case 0:\r
-               {\r
-                       tstring p_name = params;\r
-                       trim(p_name);\r
-                       lcase(p_name);\r
-                       element::ptr el_parent = parent();\r
-                       if (el_parent)\r
-                       {\r
-                               const tchar_t* attr_value = el_parent->get_attr(p_name.c_str());\r
-                               if (attr_value)\r
-                               {\r
-                                       add_text(attr_value);\r
-                               }\r
-                       }\r
-               }\r
-               break;\r
-       // counter\r
-       case 1:\r
-               break;\r
-       // url\r
-       case 2:\r
-               {\r
-                       tstring p_url = params;\r
-                       trim(p_url);\r
-                       if(!p_url.empty())\r
-                       {\r
-                               if(p_url.at(0) == _t('\'') || p_url.at(0) == _t('\"'))\r
-                               {\r
-                                       p_url.erase(0, 1);\r
-                               }\r
-                       }\r
-                       if(!p_url.empty())\r
-                       {\r
-                               if(p_url.at(p_url.length() - 1) == _t('\'') || p_url.at(p_url.length() - 1) == _t('\"'))\r
-                               {\r
-                                       p_url.erase(p_url.length() - 1, 1);\r
-                               }\r
-                       }\r
-                       if(!p_url.empty())\r
-                       {\r
-                               element::ptr el = std::make_shared<el_image>(get_document());\r
-                               el->set_attr(_t("src"), p_url.c_str());\r
-                               el->set_attr(_t("style"), _t("display:inline-block"));\r
-                               el->set_tagName(_t("img"));\r
-                               appendChild(el);\r
-                               el->parse_attributes();\r
-                       }\r
-               }\r
-               break;\r
-       }\r
-}\r
-\r
-litehtml::tchar_t litehtml::el_before_after_base::convert_escape( const tchar_t* txt )\r
-{\r
-       tchar_t* sss = 0;\r
-       return (tchar_t) t_strtol(txt, &sss, 16);\r
-}\r
-\r
-void litehtml::el_before_after_base::apply_stylesheet( const litehtml::css& stylesheet )\r
-{\r
-\r
-}\r
+#include "html.h"
+#include "el_before_after.h"
+#include "el_text.h"
+#include "el_space.h"
+#include "el_image.h"
+
+litehtml::el_before_after_base::el_before_after_base(const std::shared_ptr<litehtml::document>& doc, bool before) : html_tag(doc)
+{
+       if(before)
+       {
+               set_tagName(_t("::before"));
+       } else
+       {
+               set_tagName(_t("::after"));
+       }
+}
+
+litehtml::el_before_after_base::~el_before_after_base()
+{
+
+}
+
+void litehtml::el_before_after_base::add_style(const litehtml::style& st)
+{
+       html_tag::add_style(st);
+
+       tstring content = get_style_property(_t("content"), false, _t(""));
+       if(!content.empty())
+       {
+               int idx = value_index(content.c_str(), content_property_string);
+               if(idx < 0)
+               {
+                       tstring fnc;
+                       tstring::size_type i = 0;
+                       while(i < content.length() && i != tstring::npos)
+                       {
+                               if(content.at(i) == _t('"'))
+                               {
+                                       fnc.clear();
+                                       i++;
+                                       tstring::size_type pos = content.find(_t('"'), i);
+                                       tstring txt;
+                                       if(pos == tstring::npos)
+                                       {
+                                               txt = content.substr(i);
+                                               i = tstring::npos;
+                                       } else
+                                       {
+                                               txt = content.substr(i, pos - i);
+                                               i = pos + 1;
+                                       }
+                                       add_text(txt);
+                               } else if(content.at(i) == _t('('))
+                               {
+                                       i++;
+                                       litehtml::trim(fnc);
+                                       litehtml::lcase(fnc);
+                                       tstring::size_type pos = content.find(_t(')'), i);
+                                       tstring params;
+                                       if(pos == tstring::npos)
+                                       {
+                                               params = content.substr(i);
+                                               i = tstring::npos;
+                                       } else
+                                       {
+                                               params = content.substr(i, pos - i);
+                                               i = pos + 1;
+                                       }
+                                       add_function(fnc, params);
+                                       fnc.clear();
+                               } else
+                               {
+                                       fnc += content.at(i);
+                                       i++;
+                               }
+                       }
+               }
+       }
+}
+
+void litehtml::el_before_after_base::add_text( const tstring& txt )
+{
+       tstring word;
+       tstring esc;
+       for(tstring::size_type i = 0; i < txt.length(); i++)
+       {
+               if( (txt.at(i) == _t(' ')) || (txt.at(i) == _t('\t')) || (txt.at(i) == _t('\\') && !esc.empty()) )
+               {
+                       if(esc.empty())
+                       {
+                               if(!word.empty())
+                               {
+                                       element::ptr el = std::make_shared<el_text>(word.c_str(), get_document());
+                                       appendChild(el);
+                                       word.clear();
+                               }
+
+                               element::ptr el = std::make_shared<el_space>(txt.substr(i, 1).c_str(), get_document());
+                               appendChild(el);
+                       } else
+                       {
+                               word += convert_escape(esc.c_str() + 1);
+                               esc.clear();
+                               if(txt.at(i) == _t('\\'))
+                               {
+                                       esc += txt.at(i);
+                               }
+                       }
+               } else
+               {
+                       if(!esc.empty() || txt.at(i) == _t('\\'))
+                       {
+                               esc += txt.at(i);
+                       } else
+                       {
+                               word += txt.at(i);
+                       }
+               }
+       }
+
+       if(!esc.empty())
+       {
+               word += convert_escape(esc.c_str() + 1);
+       }
+       if(!word.empty())
+       {
+               element::ptr el = std::make_shared<el_text>(word.c_str(), get_document());
+               appendChild(el);
+               word.clear();
+       }
+}
+
+void litehtml::el_before_after_base::add_function( const tstring& fnc, const tstring& params )
+{
+       int idx = value_index(fnc.c_str(), _t("attr;counter;url"));
+       switch(idx)
+       {
+       // attr
+       case 0:
+               {
+                       tstring p_name = params;
+                       trim(p_name);
+                       lcase(p_name);
+                       element::ptr el_parent = parent();
+                       if (el_parent)
+                       {
+                               const tchar_t* attr_value = el_parent->get_attr(p_name.c_str());
+                               if (attr_value)
+                               {
+                                       add_text(attr_value);
+                               }
+                       }
+               }
+               break;
+       // counter
+       case 1:
+               break;
+       // url
+       case 2:
+               {
+                       tstring p_url = params;
+                       trim(p_url);
+                       if(!p_url.empty())
+                       {
+                               if(p_url.at(0) == _t('\'') || p_url.at(0) == _t('\"'))
+                               {
+                                       p_url.erase(0, 1);
+                               }
+                       }
+                       if(!p_url.empty())
+                       {
+                               if(p_url.at(p_url.length() - 1) == _t('\'') || p_url.at(p_url.length() - 1) == _t('\"'))
+                               {
+                                       p_url.erase(p_url.length() - 1, 1);
+                               }
+                       }
+                       if(!p_url.empty())
+                       {
+                               element::ptr el = std::make_shared<el_image>(get_document());
+                               el->set_attr(_t("src"), p_url.c_str());
+                               el->set_attr(_t("style"), _t("display:inline-block"));
+                               el->set_tagName(_t("img"));
+                               appendChild(el);
+                               el->parse_attributes();
+                       }
+               }
+               break;
+       }
+}
+
+litehtml::tchar_t litehtml::el_before_after_base::convert_escape( const tchar_t* txt )
+{
+       tchar_t* sss = 0;
+       return (tchar_t) t_strtol(txt, &sss, 16);
+}
+
+void litehtml::el_before_after_base::apply_stylesheet( const litehtml::css& stylesheet )
+{
+
+}
index 5d0e9cb1a08333fa023a5d7abfeeaaee3f870a02..1bb55f315c81b401eed1243e0d728521bd1133e9 100644 (file)
@@ -1,37 +1,41 @@
-#pragma once\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-       class el_before_after_base : public html_tag\r
-       {\r
-       public:\r
-               el_before_after_base(const std::shared_ptr<litehtml::document>& doc, bool before);\r
-               virtual ~el_before_after_base();\r
-\r
-               virtual void add_style(const litehtml::style& st) override;\r
-               virtual void apply_stylesheet(const litehtml::css& stylesheet) override;\r
-       private:\r
-               void    add_text(const tstring& txt);\r
-               void    add_function(const tstring& fnc, const tstring& params);\r
-               tchar_t convert_escape(const tchar_t* txt);\r
-       };\r
-\r
-       class el_before : public el_before_after_base\r
-       {\r
-       public:\r
-               el_before(const std::shared_ptr<litehtml::document>& doc) : el_before_after_base(doc, true)\r
-               {\r
-\r
-               }\r
-       };\r
-\r
-       class el_after : public el_before_after_base\r
-       {\r
-       public:\r
-               el_after(const std::shared_ptr<litehtml::document>& doc) : el_before_after_base(doc, false)\r
-               {\r
-\r
-               }\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_EL_BEFORE_AFTER_H
+#define LH_EL_BEFORE_AFTER_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+       class el_before_after_base : public html_tag
+       {
+       public:
+               el_before_after_base(const std::shared_ptr<litehtml::document>& doc, bool before);
+               virtual ~el_before_after_base();
+
+               virtual void add_style(const litehtml::style& st) override;
+               virtual void apply_stylesheet(const litehtml::css& stylesheet) override;
+       private:
+               void    add_text(const tstring& txt);
+               void    add_function(const tstring& fnc, const tstring& params);
+               tchar_t convert_escape(const tchar_t* txt);
+       };
+
+       class el_before : public el_before_after_base
+       {
+       public:
+               el_before(const std::shared_ptr<litehtml::document>& doc) : el_before_after_base(doc, true)
+               {
+
+               }
+       };
+
+       class el_after : public el_before_after_base
+       {
+       public:
+               el_after(const std::shared_ptr<litehtml::document>& doc) : el_before_after_base(doc, false)
+               {
+
+               }
+       };
+}
+
+#endif  // LH_EL_BEFORE_AFTER_H
index 7ada94bc2612a1fd5cf0507b8c7049d51c7579d2..61376d5d497e8d7333f12e9bc9152bc04629daaf 100644 (file)
@@ -1,17 +1,17 @@
-#include "html.h"\r
-#include "el_body.h"\r
-#include "document.h"\r
-\r
-litehtml::el_body::el_body(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)\r
-{\r
-}\r
-\r
-litehtml::el_body::~el_body()\r
-{\r
-\r
-}\r
-\r
-bool litehtml::el_body::is_body()  const\r
-{\r
-       return true;\r
-}\r
+#include "html.h"
+#include "el_body.h"
+#include "document.h"
+
+litehtml::el_body::el_body(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
+{
+}
+
+litehtml::el_body::~el_body()
+{
+
+}
+
+bool litehtml::el_body::is_body()  const
+{
+       return true;
+}
index 2248bbc2a3ca81e34b20242713d3e5f92be5533a..d03d5df3485b7c6b7638825d2b2c36cfddc7d797 100644 (file)
@@ -1,14 +1,18 @@
-#pragma once\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-       class el_body : public html_tag\r
-       {\r
-       public:\r
-               el_body(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_body();\r
-\r
-               virtual bool is_body() const override;\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_EL_BODY_H
+#define LH_EL_BODY_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+       class el_body : public html_tag
+       {
+       public:
+               el_body(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_body();
+
+               virtual bool is_body() const override;
+       };
+}
+
+#endif  // LH_EL_BODY_H
index a798912bb5c9bbdd9d8d050743ab4b4ec5113918..5523b4111da6b4c221e769631c725f6dfb92a127 100644 (file)
@@ -1,18 +1,18 @@
-#include "html.h"\r
-#include "el_break.h"\r
-\r
-litehtml::el_break::el_break(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)\r
-{\r
-\r
-}\r
-\r
-litehtml::el_break::~el_break()\r
-{\r
-\r
-}\r
-\r
-bool litehtml::el_break::is_break() const\r
-{\r
-       return true;\r
-}\r
-\r
+#include "html.h"
+#include "el_break.h"
+
+litehtml::el_break::el_break(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+
+}
+
+litehtml::el_break::~el_break()
+{
+
+}
+
+bool litehtml::el_break::is_break() const
+{
+       return true;
+}
+
index dac178915851432e97cc57d203c585b3d77eebbc..70fab321dac244525ecd7b2f2300505e90114ba0 100644 (file)
@@ -1,14 +1,18 @@
-#pragma once\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-       class el_break : public html_tag\r
-       {\r
-       public:\r
-               el_break(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_break();\r
-\r
-               virtual bool is_break() const override;\r
-       };\r
-}\r
+#ifndef LH_EL_BREAK_H
+#define LH_EL_BREAK_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+       class el_break : public html_tag
+       {
+       public:
+               el_break(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_break();
+
+               virtual bool is_break() const override;
+       };
+}
+
+#endif  // LH_EL_BREAK_H
index 6e785d140429c99939a127bda3c57c391dde4309..bb21eab10f6ad9399ca7f7a0461a5a280d5b265c 100644 (file)
@@ -1,25 +1,25 @@
-#include "html.h"\r
-#include "el_cdata.h"\r
-\r
-litehtml::el_cdata::el_cdata(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)\r
-{\r
-       m_skip = true;\r
-}\r
-\r
-litehtml::el_cdata::~el_cdata()\r
-{\r
-\r
-}\r
-\r
-void litehtml::el_cdata::get_text( tstring& text )\r
-{\r
-       text += m_text;\r
-}\r
-\r
-void litehtml::el_cdata::set_data( const tchar_t* data )\r
-{\r
-       if(data)\r
-       {\r
-               m_text += data;\r
-       }\r
-}\r
+#include "html.h"
+#include "el_cdata.h"
+
+litehtml::el_cdata::el_cdata(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
+{
+       m_skip = true;
+}
+
+litehtml::el_cdata::~el_cdata()
+{
+
+}
+
+void litehtml::el_cdata::get_text( tstring& text )
+{
+       text += m_text;
+}
+
+void litehtml::el_cdata::set_data( const tchar_t* data )
+{
+       if(data)
+       {
+               m_text += data;
+       }
+}
index e138f9de06e78746c0cab4b7665145f340bed46e..33bdfe31192039c4d8d010191a29e225ce0f0dc6 100644 (file)
@@ -1,16 +1,20 @@
-#pragma once\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-       class el_cdata : public element\r
-       {\r
-               tstring m_text;\r
-       public:\r
-               el_cdata(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_cdata();\r
-\r
-               virtual void    get_text(tstring& text) override;\r
-               virtual void    set_data(const tchar_t* data) override;\r
-       };\r
-}\r
+#ifndef LH_EL_CDATA_H
+#define LH_EL_CDATA_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+       class el_cdata : public element
+       {
+               tstring m_text;
+       public:
+               el_cdata(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_cdata();
+
+               virtual void    get_text(tstring& text) override;
+               virtual void    set_data(const tchar_t* data) override;
+       };
+}
+
+#endif  // LH_EL_CDATA_H
index 3b46e2a5133e73698ca8abcfd20425b8d56f7a16..638c960f7ec324232ceca6243590505c2fc0a6b7 100644 (file)
@@ -1,25 +1,25 @@
-#include "html.h"\r
-#include "el_comment.h"\r
-\r
-litehtml::el_comment::el_comment(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)\r
-{\r
-       m_skip = true;\r
-}\r
-\r
-litehtml::el_comment::~el_comment()\r
-{\r
-\r
-}\r
-\r
-void litehtml::el_comment::get_text( tstring& text )\r
-{\r
-       text += m_text;\r
-}\r
-\r
-void litehtml::el_comment::set_data( const tchar_t* data )\r
-{\r
-       if(data)\r
-       {\r
-               m_text += data;\r
-       }\r
-}\r
+#include "html.h"
+#include "el_comment.h"
+
+litehtml::el_comment::el_comment(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
+{
+       m_skip = true;
+}
+
+litehtml::el_comment::~el_comment()
+{
+
+}
+
+void litehtml::el_comment::get_text( tstring& text )
+{
+       text += m_text;
+}
+
+void litehtml::el_comment::set_data( const tchar_t* data )
+{
+       if(data)
+       {
+               m_text += data;
+       }
+}
index 5b8459d12e7db6850695a4fd6941742a3dc7c72d..ceffd2c056078b3ec0150ee26960d9b64d0033bd 100644 (file)
@@ -1,16 +1,20 @@
-#pragma once\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-       class el_comment : public element\r
-       {\r
-               tstring m_text;\r
-       public:\r
-               el_comment(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_comment();\r
-\r
-               virtual void    get_text(tstring& text) override;\r
-               virtual void    set_data(const tchar_t* data) override;\r
-       };\r
-}\r
+#ifndef LH_EL_COMMENT_H
+#define LH_EL_COMMENT_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+       class el_comment : public element
+       {
+               tstring m_text;
+       public:
+               el_comment(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_comment();
+
+               virtual void    get_text(tstring& text) override;
+               virtual void    set_data(const tchar_t* data) override;
+       };
+}
+
+#endif  // LH_EL_COMMENT_H
index ec63963df45590528031e453007dcaea9c209165..c4ee3c0db953c20c8a56a454258e7576036d8f02 100644 (file)
@@ -1,23 +1,23 @@
-#include "html.h"\r
-#include "el_div.h"\r
-\r
-\r
-litehtml::el_div::el_div(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)\r
-{\r
-\r
-}\r
-\r
-litehtml::el_div::~el_div()\r
-{\r
-\r
-}\r
-\r
-void litehtml::el_div::parse_attributes()\r
-{\r
-       const tchar_t* str = get_attr(_t("align"));\r
-       if(str)\r
-       {\r
-               m_style.add_property(_t("text-align"), str, 0, false);\r
-       }\r
-       html_tag::parse_attributes();\r
-}\r
+#include "html.h"
+#include "el_div.h"
+
+
+litehtml::el_div::el_div(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+
+}
+
+litehtml::el_div::~el_div()
+{
+
+}
+
+void litehtml::el_div::parse_attributes()
+{
+       const tchar_t* str = get_attr(_t("align"));
+       if(str)
+       {
+               m_style.add_property(_t("text-align"), str, 0, false);
+       }
+       html_tag::parse_attributes();
+}
index 54eed843f6c4f21254643ff898fc7f854c8bcfec..ece762f51ac31b2970547c0b77434e0f04101778 100644 (file)
@@ -1,14 +1,18 @@
-#pragma once\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-       class el_div : public html_tag\r
-       {\r
-       public:\r
-               el_div(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_div();\r
-\r
-               virtual void parse_attributes() override;\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_EL_DIV_H
+#define LH_EL_DIV_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+       class el_div : public html_tag
+       {
+       public:
+               el_div(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_div();
+
+               virtual void parse_attributes() override;
+       };
+}
+
+#endif  // LH_EL_DIV_H
index cef9aaee5f61fa39ee3b3bd3e157d6ac583617fc..da6bae984af578ed1ef3eea03b227401cdaca539 100644 (file)
@@ -1,60 +1,60 @@
-#include "html.h"\r
-#include "el_font.h"\r
-\r
-\r
-litehtml::el_font::el_font(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)\r
-{\r
-\r
-}\r
-\r
-litehtml::el_font::~el_font()\r
-{\r
-\r
-}\r
-\r
-void litehtml::el_font::parse_attributes()\r
-{\r
-       const tchar_t* str = get_attr(_t("color"));\r
-       if(str)\r
-       {\r
-               m_style.add_property(_t("color"), str, 0, false);\r
-       }\r
-\r
-       str = get_attr(_t("face"));\r
-       if(str)\r
-       {\r
-               m_style.add_property(_t("font-face"), str, 0, false);\r
-       }\r
-\r
-       str = get_attr(_t("size"));\r
-       if(str)\r
-       {\r
-               int sz = t_atoi(str);\r
-               if(sz <= 1)\r
-               {\r
-                       m_style.add_property(_t("font-size"), _t("x-small"), 0, false);\r
-               } else if(sz >= 6)\r
-               {\r
-                       m_style.add_property(_t("font-size"), _t("xx-large"), 0, false);\r
-               } else\r
-               {\r
-                       switch(sz)\r
-                       {\r
-                       case 2:\r
-                               m_style.add_property(_t("font-size"), _t("small"), 0, false);\r
-                               break;\r
-                       case 3:\r
-                               m_style.add_property(_t("font-size"), _t("medium"), 0, false);\r
-                               break;\r
-                       case 4:\r
-                               m_style.add_property(_t("font-size"), _t("large"), 0, false);\r
-                               break;\r
-                       case 5:\r
-                               m_style.add_property(_t("font-size"), _t("x-large"), 0, false);\r
-                               break;\r
-                       }\r
-               }\r
-       }\r
-\r
-       html_tag::parse_attributes();\r
-}\r
+#include "html.h"
+#include "el_font.h"
+
+
+litehtml::el_font::el_font(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+
+}
+
+litehtml::el_font::~el_font()
+{
+
+}
+
+void litehtml::el_font::parse_attributes()
+{
+       const tchar_t* str = get_attr(_t("color"));
+       if(str)
+       {
+               m_style.add_property(_t("color"), str, 0, false);
+       }
+
+       str = get_attr(_t("face"));
+       if(str)
+       {
+               m_style.add_property(_t("font-face"), str, 0, false);
+       }
+
+       str = get_attr(_t("size"));
+       if(str)
+       {
+               int sz = t_atoi(str);
+               if(sz <= 1)
+               {
+                       m_style.add_property(_t("font-size"), _t("x-small"), 0, false);
+               } else if(sz >= 6)
+               {
+                       m_style.add_property(_t("font-size"), _t("xx-large"), 0, false);
+               } else
+               {
+                       switch(sz)
+                       {
+                       case 2:
+                               m_style.add_property(_t("font-size"), _t("small"), 0, false);
+                               break;
+                       case 3:
+                               m_style.add_property(_t("font-size"), _t("medium"), 0, false);
+                               break;
+                       case 4:
+                               m_style.add_property(_t("font-size"), _t("large"), 0, false);
+                               break;
+                       case 5:
+                               m_style.add_property(_t("font-size"), _t("x-large"), 0, false);
+                               break;
+                       }
+               }
+       }
+
+       html_tag::parse_attributes();
+}
index 9d5e4a1df49c9d5e84fec43e23a8eb31da89d886..a0f391ec295f12838cecb11abf879f7124ac93c8 100644 (file)
@@ -1,14 +1,18 @@
-#pragma once\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-       class el_font : public html_tag\r
-       {\r
-       public:\r
-               el_font(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_font();\r
-\r
-               virtual void parse_attributes() override;\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_EL_FONT_H
+#define LH_EL_FONT_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+       class el_font : public html_tag
+       {
+       public:
+               el_font(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_font();
+
+               virtual void parse_attributes() override;
+       };
+}
+
+#endif  // LH_EL_FONT_H
index 4d5486b5f9458a71e228cb0572df20ecd91c1109..7de47a1898b778b557af0e5bdbcf2522314eaf43 100644 (file)
-#include "html.h"\r
-#include "el_image.h"\r
-#include "document.h"\r
-\r
-litehtml::el_image::el_image(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)\r
-{\r
-       m_display = display_inline_block;\r
-}\r
-\r
-litehtml::el_image::~el_image( void )\r
-{\r
-\r
-}\r
-\r
-void litehtml::el_image::get_content_size( size& sz, int max_width )\r
-{\r
-       get_document()->container()->get_image_size(m_src.c_str(), 0, sz);\r
-}\r
-\r
-int litehtml::el_image::line_height() const\r
-{\r
-       return height();\r
-}\r
-\r
-bool litehtml::el_image::is_replaced() const\r
-{\r
-       return true;\r
-}\r
-\r
-int litehtml::el_image::render( int x, int y, int max_width, bool second_pass )\r
-{\r
-       int parent_width = max_width;\r
-\r
-       calc_outlines(parent_width);\r
-\r
-       m_pos.move_to(x, y);\r
-\r
-       document::ptr doc = get_document();\r
-\r
-       litehtml::size sz;\r
-       doc->container()->get_image_size(m_src.c_str(), 0, sz);\r
-\r
-       m_pos.width             = sz.width;\r
-       m_pos.height    = sz.height;\r
-\r
-       if(m_css_height.is_predefined() && m_css_width.is_predefined())\r
-       {\r
-               m_pos.height    = sz.height;\r
-               m_pos.width             = sz.width;\r
-\r
-               // check for max-height\r
-               if(!m_css_max_width.is_predefined())\r
-               {\r
-                       int max_width = doc->cvt_units(m_css_max_width, m_font_size, parent_width);\r
-                       if(m_pos.width > max_width)\r
-                       {\r
-                               m_pos.width = max_width;\r
-                       }\r
-                       if(sz.width)\r
-                       {\r
-                               m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width);\r
-                       } else\r
-                       {\r
-                               m_pos.height = sz.height;\r
-                       }\r
-               }\r
-\r
-               // check for max-height\r
-               if(!m_css_max_height.is_predefined())\r
-               {\r
-                       int max_height = doc->cvt_units(m_css_max_height, m_font_size);\r
-                       if(m_pos.height > max_height)\r
-                       {\r
-                               m_pos.height = max_height;\r
-                       }\r
-                       if(sz.height)\r
-                       {\r
-                               m_pos.width = (int) (m_pos.height * (float)sz.width / (float)sz.height);\r
-                       } else\r
-                       {\r
-                               m_pos.width = sz.width;\r
-                       }\r
-               }\r
-       } else if(!m_css_height.is_predefined() && m_css_width.is_predefined())\r
-       {\r
-               if (!get_predefined_height(m_pos.height))\r
-               {\r
-                       m_pos.height = (int)m_css_height.val();\r
-               }\r
-\r
-               // check for max-height\r
-               if(!m_css_max_height.is_predefined())\r
-               {\r
-                       int max_height = doc->cvt_units(m_css_max_height, m_font_size);\r
-                       if(m_pos.height > max_height)\r
-                       {\r
-                               m_pos.height = max_height;\r
-                       }\r
-               }\r
-\r
-               if(sz.height)\r
-               {\r
-                       m_pos.width = (int) (m_pos.height * (float)sz.width / (float)sz.height);\r
-               } else\r
-               {\r
-                       m_pos.width = sz.width;\r
-               }\r
-       } else if(m_css_height.is_predefined() && !m_css_width.is_predefined())\r
-       {\r
-               m_pos.width = (int) m_css_width.calc_percent(parent_width);\r
-\r
-               // check for max-width\r
-               if(!m_css_max_width.is_predefined())\r
-               {\r
-                       int max_width = doc->cvt_units(m_css_max_width, m_font_size, parent_width);\r
-                       if(m_pos.width > max_width)\r
-                       {\r
-                               m_pos.width = max_width;\r
-                       }\r
-               }\r
-\r
-               if(sz.width)\r
-               {\r
-                       m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width);\r
-               } else\r
-               {\r
-                       m_pos.height = sz.height;\r
-               }\r
-       } else\r
-       {\r
-               m_pos.width             = (int) m_css_width.calc_percent(parent_width);\r
-               m_pos.height    = 0;\r
-               if (!get_predefined_height(m_pos.height))\r
-               {\r
-                       m_pos.height = (int)m_css_height.val();\r
-               }\r
-\r
-               // check for max-height\r
-               if(!m_css_max_height.is_predefined())\r
-               {\r
-                       int max_height = doc->cvt_units(m_css_max_height, m_font_size);\r
-                       if(m_pos.height > max_height)\r
-                       {\r
-                               m_pos.height = max_height;\r
-                       }\r
-               }\r
-\r
-               // check for max-height\r
-               if(!m_css_max_width.is_predefined())\r
-               {\r
-                       int max_width = doc->cvt_units(m_css_max_width, m_font_size, parent_width);\r
-                       if(m_pos.width > max_width)\r
-                       {\r
-                               m_pos.width = max_width;\r
-                       }\r
-               }\r
-       }\r
-\r
-       calc_auto_margins(parent_width);\r
-\r
-       m_pos.x += content_margins_left();\r
-       m_pos.y += content_margins_top();\r
-\r
-       return m_pos.width + content_margins_left() + content_margins_right();\r
-}\r
-\r
-void litehtml::el_image::parse_attributes()\r
-{\r
-       m_src = get_attr(_t("src"), _t(""));\r
-\r
-       const tchar_t* attr_height = get_attr(_t("height"));\r
-       if(attr_height)\r
-       {\r
-               m_style.add_property(_t("height"), attr_height, 0, false);\r
-       }\r
-       const tchar_t* attr_width = get_attr(_t("width"));\r
-       if(attr_width)\r
-       {\r
-               m_style.add_property(_t("width"), attr_width, 0, false);\r
-       }\r
-}\r
-\r
-void litehtml::el_image::draw( uint_ptr hdc, int x, int y, const position* clip )\r
-{\r
-       position pos = m_pos;\r
-       pos.x += x;\r
-       pos.y += y;\r
-\r
-       position el_pos = pos;\r
-       el_pos += m_padding;\r
-       el_pos += m_borders;\r
-\r
-       // draw standard background here\r
-       if (el_pos.does_intersect(clip))\r
-       {\r
-               const background* bg = get_background();\r
-               if (bg)\r
-               {\r
-                       background_paint bg_paint;\r
-                       init_background_paint(pos, bg_paint, bg);\r
-\r
-                       get_document()->container()->draw_background(hdc, bg_paint);\r
-               }\r
-       }\r
-\r
-       // draw image as background\r
-       if(pos.does_intersect(clip))\r
-       {\r
-               if (pos.width > 0 && pos.height > 0) {\r
-                       background_paint bg;\r
-                       bg.image                                = m_src;\r
-                       bg.clip_box                             = pos;\r
-                       bg.origin_box                   = pos;\r
-                       bg.border_box                   = pos;\r
-                       bg.border_box                   += m_padding;\r
-                       bg.border_box                   += m_borders;\r
-                       bg.repeat                               = background_repeat_no_repeat;\r
-                       bg.image_size.width             = pos.width;\r
-                       bg.image_size.height    = pos.height;\r
-                       bg.border_radius                = m_css_borders.radius.calc_percents(bg.border_box.width, bg.border_box.height);\r
-                       bg.position_x                   = pos.x;\r
-                       bg.position_y                   = pos.y;\r
-                       get_document()->container()->draw_background(hdc, bg);\r
-               }\r
-       }\r
-\r
-       // draw borders\r
-       if (el_pos.does_intersect(clip))\r
-       {\r
-               position border_box = pos;\r
-               border_box += m_padding;\r
-               border_box += m_borders;\r
-\r
-               borders bdr = m_css_borders;\r
-               bdr.radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);\r
-\r
-               get_document()->container()->draw_borders(hdc, bdr, border_box, have_parent() ? false : true);\r
-       }\r
-}\r
-\r
-void litehtml::el_image::parse_styles( bool is_reparse /*= false*/ )\r
-{\r
-       html_tag::parse_styles(is_reparse);\r
-\r
-       if(!m_src.empty())\r
-       {\r
-               if(!m_css_height.is_predefined() && !m_css_width.is_predefined())\r
-               {\r
-                       get_document()->container()->load_image(m_src.c_str(), 0, true);\r
-               } else\r
-               {\r
-                       get_document()->container()->load_image(m_src.c_str(), 0, false);\r
-               }\r
-       }\r
-}\r
+#include "html.h"
+#include "el_image.h"
+#include "document.h"
+
+litehtml::el_image::el_image(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+       m_display = display_inline_block;
+}
+
+litehtml::el_image::~el_image( void )
+{
+
+}
+
+void litehtml::el_image::get_content_size( size& sz, int max_width )
+{
+       get_document()->container()->get_image_size(m_src.c_str(), 0, sz);
+}
+
+int litehtml::el_image::line_height() const
+{
+       return height();
+}
+
+bool litehtml::el_image::is_replaced() const
+{
+       return true;
+}
+
+int litehtml::el_image::render( int x, int y, int max_width, bool second_pass )
+{
+       int parent_width = max_width;
+
+       calc_outlines(parent_width);
+
+       m_pos.move_to(x, y);
+
+       document::ptr doc = get_document();
+
+       litehtml::size sz;
+       doc->container()->get_image_size(m_src.c_str(), 0, sz);
+
+       m_pos.width             = sz.width;
+       m_pos.height    = sz.height;
+
+       if(m_css_height.is_predefined() && m_css_width.is_predefined())
+       {
+               m_pos.height    = sz.height;
+               m_pos.width             = sz.width;
+
+               // check for max-height
+               if(!m_css_max_width.is_predefined())
+               {
+                       int max_width = doc->cvt_units(m_css_max_width, m_font_size, parent_width);
+                       if(m_pos.width > max_width)
+                       {
+                               m_pos.width = max_width;
+                       }
+                       if(sz.width)
+                       {
+                               m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width);
+                       } else
+                       {
+                               m_pos.height = sz.height;
+                       }
+               }
+
+               // check for max-height
+               if(!m_css_max_height.is_predefined())
+               {
+                       int max_height = doc->cvt_units(m_css_max_height, m_font_size);
+                       if(m_pos.height > max_height)
+                       {
+                               m_pos.height = max_height;
+                       }
+                       if(sz.height)
+                       {
+                               m_pos.width = (int) (m_pos.height * (float)sz.width / (float)sz.height);
+                       } else
+                       {
+                               m_pos.width = sz.width;
+                       }
+               }
+       } else if(!m_css_height.is_predefined() && m_css_width.is_predefined())
+       {
+               if (!get_predefined_height(m_pos.height))
+               {
+                       m_pos.height = (int)m_css_height.val();
+               }
+
+               // check for max-height
+               if(!m_css_max_height.is_predefined())
+               {
+                       int max_height = doc->cvt_units(m_css_max_height, m_font_size);
+                       if(m_pos.height > max_height)
+                       {
+                               m_pos.height = max_height;
+                       }
+               }
+
+               if(sz.height)
+               {
+                       m_pos.width = (int) (m_pos.height * (float)sz.width / (float)sz.height);
+               } else
+               {
+                       m_pos.width = sz.width;
+               }
+       } else if(m_css_height.is_predefined() && !m_css_width.is_predefined())
+       {
+               m_pos.width = (int) m_css_width.calc_percent(parent_width);
+
+               // check for max-width
+               if(!m_css_max_width.is_predefined())
+               {
+                       int max_width = doc->cvt_units(m_css_max_width, m_font_size, parent_width);
+                       if(m_pos.width > max_width)
+                       {
+                               m_pos.width = max_width;
+                       }
+               }
+
+               if(sz.width)
+               {
+                       m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width);
+               } else
+               {
+                       m_pos.height = sz.height;
+               }
+       } else
+       {
+               m_pos.width             = (int) m_css_width.calc_percent(parent_width);
+               m_pos.height    = 0;
+               if (!get_predefined_height(m_pos.height))
+               {
+                       m_pos.height = (int)m_css_height.val();
+               }
+
+               // check for max-height
+               if(!m_css_max_height.is_predefined())
+               {
+                       int max_height = doc->cvt_units(m_css_max_height, m_font_size);
+                       if(m_pos.height > max_height)
+                       {
+                               m_pos.height = max_height;
+                       }
+               }
+
+               // check for max-height
+               if(!m_css_max_width.is_predefined())
+               {
+                       int max_width = doc->cvt_units(m_css_max_width, m_font_size, parent_width);
+                       if(m_pos.width > max_width)
+                       {
+                               m_pos.width = max_width;
+                       }
+               }
+       }
+
+       calc_auto_margins(parent_width);
+
+       m_pos.x += content_margins_left();
+       m_pos.y += content_margins_top();
+
+       return m_pos.width + content_margins_left() + content_margins_right();
+}
+
+void litehtml::el_image::parse_attributes()
+{
+       m_src = get_attr(_t("src"), _t(""));
+
+       const tchar_t* attr_height = get_attr(_t("height"));
+       if(attr_height)
+       {
+               m_style.add_property(_t("height"), attr_height, 0, false);
+       }
+       const tchar_t* attr_width = get_attr(_t("width"));
+       if(attr_width)
+       {
+               m_style.add_property(_t("width"), attr_width, 0, false);
+       }
+}
+
+void litehtml::el_image::draw( uint_ptr hdc, int x, int y, const position* clip )
+{
+       position pos = m_pos;
+       pos.x += x;
+       pos.y += y;
+
+       position el_pos = pos;
+       el_pos += m_padding;
+       el_pos += m_borders;
+
+       // draw standard background here
+       if (el_pos.does_intersect(clip))
+       {
+               const background* bg = get_background();
+               if (bg)
+               {
+                       background_paint bg_paint;
+                       init_background_paint(pos, bg_paint, bg);
+
+                       get_document()->container()->draw_background(hdc, bg_paint);
+               }
+       }
+
+       // draw image as background
+       if(pos.does_intersect(clip))
+       {
+               if (pos.width > 0 && pos.height > 0) {
+                       background_paint bg;
+                       bg.image                                = m_src;
+                       bg.clip_box                             = pos;
+                       bg.origin_box                   = pos;
+                       bg.border_box                   = pos;
+                       bg.border_box                   += m_padding;
+                       bg.border_box                   += m_borders;
+                       bg.repeat                               = background_repeat_no_repeat;
+                       bg.image_size.width             = pos.width;
+                       bg.image_size.height    = pos.height;
+                       bg.border_radius                = m_css_borders.radius.calc_percents(bg.border_box.width, bg.border_box.height);
+                       bg.position_x                   = pos.x;
+                       bg.position_y                   = pos.y;
+                       get_document()->container()->draw_background(hdc, bg);
+               }
+       }
+
+       // draw borders
+       if (el_pos.does_intersect(clip))
+       {
+               position border_box = pos;
+               border_box += m_padding;
+               border_box += m_borders;
+
+               borders bdr = m_css_borders;
+               bdr.radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
+
+               get_document()->container()->draw_borders(hdc, bdr, border_box, have_parent() ? false : true);
+       }
+}
+
+void litehtml::el_image::parse_styles( bool is_reparse /*= false*/ )
+{
+       html_tag::parse_styles(is_reparse);
+
+       if(!m_src.empty())
+       {
+               if(!m_css_height.is_predefined() && !m_css_width.is_predefined())
+               {
+                       get_document()->container()->load_image(m_src.c_str(), 0, true);
+               } else
+               {
+                       get_document()->container()->load_image(m_src.c_str(), 0, false);
+               }
+       }
+}
index 670aa663d4d76720255a9ccb377ebc70f7e04f02..377ddf85b04d693757a4b0a99690608f798d52c4 100644 (file)
@@ -1,23 +1,26 @@
-#pragma once\r
-\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-\r
-       class el_image : public html_tag\r
-       {\r
-               tstring m_src;\r
-       public:\r
-               el_image(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_image(void);\r
-\r
-               virtual int             line_height() const override;\r
-               virtual bool    is_replaced() const override;\r
-               virtual int             render(int x, int y, int max_width, bool second_pass = false) override;\r
-               virtual void    parse_attributes() override;\r
-               virtual void    parse_styles(bool is_reparse = false) override;\r
-               virtual void    draw(uint_ptr hdc, int x, int y, const position* clip) override;\r
-               virtual void    get_content_size(size& sz, int max_width) override;\r
-       };\r
-}\r
+#ifndef LH_EL_IMAGE_H
+#define LH_EL_IMAGE_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+
+       class el_image : public html_tag
+       {
+               tstring m_src;
+       public:
+               el_image(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_image(void);
+
+               virtual int             line_height() const override;
+               virtual bool    is_replaced() const override;
+               virtual int             render(int x, int y, int max_width, bool second_pass = false) override;
+               virtual void    parse_attributes() override;
+               virtual void    parse_styles(bool is_reparse = false) override;
+               virtual void    draw(uint_ptr hdc, int x, int y, const position* clip) override;
+               virtual void    get_content_size(size& sz, int max_width) override;
+       };
+}
+
+#endif  // LH_EL_IMAGE_H
index 709c3997867b4237c7725feae3a4c9284e5915a3..01561ab6c923e475b2dc607a9fc746e5110002d2 100644 (file)
@@ -1,44 +1,44 @@
-#include "html.h"\r
-#include "el_link.h"\r
-#include "document.h"\r
-\r
-\r
-litehtml::el_link::el_link(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)\r
-{\r
-\r
-}\r
-\r
-litehtml::el_link::~el_link()\r
-{\r
-\r
-}\r
-\r
-void litehtml::el_link::parse_attributes()\r
-{\r
-       bool processed = false;\r
-\r
-       document::ptr doc = get_document();\r
-\r
-       const tchar_t* rel = get_attr(_t("rel"));\r
-       if(rel && !t_strcmp(rel, _t("stylesheet")))\r
-       {\r
-               const tchar_t* media    = get_attr(_t("media"));\r
-               const tchar_t* href             = get_attr(_t("href"));\r
-               if(href && href[0])\r
-               {\r
-                       tstring css_text;\r
-                       tstring css_baseurl;\r
-                       doc->container()->import_css(css_text, href, css_baseurl);\r
-                       if(!css_text.empty())\r
-                       {\r
-                               doc->add_stylesheet(css_text.c_str(), css_baseurl.c_str(), media);\r
-                               processed = true;\r
-                       }\r
-               }\r
-       }\r
-\r
-       if(!processed)\r
-       {\r
-               doc->container()->link(doc, shared_from_this());\r
-       }\r
-}\r
+#include "html.h"
+#include "el_link.h"
+#include "document.h"
+
+
+litehtml::el_link::el_link(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
+{
+
+}
+
+litehtml::el_link::~el_link()
+{
+
+}
+
+void litehtml::el_link::parse_attributes()
+{
+       bool processed = false;
+
+       document::ptr doc = get_document();
+
+       const tchar_t* rel = get_attr(_t("rel"));
+       if(rel && !t_strcmp(rel, _t("stylesheet")))
+       {
+               const tchar_t* media    = get_attr(_t("media"));
+               const tchar_t* href             = get_attr(_t("href"));
+               if(href && href[0])
+               {
+                       tstring css_text;
+                       tstring css_baseurl;
+                       doc->container()->import_css(css_text, href, css_baseurl);
+                       if(!css_text.empty())
+                       {
+                               doc->add_stylesheet(css_text.c_str(), css_baseurl.c_str(), media);
+                               processed = true;
+                       }
+               }
+       }
+
+       if(!processed)
+       {
+               doc->container()->link(doc, shared_from_this());
+       }
+}
index ef94fb1bffa0deca4470adec98e19e81ce6a1c07..6795760ba04ed32f26b6ac95b919052b8e04e2a1 100644 (file)
@@ -1,15 +1,19 @@
-#pragma once\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-       class el_link : public html_tag\r
-       {\r
-       public:\r
-               el_link(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_link();\r
-\r
-       protected:\r
-               virtual void    parse_attributes() override;\r
-       };\r
-}\r
+#ifndef LH_EL_LINK_H
+#define LH_EL_LINK_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+       class el_link : public html_tag
+       {
+       public:
+               el_link(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_link();
+
+       protected:
+               virtual void    parse_attributes() override;
+       };
+}
+
+#endif  // LH_EL_LINK_H
index f38baa1d809213b165f0cf6422969c51b4339da9..0986e5c73e6598392a1603a17a7f75a4442cb450 100644 (file)
@@ -1,23 +1,23 @@
-#include "html.h"\r
-#include "el_para.h"\r
-#include "document.h"\r
-\r
-litehtml::el_para::el_para(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)\r
-{\r
-}\r
-\r
-litehtml::el_para::~el_para()\r
-{\r
-\r
-}\r
-\r
-void litehtml::el_para::parse_attributes()\r
-{\r
-       const tchar_t* str = get_attr(_t("align"));\r
-       if(str)\r
-       {\r
-               m_style.add_property(_t("text-align"), str, 0, false);\r
-       }\r
-\r
-       html_tag::parse_attributes();\r
-}\r
+#include "html.h"
+#include "el_para.h"
+#include "document.h"
+
+litehtml::el_para::el_para(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
+{
+}
+
+litehtml::el_para::~el_para()
+{
+
+}
+
+void litehtml::el_para::parse_attributes()
+{
+       const tchar_t* str = get_attr(_t("align"));
+       if(str)
+       {
+               m_style.add_property(_t("text-align"), str, 0, false);
+       }
+
+       html_tag::parse_attributes();
+}
index cee990e93390b91c29550ebb98dd40b74d6b1a08..82e964ba1cab7192f50d5e9b18607dc6812102db 100644 (file)
@@ -1,15 +1,19 @@
-#pragma once\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-       class el_para : public html_tag\r
-       {\r
-       public:\r
-               el_para(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_para();\r
-\r
-               virtual void    parse_attributes() override;\r
-\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_EL_PARA_H
+#define LH_EL_PARA_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+       class el_para : public html_tag
+       {
+       public:
+               el_para(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_para();
+
+               virtual void    parse_attributes() override;
+
+       };
+}
+
+#endif  // LH_EL_PARA_H
index 312c794b317865544f5a8c3c5f6682d696276948..603a46d5865e13bc38fadb3217c8e101d11c7095 100644 (file)
@@ -1,30 +1,30 @@
-#include "html.h"\r
-#include "el_script.h"\r
-#include "document.h"\r
-\r
-\r
-litehtml::el_script::el_script(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)\r
-{\r
-\r
-}\r
-\r
-litehtml::el_script::~el_script()\r
-{\r
-\r
-}\r
-\r
-void litehtml::el_script::parse_attributes()\r
-{\r
-       //TODO: pass script text to document container\r
-}\r
-\r
-bool litehtml::el_script::appendChild(const ptr &el)\r
-{\r
-       el->get_text(m_text);\r
-       return true;\r
-}\r
-\r
-const litehtml::tchar_t* litehtml::el_script::get_tagName() const\r
-{\r
-       return _t("script");\r
-}\r
+#include "html.h"
+#include "el_script.h"
+#include "document.h"
+
+
+litehtml::el_script::el_script(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
+{
+
+}
+
+litehtml::el_script::~el_script()
+{
+
+}
+
+void litehtml::el_script::parse_attributes()
+{
+       //TODO: pass script text to document container
+}
+
+bool litehtml::el_script::appendChild(const ptr &el)
+{
+       el->get_text(m_text);
+       return true;
+}
+
+const litehtml::tchar_t* litehtml::el_script::get_tagName() const
+{
+       return _t("script");
+}
index 7c4c3728daf901783f886691d68f9df7f06a33f0..b8fed36973abd3c8b5b744bbd15a023133d6cacb 100644 (file)
@@ -1,17 +1,21 @@
-#pragma once\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-       class el_script : public element\r
-       {\r
-               tstring m_text;\r
-       public:\r
-               el_script(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_script();\r
-\r
-               virtual void                    parse_attributes() override;\r
-               virtual bool                    appendChild(const ptr &el) override;\r
-               virtual const tchar_t*  get_tagName() const override;\r
-       };\r
-}\r
+#ifndef LH_EL_SCRIPT_H
+#define LH_EL_SCRIPT_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+       class el_script : public element
+       {
+               tstring m_text;
+       public:
+               el_script(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_script();
+
+               virtual void                    parse_attributes() override;
+               virtual bool                    appendChild(const ptr &el) override;
+               virtual const tchar_t*  get_tagName() const override;
+       };
+}
+
+#endif  // LH_EL_SCRIPT_H
index 7114121745cadf7ce9710e026975ba25da1a3069..5178255f120b237c22fb72db983446771fcc7f00 100644 (file)
@@ -1,39 +1,39 @@
-#include "html.h"\r
-#include "document.h"\r
-#include "el_space.h"\r
-\r
-litehtml::el_space::el_space(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc) : el_text(text, doc)\r
-{\r
-}\r
-\r
-litehtml::el_space::~el_space()\r
-{\r
-\r
-}\r
-\r
-bool litehtml::el_space::is_white_space() const\r
-{\r
-       white_space ws = get_white_space();\r
-       if(     ws == white_space_normal || \r
-               ws == white_space_nowrap ||\r
-               ws == white_space_pre_line )\r
-       {\r
-               return true;\r
-       }\r
-       return false;\r
-}\r
-\r
-bool litehtml::el_space::is_break() const\r
-{\r
-       white_space ws = get_white_space();\r
-       if(     ws == white_space_pre ||\r
-               ws == white_space_pre_line ||\r
-               ws == white_space_pre_wrap)\r
-       {\r
-               if(m_text == _t("\n"))\r
-               {\r
-                       return true;\r
-               }\r
-       }\r
-       return false;\r
-}\r
+#include "html.h"
+#include "document.h"
+#include "el_space.h"
+
+litehtml::el_space::el_space(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc) : el_text(text, doc)
+{
+}
+
+litehtml::el_space::~el_space()
+{
+
+}
+
+bool litehtml::el_space::is_white_space() const
+{
+       white_space ws = get_white_space();
+       if(     ws == white_space_normal || 
+               ws == white_space_nowrap ||
+               ws == white_space_pre_line )
+       {
+               return true;
+       }
+       return false;
+}
+
+bool litehtml::el_space::is_break() const
+{
+       white_space ws = get_white_space();
+       if(     ws == white_space_pre ||
+               ws == white_space_pre_line ||
+               ws == white_space_pre_wrap)
+       {
+               if(m_text == _t("\n"))
+               {
+                       return true;
+               }
+       }
+       return false;
+}
index 7fd9ef18caf7ba4c3d23caa71f3a72fabc2c59d2..35ce885120e314d04c9b8c1621c5319431d6ac65 100644 (file)
@@ -1,16 +1,20 @@
-#pragma once\r
-#include "html_tag.h"\r
-#include "el_text.h"\r
-\r
-namespace litehtml\r
-{\r
-       class el_space : public el_text\r
-       {\r
-       public:\r
-               el_space(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_space();\r
-\r
-               virtual bool    is_white_space() const override;\r
-               virtual bool    is_break() const override;\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_EL_SPACE_H
+#define LH_EL_SPACE_H
+
+#include "html_tag.h"
+#include "el_text.h"
+
+namespace litehtml
+{
+       class el_space : public el_text
+       {
+       public:
+               el_space(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_space();
+
+               virtual bool    is_white_space() const override;
+               virtual bool    is_break() const override;
+       };
+}
+
+#endif  // LH_EL_SPACE_H
index 26a640ff0fd9bc9249c6b139530dcd481fd09eca..1b1bb0e0f1671a8eb38c9e55efe91b8cc7ed8a4b 100644 (file)
@@ -1,36 +1,36 @@
-#include "html.h"\r
-#include "el_style.h"\r
-#include "document.h"\r
-\r
-\r
-litehtml::el_style::el_style(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)\r
-{\r
-\r
-}\r
-\r
-litehtml::el_style::~el_style()\r
-{\r
-\r
-}\r
-\r
-void litehtml::el_style::parse_attributes()\r
-{\r
-       tstring text;\r
-\r
-       for(auto& el : m_children)\r
-       {\r
-               el->get_text(text);\r
-       }\r
-       get_document()->add_stylesheet( text.c_str(), 0, get_attr(_t("media")) );\r
-}\r
-\r
-bool litehtml::el_style::appendChild(const ptr &el)\r
-{\r
-       m_children.push_back(el);\r
-       return true;\r
-}\r
-\r
-const litehtml::tchar_t* litehtml::el_style::get_tagName() const\r
-{\r
-       return _t("style");\r
-}\r
+#include "html.h"
+#include "el_style.h"
+#include "document.h"
+
+
+litehtml::el_style::el_style(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
+{
+
+}
+
+litehtml::el_style::~el_style()
+{
+
+}
+
+void litehtml::el_style::parse_attributes()
+{
+       tstring text;
+
+       for(auto& el : m_children)
+       {
+               el->get_text(text);
+       }
+       get_document()->add_stylesheet( text.c_str(), 0, get_attr(_t("media")) );
+}
+
+bool litehtml::el_style::appendChild(const ptr &el)
+{
+       m_children.push_back(el);
+       return true;
+}
+
+const litehtml::tchar_t* litehtml::el_style::get_tagName() const
+{
+       return _t("style");
+}
index 3f7b41d64df23aae09fe710fa4d9f420148035ac..8407b4b91572beecde7d78ba53a0c7cad7d40fa5 100644 (file)
@@ -1,17 +1,21 @@
-#pragma once\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-       class el_style : public element\r
-       {\r
-               elements_vector         m_children;\r
-       public:\r
-               el_style(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_style();\r
-\r
-               virtual void                    parse_attributes() override;\r
-               virtual bool                    appendChild(const ptr &el) override;\r
-               virtual const tchar_t*  get_tagName() const override;\r
-       };\r
-}\r
+#ifndef LH_EL_STYLE_H
+#define LH_EL_STYLE_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+       class el_style : public element
+       {
+               elements_vector         m_children;
+       public:
+               el_style(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_style();
+
+               virtual void                    parse_attributes() override;
+               virtual bool                    appendChild(const ptr &el) override;
+               virtual const tchar_t*  get_tagName() const override;
+       };
+}
+
+#endif  // LH_EL_STYLE_H
index 4f5ff750a36f0f27363edc4ebf73f8f917b0c21a..06d77be7dc7c4dd81c85782cf3f4c68d0f2ce744 100644 (file)
-#include "html.h"\r
-#include "el_table.h"\r
-#include "document.h"\r
-#include "iterators.h"\r
-#include <algorithm>\r
-\r
-\r
-litehtml::el_table::el_table(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)\r
-{\r
-       m_border_spacing_x      = 0;\r
-       m_border_spacing_y      = 0;\r
-       m_border_collapse       = border_collapse_separate;\r
-}\r
-\r
-\r
-litehtml::el_table::~el_table()\r
-{\r
-\r
-}\r
-\r
-bool litehtml::el_table::appendChild(const litehtml::element::ptr& el)\r
-{\r
-       if(!el) return false;\r
-       if(!t_strcmp(el->get_tagName(), _t("tbody")) || !t_strcmp(el->get_tagName(), _t("thead")) || !t_strcmp(el->get_tagName(), _t("tfoot")))\r
-       {\r
-               return html_tag::appendChild(el);\r
-       }\r
-       return false;\r
-}\r
-\r
-void litehtml::el_table::parse_styles(bool is_reparse)\r
-{\r
-       html_tag::parse_styles(is_reparse);\r
-\r
-       m_border_collapse = (border_collapse) value_index(get_style_property(_t("border-collapse"), true, _t("separate")), border_collapse_strings, border_collapse_separate);\r
-\r
-       if(m_border_collapse == border_collapse_separate)\r
-       {\r
-               m_css_border_spacing_x.fromString(get_style_property(_t("-litehtml-border-spacing-x"), true, _t("0px")));\r
-               m_css_border_spacing_y.fromString(get_style_property(_t("-litehtml-border-spacing-y"), true, _t("0px")));\r
-\r
-               int fntsz = get_font_size();\r
-               document::ptr doc = get_document();\r
-               m_border_spacing_x = doc->cvt_units(m_css_border_spacing_x, fntsz);\r
-               m_border_spacing_y = doc->cvt_units(m_css_border_spacing_y, fntsz);\r
-       } else\r
-       {\r
-               m_border_spacing_x      = 0;\r
-               m_border_spacing_y      = 0;\r
-               m_padding.bottom        = 0;\r
-               m_padding.top           = 0;\r
-               m_padding.left          = 0;\r
-               m_padding.right         = 0;\r
-               m_css_padding.bottom.set_value(0, css_units_px);\r
-               m_css_padding.top.set_value(0, css_units_px);\r
-               m_css_padding.left.set_value(0, css_units_px);\r
-               m_css_padding.right.set_value(0, css_units_px);\r
-       }\r
-}\r
-\r
-void litehtml::el_table::parse_attributes()\r
-{\r
-       const tchar_t* str = get_attr(_t("width"));\r
-       if(str)\r
-       {\r
-               m_style.add_property(_t("width"), str, 0, false);\r
-       }\r
-\r
-       str = get_attr(_t("align"));\r
-       if(str)\r
-       {\r
-               int align = value_index(str, _t("left;center;right"));\r
-               switch(align)\r
-               {\r
-               case 1:\r
-                       m_style.add_property(_t("margin-left"), _t("auto"), 0, false);\r
-                       m_style.add_property(_t("margin-right"), _t("auto"), 0, false);\r
-                       break;\r
-               case 2:\r
-                       m_style.add_property(_t("margin-left"), _t("auto"), 0, false);\r
-                       m_style.add_property(_t("margin-right"), _t("0"), 0, false);\r
-                       break;\r
-               }\r
-       }\r
-\r
-       str = get_attr(_t("cellspacing"));\r
-       if(str)\r
-       {\r
-               tstring val = str;\r
-               val += _t(" ");\r
-               val += str;\r
-               m_style.add_property(_t("border-spacing"), val.c_str(), 0, false);\r
-       }\r
-       \r
-       str = get_attr(_t("border"));\r
-       if(str)\r
-       {\r
-               m_style.add_property(_t("border-width"), str, 0, false);\r
-       }\r
-\r
-       str = get_attr(_t("bgcolor"));\r
-       if (str)\r
-       {\r
-               m_style.add_property(_t("background-color"), str, 0, false);\r
-       }\r
-\r
-       html_tag::parse_attributes();\r
-}\r
+#include "html.h"
+#include "el_table.h"
+#include "document.h"
+#include "iterators.h"
+#include <algorithm>
+
+
+litehtml::el_table::el_table(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+       m_border_spacing_x      = 0;
+       m_border_spacing_y      = 0;
+       m_border_collapse       = border_collapse_separate;
+}
+
+
+litehtml::el_table::~el_table()
+{
+
+}
+
+bool litehtml::el_table::appendChild(const litehtml::element::ptr& el)
+{
+       if(!el) return false;
+       if(!t_strcmp(el->get_tagName(), _t("tbody")) || !t_strcmp(el->get_tagName(), _t("thead")) || !t_strcmp(el->get_tagName(), _t("tfoot")))
+       {
+               return html_tag::appendChild(el);
+       }
+       return false;
+}
+
+void litehtml::el_table::parse_styles(bool is_reparse)
+{
+       html_tag::parse_styles(is_reparse);
+
+       m_border_collapse = (border_collapse) value_index(get_style_property(_t("border-collapse"), true, _t("separate")), border_collapse_strings, border_collapse_separate);
+
+       if(m_border_collapse == border_collapse_separate)
+       {
+               m_css_border_spacing_x.fromString(get_style_property(_t("-litehtml-border-spacing-x"), true, _t("0px")));
+               m_css_border_spacing_y.fromString(get_style_property(_t("-litehtml-border-spacing-y"), true, _t("0px")));
+
+               int fntsz = get_font_size();
+               document::ptr doc = get_document();
+               m_border_spacing_x = doc->cvt_units(m_css_border_spacing_x, fntsz);
+               m_border_spacing_y = doc->cvt_units(m_css_border_spacing_y, fntsz);
+       } else
+       {
+               m_border_spacing_x      = 0;
+               m_border_spacing_y      = 0;
+               m_padding.bottom        = 0;
+               m_padding.top           = 0;
+               m_padding.left          = 0;
+               m_padding.right         = 0;
+               m_css_padding.bottom.set_value(0, css_units_px);
+               m_css_padding.top.set_value(0, css_units_px);
+               m_css_padding.left.set_value(0, css_units_px);
+               m_css_padding.right.set_value(0, css_units_px);
+       }
+}
+
+void litehtml::el_table::parse_attributes()
+{
+       const tchar_t* str = get_attr(_t("width"));
+       if(str)
+       {
+               m_style.add_property(_t("width"), str, 0, false);
+       }
+
+       str = get_attr(_t("align"));
+       if(str)
+       {
+               int align = value_index(str, _t("left;center;right"));
+               switch(align)
+               {
+               case 1:
+                       m_style.add_property(_t("margin-left"), _t("auto"), 0, false);
+                       m_style.add_property(_t("margin-right"), _t("auto"), 0, false);
+                       break;
+               case 2:
+                       m_style.add_property(_t("margin-left"), _t("auto"), 0, false);
+                       m_style.add_property(_t("margin-right"), _t("0"), 0, false);
+                       break;
+               }
+       }
+
+       str = get_attr(_t("cellspacing"));
+       if(str)
+       {
+               tstring val = str;
+               val += _t(" ");
+               val += str;
+               m_style.add_property(_t("border-spacing"), val.c_str(), 0, false);
+       }
+       
+       str = get_attr(_t("border"));
+       if(str)
+       {
+               m_style.add_property(_t("border-width"), str, 0, false);
+       }
+
+       str = get_attr(_t("bgcolor"));
+       if (str)
+       {
+               m_style.add_property(_t("background-color"), str, 0, false);
+       }
+
+       html_tag::parse_attributes();
+}
index b298526ce1c1fb9eec9ea0d7fd289c120e31f302..f1ef9731538eb320e638a59ff4697caf81b129cf 100644 (file)
@@ -1,23 +1,27 @@
-#pragma once\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-       struct col_info\r
-       {\r
-               int             width;\r
-               bool    is_auto;\r
-       };\r
-\r
-\r
-       class el_table : public html_tag\r
-       {\r
-       public:\r
-               el_table(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_table();\r
-\r
-               virtual bool    appendChild(const litehtml::element::ptr& el) override;\r
-               virtual void    parse_styles(bool is_reparse = false) override;\r
-               virtual void    parse_attributes() override;\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_EL_TABLE_H
+#define LH_EL_TABLE_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+       struct col_info
+       {
+               int             width;
+               bool    is_auto;
+       };
+
+
+       class el_table : public html_tag
+       {
+       public:
+               el_table(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_table();
+
+               virtual bool    appendChild(const litehtml::element::ptr& el) override;
+               virtual void    parse_styles(bool is_reparse = false) override;
+               virtual void    parse_attributes() override;
+       };
+}
+
+#endif  // LH_EL_TABLE_H
index f32cbcd70128a9d349f3d6d8645491a6eb8e3e30..ca214402d28f62d34dbaa3c440fbfd19d7ecab69 100644 (file)
@@ -1,49 +1,49 @@
-#include "html.h"\r
-#include "el_td.h"\r
-\r
-\r
-litehtml::el_td::el_td(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)\r
-{\r
-\r
-}\r
-\r
-litehtml::el_td::~el_td()\r
-{\r
-\r
-}\r
-\r
-void litehtml::el_td::parse_attributes()\r
-{\r
-       const tchar_t* str = get_attr(_t("width"));\r
-       if(str)\r
-       {\r
-               m_style.add_property(_t("width"), str, 0, false);\r
-       }\r
-       str = get_attr(_t("background"));\r
-       if(str)\r
-       {\r
-               tstring url = _t("url('");\r
-               url += str;\r
-               url += _t("')");\r
-               m_style.add_property(_t("background-image"), url.c_str(), 0, false);\r
-       }\r
-       str = get_attr(_t("align"));\r
-       if(str)\r
-       {\r
-               m_style.add_property(_t("text-align"), str, 0, false);\r
-       }\r
-\r
-       str = get_attr(_t("bgcolor"));\r
-       if (str)\r
-       {\r
-               m_style.add_property(_t("background-color"), str, 0, false);\r
-       }\r
-\r
-       str = get_attr(_t("valign"));\r
-       if(str)\r
-       {\r
-               m_style.add_property(_t("vertical-align"), str, 0, false);\r
-       }\r
-       html_tag::parse_attributes();\r
-}\r
-\r
+#include "html.h"
+#include "el_td.h"
+
+
+litehtml::el_td::el_td(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+
+}
+
+litehtml::el_td::~el_td()
+{
+
+}
+
+void litehtml::el_td::parse_attributes()
+{
+       const tchar_t* str = get_attr(_t("width"));
+       if(str)
+       {
+               m_style.add_property(_t("width"), str, 0, false);
+       }
+       str = get_attr(_t("background"));
+       if(str)
+       {
+               tstring url = _t("url('");
+               url += str;
+               url += _t("')");
+               m_style.add_property(_t("background-image"), url.c_str(), 0, false);
+       }
+       str = get_attr(_t("align"));
+       if(str)
+       {
+               m_style.add_property(_t("text-align"), str, 0, false);
+       }
+
+       str = get_attr(_t("bgcolor"));
+       if (str)
+       {
+               m_style.add_property(_t("background-color"), str, 0, false);
+       }
+
+       str = get_attr(_t("valign"));
+       if(str)
+       {
+               m_style.add_property(_t("vertical-align"), str, 0, false);
+       }
+       html_tag::parse_attributes();
+}
+
index 88d8d68618a14aff6763761566710947e2a7bc7b..5dce950a44539e53bdc2345a85e2cedb4dc8fcca 100644 (file)
@@ -1,14 +1,18 @@
-#pragma once\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-       class el_td : public html_tag\r
-       {\r
-       public:\r
-               el_td(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_td();\r
-\r
-               virtual void parse_attributes() override;\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_EL_TD_H
+#define LH_EL_TD_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+       class el_td : public html_tag
+       {
+       public:
+               el_td(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_td();
+
+               virtual void parse_attributes() override;
+       };
+}
+
+#endif  // LH_EL_TD_H
index f29e2aa698dcb5eb43c4e767efb2d9d2e4cb54a9..9fad2a45ae6da01211ab247ad65f966c809b6aa5 100644 (file)
-#include "html.h"\r
-#include "el_text.h"\r
-#include "document.h"\r
-\r
-litehtml::el_text::el_text(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc) : element(doc)\r
-{\r
-       if(text)\r
-       {\r
-               m_text = text;\r
-       }\r
-       m_text_transform        = text_transform_none;\r
-       m_use_transformed       = false;\r
-       m_draw_spaces           = true;\r
-}\r
-\r
-litehtml::el_text::~el_text()\r
-{\r
-\r
-}\r
-\r
-void litehtml::el_text::get_content_size( size& sz, int max_width )\r
-{\r
-       sz = m_size;\r
-}\r
-\r
-void litehtml::el_text::get_text( tstring& text )\r
-{\r
-       text += m_text;\r
-}\r
-\r
-const litehtml::tchar_t* litehtml::el_text::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ )\r
-{\r
-       if(inherited)\r
-       {\r
-               element::ptr el_parent = parent();\r
-               if (el_parent)\r
-               {\r
-                       return el_parent->get_style_property(name, inherited, def);\r
-               }\r
-       }\r
-       return def;\r
-}\r
-\r
-void litehtml::el_text::parse_styles(bool is_reparse)\r
-{\r
-       m_text_transform        = (text_transform)      value_index(get_style_property(_t("text-transform"), true,      _t("none")),    text_transform_strings, text_transform_none);\r
-       if(m_text_transform != text_transform_none)\r
-       {\r
-               m_transformed_text      = m_text;\r
-               m_use_transformed = true;\r
-               get_document()->container()->transform_text(m_transformed_text, m_text_transform);\r
-       }\r
-\r
-       if(is_white_space())\r
-       {\r
-               m_transformed_text = _t(" ");\r
-               m_use_transformed = true;\r
-       } else\r
-       {\r
-               if(m_text == _t("\t"))\r
-               {\r
-                       m_transformed_text = _t("    ");\r
-                       m_use_transformed = true;\r
-               }\r
-               if(m_text == _t("\n") || m_text == _t("\r"))\r
-               {\r
-                       m_transformed_text = _t("");\r
-                       m_use_transformed = true;\r
-               }\r
-       }\r
-\r
-       font_metrics fm;\r
-       uint_ptr font = 0;\r
-       element::ptr el_parent = parent();\r
-       if (el_parent)\r
-       {\r
-               font = el_parent->get_font(&fm);\r
-       }\r
-       if(is_break())\r
-       {\r
-               m_size.height   = 0;\r
-               m_size.width    = 0;\r
-       } else\r
-       {\r
-               m_size.height   = fm.height;\r
-               m_size.width    = get_document()->container()->text_width(m_use_transformed ? m_transformed_text.c_str() : m_text.c_str(), font);\r
-       }\r
-       m_draw_spaces = fm.draw_spaces;\r
-}\r
-\r
-int litehtml::el_text::get_base_line()\r
-{\r
-       element::ptr el_parent = parent();\r
-       if (el_parent)\r
-       {\r
-               return el_parent->get_base_line();\r
-       }\r
-       return 0;\r
-}\r
-\r
-void litehtml::el_text::draw( uint_ptr hdc, int x, int y, const position* clip )\r
-{\r
-       if(is_white_space() && !m_draw_spaces)\r
-       {\r
-               return;\r
-       }\r
-\r
-       position pos = m_pos;\r
-       pos.x   += x;\r
-       pos.y   += y;\r
-\r
-       if(pos.does_intersect(clip))\r
-       {\r
-               element::ptr el_parent = parent();\r
-               if (el_parent)\r
-               {\r
-                       document::ptr doc = get_document();\r
-\r
-                       uint_ptr font = el_parent->get_font();\r
-                       litehtml::web_color color = el_parent->get_color(_t("color"), true, doc->get_def_color());\r
-                       doc->container()->draw_text(hdc, m_use_transformed ? m_transformed_text.c_str() : m_text.c_str(), font, color, pos);\r
-               }\r
-       }\r
-}\r
-\r
-int litehtml::el_text::line_height() const\r
-{\r
-       element::ptr el_parent = parent();\r
-       if (el_parent)\r
-       {\r
-               return el_parent->line_height();\r
-       }\r
-       return 0;\r
-}\r
-\r
-litehtml::uint_ptr litehtml::el_text::get_font( font_metrics* fm /*= 0*/ )\r
-{\r
-       element::ptr el_parent = parent();\r
-       if (el_parent)\r
-       {\r
-               return el_parent->get_font(fm);\r
-       }\r
-       return 0;\r
-}\r
-\r
-litehtml::style_display litehtml::el_text::get_display() const\r
-{\r
-       return display_inline_text;\r
-}\r
-\r
-litehtml::white_space litehtml::el_text::get_white_space() const\r
-{\r
-       element::ptr el_parent = parent();\r
-       if (el_parent) return el_parent->get_white_space();\r
-       return white_space_normal;\r
-}\r
-\r
-litehtml::element_position litehtml::el_text::get_element_position(css_offsets* offsets) const\r
-{\r
-       element::ptr p = parent();\r
-       while(p && p->get_display() == display_inline)\r
-       {\r
-               if(p->get_element_position() == element_position_relative)\r
-               {\r
-                       if(offsets)\r
-                       {\r
-                               *offsets = p->get_css_offsets();\r
-                       }\r
-                       return element_position_relative;\r
-               }\r
-               p = p->parent();\r
-       }\r
-       return element_position_static;\r
-}\r
-\r
-litehtml::css_offsets litehtml::el_text::get_css_offsets() const\r
-{\r
-       element::ptr p = parent();\r
-       while(p && p->get_display() == display_inline)\r
-       {\r
-               if(p->get_element_position() == element_position_relative)\r
-               {\r
-                       return p->get_css_offsets();\r
-               }\r
-               p = p->parent();\r
-       }\r
-       return css_offsets();\r
-}\r
+#include "html.h"
+#include "el_text.h"
+#include "document.h"
+
+litehtml::el_text::el_text(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc) : element(doc)
+{
+       if(text)
+       {
+               m_text = text;
+       }
+       m_text_transform        = text_transform_none;
+       m_use_transformed       = false;
+       m_draw_spaces           = true;
+}
+
+litehtml::el_text::~el_text()
+{
+
+}
+
+void litehtml::el_text::get_content_size( size& sz, int max_width )
+{
+       sz = m_size;
+}
+
+void litehtml::el_text::get_text( tstring& text )
+{
+       text += m_text;
+}
+
+const litehtml::tchar_t* litehtml::el_text::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ )
+{
+       if(inherited)
+       {
+               element::ptr el_parent = parent();
+               if (el_parent)
+               {
+                       return el_parent->get_style_property(name, inherited, def);
+               }
+       }
+       return def;
+}
+
+void litehtml::el_text::parse_styles(bool is_reparse)
+{
+       m_text_transform        = (text_transform)      value_index(get_style_property(_t("text-transform"), true,      _t("none")),    text_transform_strings, text_transform_none);
+       if(m_text_transform != text_transform_none)
+       {
+               m_transformed_text      = m_text;
+               m_use_transformed = true;
+               get_document()->container()->transform_text(m_transformed_text, m_text_transform);
+       }
+
+       if(is_white_space())
+       {
+               m_transformed_text = _t(" ");
+               m_use_transformed = true;
+       } else
+       {
+               if(m_text == _t("\t"))
+               {
+                       m_transformed_text = _t("    ");
+                       m_use_transformed = true;
+               }
+               if(m_text == _t("\n") || m_text == _t("\r"))
+               {
+                       m_transformed_text = _t("");
+                       m_use_transformed = true;
+               }
+       }
+
+       font_metrics fm;
+       uint_ptr font = 0;
+       element::ptr el_parent = parent();
+       if (el_parent)
+       {
+               font = el_parent->get_font(&fm);
+       }
+       if(is_break())
+       {
+               m_size.height   = 0;
+               m_size.width    = 0;
+       } else
+       {
+               m_size.height   = fm.height;
+               m_size.width    = get_document()->container()->text_width(m_use_transformed ? m_transformed_text.c_str() : m_text.c_str(), font);
+       }
+       m_draw_spaces = fm.draw_spaces;
+}
+
+int litehtml::el_text::get_base_line()
+{
+       element::ptr el_parent = parent();
+       if (el_parent)
+       {
+               return el_parent->get_base_line();
+       }
+       return 0;
+}
+
+void litehtml::el_text::draw( uint_ptr hdc, int x, int y, const position* clip )
+{
+       if(is_white_space() && !m_draw_spaces)
+       {
+               return;
+       }
+
+       position pos = m_pos;
+       pos.x   += x;
+       pos.y   += y;
+
+       if(pos.does_intersect(clip))
+       {
+               element::ptr el_parent = parent();
+               if (el_parent)
+               {
+                       document::ptr doc = get_document();
+
+                       uint_ptr font = el_parent->get_font();
+                       litehtml::web_color color = el_parent->get_color(_t("color"), true, doc->get_def_color());
+                       doc->container()->draw_text(hdc, m_use_transformed ? m_transformed_text.c_str() : m_text.c_str(), font, color, pos);
+               }
+       }
+}
+
+int litehtml::el_text::line_height() const
+{
+       element::ptr el_parent = parent();
+       if (el_parent)
+       {
+               return el_parent->line_height();
+       }
+       return 0;
+}
+
+litehtml::uint_ptr litehtml::el_text::get_font( font_metrics* fm /*= 0*/ )
+{
+       element::ptr el_parent = parent();
+       if (el_parent)
+       {
+               return el_parent->get_font(fm);
+       }
+       return 0;
+}
+
+litehtml::style_display litehtml::el_text::get_display() const
+{
+       return display_inline_text;
+}
+
+litehtml::white_space litehtml::el_text::get_white_space() const
+{
+       element::ptr el_parent = parent();
+       if (el_parent) return el_parent->get_white_space();
+       return white_space_normal;
+}
+
+litehtml::element_position litehtml::el_text::get_element_position(css_offsets* offsets) const
+{
+       element::ptr p = parent();
+       while(p && p->get_display() == display_inline)
+       {
+               if(p->get_element_position() == element_position_relative)
+               {
+                       if(offsets)
+                       {
+                               *offsets = p->get_css_offsets();
+                       }
+                       return element_position_relative;
+               }
+               p = p->parent();
+       }
+       return element_position_static;
+}
+
+litehtml::css_offsets litehtml::el_text::get_css_offsets() const
+{
+       element::ptr p = parent();
+       while(p && p->get_display() == display_inline)
+       {
+               if(p->get_element_position() == element_position_relative)
+               {
+                       return p->get_css_offsets();
+               }
+               p = p->parent();
+       }
+       return css_offsets();
+}
index 82c42bc705960bd33019ed1bea372eddee372184..d2149deb2c6081b0d7919b5793ca0e3dca4eb473 100644 (file)
@@ -1,35 +1,38 @@
-#pragma once\r
-\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-       class el_text : public element\r
-       {\r
-       protected:\r
-               tstring                 m_text;\r
-               tstring                 m_transformed_text;\r
-               size                    m_size;\r
-               text_transform  m_text_transform;\r
-               bool                    m_use_transformed;\r
-               bool                    m_draw_spaces;\r
-       public:\r
-               el_text(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_text();\r
-\r
-               virtual void                            get_text(tstring& text) override;\r
-               virtual const tchar_t*          get_style_property(const tchar_t* name, bool inherited, const tchar_t* def = 0) override;\r
-               virtual void                            parse_styles(bool is_reparse) override;\r
-               virtual int                                     get_base_line() override;\r
-               virtual void                            draw(uint_ptr hdc, int x, int y, const position* clip) override;\r
-               virtual int                                     line_height() const override;\r
-               virtual uint_ptr                        get_font(font_metrics* fm = 0) override;\r
-               virtual style_display           get_display() const override;\r
-               virtual white_space                     get_white_space() const override;\r
-               virtual element_position        get_element_position(css_offsets* offsets = 0) const override;\r
-               virtual css_offsets                     get_css_offsets() const override;\r
-\r
-       protected:\r
-               virtual void                            get_content_size(size& sz, int max_width) override;\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_EL_TEXT_H
+#define LH_EL_TEXT_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+       class el_text : public element
+       {
+       protected:
+               tstring                 m_text;
+               tstring                 m_transformed_text;
+               size                    m_size;
+               text_transform  m_text_transform;
+               bool                    m_use_transformed;
+               bool                    m_draw_spaces;
+       public:
+               el_text(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_text();
+
+               virtual void                            get_text(tstring& text) override;
+               virtual const tchar_t*          get_style_property(const tchar_t* name, bool inherited, const tchar_t* def = 0) override;
+               virtual void                            parse_styles(bool is_reparse) override;
+               virtual int                                     get_base_line() override;
+               virtual void                            draw(uint_ptr hdc, int x, int y, const position* clip) override;
+               virtual int                                     line_height() const override;
+               virtual uint_ptr                        get_font(font_metrics* fm = 0) override;
+               virtual style_display           get_display() const override;
+               virtual white_space                     get_white_space() const override;
+               virtual element_position        get_element_position(css_offsets* offsets = 0) const override;
+               virtual css_offsets                     get_css_offsets() const override;
+
+       protected:
+               virtual void                            get_content_size(size& sz, int max_width) override;
+       };
+}
+
+#endif  // LH_EL_TEXT_H
index 399421f2cec19a5d6e377029e63bdede929b9567..7a9590d1800bfcf46f00e10a2957a2400a07d39f 100644 (file)
@@ -1,20 +1,20 @@
-#include "html.h"\r
-#include "el_title.h"\r
-#include "document.h"\r
-\r
-litehtml::el_title::el_title(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)\r
-{\r
-\r
-}\r
-\r
-litehtml::el_title::~el_title()\r
-{\r
-\r
-}\r
-\r
-void litehtml::el_title::parse_attributes()\r
-{\r
-       tstring text;\r
-       get_text(text);\r
-       get_document()->container()->set_caption(text.c_str());\r
-}\r
+#include "html.h"
+#include "el_title.h"
+#include "document.h"
+
+litehtml::el_title::el_title(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
+{
+
+}
+
+litehtml::el_title::~el_title()
+{
+
+}
+
+void litehtml::el_title::parse_attributes()
+{
+       tstring text;
+       get_text(text);
+       get_document()->container()->set_caption(text.c_str());
+}
index b1c7139c9022a3fb8b90ba5e3ed3082d5642b733..20dc8cdd6453167b30424c81bd87e6307dda2d4a 100644 (file)
@@ -1,15 +1,19 @@
-#pragma once\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-       class el_title : public html_tag\r
-       {\r
-       public:\r
-               el_title(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_title();\r
-\r
-       protected:\r
-               virtual void    parse_attributes() override;\r
-       };\r
-}\r
+#ifndef LH_EL_TITLE_H
+#define LH_EL_TITLE_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+       class el_title : public html_tag
+       {
+       public:
+               el_title(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_title();
+
+       protected:
+               virtual void    parse_attributes() override;
+       };
+}
+
+#endif  // LH_EL_TITLE_H
index a80dde41f9cdc7e75fbb50bd5451047478f62221..0ef0675b5bdee7cdbd0ae7662daa96df33ba8bfd 100644 (file)
@@ -1,51 +1,51 @@
-#include "html.h"\r
-#include "el_tr.h"\r
-\r
-\r
-litehtml::el_tr::el_tr(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)\r
-{\r
-\r
-}\r
-\r
-litehtml::el_tr::~el_tr()\r
-{\r
-\r
-}\r
-\r
-void litehtml::el_tr::parse_attributes()\r
-{\r
-       const tchar_t* str = get_attr(_t("align"));\r
-       if(str)\r
-       {\r
-               m_style.add_property(_t("text-align"), str, 0, false);\r
-       }\r
-       str = get_attr(_t("valign"));\r
-       if(str)\r
-       {\r
-               m_style.add_property(_t("vertical-align"), str, 0, false);\r
-       }\r
-       str = get_attr(_t("bgcolor"));\r
-       if (str)\r
-       {\r
-               m_style.add_property(_t("background-color"), str, 0, false);\r
-       }\r
-       html_tag::parse_attributes();\r
-}\r
-\r
-void litehtml::el_tr::get_inline_boxes( position::vector& boxes )\r
-{\r
-       position pos;\r
-       for(auto& el : m_children)\r
-       {\r
-               if(el->get_display() == display_table_cell)\r
-               {\r
-                       pos.x           = el->left() + el->margin_left();\r
-                       pos.y           = el->top() - m_padding.top - m_borders.top;\r
-\r
-                       pos.width       = el->right() - pos.x - el->margin_right() - el->margin_left();\r
-                       pos.height      = el->height() + m_padding.top + m_padding.bottom + m_borders.top + m_borders.bottom;\r
-\r
-                       boxes.push_back(pos);\r
-               }\r
-       }\r
-}\r
+#include "html.h"
+#include "el_tr.h"
+
+
+litehtml::el_tr::el_tr(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+
+}
+
+litehtml::el_tr::~el_tr()
+{
+
+}
+
+void litehtml::el_tr::parse_attributes()
+{
+       const tchar_t* str = get_attr(_t("align"));
+       if(str)
+       {
+               m_style.add_property(_t("text-align"), str, 0, false);
+       }
+       str = get_attr(_t("valign"));
+       if(str)
+       {
+               m_style.add_property(_t("vertical-align"), str, 0, false);
+       }
+       str = get_attr(_t("bgcolor"));
+       if (str)
+       {
+               m_style.add_property(_t("background-color"), str, 0, false);
+       }
+       html_tag::parse_attributes();
+}
+
+void litehtml::el_tr::get_inline_boxes( position::vector& boxes )
+{
+       position pos;
+       for(auto& el : m_children)
+       {
+               if(el->get_display() == display_table_cell)
+               {
+                       pos.x           = el->left() + el->margin_left();
+                       pos.y           = el->top() - m_padding.top - m_borders.top;
+
+                       pos.width       = el->right() - pos.x - el->margin_right() - el->margin_left();
+                       pos.height      = el->height() + m_padding.top + m_padding.bottom + m_borders.top + m_borders.bottom;
+
+                       boxes.push_back(pos);
+               }
+       }
+}
index f4e50aa4bc3118cb9e5426b8fea6982cdc84b1a0..0fbb6c28d4a8c6e4e7c5971f815a0cdffde8424c 100644 (file)
@@ -1,15 +1,19 @@
-#pragma once\r
-#include "html_tag.h"\r
-\r
-namespace litehtml\r
-{\r
-       class el_tr : public html_tag\r
-       {\r
-       public:\r
-               el_tr(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~el_tr();\r
-\r
-               virtual void    parse_attributes() override;\r
-               virtual void    get_inline_boxes(position::vector& boxes) override;\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_EL_TR_H
+#define LH_EL_TR_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+       class el_tr : public html_tag
+       {
+       public:
+               el_tr(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~el_tr();
+
+               virtual void    parse_attributes() override;
+               virtual void    get_inline_boxes(position::vector& boxes) override;
+       };
+}
+
+#endif  // LH_EL_TR_H
index 41a69e7fb04ae73aba41517d1b2f7706d7b81f4a..9055cc1f64f552d39da55f38f027c74a39bbd04d 100644 (file)
-#include "html.h"\r
-#include "element.h"\r
-#include "document.h"\r
-\r
-#define LITEHTML_EMPTY_FUNC                    {}\r
-#define LITEHTML_RETURN_FUNC(ret)      {return ret;}\r
-\r
-litehtml::element::element(const std::shared_ptr<litehtml::document>& doc) : m_doc(doc)\r
-{\r
-       m_box           = 0;\r
-       m_skip          = false;\r
-}\r
-\r
-litehtml::element::~element()\r
-{\r
-\r
-}\r
-\r
-\r
-bool litehtml::element::is_point_inside( int x, int y )\r
-{\r
-       if(get_display() != display_inline && get_display() != display_table_row)\r
-       {\r
-               position pos = m_pos;\r
-               pos += m_padding;\r
-               pos += m_borders;\r
-               if(pos.is_point_inside(x, y))\r
-               {\r
-                       return true;\r
-               } else\r
-               {\r
-                       return false;\r
-               }\r
-       } else\r
-       {\r
-               position::vector boxes;\r
-               get_inline_boxes(boxes);\r
-               for(position::vector::iterator box = boxes.begin(); box != boxes.end(); box++)\r
-               {\r
-                       if(box->is_point_inside(x, y))\r
-                       {\r
-                               return true;\r
-                       }\r
-               }\r
-       }\r
-       return false;\r
-}\r
-\r
-litehtml::web_color litehtml::element::get_color( const tchar_t* prop_name, bool inherited, const litehtml::web_color& def_color )\r
-{\r
-       const tchar_t* clrstr = get_style_property(prop_name, inherited, 0);\r
-       if(!clrstr)\r
-       {\r
-               return def_color;\r
-       }\r
-       return web_color::from_string(clrstr);\r
-}\r
-\r
-litehtml::position litehtml::element::get_placement() const\r
-{\r
-       litehtml::position pos = m_pos;\r
-       element::ptr cur_el = parent();\r
-       while(cur_el)\r
-       {\r
-               pos.x += cur_el->m_pos.x;\r
-               pos.y += cur_el->m_pos.y;\r
-               cur_el = cur_el->parent();\r
-       }\r
-       return pos;\r
-}\r
-\r
-bool litehtml::element::is_inline_box() const\r
-{\r
-       style_display d = get_display();\r
-       if(     d == display_inline || \r
-               d == display_inline_block || \r
-               d == display_inline_text)\r
-       {\r
-               return true;\r
-       }\r
-       return false;\r
-}\r
-\r
-bool litehtml::element::collapse_top_margin() const\r
-{\r
-       if(!m_borders.top && !m_padding.top && in_normal_flow() && get_float() == float_none && m_margins.top >= 0 && have_parent())\r
-       {\r
-               return true;\r
-       }\r
-       return false;\r
-}\r
-\r
-bool litehtml::element::collapse_bottom_margin() const\r
-{\r
-       if(!m_borders.bottom && !m_padding.bottom && in_normal_flow() && get_float() == float_none && m_margins.bottom >= 0 && have_parent())\r
-       {\r
-               return true;\r
-       }\r
-       return false;\r
-}\r
-\r
-bool litehtml::element::get_predefined_height(int& p_height) const\r
-{\r
-       css_length h = get_css_height();\r
-       if(h.is_predefined())\r
-       {\r
-               p_height = m_pos.height;\r
-               return false;\r
-       }\r
-       if(h.units() == css_units_percentage)\r
-       {\r
-               element::ptr el_parent = parent();\r
-               if (!el_parent)\r
-               {\r
-                       position client_pos;\r
-                       get_document()->container()->get_client_rect(client_pos);\r
-                       p_height = h.calc_percent(client_pos.height);\r
-                       return true;\r
-               } else\r
-               {\r
-                       int ph = 0;\r
-                       if (el_parent->get_predefined_height(ph))\r
-                       {\r
-                               p_height = h.calc_percent(ph);\r
-                               if (is_body())\r
-                               {\r
-                                       p_height -= content_margins_height();\r
-                               }\r
-                               return true;\r
-                       } else\r
-                       {\r
-                               p_height = m_pos.height;\r
-                               return false;\r
-                       }\r
-               }\r
-       }\r
-       p_height = get_document()->cvt_units(h, get_font_size());\r
-       return true;\r
-}\r
-\r
-void litehtml::element::calc_document_size( litehtml::size& sz, int x /*= 0*/, int y /*= 0*/ )\r
-{\r
-       if(is_visible())\r
-       {\r
-               sz.width        = std::max(sz.width,    x + right());\r
-               sz.height       = std::max(sz.height,   y + bottom());\r
-       }\r
-}\r
-\r
-void litehtml::element::get_redraw_box(litehtml::position& pos, int x /*= 0*/, int y /*= 0*/)\r
-{\r
-       if(is_visible())\r
-       {\r
-               int p_left              = std::min(pos.left(),  x + m_pos.left() - m_padding.left - m_borders.left);\r
-               int p_right             = std::max(pos.right(), x + m_pos.right() + m_padding.left + m_borders.left);\r
-               int p_top               = std::min(pos.top(), y + m_pos.top() - m_padding.top - m_borders.top);\r
-               int p_bottom    = std::max(pos.bottom(), y + m_pos.bottom() + m_padding.bottom + m_borders.bottom);\r
-\r
-               pos.x = p_left;\r
-               pos.y = p_top;\r
-               pos.width       = p_right - p_left;\r
-               pos.height      = p_bottom - p_top;\r
-       }\r
-}\r
-\r
-int litehtml::element::calc_width(int defVal) const\r
-{\r
-       css_length w = get_css_width();\r
-       if(w.is_predefined())\r
-       {\r
-               return defVal;\r
-       }\r
-       if(w.units() == css_units_percentage)\r
-       {\r
-               element::ptr el_parent = parent();\r
-               if (!el_parent)\r
-               {\r
-                       position client_pos;\r
-                       get_document()->container()->get_client_rect(client_pos);\r
-                       return w.calc_percent(client_pos.width);\r
-               } else\r
-               {\r
-                       int pw = el_parent->calc_width(defVal);\r
-                       if (is_body())\r
-                       {\r
-                               pw -= content_margins_width();\r
-                       }\r
-                       return w.calc_percent(pw);\r
-               }\r
-       }\r
-       return  get_document()->cvt_units(w, get_font_size());\r
-}\r
-\r
-bool litehtml::element::is_ancestor(const ptr &el) const\r
-{\r
-       element::ptr el_parent = parent();\r
-       while(el_parent && el_parent != el)\r
-       {\r
-               el_parent = el_parent->parent();\r
-       }\r
-       if(el_parent)\r
-       {\r
-               return true;\r
-       }\r
-       return false;\r
-}\r
-\r
-int litehtml::element::get_inline_shift_left()\r
-{\r
-       int ret = 0;\r
-       element::ptr el_parent = parent();\r
-       if (el_parent)\r
-       {\r
-               if (el_parent->get_display() == display_inline)\r
-               {\r
-                       style_display disp = get_display();\r
-\r
-                       if (disp == display_inline_text || disp == display_inline_block)\r
-                       {\r
-                               element::ptr el = shared_from_this();\r
-                               while (el_parent && el_parent->get_display() == display_inline)\r
-                               {\r
-                                       if (el_parent->is_first_child_inline(el))\r
-                                       {\r
-                                               ret += el_parent->padding_left() + el_parent->border_left() + el_parent->margin_left();\r
-                                       }\r
-                                       el = el_parent;\r
-                                       el_parent = el_parent->parent();\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       return ret;\r
-}\r
-\r
-int litehtml::element::get_inline_shift_right()\r
-{\r
-       int ret = 0;\r
-       element::ptr el_parent = parent();\r
-       if (el_parent)\r
-       {\r
-               if (el_parent->get_display() == display_inline)\r
-               {\r
-                       style_display disp = get_display();\r
-\r
-                       if (disp == display_inline_text || disp == display_inline_block)\r
-                       {\r
-                               element::ptr el = shared_from_this();\r
-                               while (el_parent && el_parent->get_display() == display_inline)\r
-                               {\r
-                                       if (el_parent->is_last_child_inline(el))\r
-                                       {\r
-                                               ret += el_parent->padding_right() + el_parent->border_right() + el_parent->margin_right();\r
-                                       }\r
-                                       el = el_parent;\r
-                                       el_parent = el_parent->parent();\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       return ret;\r
-}\r
-\r
-void litehtml::element::apply_relative_shift(int parent_width)\r
-{\r
-       css_offsets offsets;\r
-       if (get_element_position(&offsets) == element_position_relative)\r
-       {\r
-               element::ptr parent_ptr = parent();\r
-               if (!offsets.left.is_predefined())\r
-               {\r
-                       m_pos.x += offsets.left.calc_percent(parent_width);\r
-               }\r
-               else if (!offsets.right.is_predefined())\r
-               {\r
-                       m_pos.x -= offsets.right.calc_percent(parent_width);\r
-               }\r
-               if (!offsets.top.is_predefined())\r
-               {\r
-                       int h = 0;\r
-\r
-                       if (offsets.top.units() == css_units_percentage)\r
-                       {\r
-                               element::ptr el_parent = parent();\r
-                               if (el_parent)\r
-                               {\r
-                                       el_parent->get_predefined_height(h);\r
-                               }\r
-                       }\r
-\r
-                       m_pos.y += offsets.top.calc_percent(h);\r
-               }\r
-               else if (!offsets.bottom.is_predefined())\r
-               {\r
-                       int h = 0;\r
-\r
-                       if (offsets.top.units() == css_units_percentage)\r
-                       {\r
-                               element::ptr el_parent = parent();\r
-                               if (el_parent)\r
-                               {\r
-                                       el_parent->get_predefined_height(h);\r
-                               }\r
-                       }\r
-\r
-                       m_pos.y -= offsets.bottom.calc_percent(h);\r
-               }\r
-       }\r
-}\r
-\r
-void litehtml::element::calc_auto_margins(int parent_width)                                                    LITEHTML_EMPTY_FUNC\r
-const litehtml::background* litehtml::element::get_background(bool own_only)           LITEHTML_RETURN_FUNC(0)\r
-litehtml::element::ptr litehtml::element::get_element_by_point(int x, int y, int client_x, int client_y)       LITEHTML_RETURN_FUNC(0)\r
-litehtml::element::ptr litehtml::element::get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex) LITEHTML_RETURN_FUNC(0)\r
-void litehtml::element::get_line_left_right( int y, int def_right, int& ln_left, int& ln_right ) LITEHTML_EMPTY_FUNC\r
-void litehtml::element::add_style( const litehtml::style& st )                                         LITEHTML_EMPTY_FUNC\r
-void litehtml::element::select_all(const css_selector& selector, litehtml::elements_vector& res)       LITEHTML_EMPTY_FUNC\r
-litehtml::elements_vector litehtml::element::select_all(const litehtml::css_selector& selector)         LITEHTML_RETURN_FUNC(litehtml::elements_vector())\r
-litehtml::elements_vector litehtml::element::select_all(const litehtml::tstring& selector)                      LITEHTML_RETURN_FUNC(litehtml::elements_vector())\r
-litehtml::element::ptr litehtml::element::select_one( const css_selector& selector ) LITEHTML_RETURN_FUNC(0)\r
-litehtml::element::ptr litehtml::element::select_one( const tstring& selector )                LITEHTML_RETURN_FUNC(0)\r
-litehtml::element::ptr litehtml::element::find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/) LITEHTML_RETURN_FUNC(0)\r
-litehtml::element::ptr litehtml::element::find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/) LITEHTML_RETURN_FUNC(0)\r
-bool litehtml::element::is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const                LITEHTML_RETURN_FUNC(false)\r
-bool litehtml::element::is_nth_child(const element::ptr&, int num, int off, bool of_type) const                LITEHTML_RETURN_FUNC(false)\r
-bool litehtml::element::is_only_child(const element::ptr& el, bool of_type)     const  LITEHTML_RETURN_FUNC(false)\r
-litehtml::overflow litehtml::element::get_overflow() const                                                     LITEHTML_RETURN_FUNC(overflow_visible)\r
-void litehtml::element::draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex ) LITEHTML_EMPTY_FUNC\r
-void litehtml::element::draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned ) LITEHTML_EMPTY_FUNC\r
-void litehtml::element::render_positioned(render_type rt)                                                      LITEHTML_EMPTY_FUNC\r
-int litehtml::element::get_zindex() const                                                                                      LITEHTML_RETURN_FUNC(0)\r
-bool litehtml::element::fetch_positioned()                                                                                     LITEHTML_RETURN_FUNC(false)\r
-litehtml::visibility litehtml::element::get_visibility() const                                         LITEHTML_RETURN_FUNC(visibility_visible)\r
-void litehtml::element::apply_vertical_align()                                                                         LITEHTML_EMPTY_FUNC\r
-void litehtml::element::set_css_width( css_length& w )                                                         LITEHTML_EMPTY_FUNC\r
-litehtml::element::ptr litehtml::element::get_child( int idx ) const                           LITEHTML_RETURN_FUNC(0)\r
-size_t litehtml::element::get_children_count() const                                                           LITEHTML_RETURN_FUNC(0)\r
-void litehtml::element::calc_outlines( int parent_width )                                                      LITEHTML_EMPTY_FUNC\r
-litehtml::css_length litehtml::element::get_css_width() const                                          LITEHTML_RETURN_FUNC(css_length())\r
-litehtml::css_length litehtml::element::get_css_height() const                                         LITEHTML_RETURN_FUNC(css_length())\r
-litehtml::element_clear litehtml::element::get_clear() const                                           LITEHTML_RETURN_FUNC(clear_none)\r
-litehtml::css_length litehtml::element::get_css_left() const                                           LITEHTML_RETURN_FUNC(css_length())\r
-litehtml::css_length litehtml::element::get_css_right() const                                          LITEHTML_RETURN_FUNC(css_length())\r
-litehtml::css_length litehtml::element::get_css_top() const                                                    LITEHTML_RETURN_FUNC(css_length())\r
-litehtml::css_length litehtml::element::get_css_bottom() const                                         LITEHTML_RETURN_FUNC(css_length())\r
-litehtml::css_offsets litehtml::element::get_css_offsets() const                                       LITEHTML_RETURN_FUNC(css_offsets())\r
-litehtml::vertical_align litehtml::element::get_vertical_align() const                         LITEHTML_RETURN_FUNC(va_baseline)\r
-int litehtml::element::place_element(const ptr &el, int max_width)                                     LITEHTML_RETURN_FUNC(0)\r
-int litehtml::element::render_inline(const ptr &container, int max_width)                      LITEHTML_RETURN_FUNC(0)\r
-void litehtml::element::add_positioned(const ptr &el)                                                  LITEHTML_EMPTY_FUNC\r
-int litehtml::element::find_next_line_top( int top, int width, int def_right )         LITEHTML_RETURN_FUNC(0)\r
-litehtml::element_float litehtml::element::get_float() const                                           LITEHTML_RETURN_FUNC(float_none)\r
-void litehtml::element::add_float(const ptr &el, int x, int y)                                 LITEHTML_EMPTY_FUNC\r
-void litehtml::element::update_floats(int dy, const ptr &parent)                                       LITEHTML_EMPTY_FUNC\r
-int litehtml::element::get_line_left( int y )                                                                          LITEHTML_RETURN_FUNC(0)\r
-int litehtml::element::get_line_right( int y, int def_right )                                          LITEHTML_RETURN_FUNC(def_right)\r
-int litehtml::element::get_left_floats_height() const                                                          LITEHTML_RETURN_FUNC(0)\r
-int litehtml::element::get_right_floats_height() const                                                         LITEHTML_RETURN_FUNC(0)\r
-int litehtml::element::get_floats_height(element_float el_float) const                         LITEHTML_RETURN_FUNC(0)\r
-bool litehtml::element::is_floats_holder() const                                                                       LITEHTML_RETURN_FUNC(false)\r
-void litehtml::element::get_content_size( size& sz, int max_width )                                    LITEHTML_EMPTY_FUNC\r
-void litehtml::element::init()                                                                                                         LITEHTML_EMPTY_FUNC\r
-int litehtml::element::render( int x, int y, int max_width, bool second_pass )         LITEHTML_RETURN_FUNC(0)\r
-bool litehtml::element::appendChild(const ptr &el)                                             LITEHTML_RETURN_FUNC(false)\r
-bool litehtml::element::removeChild(const ptr &el)                                             LITEHTML_RETURN_FUNC(false)\r
-void litehtml::element::clearRecursive()                                                                                       LITEHTML_EMPTY_FUNC\r
-const litehtml::tchar_t* litehtml::element::get_tagName() const                                                LITEHTML_RETURN_FUNC(_t(""))\r
-void litehtml::element::set_tagName( const tchar_t* tag )                                                      LITEHTML_EMPTY_FUNC\r
-void litehtml::element::set_data( const tchar_t* data )                                                                LITEHTML_EMPTY_FUNC\r
-void litehtml::element::set_attr( const tchar_t* name, const tchar_t* val )                    LITEHTML_EMPTY_FUNC\r
-void litehtml::element::apply_stylesheet( const litehtml::css& stylesheet )                    LITEHTML_EMPTY_FUNC\r
-void litehtml::element::refresh_styles()                                                                                       LITEHTML_EMPTY_FUNC\r
-void litehtml::element::on_click()                                                                                                     LITEHTML_EMPTY_FUNC\r
-void litehtml::element::init_font()                                                                                                    LITEHTML_EMPTY_FUNC\r
-void litehtml::element::get_inline_boxes( position::vector& boxes )                                    LITEHTML_EMPTY_FUNC\r
-void litehtml::element::parse_styles( bool is_reparse /*= false*/ )                                    LITEHTML_EMPTY_FUNC\r
-const litehtml::tchar_t* litehtml::element::get_attr( const tchar_t* name, const tchar_t* def /*= 0*/ )        LITEHTML_RETURN_FUNC(def)\r
-bool litehtml::element::is_white_space() const                                                                         LITEHTML_RETURN_FUNC(false)\r
-bool litehtml::element::is_body() const                                                                                                LITEHTML_RETURN_FUNC(false)\r
-bool litehtml::element::is_break() const                                                                                       LITEHTML_RETURN_FUNC(false)\r
-int litehtml::element::get_base_line()                                                                                         LITEHTML_RETURN_FUNC(0)\r
-bool litehtml::element::on_mouse_over()                                                                                                LITEHTML_RETURN_FUNC(false)\r
-bool litehtml::element::on_mouse_leave()                                                                                       LITEHTML_RETURN_FUNC(false)\r
-bool litehtml::element::on_lbutton_down()                                                                                      LITEHTML_RETURN_FUNC(false)\r
-bool litehtml::element::on_lbutton_up()                                                                                                LITEHTML_RETURN_FUNC(false)\r
-bool litehtml::element::find_styles_changes( position::vector& redraw_boxes, int x, int y )    LITEHTML_RETURN_FUNC(false)\r
-const litehtml::tchar_t* litehtml::element::get_cursor()                                                       LITEHTML_RETURN_FUNC(0)\r
-litehtml::white_space litehtml::element::get_white_space() const                                       LITEHTML_RETURN_FUNC(white_space_normal)\r
-litehtml::style_display litehtml::element::get_display() const                                         LITEHTML_RETURN_FUNC(display_none)\r
-bool litehtml::element::set_pseudo_class( const tchar_t* pclass, bool add )                    LITEHTML_RETURN_FUNC(false)\r
-bool litehtml::element::set_class( const tchar_t* pclass, bool add )                           LITEHTML_RETURN_FUNC(false)\r
-litehtml::element_position litehtml::element::get_element_position(css_offsets* offsets) const                 LITEHTML_RETURN_FUNC(element_position_static)\r
-bool litehtml::element::is_replaced() const                                                                                    LITEHTML_RETURN_FUNC(false)\r
-int litehtml::element::line_height() const                                                                                     LITEHTML_RETURN_FUNC(0)\r
-void litehtml::element::draw( uint_ptr hdc, int x, int y, const position* clip )       LITEHTML_EMPTY_FUNC\r
-void litehtml::element::draw_background( uint_ptr hdc, int x, int y, const position* clip )    LITEHTML_EMPTY_FUNC\r
-const litehtml::tchar_t* litehtml::element::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ )      LITEHTML_RETURN_FUNC(0)\r
-litehtml::uint_ptr litehtml::element::get_font( font_metrics* fm /*= 0*/ )                     LITEHTML_RETURN_FUNC(0)\r
-int litehtml::element::get_font_size() const                                                                           LITEHTML_RETURN_FUNC(0)\r
-void litehtml::element::get_text( tstring& text )                                                                      LITEHTML_EMPTY_FUNC\r
-void litehtml::element::parse_attributes()                                                                                     LITEHTML_EMPTY_FUNC\r
-int litehtml::element::select( const css_selector& selector, bool apply_pseudo)                LITEHTML_RETURN_FUNC(select_no_match)\r
-int litehtml::element::select( const css_element_selector& selector, bool apply_pseudo /*= true*/ )    LITEHTML_RETURN_FUNC(select_no_match)\r
-litehtml::element::ptr litehtml::element::find_ancestor(const css_selector& selector, bool apply_pseudo, bool* is_pseudo)      LITEHTML_RETURN_FUNC(0)\r
-bool litehtml::element::is_first_child_inline(const element::ptr& el) const                    LITEHTML_RETURN_FUNC(false)\r
-bool litehtml::element::is_last_child_inline(const element::ptr& el)                           LITEHTML_RETURN_FUNC(false)\r
-bool litehtml::element::have_inline_child() const                                                                      LITEHTML_RETURN_FUNC(false)\r
+#include "html.h"
+#include "element.h"
+#include "document.h"
+
+#define LITEHTML_EMPTY_FUNC                    {}
+#define LITEHTML_RETURN_FUNC(ret)      {return ret;}
+
+litehtml::element::element(const std::shared_ptr<litehtml::document>& doc) : m_doc(doc)
+{
+       m_box           = 0;
+       m_skip          = false;
+}
+
+litehtml::element::~element()
+{
+
+}
+
+
+bool litehtml::element::is_point_inside( int x, int y )
+{
+       if(get_display() != display_inline && get_display() != display_table_row)
+       {
+               position pos = m_pos;
+               pos += m_padding;
+               pos += m_borders;
+               if(pos.is_point_inside(x, y))
+               {
+                       return true;
+               } else
+               {
+                       return false;
+               }
+       } else
+       {
+               position::vector boxes;
+               get_inline_boxes(boxes);
+               for(position::vector::iterator box = boxes.begin(); box != boxes.end(); box++)
+               {
+                       if(box->is_point_inside(x, y))
+                       {
+                               return true;
+                       }
+               }
+       }
+       return false;
+}
+
+litehtml::web_color litehtml::element::get_color( const tchar_t* prop_name, bool inherited, const litehtml::web_color& def_color )
+{
+       const tchar_t* clrstr = get_style_property(prop_name, inherited, 0);
+       if(!clrstr)
+       {
+               return def_color;
+       }
+       return web_color::from_string(clrstr, get_document()->container());
+}
+
+litehtml::position litehtml::element::get_placement() const
+{
+       litehtml::position pos = m_pos;
+       element::ptr cur_el = parent();
+       while(cur_el)
+       {
+               pos.x += cur_el->m_pos.x;
+               pos.y += cur_el->m_pos.y;
+               cur_el = cur_el->parent();
+       }
+       return pos;
+}
+
+bool litehtml::element::is_inline_box() const
+{
+       style_display d = get_display();
+       if(     d == display_inline || 
+               d == display_inline_block || 
+               d == display_inline_text)
+       {
+               return true;
+       }
+       return false;
+}
+
+bool litehtml::element::collapse_top_margin() const
+{
+       if(!m_borders.top && !m_padding.top && in_normal_flow() && get_float() == float_none && m_margins.top >= 0 && have_parent())
+       {
+               return true;
+       }
+       return false;
+}
+
+bool litehtml::element::collapse_bottom_margin() const
+{
+       if(!m_borders.bottom && !m_padding.bottom && in_normal_flow() && get_float() == float_none && m_margins.bottom >= 0 && have_parent())
+       {
+               return true;
+       }
+       return false;
+}
+
+bool litehtml::element::get_predefined_height(int& p_height) const
+{
+       css_length h = get_css_height();
+       if(h.is_predefined())
+       {
+               p_height = m_pos.height;
+               return false;
+       }
+       if(h.units() == css_units_percentage)
+       {
+               element::ptr el_parent = parent();
+               if (!el_parent)
+               {
+                       position client_pos;
+                       get_document()->container()->get_client_rect(client_pos);
+                       p_height = h.calc_percent(client_pos.height);
+                       return true;
+               } else
+               {
+                       int ph = 0;
+                       if (el_parent->get_predefined_height(ph))
+                       {
+                               p_height = h.calc_percent(ph);
+                               if (is_body())
+                               {
+                                       p_height -= content_margins_height();
+                               }
+                               return true;
+                       } else
+                       {
+                               p_height = m_pos.height;
+                               return false;
+                       }
+               }
+       }
+       p_height = get_document()->cvt_units(h, get_font_size());
+       return true;
+}
+
+void litehtml::element::calc_document_size( litehtml::size& sz, int x /*= 0*/, int y /*= 0*/ )
+{
+       if(is_visible())
+       {
+               sz.width        = std::max(sz.width,    x + right());
+               sz.height       = std::max(sz.height,   y + bottom());
+       }
+}
+
+void litehtml::element::get_redraw_box(litehtml::position& pos, int x /*= 0*/, int y /*= 0*/)
+{
+       if(is_visible())
+       {
+               int p_left              = std::min(pos.left(),  x + m_pos.left() - m_padding.left - m_borders.left);
+               int p_right             = std::max(pos.right(), x + m_pos.right() + m_padding.left + m_borders.left);
+               int p_top               = std::min(pos.top(), y + m_pos.top() - m_padding.top - m_borders.top);
+               int p_bottom    = std::max(pos.bottom(), y + m_pos.bottom() + m_padding.bottom + m_borders.bottom);
+
+               pos.x = p_left;
+               pos.y = p_top;
+               pos.width       = p_right - p_left;
+               pos.height      = p_bottom - p_top;
+       }
+}
+
+int litehtml::element::calc_width(int defVal) const
+{
+       css_length w = get_css_width();
+       if(w.is_predefined())
+       {
+               return defVal;
+       }
+       if(w.units() == css_units_percentage)
+       {
+               element::ptr el_parent = parent();
+               if (!el_parent)
+               {
+                       position client_pos;
+                       get_document()->container()->get_client_rect(client_pos);
+                       return w.calc_percent(client_pos.width);
+               } else
+               {
+                       int pw = el_parent->calc_width(defVal);
+                       if (is_body())
+                       {
+                               pw -= content_margins_width();
+                       }
+                       return w.calc_percent(pw);
+               }
+       }
+       return  get_document()->cvt_units(w, get_font_size());
+}
+
+bool litehtml::element::is_ancestor(const ptr &el) const
+{
+       element::ptr el_parent = parent();
+       while(el_parent && el_parent != el)
+       {
+               el_parent = el_parent->parent();
+       }
+       if(el_parent)
+       {
+               return true;
+       }
+       return false;
+}
+
+int litehtml::element::get_inline_shift_left()
+{
+       int ret = 0;
+       element::ptr el_parent = parent();
+       if (el_parent)
+       {
+               if (el_parent->get_display() == display_inline)
+               {
+                       style_display disp = get_display();
+
+                       if (disp == display_inline_text || disp == display_inline_block)
+                       {
+                               element::ptr el = shared_from_this();
+                               while (el_parent && el_parent->get_display() == display_inline)
+                               {
+                                       if (el_parent->is_first_child_inline(el))
+                                       {
+                                               ret += el_parent->padding_left() + el_parent->border_left() + el_parent->margin_left();
+                                       }
+                                       el = el_parent;
+                                       el_parent = el_parent->parent();
+                               }
+                       }
+               }
+       }
+
+       return ret;
+}
+
+int litehtml::element::get_inline_shift_right()
+{
+       int ret = 0;
+       element::ptr el_parent = parent();
+       if (el_parent)
+       {
+               if (el_parent->get_display() == display_inline)
+               {
+                       style_display disp = get_display();
+
+                       if (disp == display_inline_text || disp == display_inline_block)
+                       {
+                               element::ptr el = shared_from_this();
+                               while (el_parent && el_parent->get_display() == display_inline)
+                               {
+                                       if (el_parent->is_last_child_inline(el))
+                                       {
+                                               ret += el_parent->padding_right() + el_parent->border_right() + el_parent->margin_right();
+                                       }
+                                       el = el_parent;
+                                       el_parent = el_parent->parent();
+                               }
+                       }
+               }
+       }
+
+       return ret;
+}
+
+void litehtml::element::apply_relative_shift(int parent_width)
+{
+       css_offsets offsets;
+       if (get_element_position(&offsets) == element_position_relative)
+       {
+               element::ptr parent_ptr = parent();
+               if (!offsets.left.is_predefined())
+               {
+                       m_pos.x += offsets.left.calc_percent(parent_width);
+               }
+               else if (!offsets.right.is_predefined())
+               {
+                       m_pos.x -= offsets.right.calc_percent(parent_width);
+               }
+               if (!offsets.top.is_predefined())
+               {
+                       int h = 0;
+
+                       if (offsets.top.units() == css_units_percentage)
+                       {
+                               element::ptr el_parent = parent();
+                               if (el_parent)
+                               {
+                                       el_parent->get_predefined_height(h);
+                               }
+                       }
+
+                       m_pos.y += offsets.top.calc_percent(h);
+               }
+               else if (!offsets.bottom.is_predefined())
+               {
+                       int h = 0;
+
+                       if (offsets.top.units() == css_units_percentage)
+                       {
+                               element::ptr el_parent = parent();
+                               if (el_parent)
+                               {
+                                       el_parent->get_predefined_height(h);
+                               }
+                       }
+
+                       m_pos.y -= offsets.bottom.calc_percent(h);
+               }
+       }
+}
+
+void litehtml::element::calc_auto_margins(int parent_width)                                                    LITEHTML_EMPTY_FUNC
+const litehtml::background* litehtml::element::get_background(bool own_only)           LITEHTML_RETURN_FUNC(0)
+litehtml::element::ptr litehtml::element::get_element_by_point(int x, int y, int client_x, int client_y)       LITEHTML_RETURN_FUNC(0)
+litehtml::element::ptr litehtml::element::get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex) LITEHTML_RETURN_FUNC(0)
+void litehtml::element::get_line_left_right( int y, int def_right, int& ln_left, int& ln_right ) LITEHTML_EMPTY_FUNC
+void litehtml::element::add_style( const litehtml::style& st )                                         LITEHTML_EMPTY_FUNC
+void litehtml::element::select_all(const css_selector& selector, litehtml::elements_vector& res)       LITEHTML_EMPTY_FUNC
+litehtml::elements_vector litehtml::element::select_all(const litehtml::css_selector& selector)         LITEHTML_RETURN_FUNC(litehtml::elements_vector())
+litehtml::elements_vector litehtml::element::select_all(const litehtml::tstring& selector)                      LITEHTML_RETURN_FUNC(litehtml::elements_vector())
+litehtml::element::ptr litehtml::element::select_one( const css_selector& selector ) LITEHTML_RETURN_FUNC(0)
+litehtml::element::ptr litehtml::element::select_one( const tstring& selector )                LITEHTML_RETURN_FUNC(0)
+litehtml::element::ptr litehtml::element::find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/) LITEHTML_RETURN_FUNC(0)
+litehtml::element::ptr litehtml::element::find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/) LITEHTML_RETURN_FUNC(0)
+bool litehtml::element::is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const                LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::is_nth_child(const element::ptr&, int num, int off, bool of_type) const                LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::is_only_child(const element::ptr& el, bool of_type)     const  LITEHTML_RETURN_FUNC(false)
+litehtml::overflow litehtml::element::get_overflow() const                                                     LITEHTML_RETURN_FUNC(overflow_visible)
+void litehtml::element::draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex ) LITEHTML_EMPTY_FUNC
+void litehtml::element::draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned ) LITEHTML_EMPTY_FUNC
+void litehtml::element::render_positioned(render_type rt)                                                      LITEHTML_EMPTY_FUNC
+int litehtml::element::get_zindex() const                                                                                      LITEHTML_RETURN_FUNC(0)
+bool litehtml::element::fetch_positioned()                                                                                     LITEHTML_RETURN_FUNC(false)
+litehtml::visibility litehtml::element::get_visibility() const                                         LITEHTML_RETURN_FUNC(visibility_visible)
+void litehtml::element::apply_vertical_align()                                                                         LITEHTML_EMPTY_FUNC
+void litehtml::element::set_css_width( css_length& w )                                                         LITEHTML_EMPTY_FUNC
+litehtml::element::ptr litehtml::element::get_child( int idx ) const                           LITEHTML_RETURN_FUNC(0)
+size_t litehtml::element::get_children_count() const                                                           LITEHTML_RETURN_FUNC(0)
+void litehtml::element::calc_outlines( int parent_width )                                                      LITEHTML_EMPTY_FUNC
+litehtml::css_length litehtml::element::get_css_width() const                                          LITEHTML_RETURN_FUNC(css_length())
+litehtml::css_length litehtml::element::get_css_height() const                                         LITEHTML_RETURN_FUNC(css_length())
+litehtml::element_clear litehtml::element::get_clear() const                                           LITEHTML_RETURN_FUNC(clear_none)
+litehtml::css_length litehtml::element::get_css_left() const                                           LITEHTML_RETURN_FUNC(css_length())
+litehtml::css_length litehtml::element::get_css_right() const                                          LITEHTML_RETURN_FUNC(css_length())
+litehtml::css_length litehtml::element::get_css_top() const                                                    LITEHTML_RETURN_FUNC(css_length())
+litehtml::css_length litehtml::element::get_css_bottom() const                                         LITEHTML_RETURN_FUNC(css_length())
+litehtml::css_offsets litehtml::element::get_css_offsets() const                                       LITEHTML_RETURN_FUNC(css_offsets())
+litehtml::vertical_align litehtml::element::get_vertical_align() const                         LITEHTML_RETURN_FUNC(va_baseline)
+int litehtml::element::place_element(const ptr &el, int max_width)                                     LITEHTML_RETURN_FUNC(0)
+int litehtml::element::render_inline(const ptr &container, int max_width)                      LITEHTML_RETURN_FUNC(0)
+void litehtml::element::add_positioned(const ptr &el)                                                  LITEHTML_EMPTY_FUNC
+int litehtml::element::find_next_line_top( int top, int width, int def_right )         LITEHTML_RETURN_FUNC(0)
+litehtml::element_float litehtml::element::get_float() const                                           LITEHTML_RETURN_FUNC(float_none)
+void litehtml::element::add_float(const ptr &el, int x, int y)                                 LITEHTML_EMPTY_FUNC
+void litehtml::element::update_floats(int dy, const ptr &parent)                                       LITEHTML_EMPTY_FUNC
+int litehtml::element::get_line_left( int y )                                                                          LITEHTML_RETURN_FUNC(0)
+int litehtml::element::get_line_right( int y, int def_right )                                          LITEHTML_RETURN_FUNC(def_right)
+int litehtml::element::get_left_floats_height() const                                                          LITEHTML_RETURN_FUNC(0)
+int litehtml::element::get_right_floats_height() const                                                         LITEHTML_RETURN_FUNC(0)
+int litehtml::element::get_floats_height(element_float el_float) const                         LITEHTML_RETURN_FUNC(0)
+bool litehtml::element::is_floats_holder() const                                                                       LITEHTML_RETURN_FUNC(false)
+void litehtml::element::get_content_size( size& sz, int max_width )                                    LITEHTML_EMPTY_FUNC
+void litehtml::element::init()                                                                                                         LITEHTML_EMPTY_FUNC
+int litehtml::element::render( int x, int y, int max_width, bool second_pass )         LITEHTML_RETURN_FUNC(0)
+bool litehtml::element::appendChild(const ptr &el)                                             LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::removeChild(const ptr &el)                                             LITEHTML_RETURN_FUNC(false)
+void litehtml::element::clearRecursive()                                                                                       LITEHTML_EMPTY_FUNC
+const litehtml::tchar_t* litehtml::element::get_tagName() const                                                LITEHTML_RETURN_FUNC(_t(""))
+void litehtml::element::set_tagName( const tchar_t* tag )                                                      LITEHTML_EMPTY_FUNC
+void litehtml::element::set_data( const tchar_t* data )                                                                LITEHTML_EMPTY_FUNC
+void litehtml::element::set_attr( const tchar_t* name, const tchar_t* val )                    LITEHTML_EMPTY_FUNC
+void litehtml::element::apply_stylesheet( const litehtml::css& stylesheet )                    LITEHTML_EMPTY_FUNC
+void litehtml::element::refresh_styles()                                                                                       LITEHTML_EMPTY_FUNC
+void litehtml::element::on_click()                                                                                                     LITEHTML_EMPTY_FUNC
+void litehtml::element::init_font()                                                                                                    LITEHTML_EMPTY_FUNC
+void litehtml::element::get_inline_boxes( position::vector& boxes )                                    LITEHTML_EMPTY_FUNC
+void litehtml::element::parse_styles( bool is_reparse /*= false*/ )                                    LITEHTML_EMPTY_FUNC
+const litehtml::tchar_t* litehtml::element::get_attr( const tchar_t* name, const tchar_t* def /*= 0*/ )        LITEHTML_RETURN_FUNC(def)
+bool litehtml::element::is_white_space() const                                                                         LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::is_body() const                                                                                                LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::is_break() const                                                                                       LITEHTML_RETURN_FUNC(false)
+int litehtml::element::get_base_line()                                                                                         LITEHTML_RETURN_FUNC(0)
+bool litehtml::element::on_mouse_over()                                                                                                LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::on_mouse_leave()                                                                                       LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::on_lbutton_down()                                                                                      LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::on_lbutton_up()                                                                                                LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::find_styles_changes( position::vector& redraw_boxes, int x, int y )    LITEHTML_RETURN_FUNC(false)
+const litehtml::tchar_t* litehtml::element::get_cursor()                                                       LITEHTML_RETURN_FUNC(0)
+litehtml::white_space litehtml::element::get_white_space() const                                       LITEHTML_RETURN_FUNC(white_space_normal)
+litehtml::style_display litehtml::element::get_display() const                                         LITEHTML_RETURN_FUNC(display_none)
+bool litehtml::element::set_pseudo_class( const tchar_t* pclass, bool add )                    LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::set_class( const tchar_t* pclass, bool add )                           LITEHTML_RETURN_FUNC(false)
+litehtml::element_position litehtml::element::get_element_position(css_offsets* offsets) const                 LITEHTML_RETURN_FUNC(element_position_static)
+bool litehtml::element::is_replaced() const                                                                                    LITEHTML_RETURN_FUNC(false)
+int litehtml::element::line_height() const                                                                                     LITEHTML_RETURN_FUNC(0)
+void litehtml::element::draw( uint_ptr hdc, int x, int y, const position* clip )       LITEHTML_EMPTY_FUNC
+void litehtml::element::draw_background( uint_ptr hdc, int x, int y, const position* clip )    LITEHTML_EMPTY_FUNC
+const litehtml::tchar_t* litehtml::element::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ )      LITEHTML_RETURN_FUNC(0)
+litehtml::uint_ptr litehtml::element::get_font( font_metrics* fm /*= 0*/ )                     LITEHTML_RETURN_FUNC(0)
+int litehtml::element::get_font_size() const                                                                           LITEHTML_RETURN_FUNC(0)
+void litehtml::element::get_text( tstring& text )                                                                      LITEHTML_EMPTY_FUNC
+void litehtml::element::parse_attributes()                                                                                     LITEHTML_EMPTY_FUNC
+int litehtml::element::select( const css_selector& selector, bool apply_pseudo)                LITEHTML_RETURN_FUNC(select_no_match)
+int litehtml::element::select( const css_element_selector& selector, bool apply_pseudo /*= true*/ )    LITEHTML_RETURN_FUNC(select_no_match)
+litehtml::element::ptr litehtml::element::find_ancestor(const css_selector& selector, bool apply_pseudo, bool* is_pseudo)      LITEHTML_RETURN_FUNC(0)
+bool litehtml::element::is_first_child_inline(const element::ptr& el) const                    LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::is_last_child_inline(const element::ptr& el)                           LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::have_inline_child() const                                                                      LITEHTML_RETURN_FUNC(false)
index f1af05b018f19ac209a4c79f1f74efb9882a5f50..37abc34384010e7d8c7e3cba6f34061b860817bc 100644 (file)
-#pragma once\r
-#include <memory>\r
-#include "stylesheet.h"\r
-#include "css_offsets.h"\r
-\r
-namespace litehtml\r
-{\r
-       class box;\r
-\r
-       class element : public std::enable_shared_from_this<element>\r
-       {\r
-               friend class block_box;\r
-               friend class line_box;\r
-               friend class html_tag;\r
-               friend class el_table;\r
-               friend class document;\r
-       public:\r
-               typedef std::shared_ptr<litehtml::element>              ptr;\r
-               typedef std::weak_ptr<litehtml::element>                weak_ptr;\r
-       protected:\r
-               std::weak_ptr<element>          m_parent;\r
-               std::weak_ptr<litehtml::document>       m_doc;\r
-               litehtml::box*                          m_box;\r
-               elements_vector                         m_children;\r
-               position                                        m_pos;\r
-               margins                                         m_margins;\r
-               margins                                         m_padding;\r
-               margins                                         m_borders;\r
-               bool                                            m_skip;\r
-               \r
-               virtual void select_all(const css_selector& selector, elements_vector& res);\r
-       public:\r
-               element(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~element();\r
-\r
-               // returns refer to m_pos member;\r
-               position&                                       get_position();\r
-\r
-               int                                                     left()                                          const;\r
-               int                                                     right()                                         const;\r
-               int                                                     top()                                           const;\r
-               int                                                     bottom()                                        const;\r
-               int                                                     height()                                        const;\r
-               int                                                     width()                                         const;\r
-\r
-               int                                                     content_margins_top()           const;\r
-               int                                                     content_margins_bottom()        const;\r
-               int                                                     content_margins_left()          const;\r
-               int                                                     content_margins_right()         const;\r
-               int                                                     content_margins_width()         const;\r
-               int                                                     content_margins_height()        const;\r
-\r
-               int                                                     margin_top()                            const;\r
-               int                                                     margin_bottom()                         const;\r
-               int                                                     margin_left()                           const;\r
-               int                                                     margin_right()                          const;\r
-               margins                                         get_margins()                           const;\r
-\r
-               int                                                     padding_top()                           const;\r
-               int                                                     padding_bottom()                        const;\r
-               int                                                     padding_left()                          const;\r
-               int                                                     padding_right()                         const;\r
-               margins                                         get_paddings()                          const;\r
-\r
-               int                                                     border_top()                            const;\r
-               int                                                     border_bottom()                         const;\r
-               int                                                     border_left()                           const;\r
-               int                                                     border_right()                          const;\r
-               margins                                         get_borders()                           const;\r
-\r
-               bool                                            in_normal_flow()                        const;\r
-               litehtml::web_color                     get_color(const tchar_t* prop_name, bool inherited, const litehtml::web_color& def_color = litehtml::web_color());\r
-               bool                                            is_inline_box()                         const;\r
-               position                                        get_placement()                         const;\r
-               bool                                            collapse_top_margin()           const;\r
-               bool                                            collapse_bottom_margin()        const;\r
-               bool                                            is_positioned()                         const;\r
-\r
-               bool                                            skip();\r
-               void                                            skip(bool val);\r
-               bool                                            have_parent() const;\r
-               element::ptr                            parent() const;\r
-               void                                            parent(element::ptr par);\r
-               bool                                            is_visible() const;\r
-               int                                                     calc_width(int defVal) const;\r
-               int                                                     get_inline_shift_left();\r
-               int                                                     get_inline_shift_right();\r
-               void                                            apply_relative_shift(int parent_width);\r
-\r
-               std::shared_ptr<document>       get_document() const;\r
-\r
-               virtual elements_vector         select_all(const tstring& selector);\r
-               virtual elements_vector         select_all(const css_selector& selector);\r
-\r
-               virtual element::ptr            select_one(const tstring& selector);\r
-               virtual element::ptr            select_one(const css_selector& selector);\r
-\r
-               virtual int                                     render(int x, int y, int max_width, bool second_pass = false);\r
-               virtual int                                     render_inline(const ptr &container, int max_width);\r
-               virtual int                                     place_element(const ptr &el, int max_width);\r
-               virtual void                            calc_outlines( int parent_width );\r
-               virtual void                            calc_auto_margins(int parent_width);\r
-               virtual void                            apply_vertical_align();\r
-               virtual bool                            fetch_positioned();\r
-               virtual void                            render_positioned(render_type rt = render_all);\r
-\r
-               virtual bool                            appendChild(const ptr &el);\r
-               virtual bool                            removeChild(const ptr &el);\r
-               virtual void                            clearRecursive();\r
-\r
-               virtual const tchar_t*          get_tagName() const;\r
-               virtual void                            set_tagName(const tchar_t* tag);\r
-               virtual void                            set_data(const tchar_t* data);\r
-               virtual element_float           get_float() const;\r
-               virtual vertical_align          get_vertical_align() const;\r
-               virtual element_clear           get_clear() const;\r
-               virtual size_t                          get_children_count() const;\r
-               virtual element::ptr            get_child(int idx) const;\r
-               virtual overflow                        get_overflow() const;\r
-\r
-               virtual css_length                      get_css_left() const;\r
-               virtual css_length                      get_css_right() const;\r
-               virtual css_length                      get_css_top() const;\r
-               virtual css_length                      get_css_bottom() const;\r
-               virtual css_offsets                     get_css_offsets() const;\r
-               virtual css_length                      get_css_width() const;\r
-               virtual void                            set_css_width(css_length& w);\r
-               virtual css_length                      get_css_height() const;\r
-\r
-               virtual void                            set_attr(const tchar_t* name, const tchar_t* val);\r
-               virtual const tchar_t*          get_attr(const tchar_t* name, const tchar_t* def = 0);\r
-               virtual void                            apply_stylesheet(const litehtml::css& stylesheet);\r
-               virtual void                            refresh_styles();\r
-               virtual bool                            is_white_space() const;\r
-               virtual bool                            is_body() const;\r
-               virtual bool                            is_break() const;\r
-               virtual int                                     get_base_line();\r
-               virtual bool                            on_mouse_over();\r
-               virtual bool                            on_mouse_leave();\r
-               virtual bool                            on_lbutton_down();\r
-               virtual bool                            on_lbutton_up();\r
-               virtual void                            on_click();\r
-               virtual bool                            find_styles_changes(position::vector& redraw_boxes, int x, int y);\r
-               virtual const tchar_t*          get_cursor();\r
-               virtual void                            init_font();\r
-               virtual bool                            is_point_inside(int x, int y);\r
-               virtual bool                            set_pseudo_class(const tchar_t* pclass, bool add);\r
-               virtual bool                            set_class(const tchar_t* pclass, bool add);\r
-               virtual bool                            is_replaced() const;\r
-               virtual int                                     line_height() const;\r
-               virtual white_space                     get_white_space() const;\r
-               virtual style_display           get_display() const;\r
-               virtual visibility                      get_visibility() const;\r
-               virtual element_position        get_element_position(css_offsets* offsets = 0) const;\r
-               virtual void                            get_inline_boxes(position::vector& boxes);\r
-               virtual void                            parse_styles(bool is_reparse = false);\r
-               virtual void                            draw(uint_ptr hdc, int x, int y, const position* clip);\r
-               virtual void                            draw_background( uint_ptr hdc, int x, int y, const position* clip );\r
-               virtual const tchar_t*          get_style_property(const tchar_t* name, bool inherited, const tchar_t* def = 0);\r
-               virtual uint_ptr                        get_font(font_metrics* fm = 0);\r
-               virtual int                                     get_font_size() const;\r
-               virtual void                            get_text(tstring& text);\r
-               virtual void                            parse_attributes();\r
-               virtual int                                     select(const css_selector& selector, bool apply_pseudo = true);\r
-               virtual int                                     select(const css_element_selector& selector, bool apply_pseudo = true);\r
-               virtual element::ptr            find_ancestor(const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0);\r
-               virtual bool                            is_ancestor(const ptr &el) const;\r
-               virtual element::ptr            find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0);\r
-               virtual element::ptr            find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0);\r
-               virtual bool                            is_first_child_inline(const element::ptr& el) const;\r
-               virtual bool                            is_last_child_inline(const element::ptr& el);\r
-               virtual bool                            have_inline_child() const;\r
-               virtual void                            get_content_size(size& sz, int max_width);\r
-               virtual void                            init();\r
-               virtual bool                            is_floats_holder() const;\r
-               virtual int                                     get_floats_height(element_float el_float = float_none) const;\r
-               virtual int                                     get_left_floats_height() const;\r
-               virtual int                                     get_right_floats_height() const;\r
-               virtual int                                     get_line_left(int y);\r
-               virtual int                                     get_line_right(int y, int def_right);\r
-               virtual void                            get_line_left_right(int y, int def_right, int& ln_left, int& ln_right);\r
-               virtual void                            add_float(const ptr &el, int x, int y);\r
-               virtual void                            update_floats(int dy, const ptr &parent);\r
-               virtual void                            add_positioned(const ptr &el);\r
-               virtual int                                     find_next_line_top(int top, int width, int def_right);\r
-               virtual int                                     get_zindex() const;\r
-               virtual void                            draw_stacking_context(uint_ptr hdc, int x, int y, const position* clip, bool with_positioned);\r
-               virtual void                            draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex );\r
-               virtual bool                            is_nth_child(const element::ptr& el, int num, int off, bool of_type) const;\r
-               virtual bool                            is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const;\r
-               virtual bool                            is_only_child(const element::ptr& el, bool of_type) const;\r
-               virtual bool                            get_predefined_height(int& p_height) const;\r
-               virtual void                            calc_document_size(litehtml::size& sz, int x = 0, int y = 0);\r
-               virtual void                            get_redraw_box(litehtml::position& pos, int x = 0, int y = 0);\r
-               virtual void                            add_style(const litehtml::style& st);\r
-               virtual element::ptr            get_element_by_point(int x, int y, int client_x, int client_y);\r
-               virtual element::ptr            get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex);\r
-               virtual const background*       get_background(bool own_only = false);\r
-       };\r
-\r
-       //////////////////////////////////////////////////////////////////////////\r
-       //                                                      INLINE FUNCTIONS                                                        //\r
-       //////////////////////////////////////////////////////////////////////////\r
-\r
-       inline int litehtml::element::right() const\r
-       {\r
-               return left() + width();\r
-       }\r
-\r
-       inline int litehtml::element::left() const\r
-       {\r
-               return m_pos.left() - margin_left() - m_padding.left - m_borders.left;\r
-       }\r
-\r
-       inline int litehtml::element::top() const\r
-       {\r
-               return m_pos.top() - margin_top() - m_padding.top - m_borders.top;\r
-       }\r
-\r
-       inline int litehtml::element::bottom() const\r
-       {\r
-               return top() + height();\r
-       }\r
-\r
-       inline int litehtml::element::height() const\r
-       {\r
-               return m_pos.height + margin_top() + margin_bottom() + m_padding.height() + m_borders.height();\r
-       }\r
-\r
-       inline int litehtml::element::width() const\r
-       {\r
-               return m_pos.width + margin_left() + margin_right() + m_padding.width() + m_borders.width();\r
-       }\r
-\r
-       inline int litehtml::element::content_margins_top() const\r
-       {\r
-               return margin_top() + m_padding.top + m_borders.top;\r
-       }\r
-\r
-       inline int litehtml::element::content_margins_bottom() const\r
-       {\r
-               return margin_bottom() + m_padding.bottom + m_borders.bottom;\r
-       }\r
-\r
-       inline int litehtml::element::content_margins_left() const\r
-       {\r
-               return margin_left() + m_padding.left + m_borders.left;\r
-       }\r
-\r
-       inline int litehtml::element::content_margins_right() const\r
-       {\r
-               return margin_right() + m_padding.right + m_borders.right;\r
-       }\r
-\r
-       inline int litehtml::element::content_margins_width() const\r
-       {\r
-               return content_margins_left() + content_margins_right();\r
-       }\r
-\r
-       inline int litehtml::element::content_margins_height() const\r
-       {\r
-               return content_margins_top() + content_margins_bottom();\r
-       }\r
-\r
-       inline litehtml::margins litehtml::element::get_paddings()      const\r
-       {\r
-               return m_padding;\r
-       }\r
-\r
-       inline litehtml::margins litehtml::element::get_borders()       const\r
-       {\r
-               return m_borders;\r
-       }\r
-\r
-       inline int litehtml::element::padding_top() const\r
-       {\r
-               return m_padding.top;\r
-       }\r
-\r
-       inline int litehtml::element::padding_bottom() const\r
-       {\r
-               return m_padding.bottom;\r
-       }\r
-\r
-       inline int litehtml::element::padding_left() const\r
-       {\r
-               return m_padding.left;\r
-       }\r
-\r
-       inline int litehtml::element::padding_right() const\r
-       {\r
-               return m_padding.right;\r
-       }\r
-\r
-       inline bool litehtml::element::in_normal_flow() const\r
-       {\r
-               if(get_element_position() != element_position_absolute && get_display() != display_none)\r
-               {\r
-                       return true;\r
-               }\r
-               return false;\r
-       }\r
-\r
-       inline int litehtml::element::border_top() const\r
-       {\r
-               return m_borders.top;\r
-       }\r
-\r
-       inline int litehtml::element::border_bottom() const\r
-       {\r
-               return m_borders.bottom;\r
-       }\r
-\r
-       inline int litehtml::element::border_left() const\r
-       {\r
-               return m_borders.left;\r
-       }\r
-\r
-       inline int litehtml::element::border_right() const\r
-       {\r
-               return m_borders.right;\r
-       }\r
-\r
-       inline bool litehtml::element::skip()\r
-       {\r
-               return m_skip;\r
-       }\r
-\r
-       inline void litehtml::element::skip(bool val)\r
-       {\r
-               m_skip = val;\r
-       }\r
-\r
-       inline bool litehtml::element::have_parent() const\r
-       {\r
-               return !m_parent.expired();\r
-       }\r
-\r
-       inline element::ptr litehtml::element::parent() const\r
-       {\r
-               return m_parent.lock();\r
-       }\r
-\r
-       inline void litehtml::element::parent(element::ptr par)\r
-       {\r
-               m_parent = par;\r
-       }\r
-\r
-       inline int litehtml::element::margin_top() const\r
-       {\r
-               return m_margins.top;\r
-       }\r
-\r
-       inline int litehtml::element::margin_bottom() const\r
-       {\r
-               return m_margins.bottom;\r
-       }\r
-\r
-       inline int litehtml::element::margin_left() const\r
-       {\r
-               return m_margins.left;\r
-       }\r
-\r
-       inline int litehtml::element::margin_right() const\r
-       {\r
-               return m_margins.right;\r
-       }\r
-\r
-       inline litehtml::margins litehtml::element::get_margins() const\r
-       {\r
-               margins ret;\r
-               ret.left        = margin_left();\r
-               ret.right       = margin_right();\r
-               ret.top         = margin_top();\r
-               ret.bottom      = margin_bottom();\r
-\r
-               return ret;\r
-       }\r
-\r
-       inline bool litehtml::element::is_positioned()  const\r
-       {\r
-               return (get_element_position() > element_position_static);\r
-       }\r
-\r
-       inline bool litehtml::element::is_visible() const\r
-       {\r
-               return !(m_skip || get_display() == display_none || get_visibility() != visibility_visible);\r
-       }\r
-\r
-       inline position& litehtml::element::get_position()\r
-       {\r
-               return m_pos;\r
-       }\r
-\r
-       inline std::shared_ptr<document> element::get_document() const\r
-       {\r
-               return m_doc.lock();\r
-       }\r
-}\r
+#ifndef LH_ELEMENT_H
+#define LH_ELEMENT_H
+
+#include <memory>
+#include "stylesheet.h"
+#include "css_offsets.h"
+
+namespace litehtml
+{
+       class box;
+
+       class element : public std::enable_shared_from_this<element>
+       {
+               friend class block_box;
+               friend class line_box;
+               friend class html_tag;
+               friend class el_table;
+               friend class document;
+       public:
+               typedef std::shared_ptr<litehtml::element>              ptr;
+               typedef std::weak_ptr<litehtml::element>                weak_ptr;
+       protected:
+               std::weak_ptr<element>          m_parent;
+               std::weak_ptr<litehtml::document>       m_doc;
+               litehtml::box*                          m_box;
+               elements_vector                         m_children;
+               position                                        m_pos;
+               margins                                         m_margins;
+               margins                                         m_padding;
+               margins                                         m_borders;
+               bool                                            m_skip;
+               
+               virtual void select_all(const css_selector& selector, elements_vector& res);
+       public:
+               element(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~element();
+
+               // returns refer to m_pos member;
+               position&                                       get_position();
+
+               int                                                     left()                                          const;
+               int                                                     right()                                         const;
+               int                                                     top()                                           const;
+               int                                                     bottom()                                        const;
+               int                                                     height()                                        const;
+               int                                                     width()                                         const;
+
+               int                                                     content_margins_top()           const;
+               int                                                     content_margins_bottom()        const;
+               int                                                     content_margins_left()          const;
+               int                                                     content_margins_right()         const;
+               int                                                     content_margins_width()         const;
+               int                                                     content_margins_height()        const;
+
+               int                                                     margin_top()                            const;
+               int                                                     margin_bottom()                         const;
+               int                                                     margin_left()                           const;
+               int                                                     margin_right()                          const;
+               margins                                         get_margins()                           const;
+
+               int                                                     padding_top()                           const;
+               int                                                     padding_bottom()                        const;
+               int                                                     padding_left()                          const;
+               int                                                     padding_right()                         const;
+               margins                                         get_paddings()                          const;
+
+               int                                                     border_top()                            const;
+               int                                                     border_bottom()                         const;
+               int                                                     border_left()                           const;
+               int                                                     border_right()                          const;
+               margins                                         get_borders()                           const;
+
+               bool                                            in_normal_flow()                        const;
+               litehtml::web_color                     get_color(const tchar_t* prop_name, bool inherited, const litehtml::web_color& def_color = litehtml::web_color());
+               bool                                            is_inline_box()                         const;
+               position                                        get_placement()                         const;
+               bool                                            collapse_top_margin()           const;
+               bool                                            collapse_bottom_margin()        const;
+               bool                                            is_positioned()                         const;
+
+               bool                                            skip();
+               void                                            skip(bool val);
+               bool                                            have_parent() const;
+               element::ptr                            parent() const;
+               void                                            parent(element::ptr par);
+               bool                                            is_visible() const;
+               int                                                     calc_width(int defVal) const;
+               int                                                     get_inline_shift_left();
+               int                                                     get_inline_shift_right();
+               void                                            apply_relative_shift(int parent_width);
+
+               std::shared_ptr<document>       get_document() const;
+
+               virtual elements_vector         select_all(const tstring& selector);
+               virtual elements_vector         select_all(const css_selector& selector);
+
+               virtual element::ptr            select_one(const tstring& selector);
+               virtual element::ptr            select_one(const css_selector& selector);
+
+               virtual int                                     render(int x, int y, int max_width, bool second_pass = false);
+               virtual int                                     render_inline(const ptr &container, int max_width);
+               virtual int                                     place_element(const ptr &el, int max_width);
+               virtual void                            calc_outlines( int parent_width );
+               virtual void                            calc_auto_margins(int parent_width);
+               virtual void                            apply_vertical_align();
+               virtual bool                            fetch_positioned();
+               virtual void                            render_positioned(render_type rt = render_all);
+
+               virtual bool                            appendChild(const ptr &el);
+               virtual bool                            removeChild(const ptr &el);
+               virtual void                            clearRecursive();
+
+               virtual const tchar_t*          get_tagName() const;
+               virtual void                            set_tagName(const tchar_t* tag);
+               virtual void                            set_data(const tchar_t* data);
+               virtual element_float           get_float() const;
+               virtual vertical_align          get_vertical_align() const;
+               virtual element_clear           get_clear() const;
+               virtual size_t                          get_children_count() const;
+               virtual element::ptr            get_child(int idx) const;
+               virtual overflow                        get_overflow() const;
+
+               virtual css_length                      get_css_left() const;
+               virtual css_length                      get_css_right() const;
+               virtual css_length                      get_css_top() const;
+               virtual css_length                      get_css_bottom() const;
+               virtual css_offsets                     get_css_offsets() const;
+               virtual css_length                      get_css_width() const;
+               virtual void                            set_css_width(css_length& w);
+               virtual css_length                      get_css_height() const;
+
+               virtual void                            set_attr(const tchar_t* name, const tchar_t* val);
+               virtual const tchar_t*          get_attr(const tchar_t* name, const tchar_t* def = 0);
+               virtual void                            apply_stylesheet(const litehtml::css& stylesheet);
+               virtual void                            refresh_styles();
+               virtual bool                            is_white_space() const;
+               virtual bool                            is_body() const;
+               virtual bool                            is_break() const;
+               virtual int                                     get_base_line();
+               virtual bool                            on_mouse_over();
+               virtual bool                            on_mouse_leave();
+               virtual bool                            on_lbutton_down();
+               virtual bool                            on_lbutton_up();
+               virtual void                            on_click();
+               virtual bool                            find_styles_changes(position::vector& redraw_boxes, int x, int y);
+               virtual const tchar_t*          get_cursor();
+               virtual void                            init_font();
+               virtual bool                            is_point_inside(int x, int y);
+               virtual bool                            set_pseudo_class(const tchar_t* pclass, bool add);
+               virtual bool                            set_class(const tchar_t* pclass, bool add);
+               virtual bool                            is_replaced() const;
+               virtual int                                     line_height() const;
+               virtual white_space                     get_white_space() const;
+               virtual style_display           get_display() const;
+               virtual visibility                      get_visibility() const;
+               virtual element_position        get_element_position(css_offsets* offsets = 0) const;
+               virtual void                            get_inline_boxes(position::vector& boxes);
+               virtual void                            parse_styles(bool is_reparse = false);
+               virtual void                            draw(uint_ptr hdc, int x, int y, const position* clip);
+               virtual void                            draw_background( uint_ptr hdc, int x, int y, const position* clip );
+               virtual const tchar_t*          get_style_property(const tchar_t* name, bool inherited, const tchar_t* def = 0);
+               virtual uint_ptr                        get_font(font_metrics* fm = 0);
+               virtual int                                     get_font_size() const;
+               virtual void                            get_text(tstring& text);
+               virtual void                            parse_attributes();
+               virtual int                                     select(const css_selector& selector, bool apply_pseudo = true);
+               virtual int                                     select(const css_element_selector& selector, bool apply_pseudo = true);
+               virtual element::ptr            find_ancestor(const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0);
+               virtual bool                            is_ancestor(const ptr &el) const;
+               virtual element::ptr            find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0);
+               virtual element::ptr            find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0);
+               virtual bool                            is_first_child_inline(const element::ptr& el) const;
+               virtual bool                            is_last_child_inline(const element::ptr& el);
+               virtual bool                            have_inline_child() const;
+               virtual void                            get_content_size(size& sz, int max_width);
+               virtual void                            init();
+               virtual bool                            is_floats_holder() const;
+               virtual int                                     get_floats_height(element_float el_float = float_none) const;
+               virtual int                                     get_left_floats_height() const;
+               virtual int                                     get_right_floats_height() const;
+               virtual int                                     get_line_left(int y);
+               virtual int                                     get_line_right(int y, int def_right);
+               virtual void                            get_line_left_right(int y, int def_right, int& ln_left, int& ln_right);
+               virtual void                            add_float(const ptr &el, int x, int y);
+               virtual void                            update_floats(int dy, const ptr &parent);
+               virtual void                            add_positioned(const ptr &el);
+               virtual int                                     find_next_line_top(int top, int width, int def_right);
+               virtual int                                     get_zindex() const;
+               virtual void                            draw_stacking_context(uint_ptr hdc, int x, int y, const position* clip, bool with_positioned);
+               virtual void                            draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex );
+               virtual bool                            is_nth_child(const element::ptr& el, int num, int off, bool of_type) const;
+               virtual bool                            is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const;
+               virtual bool                            is_only_child(const element::ptr& el, bool of_type) const;
+               virtual bool                            get_predefined_height(int& p_height) const;
+               virtual void                            calc_document_size(litehtml::size& sz, int x = 0, int y = 0);
+               virtual void                            get_redraw_box(litehtml::position& pos, int x = 0, int y = 0);
+               virtual void                            add_style(const litehtml::style& st);
+               virtual element::ptr            get_element_by_point(int x, int y, int client_x, int client_y);
+               virtual element::ptr            get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex);
+               virtual const background*       get_background(bool own_only = false);
+       };
+
+       //////////////////////////////////////////////////////////////////////////
+       //                                                      INLINE FUNCTIONS                                                        //
+       //////////////////////////////////////////////////////////////////////////
+
+       inline int litehtml::element::right() const
+       {
+               return left() + width();
+       }
+
+       inline int litehtml::element::left() const
+       {
+               return m_pos.left() - margin_left() - m_padding.left - m_borders.left;
+       }
+
+       inline int litehtml::element::top() const
+       {
+               return m_pos.top() - margin_top() - m_padding.top - m_borders.top;
+       }
+
+       inline int litehtml::element::bottom() const
+       {
+               return top() + height();
+       }
+
+       inline int litehtml::element::height() const
+       {
+               return m_pos.height + margin_top() + margin_bottom() + m_padding.height() + m_borders.height();
+       }
+
+       inline int litehtml::element::width() const
+       {
+               return m_pos.width + margin_left() + margin_right() + m_padding.width() + m_borders.width();
+       }
+
+       inline int litehtml::element::content_margins_top() const
+       {
+               return margin_top() + m_padding.top + m_borders.top;
+       }
+
+       inline int litehtml::element::content_margins_bottom() const
+       {
+               return margin_bottom() + m_padding.bottom + m_borders.bottom;
+       }
+
+       inline int litehtml::element::content_margins_left() const
+       {
+               return margin_left() + m_padding.left + m_borders.left;
+       }
+
+       inline int litehtml::element::content_margins_right() const
+       {
+               return margin_right() + m_padding.right + m_borders.right;
+       }
+
+       inline int litehtml::element::content_margins_width() const
+       {
+               return content_margins_left() + content_margins_right();
+       }
+
+       inline int litehtml::element::content_margins_height() const
+       {
+               return content_margins_top() + content_margins_bottom();
+       }
+
+       inline litehtml::margins litehtml::element::get_paddings()      const
+       {
+               return m_padding;
+       }
+
+       inline litehtml::margins litehtml::element::get_borders()       const
+       {
+               return m_borders;
+       }
+
+       inline int litehtml::element::padding_top() const
+       {
+               return m_padding.top;
+       }
+
+       inline int litehtml::element::padding_bottom() const
+       {
+               return m_padding.bottom;
+       }
+
+       inline int litehtml::element::padding_left() const
+       {
+               return m_padding.left;
+       }
+
+       inline int litehtml::element::padding_right() const
+       {
+               return m_padding.right;
+       }
+
+       inline bool litehtml::element::in_normal_flow() const
+       {
+               if(get_element_position() != element_position_absolute && get_display() != display_none)
+               {
+                       return true;
+               }
+               return false;
+       }
+
+       inline int litehtml::element::border_top() const
+       {
+               return m_borders.top;
+       }
+
+       inline int litehtml::element::border_bottom() const
+       {
+               return m_borders.bottom;
+       }
+
+       inline int litehtml::element::border_left() const
+       {
+               return m_borders.left;
+       }
+
+       inline int litehtml::element::border_right() const
+       {
+               return m_borders.right;
+       }
+
+       inline bool litehtml::element::skip()
+       {
+               return m_skip;
+       }
+
+       inline void litehtml::element::skip(bool val)
+       {
+               m_skip = val;
+       }
+
+       inline bool litehtml::element::have_parent() const
+       {
+               return !m_parent.expired();
+       }
+
+       inline element::ptr litehtml::element::parent() const
+       {
+               return m_parent.lock();
+       }
+
+       inline void litehtml::element::parent(element::ptr par)
+       {
+               m_parent = par;
+       }
+
+       inline int litehtml::element::margin_top() const
+       {
+               return m_margins.top;
+       }
+
+       inline int litehtml::element::margin_bottom() const
+       {
+               return m_margins.bottom;
+       }
+
+       inline int litehtml::element::margin_left() const
+       {
+               return m_margins.left;
+       }
+
+       inline int litehtml::element::margin_right() const
+       {
+               return m_margins.right;
+       }
+
+       inline litehtml::margins litehtml::element::get_margins() const
+       {
+               margins ret;
+               ret.left        = margin_left();
+               ret.right       = margin_right();
+               ret.top         = margin_top();
+               ret.bottom      = margin_bottom();
+
+               return ret;
+       }
+
+       inline bool litehtml::element::is_positioned()  const
+       {
+               return (get_element_position() > element_position_static);
+       }
+
+       inline bool litehtml::element::is_visible() const
+       {
+               return !(m_skip || get_display() == display_none || get_visibility() != visibility_visible);
+       }
+
+       inline position& litehtml::element::get_position()
+       {
+               return m_pos;
+       }
+
+       inline std::shared_ptr<document> element::get_document() const
+       {
+               return m_doc.lock();
+       }
+}
+
+#endif  // LH_ELEMENT_H
index a11e2e425807da5adb3a049b7f4246f0caee2f3b..a27dacac8a04a4e12328a108313f566c4c6a0685 100644 (file)
-#include "html.h"\r
-#include "types.h"\r
-#include "html_tag.h"\r
-\r
-void litehtml::trim(tstring &s) \r
-{\r
-       tstring::size_type pos = s.find_first_not_of(_t(" \n\r\t"));\r
-       if(pos != tstring::npos)\r
-       {\r
-               s.erase(s.begin(), s.begin() + pos);\r
-       }\r
-       pos = s.find_last_not_of(_t(" \n\r\t"));\r
-       if(pos != tstring::npos)\r
-       {\r
-               s.erase(s.begin() + pos + 1, s.end());\r
-       }\r
-}\r
-\r
-void litehtml::lcase(tstring &s) \r
-{\r
-       for(tstring::iterator i = s.begin(); i != s.end(); i++)\r
-       {\r
-               (*i) = t_tolower(*i);\r
-       }\r
-}\r
-\r
-litehtml::tstring::size_type litehtml::find_close_bracket(const tstring &s, tstring::size_type off, tchar_t open_b, tchar_t close_b)\r
-{\r
-       int cnt = 0;\r
-       for(tstring::size_type i = off; i < s.length(); i++)\r
-       {\r
-               if(s[i] == open_b)\r
-               {\r
-                       cnt++;\r
-               } else if(s[i] == close_b)\r
-               {\r
-                       cnt--;\r
-                       if(!cnt)\r
-                       {\r
-                               return i;\r
-                       }\r
-               }\r
-       }\r
-       return tstring::npos;\r
-}\r
-\r
-int litehtml::value_index( const tstring& val, const tstring& strings, int defValue, tchar_t delim )\r
-{\r
-       if(val.empty() || strings.empty() || !delim)\r
-       {\r
-               return defValue;\r
-       }\r
-\r
-       int idx = 0;\r
-       tstring::size_type delim_start  = 0;\r
-       tstring::size_type delim_end    = strings.find(delim, delim_start);\r
-       tstring::size_type item_len             = 0;\r
-       while(true)\r
-       {\r
-               if(delim_end == tstring::npos)\r
-               {\r
-                       item_len = strings.length() - delim_start;\r
-               } else\r
-               {\r
-                       item_len = delim_end - delim_start;\r
-               }\r
-               if(item_len == val.length())\r
-               {\r
-                       if(val == strings.substr(delim_start, item_len))\r
-                       {\r
-                               return idx;\r
-                       }\r
-               }\r
-               idx++;\r
-               delim_start = delim_end;\r
-               if(delim_start == tstring::npos) break;\r
-               delim_start++;\r
-               if(delim_start == strings.length()) break;\r
-               delim_end = strings.find(delim, delim_start);\r
-       }\r
-       return defValue;\r
-}\r
-\r
-bool litehtml::value_in_list( const tstring& val, const tstring& strings, tchar_t delim )\r
-{\r
-       int idx = value_index(val, strings, -1, delim);\r
-       if(idx >= 0)\r
-       {\r
-               return true;\r
-       }\r
-       return false;\r
-}\r
-\r
-void litehtml::split_string(const tstring& str, string_vector& tokens, const tstring& delims, const tstring& delims_preserve, const tstring& quote)\r
-{\r
-       if(str.empty() || (delims.empty() && delims_preserve.empty()))\r
-       {\r
-               return;\r
-       }\r
-\r
-       tstring all_delims = delims + delims_preserve + quote;\r
-\r
-       tstring::size_type token_start  = 0;\r
-       tstring::size_type token_end    = str.find_first_of(all_delims, token_start);\r
-       tstring::size_type token_len    = 0;\r
-       tstring token;\r
-       while(true)\r
-       {\r
-               while( token_end != tstring::npos && quote.find_first_of(str[token_end]) != tstring::npos )\r
-               {\r
-                       if(str[token_end] == _t('('))\r
-                       {\r
-                               token_end = find_close_bracket(str, token_end, _t('('), _t(')'));\r
-                       } else if(str[token_end] == _t('['))\r
-                       {\r
-                               token_end = find_close_bracket(str, token_end, _t('['), _t(']'));\r
-                       } else if(str[token_end] == _t('{'))\r
-                       {\r
-                               token_end = find_close_bracket(str, token_end, _t('{'), _t('}'));\r
-                       } else\r
-                       {\r
-                               token_end = str.find_first_of(str[token_end], token_end + 1);\r
-                       }\r
-                       if(token_end != tstring::npos)\r
-                       {\r
-                               token_end = str.find_first_of(all_delims, token_end + 1);\r
-                       }\r
-               }\r
-\r
-               if(token_end == tstring::npos)\r
-               {\r
-                       token_len = tstring::npos;\r
-               } else\r
-               {\r
-                       token_len = token_end - token_start;\r
-               }\r
-\r
-               token = str.substr(token_start, token_len);\r
-               if(!token.empty())\r
-               {\r
-                       tokens.push_back( token );\r
-               }\r
-               if(token_end != tstring::npos && !delims_preserve.empty() && delims_preserve.find_first_of(str[token_end]) != tstring::npos)\r
-               {\r
-                       tokens.push_back( str.substr(token_end, 1) );\r
-               }\r
-\r
-               token_start = token_end;\r
-               if(token_start == tstring::npos) break;\r
-               token_start++;\r
-               if(token_start == str.length()) break;\r
-               token_end = str.find_first_of(all_delims, token_start);\r
-       }\r
-}\r
-\r
-void litehtml::join_string(tstring& str, const string_vector& tokens, const tstring& delims)\r
-{\r
-       tstringstream ss;\r
-       for(size_t i=0; i<tokens.size(); ++i)\r
-       {\r
-               if(i != 0)\r
-               {\r
-                       ss << delims;\r
-               }\r
-               ss << tokens[i];\r
-       }\r
-\r
-       str = ss.str();\r
-}\r
+#include "html.h"
+#include "types.h"
+#include "html_tag.h"
+
+void litehtml::trim(tstring &s) 
+{
+       tstring::size_type pos = s.find_first_not_of(_t(" \n\r\t"));
+       if(pos != tstring::npos)
+       {
+           s.erase(s.begin(), s.begin() + pos);
+       }
+       pos = s.find_last_not_of(_t(" \n\r\t"));
+       if(pos != tstring::npos)
+       {
+           s.erase(s.begin() + pos + 1, s.end());
+       }
+}
+
+void litehtml::lcase(tstring &s) 
+{
+       for(tstring::iterator i = s.begin(); i != s.end(); i++)
+       {
+               (*i) = t_tolower(*i);
+       }
+}
+
+litehtml::tstring::size_type litehtml::find_close_bracket(const tstring &s, tstring::size_type off, tchar_t open_b, tchar_t close_b)
+{
+       int cnt = 0;
+       for(tstring::size_type i = off; i < s.length(); i++)
+       {
+               if(s[i] == open_b)
+               {
+                       cnt++;
+               } else if(s[i] == close_b)
+               {
+                       cnt--;
+                       if(!cnt)
+                       {
+                               return i;
+                       }
+               }
+       }
+       return tstring::npos;
+}
+
+int litehtml::value_index( const tstring& val, const tstring& strings, int defValue, tchar_t delim )
+{
+       if(val.empty() || strings.empty() || !delim)
+       {
+               return defValue;
+       }
+
+       int idx = 0;
+       tstring::size_type delim_start  = 0;
+       tstring::size_type delim_end    = strings.find(delim, delim_start);
+       tstring::size_type item_len             = 0;
+       while(true)
+       {
+               if(delim_end == tstring::npos)
+               {
+                       item_len = strings.length() - delim_start;
+               } else
+               {
+                       item_len = delim_end - delim_start;
+               }
+               if(item_len == val.length())
+               {
+                       if(val == strings.substr(delim_start, item_len))
+                       {
+                               return idx;
+                       }
+               }
+               idx++;
+               delim_start = delim_end;
+               if(delim_start == tstring::npos) break;
+               delim_start++;
+               if(delim_start == strings.length()) break;
+               delim_end = strings.find(delim, delim_start);
+       }
+       return defValue;
+}
+
+bool litehtml::value_in_list( const tstring& val, const tstring& strings, tchar_t delim )
+{
+       int idx = value_index(val, strings, -1, delim);
+       if(idx >= 0)
+       {
+               return true;
+       }
+       return false;
+}
+
+void litehtml::split_string(const tstring& str, string_vector& tokens, const tstring& delims, const tstring& delims_preserve, const tstring& quote)
+{
+       if(str.empty() || (delims.empty() && delims_preserve.empty()))
+       {
+               return;
+       }
+
+       tstring all_delims = delims + delims_preserve + quote;
+
+       tstring::size_type token_start  = 0;
+       tstring::size_type token_end    = str.find_first_of(all_delims, token_start);
+       tstring::size_type token_len    = 0;
+       tstring token;
+       while(true)
+       {
+               while( token_end != tstring::npos && quote.find_first_of(str[token_end]) != tstring::npos )
+               {
+                       if(str[token_end] == _t('('))
+                       {
+                               token_end = find_close_bracket(str, token_end, _t('('), _t(')'));
+                       } else if(str[token_end] == _t('['))
+                       {
+                               token_end = find_close_bracket(str, token_end, _t('['), _t(']'));
+                       } else if(str[token_end] == _t('{'))
+                       {
+                               token_end = find_close_bracket(str, token_end, _t('{'), _t('}'));
+                       } else
+                       {
+                               token_end = str.find_first_of(str[token_end], token_end + 1);
+                       }
+                       if(token_end != tstring::npos)
+                       {
+                               token_end = str.find_first_of(all_delims, token_end + 1);
+                       }
+               }
+
+               if(token_end == tstring::npos)
+               {
+                       token_len = tstring::npos;
+               } else
+               {
+                       token_len = token_end - token_start;
+               }
+
+               token = str.substr(token_start, token_len);
+               if(!token.empty())
+               {
+                       tokens.push_back( token );
+               }
+               if(token_end != tstring::npos && !delims_preserve.empty() && delims_preserve.find_first_of(str[token_end]) != tstring::npos)
+               {
+                       tokens.push_back( str.substr(token_end, 1) );
+               }
+
+               token_start = token_end;
+               if(token_start == tstring::npos) break;
+               token_start++;
+               if(token_start == str.length()) break;
+               token_end = str.find_first_of(all_delims, token_start);
+       }
+}
+
+void litehtml::join_string(tstring& str, const string_vector& tokens, const tstring& delims)
+{
+       tstringstream ss;
+       for(size_t i=0; i<tokens.size(); ++i)
+       {
+               if(i != 0)
+               {
+                       ss << delims;
+               }
+               ss << tokens[i];
+       }
+
+       str = ss.str();
+}
index 31852c366b8d4c36c079cfd4b93044a4a080da16..2c5c5561fc993e14a1d2c3974194bd71c88e44b5 100644 (file)
@@ -1,92 +1,96 @@
-#pragma once\r
-\r
-#include <stdlib.h>\r
-#include <string>\r
-#include <ctype.h>\r
-#include <vector>\r
-#include <map>\r
-#include <cstring>\r
-#include <algorithm>\r
-#include <sstream>\r
-#include "os_types.h"\r
-#include "types.h"\r
-#include "background.h"\r
-#include "borders.h"\r
-#include "html_tag.h"\r
-#include "web_color.h"\r
-#include "media_query.h"\r
-\r
-namespace litehtml\r
-{\r
-       struct list_marker\r
-       {\r
-               tstring                 image;\r
-               const tchar_t*  baseurl;\r
-               list_style_type marker_type;\r
-               web_color               color;\r
-               position                pos;\r
-       };\r
-\r
-       // call back interface to draw text, images and other elements\r
-       class document_container\r
-       {\r
-       public:\r
-               virtual litehtml::uint_ptr      create_font(const litehtml::tchar_t* faceName, int size, int weight, litehtml::font_style italic, unsigned int decoration, litehtml::font_metrics* fm) = 0;\r
-               virtual void                            delete_font(litehtml::uint_ptr hFont) = 0;\r
-               virtual int                                     text_width(const litehtml::tchar_t* text, litehtml::uint_ptr hFont) = 0;\r
-               virtual void                            draw_text(litehtml::uint_ptr hdc, const litehtml::tchar_t* text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos) = 0;\r
-               virtual int                                     pt_to_px(int pt) = 0;\r
-               virtual int                                     get_default_font_size() const = 0;\r
-               virtual const litehtml::tchar_t*        get_default_font_name() const = 0;\r
-               virtual void                            draw_list_marker(litehtml::uint_ptr hdc, const litehtml::list_marker& marker) = 0;\r
-               virtual void                            load_image(const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, bool redraw_on_ready) = 0;\r
-               virtual void                            get_image_size(const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, litehtml::size& sz) = 0;\r
-               virtual void                            draw_background(litehtml::uint_ptr hdc, const litehtml::background_paint& bg) = 0;\r
-               virtual void                            draw_borders(litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root) = 0;\r
-\r
-               virtual void                            set_caption(const litehtml::tchar_t* caption) = 0;\r
-               virtual void                            set_base_url(const litehtml::tchar_t* base_url) = 0;\r
-               virtual void                            link(const std::shared_ptr<litehtml::document>& doc, const litehtml::element::ptr& el) = 0;\r
-               virtual void                            on_anchor_click(const litehtml::tchar_t* url, const litehtml::element::ptr& el) = 0;\r
-               virtual void                            set_cursor(const litehtml::tchar_t* cursor) = 0;\r
-               virtual void                            transform_text(litehtml::tstring& text, litehtml::text_transform tt) = 0;\r
-               virtual void                            import_css(litehtml::tstring& text, const litehtml::tstring& url, litehtml::tstring& baseurl) = 0;\r
-               virtual void                            set_clip(const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius, bool valid_x, bool valid_y) = 0;\r
-               virtual void                            del_clip() = 0;\r
-               virtual void                            get_client_rect(litehtml::position& client) const = 0;\r
-               virtual std::shared_ptr<litehtml::element>      create_element(const litehtml::tchar_t *tag_name,\r
-                                                                                                                                        const litehtml::string_map &attributes,\r
-                                                                                                                                        const std::shared_ptr<litehtml::document> &doc) = 0;\r
-\r
-               virtual void                            get_media_features(litehtml::media_features& media) const = 0;\r
-               virtual void                            get_language(litehtml::tstring& language, litehtml::tstring & culture) const = 0;\r
-       };\r
-\r
-       void trim(tstring &s);\r
-       void lcase(tstring &s);\r
-       int      value_index(const tstring& val, const tstring& strings, int defValue = -1, tchar_t delim = _t(';'));\r
-       bool value_in_list(const tstring& val, const tstring& strings, tchar_t delim = _t(';'));\r
-       tstring::size_type find_close_bracket(const tstring &s, tstring::size_type off, tchar_t open_b = _t('('), tchar_t close_b = _t(')'));\r
-       void split_string(const tstring& str, string_vector& tokens, const tstring& delims, const tstring& delims_preserve = _t(""), const tstring& quote = _t("\""));\r
-       void join_string(tstring& str, const string_vector& tokens, const tstring& delims);\r
-\r
-       inline int round_f(float val)\r
-       {\r
-               int int_val = (int) val;\r
-               if(val - int_val >= 0.5)\r
-               {\r
-                       int_val++;\r
-               }\r
-               return int_val;\r
-       }\r
-\r
-       inline int round_d(double val)\r
-       {\r
-               int int_val = (int) val;\r
-               if(val - int_val >= 0.5)\r
-               {\r
-                       int_val++;\r
-               }\r
-               return int_val;\r
-       }\r
-}\r
+#ifndef LH_HTML_H
+#define LH_HTML_H
+
+#include <stdlib.h>
+#include <string>
+#include <ctype.h>
+#include <vector>
+#include <map>
+#include <cstring>
+#include <algorithm>
+#include <sstream>
+#include "os_types.h"
+#include "types.h"
+#include "background.h"
+#include "borders.h"
+#include "html_tag.h"
+#include "web_color.h"
+#include "media_query.h"
+
+namespace litehtml
+{
+       struct list_marker
+       {
+               tstring                 image;
+               const tchar_t*  baseurl;
+               list_style_type marker_type;
+               web_color               color;
+               position                pos;
+       };
+
+       // call back interface to draw text, images and other elements
+       class document_container
+       {
+       public:
+               virtual litehtml::uint_ptr      create_font(const litehtml::tchar_t* faceName, int size, int weight, litehtml::font_style italic, unsigned int decoration, litehtml::font_metrics* fm) = 0;
+               virtual void                            delete_font(litehtml::uint_ptr hFont) = 0;
+               virtual int                                     text_width(const litehtml::tchar_t* text, litehtml::uint_ptr hFont) = 0;
+               virtual void                            draw_text(litehtml::uint_ptr hdc, const litehtml::tchar_t* text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos) = 0;
+               virtual int                                     pt_to_px(int pt) = 0;
+               virtual int                                     get_default_font_size() const = 0;
+               virtual const litehtml::tchar_t*        get_default_font_name() const = 0;
+               virtual void                            draw_list_marker(litehtml::uint_ptr hdc, const litehtml::list_marker& marker) = 0;
+               virtual void                            load_image(const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, bool redraw_on_ready) = 0;
+               virtual void                            get_image_size(const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, litehtml::size& sz) = 0;
+               virtual void                            draw_background(litehtml::uint_ptr hdc, const litehtml::background_paint& bg) = 0;
+               virtual void                            draw_borders(litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root) = 0;
+
+               virtual void                            set_caption(const litehtml::tchar_t* caption) = 0;
+               virtual void                            set_base_url(const litehtml::tchar_t* base_url) = 0;
+               virtual void                            link(const std::shared_ptr<litehtml::document>& doc, const litehtml::element::ptr& el) = 0;
+               virtual void                            on_anchor_click(const litehtml::tchar_t* url, const litehtml::element::ptr& el) = 0;
+               virtual void                            set_cursor(const litehtml::tchar_t* cursor) = 0;
+               virtual void                            transform_text(litehtml::tstring& text, litehtml::text_transform tt) = 0;
+               virtual void                            import_css(litehtml::tstring& text, const litehtml::tstring& url, litehtml::tstring& baseurl) = 0;
+               virtual void                            set_clip(const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius, bool valid_x, bool valid_y) = 0;
+               virtual void                            del_clip() = 0;
+               virtual void                            get_client_rect(litehtml::position& client) const = 0;
+               virtual std::shared_ptr<litehtml::element>      create_element(const litehtml::tchar_t *tag_name,
+                                                                                                                                        const litehtml::string_map &attributes,
+                                                                                                                                        const std::shared_ptr<litehtml::document> &doc) = 0;
+
+               virtual void                            get_media_features(litehtml::media_features& media) const = 0;
+               virtual void                            get_language(litehtml::tstring& language, litehtml::tstring & culture) const = 0;
+               virtual litehtml::tstring       resolve_color(const litehtml::tstring& color) const  { return litehtml::tstring(); }
+       };
+
+       void trim(tstring &s);
+       void lcase(tstring &s);
+       int      value_index(const tstring& val, const tstring& strings, int defValue = -1, tchar_t delim = _t(';'));
+       bool value_in_list(const tstring& val, const tstring& strings, tchar_t delim = _t(';'));
+       tstring::size_type find_close_bracket(const tstring &s, tstring::size_type off, tchar_t open_b = _t('('), tchar_t close_b = _t(')'));
+       void split_string(const tstring& str, string_vector& tokens, const tstring& delims, const tstring& delims_preserve = _t(""), const tstring& quote = _t("\""));
+       void join_string(tstring& str, const string_vector& tokens, const tstring& delims);
+
+       inline int round_f(float val)
+       {
+               int int_val = (int) val;
+               if(val - int_val >= 0.5)
+               {
+                       int_val++;
+               }
+               return int_val;
+       }
+
+       inline int round_d(double val)
+       {
+               int int_val = (int) val;
+               if(val - int_val >= 0.5)
+               {
+                       int_val++;
+               }
+               return int_val;
+       }
+}
+
+#endif  // LH_HTML_H
index 40a76deeba45671441c74b16b822b2b8c8392d5b..f856b1e81fbe6701a4228c8ade3d04b122fbd15b 100644 (file)
-#include "html.h"\r
-#include "html_tag.h"\r
-#include "document.h"\r
-#include "iterators.h"\r
-#include "stylesheet.h"\r
-#include "table.h"\r
-#include <algorithm>\r
-#include <locale>\r
-#include "el_before_after.h"\r
-\r
-litehtml::html_tag::html_tag(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)\r
-{\r
-       m_box_sizing                    = box_sizing_content_box;\r
-       m_z_index                               = 0;\r
-       m_overflow                              = overflow_visible;\r
-       m_box                                   = 0;\r
-       m_text_align                    = text_align_left;\r
-       m_el_position                   = element_position_static;\r
-       m_display                               = display_inline;\r
-       m_vertical_align                = va_baseline;\r
-       m_list_style_type               = list_style_type_none;\r
-       m_list_style_position   = list_style_position_outside;\r
-       m_float                                 = float_none;\r
-       m_clear                                 = clear_none;\r
-       m_font                                  = 0;\r
-       m_font_size                             = 0;\r
-       m_white_space                   = white_space_normal;\r
-       m_lh_predefined                 = false;\r
-       m_line_height                   = 0;\r
-       m_visibility                    = visibility_visible;\r
-       m_border_spacing_x              = 0;\r
-       m_border_spacing_y              = 0;\r
-       m_border_collapse               = border_collapse_separate;\r
-}\r
-\r
-litehtml::html_tag::~html_tag()\r
-{\r
-\r
-}\r
-\r
-bool litehtml::html_tag::appendChild(const element::ptr &el)\r
-{\r
-       if(el)\r
-       {\r
-               el->parent(shared_from_this());\r
-               m_children.push_back(el);\r
-               return true;\r
-       }\r
-       return false;\r
-}\r
-\r
-bool litehtml::html_tag::removeChild(const element::ptr &el)\r
-{\r
-       if(el && el->parent() == shared_from_this())\r
-       {\r
-               el->parent(nullptr);\r
-               m_children.erase(std::remove(m_children.begin(), m_children.end(), el), m_children.end());\r
-               return true;\r
-       }\r
-       return false;\r
-}\r
-\r
-void litehtml::html_tag::clearRecursive()\r
-{\r
-       for(auto& el : m_children)\r
-       {\r
-               el->clearRecursive();\r
-               el->parent(nullptr);\r
-       }\r
-       m_children.clear();\r
-}\r
-\r
-\r
-const litehtml::tchar_t* litehtml::html_tag::get_tagName() const\r
-{\r
-       return m_tag.c_str();\r
-}\r
-\r
-void litehtml::html_tag::set_attr( const tchar_t* name, const tchar_t* val )\r
-{\r
-       if(name && val)\r
-       {\r
-               tstring s_val = name;\r
-               std::locale lc = std::locale::global(std::locale::classic());\r
-               for(size_t i = 0; i < s_val.length(); i++)\r
-               {\r
-                       s_val[i] = std::tolower(s_val[i], lc);\r
-               }\r
-               m_attrs[s_val] = val;\r
-\r
-               if( t_strcasecmp( name, _t("class") ) == 0 )\r
-               {\r
-                       m_class_values.resize( 0 );\r
-                       split_string( val, m_class_values, _t(" ") );\r
-               }\r
-       }\r
-}\r
-\r
-const litehtml::tchar_t* litehtml::html_tag::get_attr( const tchar_t* name, const tchar_t* def )\r
-{\r
-       string_map::const_iterator attr = m_attrs.find(name);\r
-       if(attr != m_attrs.end())\r
-       {\r
-               return attr->second.c_str();\r
-       }\r
-       return def;\r
-}\r
-\r
-litehtml::elements_vector litehtml::html_tag::select_all( const tstring& selector )\r
-{\r
-       css_selector sel(media_query_list::ptr(0));\r
-       sel.parse(selector);\r
-       \r
-       return select_all(sel);\r
-}\r
-\r
-litehtml::elements_vector litehtml::html_tag::select_all( const css_selector& selector )\r
-{\r
-       litehtml::elements_vector res;\r
-       select_all(selector, res);\r
-       return res;\r
-}\r
-\r
-void litehtml::html_tag::select_all(const css_selector& selector, elements_vector& res)\r
-{\r
-       if(select(selector))\r
-       {\r
-               res.push_back(shared_from_this());\r
-       }\r
-       \r
-       for(auto& el : m_children)\r
-       {\r
-               el->select_all(selector, res);\r
-       }\r
-}\r
-\r
-\r
-litehtml::element::ptr litehtml::html_tag::select_one( const tstring& selector )\r
-{\r
-       css_selector sel(media_query_list::ptr(0));\r
-       sel.parse(selector);\r
-\r
-       return select_one(sel);\r
-}\r
-\r
-litehtml::element::ptr litehtml::html_tag::select_one( const css_selector& selector )\r
-{\r
-       if(select(selector))\r
-       {\r
-               return shared_from_this();\r
-       }\r
-\r
-       for(auto& el : m_children)\r
-       {\r
-               element::ptr res = el->select_one(selector);\r
-               if(res)\r
-               {\r
-                       return res;\r
-               }\r
-       }\r
-       return 0;\r
-}\r
-\r
-void litehtml::html_tag::apply_stylesheet( const litehtml::css& stylesheet )\r
-{\r
-       remove_before_after();\r
-\r
-       for(const auto& sel : stylesheet.selectors())\r
-       {\r
-               int apply = select(*sel, false);\r
-\r
-               if(apply != select_no_match)\r
-               {\r
-                       used_selector::ptr us = std::unique_ptr<used_selector>(new used_selector(sel, false));\r
-\r
-                       if(sel->is_media_valid())\r
-                       {\r
-                               if(apply & select_match_pseudo_class)\r
-                               {\r
-                                       if(select(*sel, true))\r
-                                       {\r
-                                               if(apply & select_match_with_after)\r
-                                               {\r
-                                                       element::ptr el = get_element_after();\r
-                                                       if(el)\r
-                                                       {\r
-                                                               el->add_style(*sel->m_style);\r
-                                                       }\r
-                                               } else if(apply & select_match_with_before)\r
-                                               {\r
-                                                       element::ptr el = get_element_before();\r
-                                                       if(el)\r
-                                                       {\r
-                                                               el->add_style(*sel->m_style);\r
-                                                       }\r
-                                               }\r
-                                               else\r
-                                               {\r
-                                                       add_style(*sel->m_style);\r
-                                                       us->m_used = true;\r
-                                               }\r
-                                       }\r
-                               } else if(apply & select_match_with_after)\r
-                               {\r
-                                       element::ptr el = get_element_after();\r
-                                       if(el)\r
-                                       {\r
-                                               el->add_style(*sel->m_style);\r
-                                       }\r
-                               } else if(apply & select_match_with_before)\r
-                               {\r
-                                       element::ptr el = get_element_before();\r
-                                       if(el)\r
-                                       {\r
-                                               el->add_style(*sel->m_style);\r
-                                       }\r
-                               } else\r
-                               {\r
-                                       add_style(*sel->m_style);\r
-                                       us->m_used = true;\r
-                               }\r
-                       }\r
-                       m_used_styles.push_back(std::move(us));\r
-               }\r
-       }\r
-\r
-       for(auto& el : m_children)\r
-       {\r
-               if(el->get_display() != display_inline_text)\r
-               {\r
-                       el->apply_stylesheet(stylesheet);\r
-               }\r
-       }\r
-}\r
-\r
-void litehtml::html_tag::get_content_size( size& sz, int max_width )\r
-{\r
-       sz.height       = 0;\r
-       if(m_display == display_block)\r
-       {\r
-               sz.width        = max_width;\r
-       } else\r
-       {\r
-               sz.width        = 0;\r
-       }\r
-}\r
-\r
-void litehtml::html_tag::draw( uint_ptr hdc, int x, int y, const position* clip )\r
-{\r
-       position pos = m_pos;\r
-       pos.x   += x;\r
-       pos.y   += y;\r
-\r
-       draw_background(hdc, x, y, clip);\r
-\r
-       if(m_display == display_list_item && m_list_style_type != list_style_type_none)\r
-       {\r
-               if(m_overflow > overflow_visible)\r
-               {\r
-                       position border_box = pos;\r
-                       border_box += m_padding;\r
-                       border_box += m_borders;\r
-\r
-                       border_radiuses bdr_radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);\r
-\r
-                       bdr_radius -= m_borders;\r
-                       bdr_radius -= m_padding;\r
-\r
-                       get_document()->container()->set_clip(pos, bdr_radius, true, true);\r
-               }\r
-\r
-               draw_list_marker(hdc, pos);\r
-\r
-               if(m_overflow > overflow_visible)\r
-               {\r
-                       get_document()->container()->del_clip();\r
-               }\r
-       }\r
-}\r
-\r
-litehtml::uint_ptr litehtml::html_tag::get_font(font_metrics* fm)\r
-{\r
-       if(fm)\r
-       {\r
-               *fm = m_font_metrics;\r
-       }\r
-       return m_font;\r
-}\r
-\r
-const litehtml::tchar_t* litehtml::html_tag::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ )\r
-{\r
-       const tchar_t* ret = m_style.get_property(name);\r
-       element::ptr el_parent = parent();\r
-       if (el_parent)\r
-       {\r
-               if ( ( ret && !t_strcasecmp(ret, _t("inherit")) ) || (!ret && inherited) )\r
-               {\r
-                       ret = el_parent->get_style_property(name, inherited, def);\r
-               }\r
-       }\r
-\r
-       if(!ret)\r
-       {\r
-               ret = def;\r
-       }\r
-\r
-       return ret;\r
-}\r
-\r
-void litehtml::html_tag::parse_styles(bool is_reparse)\r
-{\r
-       const tchar_t* style = get_attr(_t("style"));\r
-\r
-       if(style)\r
-       {\r
-               m_style.add(style, NULL);\r
-       }\r
-\r
-       init_font();\r
-       document::ptr doc = get_document();\r
-\r
-       m_el_position   = (element_position)    value_index(get_style_property(_t("position"),          false,  _t("static")),          element_position_strings,       element_position_fixed);\r
-       m_text_align    = (text_align)                  value_index(get_style_property(_t("text-align"),                true,   _t("left")),            text_align_strings,                     text_align_left);\r
-       m_overflow              = (overflow)                    value_index(get_style_property(_t("overflow"),          false,  _t("visible")),         overflow_strings,                       overflow_visible);\r
-       m_white_space   = (white_space)                 value_index(get_style_property(_t("white-space"),       true,   _t("normal")),          white_space_strings,            white_space_normal);\r
-       m_display               = (style_display)               value_index(get_style_property(_t("display"),           false,  _t("inline")),          style_display_strings,          display_inline);\r
-       m_visibility    = (visibility)                  value_index(get_style_property(_t("visibility"),        true,   _t("visible")),         visibility_strings,                     visibility_visible);\r
-       m_box_sizing    = (box_sizing)                  value_index(get_style_property(_t("box-sizing"),                false,  _t("content-box")),     box_sizing_strings,                     box_sizing_content_box);\r
-\r
-       if(m_el_position != element_position_static)\r
-       {\r
-               const tchar_t* val = get_style_property(_t("z-index"), false, 0);\r
-               if(val)\r
-               {\r
-                       m_z_index = t_atoi(val);\r
-               }\r
-       }\r
-\r
-       const tchar_t* va       = get_style_property(_t("vertical-align"), true,        _t("baseline"));\r
-       m_vertical_align = (vertical_align) value_index(va, vertical_align_strings, va_baseline);\r
-\r
-       const tchar_t* fl       = get_style_property(_t("float"), false,        _t("none"));\r
-       m_float = (element_float) value_index(fl, element_float_strings, float_none);\r
-\r
-       m_clear = (element_clear) value_index(get_style_property(_t("clear"), false, _t("none")), element_clear_strings, clear_none);\r
-\r
-       if (m_float != float_none)\r
-       {\r
-               // reset display in to block for floating elements\r
-               if (m_display != display_none)\r
-               {\r
-                       m_display = display_block;\r
-               }\r
-       }\r
-       else if (m_display == display_table ||\r
-               m_display == display_table_caption ||\r
-               m_display == display_table_cell ||\r
-               m_display == display_table_column ||\r
-               m_display == display_table_column_group ||\r
-               m_display == display_table_footer_group ||\r
-               m_display == display_table_header_group ||\r
-               m_display == display_table_row ||\r
-               m_display == display_table_row_group)\r
-       {\r
-               doc->add_tabular(shared_from_this());\r
-       }\r
-       // fix inline boxes with absolute/fixed positions\r
-       else if (m_display != display_none && is_inline_box())\r
-       {\r
-               if (m_el_position == element_position_absolute || m_el_position == element_position_fixed)\r
-               {\r
-                       m_display = display_block;\r
-               }\r
-       }\r
-\r
-       m_css_text_indent.fromString(   get_style_property(_t("text-indent"),   true,   _t("0")),       _t("0"));\r
-\r
-       m_css_width.fromString(                 get_style_property(_t("width"),                 false,  _t("auto")), _t("auto"));\r
-       m_css_height.fromString(                get_style_property(_t("height"),                false,  _t("auto")), _t("auto"));\r
-\r
-       doc->cvt_units(m_css_width, m_font_size);\r
-       doc->cvt_units(m_css_height, m_font_size);\r
-\r
-       m_css_min_width.fromString(             get_style_property(_t("min-width"),             false,  _t("0")));\r
-       m_css_min_height.fromString(    get_style_property(_t("min-height"),            false,  _t("0")));\r
-\r
-       m_css_max_width.fromString(             get_style_property(_t("max-width"),             false,  _t("none")),    _t("none"));\r
-       m_css_max_height.fromString(    get_style_property(_t("max-height"),            false,  _t("none")),    _t("none"));\r
-       \r
-       doc->cvt_units(m_css_min_width, m_font_size);\r
-       doc->cvt_units(m_css_min_height, m_font_size);\r
-\r
-       m_css_offsets.left.fromString(          get_style_property(_t("left"),                          false,  _t("auto")), _t("auto"));\r
-       m_css_offsets.right.fromString(         get_style_property(_t("right"),                         false,  _t("auto")), _t("auto"));\r
-       m_css_offsets.top.fromString(           get_style_property(_t("top"),                           false,  _t("auto")), _t("auto"));\r
-       m_css_offsets.bottom.fromString(        get_style_property(_t("bottom"),                        false,  _t("auto")), _t("auto"));\r
-\r
-       doc->cvt_units(m_css_offsets.left, m_font_size);\r
-       doc->cvt_units(m_css_offsets.right, m_font_size);\r
-       doc->cvt_units(m_css_offsets.top,               m_font_size);\r
-       doc->cvt_units(m_css_offsets.bottom,    m_font_size);\r
-\r
-       m_css_margins.left.fromString(          get_style_property(_t("margin-left"),           false,  _t("0")), _t("auto"));\r
-       m_css_margins.right.fromString(         get_style_property(_t("margin-right"),          false,  _t("0")), _t("auto"));\r
-       m_css_margins.top.fromString(           get_style_property(_t("margin-top"),                    false,  _t("0")), _t("auto"));\r
-       m_css_margins.bottom.fromString(        get_style_property(_t("margin-bottom"),         false,  _t("0")), _t("auto"));\r
-\r
-       m_css_padding.left.fromString(          get_style_property(_t("padding-left"),          false,  _t("0")), _t(""));\r
-       m_css_padding.right.fromString(         get_style_property(_t("padding-right"),         false,  _t("0")), _t(""));\r
-       m_css_padding.top.fromString(           get_style_property(_t("padding-top"),           false,  _t("0")), _t(""));\r
-       m_css_padding.bottom.fromString(        get_style_property(_t("padding-bottom"),                false,  _t("0")), _t(""));\r
-\r
-       m_css_borders.left.width.fromString(    get_style_property(_t("border-left-width"),             false,  _t("medium")), border_width_strings);\r
-       m_css_borders.right.width.fromString(   get_style_property(_t("border-right-width"),            false,  _t("medium")), border_width_strings);\r
-       m_css_borders.top.width.fromString(             get_style_property(_t("border-top-width"),              false,  _t("medium")), border_width_strings);\r
-       m_css_borders.bottom.width.fromString(  get_style_property(_t("border-bottom-width"),   false,  _t("medium")), border_width_strings);\r
-\r
-       m_css_borders.left.color = web_color::from_string(get_style_property(_t("border-left-color"),   false,  _t("")));\r
-       m_css_borders.left.style = (border_style) value_index(get_style_property(_t("border-left-style"), false, _t("none")), border_style_strings, border_style_none);\r
-\r
-       m_css_borders.right.color = web_color::from_string(get_style_property(_t("border-right-color"), false,  _t("")));\r
-       m_css_borders.right.style = (border_style) value_index(get_style_property(_t("border-right-style"), false, _t("none")), border_style_strings, border_style_none);\r
-\r
-       m_css_borders.top.color = web_color::from_string(get_style_property(_t("border-top-color"),     false,  _t("")));\r
-       m_css_borders.top.style = (border_style) value_index(get_style_property(_t("border-top-style"), false, _t("none")), border_style_strings, border_style_none);\r
-\r
-       m_css_borders.bottom.color = web_color::from_string(get_style_property(_t("border-bottom-color"),       false,  _t("")));\r
-       m_css_borders.bottom.style = (border_style) value_index(get_style_property(_t("border-bottom-style"), false, _t("none")), border_style_strings, border_style_none);\r
-\r
-       m_css_borders.radius.top_left_x.fromString(get_style_property(_t("border-top-left-radius-x"), false, _t("0")));\r
-       m_css_borders.radius.top_left_y.fromString(get_style_property(_t("border-top-left-radius-y"), false, _t("0")));\r
-\r
-       m_css_borders.radius.top_right_x.fromString(get_style_property(_t("border-top-right-radius-x"), false, _t("0")));\r
-       m_css_borders.radius.top_right_y.fromString(get_style_property(_t("border-top-right-radius-y"), false, _t("0")));\r
-\r
-       m_css_borders.radius.bottom_right_x.fromString(get_style_property(_t("border-bottom-right-radius-x"), false, _t("0")));\r
-       m_css_borders.radius.bottom_right_y.fromString(get_style_property(_t("border-bottom-right-radius-y"), false, _t("0")));\r
-\r
-       m_css_borders.radius.bottom_left_x.fromString(get_style_property(_t("border-bottom-left-radius-x"), false, _t("0")));\r
-       m_css_borders.radius.bottom_left_y.fromString(get_style_property(_t("border-bottom-left-radius-y"), false, _t("0")));\r
-\r
-       doc->cvt_units(m_css_borders.radius.bottom_left_x,                      m_font_size);\r
-       doc->cvt_units(m_css_borders.radius.bottom_left_y,                      m_font_size);\r
-       doc->cvt_units(m_css_borders.radius.bottom_right_x,                     m_font_size);\r
-       doc->cvt_units(m_css_borders.radius.bottom_right_y,                     m_font_size);\r
-       doc->cvt_units(m_css_borders.radius.top_left_x,                         m_font_size);\r
-       doc->cvt_units(m_css_borders.radius.top_left_y,                         m_font_size);\r
-       doc->cvt_units(m_css_borders.radius.top_right_x,                                m_font_size);\r
-       doc->cvt_units(m_css_borders.radius.top_right_y,                                m_font_size);\r
-\r
-       doc->cvt_units(m_css_text_indent,                                                               m_font_size);\r
-\r
-       m_margins.left          = doc->cvt_units(m_css_margins.left,            m_font_size);\r
-       m_margins.right         = doc->cvt_units(m_css_margins.right,           m_font_size);\r
-       m_margins.top           = doc->cvt_units(m_css_margins.top,             m_font_size);\r
-       m_margins.bottom        = doc->cvt_units(m_css_margins.bottom,  m_font_size);\r
-\r
-       m_padding.left          = doc->cvt_units(m_css_padding.left,            m_font_size);\r
-       m_padding.right         = doc->cvt_units(m_css_padding.right,           m_font_size);\r
-       m_padding.top           = doc->cvt_units(m_css_padding.top,             m_font_size);\r
-       m_padding.bottom        = doc->cvt_units(m_css_padding.bottom,  m_font_size);\r
-\r
-       m_borders.left          = doc->cvt_units(m_css_borders.left.width,      m_font_size);\r
-       m_borders.right         = doc->cvt_units(m_css_borders.right.width,     m_font_size);\r
-       m_borders.top           = doc->cvt_units(m_css_borders.top.width,               m_font_size);\r
-       m_borders.bottom        = doc->cvt_units(m_css_borders.bottom.width,    m_font_size);\r
-\r
-       css_length line_height;\r
-       line_height.fromString(get_style_property(_t("line-height"),    true,   _t("normal")), _t("normal"));\r
-       if(line_height.is_predefined())\r
-       {\r
-               m_line_height = m_font_metrics.height;\r
-               m_lh_predefined = true;\r
-       } else if(line_height.units() == css_units_none)\r
-       {\r
-               m_line_height = (int) (line_height.val() * m_font_size);\r
-               m_lh_predefined = false;\r
-       } else\r
-       {\r
-               m_line_height =  doc->cvt_units(line_height,    m_font_size, m_font_size);\r
-               m_lh_predefined = false;\r
-       }\r
-\r
-\r
-       if(m_display == display_list_item)\r
-       {\r
-               const tchar_t* list_type = get_style_property(_t("list-style-type"), true, _t("disc"));\r
-               m_list_style_type = (list_style_type) value_index(list_type, list_style_type_strings, list_style_type_disc);\r
-\r
-               const tchar_t* list_pos = get_style_property(_t("list-style-position"), true, _t("outside"));\r
-               m_list_style_position = (list_style_position) value_index(list_pos, list_style_position_strings, list_style_position_outside);\r
-\r
-               const tchar_t* list_image = get_style_property(_t("list-style-image"), true, 0);\r
-               if(list_image && list_image[0])\r
-               {\r
-                       tstring url;\r
-                       css::parse_css_url(list_image, url);\r
-\r
-                       const tchar_t* list_image_baseurl = get_style_property(_t("list-style-image-baseurl"), true, 0);\r
-                       doc->container()->load_image(url.c_str(), list_image_baseurl, true);\r
-               }\r
-\r
-       }\r
-\r
-       parse_background();\r
-\r
-       if(!is_reparse)\r
-       {\r
-               for(auto& el : m_children)\r
-               {\r
-                       el->parse_styles();\r
-               }\r
-       }\r
-}\r
-\r
-int litehtml::html_tag::render( int x, int y, int max_width, bool second_pass )\r
-{\r
-       if (m_display == display_table || m_display == display_inline_table)\r
-       {\r
-               return render_table(x, y, max_width, second_pass);\r
-       }\r
-\r
-       return render_box(x, y, max_width, second_pass);\r
-}\r
-\r
-bool litehtml::html_tag::is_white_space() const\r
-{\r
-       return false;\r
-}\r
-\r
-int litehtml::html_tag::get_font_size() const\r
-{\r
-       return m_font_size;\r
-}\r
-\r
-int litehtml::html_tag::get_base_line()\r
-{\r
-       if(is_replaced())\r
-       {\r
-               return 0;\r
-       }\r
-       int bl = 0;\r
-       if(!m_boxes.empty())\r
-       {\r
-               bl = m_boxes.back()->baseline() + content_margins_bottom();\r
-       }\r
-       return bl;\r
-}\r
-\r
-void litehtml::html_tag::init()\r
-{\r
-       if (m_display == display_table || m_display == display_inline_table)\r
-       {\r
-               if (m_grid)\r
-               {\r
-                       m_grid->clear();\r
-               }\r
-               else\r
-               {\r
-                       m_grid = std::unique_ptr<table_grid>(new table_grid());\r
-               }\r
-\r
-               go_inside_table                 table_selector;\r
-               table_rows_selector             row_selector;\r
-               table_cells_selector    cell_selector;\r
-\r
-               elements_iterator row_iter(shared_from_this(), &table_selector, &row_selector);\r
-\r
-               element::ptr row = row_iter.next(false);\r
-               while (row)\r
-               {\r
-                       m_grid->begin_row(row);\r
-\r
-                       elements_iterator cell_iter(row, &table_selector, &cell_selector);\r
-                       element::ptr cell = cell_iter.next();\r
-                       while (cell)\r
-                       {\r
-                               m_grid->add_cell(cell);\r
-\r
-                               cell = cell_iter.next(false);\r
-                       }\r
-                       row = row_iter.next(false);\r
-               }\r
-\r
-               m_grid->finish();\r
-       }\r
-\r
-       for (auto& el : m_children)\r
-       {\r
-               el->init();\r
-       }\r
-}\r
-\r
-int litehtml::html_tag::select(const css_selector& selector, bool apply_pseudo)\r
-{\r
-       int right_res = select(selector.m_right, apply_pseudo);\r
-       if(right_res == select_no_match)\r
-       {\r
-               return select_no_match;\r
-       }\r
-       element::ptr el_parent = parent();\r
-       if(selector.m_left)\r
-       {\r
-               if (!el_parent)\r
-               {\r
-                       return select_no_match;\r
-               }\r
-               switch(selector.m_combinator)\r
-               {\r
-               case combinator_descendant:\r
-                       {\r
-                               bool is_pseudo = false;\r
-                               element::ptr res = find_ancestor(*selector.m_left, apply_pseudo, &is_pseudo);\r
-                               if(!res)\r
-                               {\r
-                                       return select_no_match;\r
-                               } else\r
-                               {\r
-                                       if(is_pseudo)\r
-                                       {\r
-                                               right_res |= select_match_pseudo_class;\r
-                                       }\r
-                               }\r
-                       }\r
-                       break;\r
-               case combinator_child:\r
-                       {\r
-                               int res = el_parent->select(*selector.m_left, apply_pseudo);\r
-                               if(res == select_no_match)\r
-                               {\r
-                                       return select_no_match;\r
-                               } else\r
-                               {\r
-                                       if(right_res != select_match_pseudo_class)\r
-                                       {\r
-                                               right_res |= res;\r
-                                       }\r
-                               }\r
-                       }\r
-                       break;\r
-               case combinator_adjacent_sibling:\r
-                       {\r
-                               bool is_pseudo = false;\r
-                               element::ptr res = el_parent->find_adjacent_sibling(shared_from_this(), *selector.m_left, apply_pseudo, &is_pseudo);\r
-                               if(!res)\r
-                               {\r
-                                       return select_no_match;\r
-                               } else\r
-                               {\r
-                                       if(is_pseudo)\r
-                                       {\r
-                                               right_res |= select_match_pseudo_class;\r
-                                       }\r
-                               }\r
-                       }\r
-                       break;\r
-               case combinator_general_sibling:\r
-                       {\r
-                               bool is_pseudo = false;\r
-                               element::ptr res =  el_parent->find_sibling(shared_from_this(), *selector.m_left, apply_pseudo, &is_pseudo);\r
-                               if(!res)\r
-                               {\r
-                                       return select_no_match;\r
-                               } else\r
-                               {\r
-                                       if(is_pseudo)\r
-                                       {\r
-                                               right_res |= select_match_pseudo_class;\r
-                                       }\r
-                               }\r
-                       }\r
-                       break;\r
-               default:\r
-                       right_res = select_no_match;\r
-               }\r
-       }\r
-       return right_res;\r
-}\r
-\r
-int litehtml::html_tag::select(const css_element_selector& selector, bool apply_pseudo)\r
-{\r
-       if(!selector.m_tag.empty() && selector.m_tag != _t("*"))\r
-       {\r
-               if(selector.m_tag != m_tag)\r
-               {\r
-                       return select_no_match;\r
-               }\r
-       }\r
-\r
-       int res = select_match;\r
-       element::ptr el_parent = parent();\r
-\r
-       for(css_attribute_selector::vector::const_iterator i = selector.m_attrs.begin(); i != selector.m_attrs.end(); i++)\r
-       {\r
-               const tchar_t* attr_value = get_attr(i->attribute.c_str());\r
-               switch(i->condition)\r
-               {\r
-               case select_exists:\r
-                       if(!attr_value)\r
-                       {\r
-                               return select_no_match;\r
-                       }\r
-                       break;\r
-               case select_equal:\r
-                       if(!attr_value)\r
-                       {\r
-                               return select_no_match;\r
-                       } else \r
-                       {\r
-                               if(i->attribute == _t("class"))\r
-                               {\r
-                                       const string_vector & tokens1 = m_class_values;\r
-                                       const string_vector & tokens2 = i->class_val;\r
-                                       bool found = true;\r
-                                       for(string_vector::const_iterator str1 = tokens2.begin(); str1 != tokens2.end() && found; str1++)\r
-                                       {\r
-                                               bool f = false;\r
-                                               for(string_vector::const_iterator str2 = tokens1.begin(); str2 != tokens1.end() && !f; str2++)\r
-                                               {\r
-                                                       if( !t_strcasecmp(str1->c_str(), str2->c_str()) )\r
-                                                       {\r
-                                                               f = true;\r
-                                                       }\r
-                                               }\r
-                                               if(!f)\r
-                                               {\r
-                                                       found = false;\r
-                                               }\r
-                                       }\r
-                                       if(!found)\r
-                                       {\r
-                                               return select_no_match;\r
-                                       }\r
-                               } else\r
-                               {\r
-                                       if( t_strcasecmp(i->val.c_str(), attr_value) )\r
-                                       {\r
-                                               return select_no_match;\r
-                                       }\r
-                               }\r
-                       }\r
-                       break;\r
-               case select_contain_str:\r
-                       if(!attr_value)\r
-                       {\r
-                               return select_no_match;\r
-                       } else if(!t_strstr(attr_value, i->val.c_str()))\r
-                       {\r
-                               return select_no_match;\r
-                       }\r
-                       break;\r
-               case select_start_str:\r
-                       if(!attr_value)\r
-                       {\r
-                               return select_no_match;\r
-                       } else if(t_strncmp(attr_value, i->val.c_str(), i->val.length()))\r
-                       {\r
-                               return select_no_match;\r
-                       }\r
-                       break;\r
-               case select_end_str:\r
-                       if(!attr_value)\r
-                       {\r
-                               return select_no_match;\r
-                       } else if(t_strncmp(attr_value, i->val.c_str(), i->val.length()))\r
-                       {\r
-                               const tchar_t* s = attr_value + t_strlen(attr_value) - i->val.length() - 1;\r
-                               if(s < attr_value)\r
-                               {\r
-                                       return select_no_match;\r
-                               }\r
-                               if(i->val != s)\r
-                               {\r
-                                       return select_no_match;\r
-                               }\r
-                       }\r
-                       break;\r
-               case select_pseudo_element:\r
-                       if(i->val == _t("after"))\r
-                       {\r
-                               res |= select_match_with_after;\r
-                       } else if(i->val == _t("before"))\r
-                       {\r
-                               res |= select_match_with_before;\r
-                       } else\r
-                       {\r
-                               return select_no_match;\r
-                       }\r
-                       break;\r
-               case select_pseudo_class:\r
-                       if(apply_pseudo)\r
-                       {\r
-                               if (!el_parent) return select_no_match;\r
-\r
-                               tstring selector_param;\r
-                               tstring selector_name;\r
-\r
-                               tstring::size_type begin        = i->val.find_first_of(_t('('));\r
-                               tstring::size_type end          = (begin == tstring::npos) ? tstring::npos : find_close_bracket(i->val, begin);\r
-                               if(begin != tstring::npos && end != tstring::npos)\r
-                               {\r
-                                       selector_param = i->val.substr(begin + 1, end - begin - 1);\r
-                               }\r
-                               if(begin != tstring::npos)\r
-                               {\r
-                                       selector_name = i->val.substr(0, begin);\r
-                                       litehtml::trim(selector_name);\r
-                               } else\r
-                               {\r
-                                       selector_name = i->val;\r
-                               }\r
-\r
-                               int selector = value_index(selector_name.c_str(), pseudo_class_strings);\r
-                               \r
-                               switch(selector)\r
-                               {\r
-                               case pseudo_class_only_child:\r
-                                       if (!el_parent->is_only_child(shared_from_this(), false))\r
-                                       {\r
-                                               return select_no_match;\r
-                                       }\r
-                                       break;\r
-                               case pseudo_class_only_of_type:\r
-                                       if (!el_parent->is_only_child(shared_from_this(), true))\r
-                                       {\r
-                                               return select_no_match;\r
-                                       }\r
-                                       break;\r
-                               case pseudo_class_first_child:\r
-                                       if (!el_parent->is_nth_child(shared_from_this(), 0, 1, false))\r
-                                       {\r
-                                               return select_no_match;\r
-                                       }\r
-                                       break;\r
-                               case pseudo_class_first_of_type:\r
-                                       if (!el_parent->is_nth_child(shared_from_this(), 0, 1, true))\r
-                                       {\r
-                                               return select_no_match;\r
-                                       }\r
-                                       break;\r
-                               case pseudo_class_last_child:\r
-                                       if (!el_parent->is_nth_last_child(shared_from_this(), 0, 1, false))\r
-                                       {\r
-                                               return select_no_match;\r
-                                       }\r
-                                       break;\r
-                               case pseudo_class_last_of_type:\r
-                                       if (!el_parent->is_nth_last_child(shared_from_this(), 0, 1, true))\r
-                                       {\r
-                                               return select_no_match;\r
-                                       }\r
-                                       break;\r
-                               case pseudo_class_nth_child:\r
-                               case pseudo_class_nth_of_type:\r
-                               case pseudo_class_nth_last_child:\r
-                               case pseudo_class_nth_last_of_type:\r
-                                       {\r
-                                               if(selector_param.empty()) return select_no_match;\r
-\r
-                                               int num = 0;\r
-                                               int off = 0;\r
-\r
-                                               parse_nth_child_params(selector_param, num, off);\r
-                                               if(!num && !off) return select_no_match;\r
-                                               switch(selector)\r
-                                               {\r
-                                               case pseudo_class_nth_child:\r
-                                                       if (!el_parent->is_nth_child(shared_from_this(), num, off, false))\r
-                                                       {\r
-                                                               return select_no_match;\r
-                                                       }\r
-                                                       break;\r
-                                               case pseudo_class_nth_of_type:\r
-                                                       if (!el_parent->is_nth_child(shared_from_this(), num, off, true))\r
-                                                       {\r
-                                                               return select_no_match;\r
-                                                       }\r
-                                                       break;\r
-                                               case pseudo_class_nth_last_child:\r
-                                                       if (!el_parent->is_nth_last_child(shared_from_this(), num, off, false))\r
-                                                       {\r
-                                                               return select_no_match;\r
-                                                       }\r
-                                                       break;\r
-                                               case pseudo_class_nth_last_of_type:\r
-                                                       if (!el_parent->is_nth_last_child(shared_from_this(), num, off, true))\r
-                                                       {\r
-                                                               return select_no_match;\r
-                                                       }\r
-                                                       break;\r
-                                               }\r
-\r
-                                       }\r
-                                       break;\r
-                               case pseudo_class_not:\r
-                                       {\r
-                                               css_element_selector sel;\r
-                                               sel.parse(selector_param);\r
-                                               if(select(sel, apply_pseudo))\r
-                                               {\r
-                                                       return select_no_match;\r
-                                               }\r
-                                       }\r
-                                       break;\r
-                               case pseudo_class_lang:\r
-                                       {\r
-                                               trim( selector_param );\r
-\r
-                                               if( !get_document()->match_lang( selector_param ) )\r
-                                               {\r
-                                                       return select_no_match;\r
-                                               }\r
-                                       }\r
-                                       break;\r
-                               default:\r
-                                       if(std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), i->val) == m_pseudo_classes.end())\r
-                                       {\r
-                                               return select_no_match;\r
-                                       }\r
-                                       break;\r
-                               }\r
-                       } else\r
-                       {\r
-                               res |= select_match_pseudo_class;\r
-                       }\r
-                       break;\r
-               }\r
-       }\r
-       return res;\r
-}\r
-\r
-litehtml::element::ptr litehtml::html_tag::find_ancestor(const css_selector& selector, bool apply_pseudo, bool* is_pseudo)\r
-{\r
-       element::ptr el_parent = parent();\r
-       if (!el_parent)\r
-       {\r
-               return nullptr;\r
-       }\r
-       int res = el_parent->select(selector, apply_pseudo);\r
-       if(res != select_no_match)\r
-       {\r
-               if(is_pseudo)\r
-               {\r
-                       if(res & select_match_pseudo_class)\r
-                       {\r
-                               *is_pseudo = true;\r
-                       } else\r
-                       {\r
-                               *is_pseudo = false;\r
-                       }\r
-               }\r
-               return el_parent;\r
-       }\r
-       return el_parent->find_ancestor(selector, apply_pseudo, is_pseudo);\r
-}\r
-\r
-int litehtml::html_tag::get_floats_height(element_float el_float) const\r
-{\r
-       if(is_floats_holder())\r
-       {\r
-               int h = 0;\r
-\r
-               bool process = false;\r
-\r
-               for(const auto& fb : m_floats_left)\r
-               {\r
-                       process = false;\r
-                       switch(el_float)\r
-                       {\r
-                       case float_none:\r
-                               process = true;\r
-                               break;\r
-                       case float_left:\r
-                               if (fb.clear_floats == clear_left || fb.clear_floats == clear_both)\r
-                               {\r
-                                       process = true;\r
-                               }\r
-                               break;\r
-                       case float_right:\r
-                               if (fb.clear_floats == clear_right || fb.clear_floats == clear_both)\r
-                               {\r
-                                       process = true;\r
-                               }\r
-                               break;\r
-                       }\r
-                       if(process)\r
-                       {\r
-                               if(el_float == float_none)\r
-                               {\r
-                                       h = std::max(h, fb.pos.bottom());\r
-                               } else\r
-                               {\r
-                                       h = std::max(h, fb.pos.top());\r
-                               }\r
-                       }\r
-               }\r
-\r
-\r
-               for(const auto fb : m_floats_right)\r
-               {\r
-                       process = false;\r
-                       switch(el_float)\r
-                       {\r
-                       case float_none:\r
-                               process = true;\r
-                               break;\r
-                       case float_left:\r
-                               if (fb.clear_floats == clear_left || fb.clear_floats == clear_both)\r
-                               {\r
-                                       process = true;\r
-                               }\r
-                               break;\r
-                       case float_right:\r
-                               if (fb.clear_floats == clear_right || fb.clear_floats == clear_both)\r
-                               {\r
-                                       process = true;\r
-                               }\r
-                               break;\r
-                       }\r
-                       if(process)\r
-                       {\r
-                               if(el_float == float_none)\r
-                               {\r
-                                       h = std::max(h, fb.pos.bottom());\r
-                               } else\r
-                               {\r
-                                       h = std::max(h, fb.pos.top());\r
-                               }\r
-                       }\r
-               }\r
-\r
-               return h;\r
-       }\r
-       element::ptr el_parent = parent();\r
-       if (el_parent)\r
-       {\r
-               int h = el_parent->get_floats_height(el_float);\r
-               return h - m_pos.y;\r
-       }\r
-       return 0;\r
-}\r
-\r
-int litehtml::html_tag::get_left_floats_height() const\r
-{\r
-       if(is_floats_holder())\r
-       {\r
-               int h = 0;\r
-               if(!m_floats_left.empty())\r
-               {\r
-                       for (const auto& fb : m_floats_left)\r
-                       {\r
-                               h = std::max(h, fb.pos.bottom());\r
-                       }\r
-               }\r
-               return h;\r
-       }\r
-       element::ptr el_parent = parent();\r
-       if (el_parent)\r
-       {\r
-               int h = el_parent->get_left_floats_height();\r
-               return h - m_pos.y;\r
-       }\r
-       return 0;\r
-}\r
-\r
-int litehtml::html_tag::get_right_floats_height() const\r
-{\r
-       if(is_floats_holder())\r
-       {\r
-               int h = 0;\r
-               if(!m_floats_right.empty())\r
-               {\r
-                       for(const auto& fb : m_floats_right)\r
-                       {\r
-                               h = std::max(h, fb.pos.bottom());\r
-                       }\r
-               }\r
-               return h;\r
-       }\r
-       element::ptr el_parent = parent();\r
-       if (el_parent)\r
-       {\r
-               int h = el_parent->get_right_floats_height();\r
-               return h - m_pos.y;\r
-       }\r
-       return 0;\r
-}\r
-\r
-int litehtml::html_tag::get_line_left( int y )\r
-{\r
-       if(is_floats_holder())\r
-       {\r
-               if(m_cahe_line_left.is_valid && m_cahe_line_left.hash == y)\r
-               {\r
-                       return m_cahe_line_left.val;\r
-               }\r
-\r
-               int w = 0;\r
-               for(const auto& fb : m_floats_left)\r
-               {\r
-                       if (y >= fb.pos.top() && y < fb.pos.bottom())\r
-                       {\r
-                               w = std::max(w, fb.pos.right());\r
-                               if (w < fb.pos.right())\r
-                               {\r
-                                       break;\r
-                               }\r
-                       }\r
-               }\r
-               m_cahe_line_left.set_value(y, w);\r
-               return w;\r
-       }\r
-       element::ptr el_parent = parent();\r
-       if (el_parent)\r
-       {\r
-               int w = el_parent->get_line_left(y + m_pos.y);\r
-               if (w < 0)\r
-               {\r
-                       w = 0;\r
-               }\r
-               return w - (w ? m_pos.x : 0);\r
-       }\r
-       return 0;\r
-}\r
-\r
-int litehtml::html_tag::get_line_right( int y, int def_right )\r
-{\r
-       if(is_floats_holder())\r
-       {\r
-               if(m_cahe_line_right.is_valid && m_cahe_line_right.hash == y)\r
-               {\r
-                       if(m_cahe_line_right.is_default)\r
-                       {\r
-                               return def_right;\r
-                       } else\r
-                       {\r
-                               return std::min(m_cahe_line_right.val, def_right);\r
-                       }\r
-               }\r
-\r
-               int w = def_right;\r
-               m_cahe_line_right.is_default = true;\r
-               for(const auto& fb : m_floats_right)\r
-               {\r
-                       if(y >= fb.pos.top() && y < fb.pos.bottom())\r
-                       {\r
-                               w = std::min(w, fb.pos.left());\r
-                               m_cahe_line_right.is_default = false;\r
-                               if(w > fb.pos.left())\r
-                               {\r
-                                       break;\r
-                               }\r
-                       }\r
-               }\r
-               m_cahe_line_right.set_value(y, w);\r
-               return w;\r
-       }\r
-       element::ptr el_parent = parent();\r
-       if (el_parent)\r
-       {\r
-               int w = el_parent->get_line_right(y + m_pos.y, def_right + m_pos.x);\r
-               return w - m_pos.x;\r
-       }\r
-       return 0;\r
-}\r
-\r
-\r
-void litehtml::html_tag::get_line_left_right( int y, int def_right, int& ln_left, int& ln_right )\r
-{\r
-       if(is_floats_holder())\r
-       {\r
-               ln_left         = get_line_left(y);\r
-               ln_right        = get_line_right(y, def_right);\r
-       } else\r
-       {\r
-               element::ptr el_parent = parent();\r
-               if (el_parent)\r
-               {\r
-                       el_parent->get_line_left_right(y + m_pos.y, def_right + m_pos.x, ln_left, ln_right);\r
-               }\r
-               ln_right -= m_pos.x;\r
-               ln_left -= m_pos.x;\r
-\r
-               if(ln_left < 0)\r
-               {\r
-                       ln_left = 0;\r
-               }\r
-       }\r
-}\r
-\r
-int litehtml::html_tag::fix_line_width( int max_width, element_float flt )\r
-{\r
-       int ret_width = 0;\r
-       if(!m_boxes.empty())\r
-       {\r
-               elements_vector els;\r
-               m_boxes.back()->get_elements(els);\r
-               bool was_cleared = false;\r
-               if(!els.empty() && els.front()->get_clear() != clear_none)\r
-               {\r
-                       if(els.front()->get_clear() == clear_both)\r
-                       {\r
-                               was_cleared = true;\r
-                       } else\r
-                       {\r
-                               if(     (flt == float_left      && els.front()->get_clear() == clear_left) ||\r
-                                       (flt == float_right     && els.front()->get_clear() == clear_right) )\r
-                               {\r
-                                       was_cleared = true;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               if(!was_cleared)\r
-               {\r
-                       m_boxes.pop_back();\r
-\r
-                       for(elements_vector::iterator i = els.begin(); i != els.end(); i++)\r
-                       {\r
-                               int rw = place_element((*i), max_width);\r
-                               if(rw > ret_width)\r
-                               {\r
-                                       ret_width = rw;\r
-                               }\r
-                       }\r
-               } else\r
-               {\r
-                       int line_top = 0;\r
-                       if(m_boxes.back()->get_type() == box_line)\r
-                       {\r
-                               line_top = m_boxes.back()->top();\r
-                       } else\r
-                       {\r
-                               line_top = m_boxes.back()->bottom();\r
-                       }\r
-\r
-                       int line_left   = 0;\r
-                       int line_right  = max_width;\r
-                       get_line_left_right(line_top, max_width, line_left, line_right);\r
-\r
-                       if(m_boxes.back()->get_type() == box_line)\r
-                       {\r
-                               if(m_boxes.size() == 1 && m_list_style_type != list_style_type_none && m_list_style_position == list_style_position_inside)\r
-                               {\r
-                                       int sz_font = get_font_size();\r
-                                       line_left += sz_font;\r
-                               }\r
-\r
-                               if(m_css_text_indent.val() != 0)\r
-                               {\r
-                                       bool line_box_found = false;\r
-                                       for(box::vector::iterator iter = m_boxes.begin(); iter < m_boxes.end(); iter++)\r
-                                       {\r
-                                               if((*iter)->get_type() == box_line)\r
-                                               {\r
-                                                       line_box_found = true;\r
-                                                       break;\r
-                                               }\r
-                                       }\r
-                                       if(!line_box_found)\r
-                                       {\r
-                                               line_left += m_css_text_indent.calc_percent(max_width);\r
-                                       }\r
-                               }\r
-\r
-                       }\r
-\r
-                       elements_vector els;\r
-                       m_boxes.back()->new_width(line_left, line_right, els);\r
-                       for(auto& el : els)\r
-                       {\r
-                               int rw = place_element(el, max_width);\r
-                               if(rw > ret_width)\r
-                               {\r
-                                       ret_width = rw;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       return ret_width;\r
-}\r
-\r
-void litehtml::html_tag::add_float(const element::ptr &el, int x, int y)\r
-{\r
-       if(is_floats_holder())\r
-       {\r
-               floated_box fb;\r
-               fb.pos.x                = el->left() + x;\r
-               fb.pos.y                = el->top()  + y;\r
-               fb.pos.width    = el->width();\r
-               fb.pos.height   = el->height();\r
-               fb.float_side   = el->get_float();\r
-               fb.clear_floats = el->get_clear();\r
-               fb.el                   = el;\r
-\r
-               if(fb.float_side == float_left)\r
-               {\r
-                       if(m_floats_left.empty())\r
-                       {\r
-                               m_floats_left.push_back(fb);\r
-                       } else\r
-                       {\r
-                               bool inserted = false;\r
-                               for(floated_box::vector::iterator i = m_floats_left.begin(); i != m_floats_left.end(); i++)\r
-                               {\r
-                                       if(fb.pos.right() > i->pos.right())\r
-                                       {\r
-                                               m_floats_left.insert(i, std::move(fb));\r
-                                               inserted = true;\r
-                                               break;\r
-                                       }\r
-                               }\r
-                               if(!inserted)\r
-                               {\r
-                                       m_floats_left.push_back(std::move(fb));\r
-                               }\r
-                       }\r
-                       m_cahe_line_left.invalidate();\r
-               } else if(fb.float_side == float_right)\r
-               {\r
-                       if(m_floats_right.empty())\r
-                       {\r
-                               m_floats_right.push_back(std::move(fb));\r
-                       } else\r
-                       {\r
-                               bool inserted = false;\r
-                               for(floated_box::vector::iterator i = m_floats_right.begin(); i != m_floats_right.end(); i++)\r
-                               {\r
-                                       if(fb.pos.left() < i->pos.left())\r
-                                       {\r
-                                               m_floats_right.insert(i, std::move(fb));\r
-                                               inserted = true;\r
-                                               break;\r
-                                       }\r
-                               }\r
-                               if(!inserted)\r
-                               {\r
-                                       m_floats_right.push_back(fb);\r
-                               }\r
-                       }\r
-                       m_cahe_line_right.invalidate();\r
-               }\r
-       } else\r
-       {\r
-               element::ptr el_parent = parent();\r
-               if (el_parent)\r
-               {\r
-                       el_parent->add_float(el, x + m_pos.x, y + m_pos.y);\r
-               }\r
-       }\r
-}\r
-\r
-int litehtml::html_tag::find_next_line_top( int top, int width, int def_right )\r
-{\r
-       if(is_floats_holder())\r
-       {\r
-               int new_top = top;\r
-               int_vector points;\r
-\r
-               for(const auto& fb : m_floats_left)\r
-               {\r
-                       if(fb.pos.top() >= top)\r
-                       {\r
-                               if(find(points.begin(), points.end(), fb.pos.top()) == points.end())\r
-                               {\r
-                                       points.push_back(fb.pos.top());\r
-                               }\r
-                       }\r
-                       if (fb.pos.bottom() >= top)\r
-                       {\r
-                               if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end())\r
-                               {\r
-                                       points.push_back(fb.pos.bottom());\r
-                               }\r
-                       }\r
-               }\r
-\r
-               for (const auto& fb : m_floats_right)\r
-               {\r
-                       if (fb.pos.top() >= top)\r
-                       {\r
-                               if (find(points.begin(), points.end(), fb.pos.top()) == points.end())\r
-                               {\r
-                                       points.push_back(fb.pos.top());\r
-                               }\r
-                       }\r
-                       if (fb.pos.bottom() >= top)\r
-                       {\r
-                               if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end())\r
-                               {\r
-                                       points.push_back(fb.pos.bottom());\r
-                               }\r
-                       }\r
-               }\r
-\r
-               if(!points.empty())\r
-               {\r
-                       sort(points.begin(), points.end(), std::less<int>( ));\r
-                       new_top = points.back();\r
-\r
-                       for(auto pt : points)\r
-                       {\r
-                               int pos_left    = 0;\r
-                               int pos_right   = def_right;\r
-                               get_line_left_right(pt, def_right, pos_left, pos_right);\r
-\r
-                               if(pos_right - pos_left >= width)\r
-                               {\r
-                                       new_top = pt;\r
-                                       break;\r
-                               }\r
-                       }\r
-               }\r
-               return new_top;\r
-       }\r
-       element::ptr el_parent = parent();\r
-       if (el_parent)\r
-       {\r
-               int new_top = el_parent->find_next_line_top(top + m_pos.y, width, def_right + m_pos.x);\r
-               return new_top - m_pos.y;\r
-       }\r
-       return 0;\r
-}\r
-\r
-void litehtml::html_tag::parse_background()\r
-{\r
-       // parse background-color\r
-       m_bg.m_color            = get_color(_t("background-color"), false, web_color(0, 0, 0, 0));\r
-\r
-       // parse background-position\r
-       const tchar_t* str = get_style_property(_t("background-position"), false, _t("0% 0%"));\r
-       if(str)\r
-       {\r
-               string_vector res;\r
-               split_string(str, res, _t(" \t"));\r
-               if(res.size() > 0)\r
-               {\r
-                       if(res.size() == 1)\r
-                       {\r
-                               if( value_in_list(res[0].c_str(), _t("left;right;center")) )\r
-                               {\r
-                                       m_bg.m_position.x.fromString(res[0], _t("left;right;center"));\r
-                                       m_bg.m_position.y.set_value(50, css_units_percentage);\r
-                               } else if( value_in_list(res[0].c_str(), _t("top;bottom;center")) )\r
-                               {\r
-                                       m_bg.m_position.y.fromString(res[0], _t("top;bottom;center"));\r
-                                       m_bg.m_position.x.set_value(50, css_units_percentage);\r
-                               } else\r
-                               {\r
-                                       m_bg.m_position.x.fromString(res[0], _t("left;right;center"));\r
-                                       m_bg.m_position.y.set_value(50, css_units_percentage);\r
-                               }\r
-                       } else\r
-                       {\r
-                               if(value_in_list(res[0].c_str(), _t("left;right")))\r
-                               {\r
-                                       m_bg.m_position.x.fromString(res[0], _t("left;right;center"));\r
-                                       m_bg.m_position.y.fromString(res[1], _t("top;bottom;center"));\r
-                               } else if(value_in_list(res[0].c_str(), _t("top;bottom")))\r
-                               {\r
-                                       m_bg.m_position.x.fromString(res[1], _t("left;right;center"));\r
-                                       m_bg.m_position.y.fromString(res[0], _t("top;bottom;center"));\r
-                               } else if(value_in_list(res[1].c_str(), _t("left;right")))\r
-                               {\r
-                                       m_bg.m_position.x.fromString(res[1], _t("left;right;center"));\r
-                                       m_bg.m_position.y.fromString(res[0], _t("top;bottom;center"));\r
-                               }else if(value_in_list(res[1].c_str(), _t("top;bottom")))\r
-                               {\r
-                                       m_bg.m_position.x.fromString(res[0], _t("left;right;center"));\r
-                                       m_bg.m_position.y.fromString(res[1], _t("top;bottom;center"));\r
-                               } else\r
-                               {\r
-                                       m_bg.m_position.x.fromString(res[0], _t("left;right;center"));\r
-                                       m_bg.m_position.y.fromString(res[1], _t("top;bottom;center"));\r
-                               }\r
-                       }\r
-\r
-                       if(m_bg.m_position.x.is_predefined())\r
-                       {\r
-                               switch(m_bg.m_position.x.predef())\r
-                               {\r
-                               case 0:\r
-                                       m_bg.m_position.x.set_value(0, css_units_percentage);\r
-                                       break;\r
-                               case 1:\r
-                                       m_bg.m_position.x.set_value(100, css_units_percentage);\r
-                                       break;\r
-                               case 2:\r
-                                       m_bg.m_position.x.set_value(50, css_units_percentage);\r
-                                       break;\r
-                               }\r
-                       }\r
-                       if(m_bg.m_position.y.is_predefined())\r
-                       {\r
-                               switch(m_bg.m_position.y.predef())\r
-                               {\r
-                               case 0:\r
-                                       m_bg.m_position.y.set_value(0, css_units_percentage);\r
-                                       break;\r
-                               case 1:\r
-                                       m_bg.m_position.y.set_value(100, css_units_percentage);\r
-                                       break;\r
-                               case 2:\r
-                                       m_bg.m_position.y.set_value(50, css_units_percentage);\r
-                                       break;\r
-                               }\r
-                       }\r
-               } else\r
-               {\r
-                       m_bg.m_position.x.set_value(0, css_units_percentage);\r
-                       m_bg.m_position.y.set_value(0, css_units_percentage);\r
-               }\r
-       } else\r
-       {\r
-               m_bg.m_position.y.set_value(0, css_units_percentage);\r
-               m_bg.m_position.x.set_value(0, css_units_percentage);\r
-       }\r
-\r
-       str = get_style_property(_t("background-size"), false, _t("auto"));\r
-       if(str)\r
-       {\r
-               string_vector res;\r
-               split_string(str, res, _t(" \t"));\r
-               if(!res.empty())\r
-               {\r
-                       m_bg.m_position.width.fromString(res[0], background_size_strings);\r
-                       if(res.size() > 1)\r
-                       {\r
-                               m_bg.m_position.height.fromString(res[1], background_size_strings);\r
-                       } else\r
-                       {\r
-                               m_bg.m_position.height.predef(background_size_auto);\r
-                       }\r
-               } else\r
-               {\r
-                       m_bg.m_position.width.predef(background_size_auto);\r
-                       m_bg.m_position.height.predef(background_size_auto);\r
-               }\r
-       }\r
-\r
-       document::ptr doc = get_document();\r
-\r
-       doc->cvt_units(m_bg.m_position.x,               m_font_size);\r
-       doc->cvt_units(m_bg.m_position.y,               m_font_size);\r
-       doc->cvt_units(m_bg.m_position.width,   m_font_size);\r
-       doc->cvt_units(m_bg.m_position.height,  m_font_size);\r
-\r
-       // parse background_attachment\r
-       m_bg.m_attachment = (background_attachment) value_index(\r
-               get_style_property(_t("background-attachment"), false, _t("scroll")), \r
-               background_attachment_strings, \r
-               background_attachment_scroll);\r
-\r
-       // parse background_attachment\r
-       m_bg.m_repeat = (background_repeat) value_index(\r
-               get_style_property(_t("background-repeat"), false, _t("repeat")), \r
-               background_repeat_strings, \r
-               background_repeat_repeat);\r
-\r
-       // parse background_clip\r
-       m_bg.m_clip = (background_box) value_index(\r
-               get_style_property(_t("background-clip"), false, _t("border-box")), \r
-               background_box_strings, \r
-               background_box_border);\r
-\r
-       // parse background_origin\r
-       m_bg.m_origin = (background_box) value_index(\r
-               get_style_property(_t("background-origin"), false, _t("padding-box")), \r
-               background_box_strings, \r
-               background_box_content);\r
-\r
-       // parse background-image\r
-       css::parse_css_url(get_style_property(_t("background-image"), false, _t("")), m_bg.m_image);\r
-       m_bg.m_baseurl = get_style_property(_t("background-image-baseurl"), false, _t(""));\r
-\r
-       if(!m_bg.m_image.empty())\r
-       {\r
-               doc->container()->load_image(m_bg.m_image.c_str(), m_bg.m_baseurl.empty() ? 0 : m_bg.m_baseurl.c_str(), true);\r
-       }\r
-}\r
-\r
-void litehtml::html_tag::add_positioned(const element::ptr &el)\r
-{\r
-       if (m_el_position != element_position_static || (!have_parent()))\r
-       {\r
-               m_positioned.push_back(el);\r
-       } else\r
-       {\r
-               element::ptr el_parent = parent();\r
-               if (el_parent)\r
-               {\r
-                       el_parent->add_positioned(el);\r
-               }\r
-       }\r
-}\r
-\r
-void litehtml::html_tag::calc_outlines( int parent_width )\r
-{\r
-       m_padding.left  = m_css_padding.left.calc_percent(parent_width);\r
-       m_padding.right = m_css_padding.right.calc_percent(parent_width);\r
-\r
-       m_borders.left  = m_css_borders.left.width.calc_percent(parent_width);\r
-       m_borders.right = m_css_borders.right.width.calc_percent(parent_width);\r
-\r
-       m_margins.left  = m_css_margins.left.calc_percent(parent_width);\r
-       m_margins.right = m_css_margins.right.calc_percent(parent_width);\r
-\r
-       m_margins.top           = m_css_margins.top.calc_percent(parent_width);\r
-       m_margins.bottom        = m_css_margins.bottom.calc_percent(parent_width);\r
-\r
-       m_padding.top           = m_css_padding.top.calc_percent(parent_width);\r
-       m_padding.bottom        = m_css_padding.bottom.calc_percent(parent_width);\r
-}\r
-\r
-void litehtml::html_tag::calc_auto_margins(int parent_width)\r
-{\r
-       if (get_element_position() != element_position_absolute && (m_display == display_block || m_display == display_table))\r
-       {\r
-               if (m_css_margins.left.is_predefined() && m_css_margins.right.is_predefined())\r
-               {\r
-                       int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right;\r
-                       if (el_width <= parent_width)\r
-                       {\r
-                               m_margins.left = (parent_width - el_width) / 2;\r
-                               m_margins.right = (parent_width - el_width) - m_margins.left;\r
-                       }\r
-                       else\r
-                       {\r
-                               m_margins.left = 0;\r
-                               m_margins.right = 0;\r
-                       }\r
-               }\r
-               else if (m_css_margins.left.is_predefined() && !m_css_margins.right.is_predefined())\r
-               {\r
-                       int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right + m_margins.right;\r
-                       m_margins.left = parent_width - el_width;\r
-                       if (m_margins.left < 0) m_margins.left = 0;\r
-               }\r
-               else if (!m_css_margins.left.is_predefined() && m_css_margins.right.is_predefined())\r
-               {\r
-                       int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right + m_margins.left;\r
-                       m_margins.right = parent_width - el_width;\r
-                       if (m_margins.right < 0) m_margins.right = 0;\r
-               }\r
-       }\r
-}\r
-\r
-void litehtml::html_tag::parse_attributes()\r
-{\r
-       for(auto& el : m_children)\r
-       {\r
-               el->parse_attributes();\r
-       }\r
-}\r
-\r
-void litehtml::html_tag::get_text( tstring& text )\r
-{\r
-       for (auto& el : m_children)\r
-       {\r
-               el->get_text(text);\r
-       }\r
-}\r
-\r
-bool litehtml::html_tag::is_body()  const\r
-{\r
-       return false;\r
-}\r
-\r
-void litehtml::html_tag::set_data( const tchar_t* data )\r
-{\r
-\r
-}\r
-\r
-void litehtml::html_tag::get_inline_boxes( position::vector& boxes )\r
-{\r
-       litehtml::box* old_box = 0;\r
-       position pos;\r
-       for(auto& el : m_children)\r
-       {\r
-               if(!el->skip())\r
-               {\r
-                       if(el->m_box)\r
-                       {\r
-                               if(el->m_box != old_box)\r
-                               {\r
-                                       if(old_box)\r
-                                       {\r
-                                               if(boxes.empty())\r
-                                               {\r
-                                                       pos.x           -= m_padding.left + m_borders.left;\r
-                                                       pos.width       += m_padding.left + m_borders.left;\r
-                                               }\r
-                                               boxes.push_back(pos);\r
-                                       }\r
-                                       old_box         = el->m_box;\r
-                                       pos.x           = el->left() + el->margin_left();\r
-                                       pos.y           = el->top() - m_padding.top - m_borders.top;\r
-                                       pos.width       = 0;\r
-                                       pos.height      = 0;\r
-                               }\r
-                               pos.width       = el->right() - pos.x - el->margin_right() - el->margin_left();\r
-                               pos.height      = std::max(pos.height, el->height() + m_padding.top + m_padding.bottom + m_borders.top + m_borders.bottom);\r
-                       } else if(el->get_display() == display_inline)\r
-                       {\r
-                               position::vector sub_boxes;\r
-                               el->get_inline_boxes(sub_boxes);\r
-                               if(!sub_boxes.empty())\r
-                               {\r
-                                       sub_boxes.rbegin()->width += el->margin_right();\r
-                                       if(boxes.empty())\r
-                                       {\r
-                                               if(m_padding.left + m_borders.left > 0)\r
-                                               {\r
-                                                       position padding_box = (*sub_boxes.begin());\r
-                                                       padding_box.x           -= m_padding.left + m_borders.left + el->margin_left();\r
-                                                       padding_box.width       = m_padding.left + m_borders.left + el->margin_left();\r
-                                                       boxes.push_back(padding_box);\r
-                                               }\r
-                                       }\r
-\r
-                                       sub_boxes.rbegin()->width += el->margin_right();\r
-\r
-                                       boxes.insert(boxes.end(), sub_boxes.begin(), sub_boxes.end());\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       if(pos.width || pos.height)\r
-       {\r
-               if(boxes.empty())\r
-               {\r
-                       pos.x           -= m_padding.left + m_borders.left;\r
-                       pos.width       += m_padding.left + m_borders.left;\r
-               }\r
-               boxes.push_back(pos);\r
-       }\r
-       if(!boxes.empty())\r
-       {\r
-               if(m_padding.right + m_borders.right > 0)\r
-               {\r
-                       boxes.back().width += m_padding.right + m_borders.right;\r
-               }\r
-       }\r
-}\r
-\r
-bool litehtml::html_tag::on_mouse_over()\r
-{\r
-       bool ret = false;\r
-\r
-       element::ptr el = shared_from_this();\r
-       while(el)\r
-       {\r
-               if(el->set_pseudo_class(_t("hover"), true))\r
-               {\r
-                       ret = true;\r
-               }\r
-               el = el->parent();\r
-       }\r
-\r
-       return ret;\r
-}\r
-\r
-bool litehtml::html_tag::find_styles_changes( position::vector& redraw_boxes, int x, int y )\r
-{\r
-       if(m_display == display_inline_text)\r
-       {\r
-               return false;\r
-       }\r
-\r
-       bool ret = false;\r
-       bool apply = false;\r
-       for (used_selector::vector::iterator iter = m_used_styles.begin(); iter != m_used_styles.end() && !apply; iter++)\r
-       {\r
-               if((*iter)->m_selector->is_media_valid())\r
-               {\r
-                       int res = select(*((*iter)->m_selector), true);\r
-                       if( (res == select_no_match && (*iter)->m_used) || (res == select_match && !(*iter)->m_used) )\r
-                       {\r
-                               apply = true;\r
-                       }\r
-               }\r
-       }\r
-\r
-       if(apply)\r
-       {\r
-               if(m_display == display_inline ||  m_display == display_table_row)\r
-               {\r
-                       position::vector boxes;\r
-                       get_inline_boxes(boxes);\r
-                       for(position::vector::iterator pos = boxes.begin(); pos != boxes.end(); pos++)\r
-                       {\r
-                               pos->x  += x;\r
-                               pos->y  += y;\r
-                               redraw_boxes.push_back(*pos);\r
-                       }\r
-               } else\r
-               {\r
-                       position pos = m_pos;\r
-                       if(m_el_position != element_position_fixed)\r
-                       {\r
-                               pos.x += x;\r
-                               pos.y += y;\r
-                       }\r
-                       pos += m_padding;\r
-                       pos += m_borders;\r
-                       redraw_boxes.push_back(pos);\r
-               }\r
-\r
-               ret = true;\r
-               refresh_styles();\r
-               parse_styles();\r
-       }\r
-       for (auto& el : m_children)\r
-       {\r
-               if(!el->skip())\r
-               {\r
-                       if(m_el_position != element_position_fixed)\r
-                       {\r
-                               if(el->find_styles_changes(redraw_boxes, x + m_pos.x, y + m_pos.y))\r
-                               {\r
-                                       ret = true;\r
-                               }\r
-                       } else\r
-                       {\r
-                               if(el->find_styles_changes(redraw_boxes, m_pos.x, m_pos.y))\r
-                               {\r
-                                       ret = true;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       return ret;\r
-}\r
-\r
-bool litehtml::html_tag::on_mouse_leave()\r
-{\r
-       bool ret = false;\r
-\r
-       element::ptr el = shared_from_this();\r
-       while(el)\r
-       {\r
-               if(el->set_pseudo_class(_t("hover"), false))\r
-               {\r
-                       ret = true;\r
-               }\r
-               if(el->set_pseudo_class(_t("active"), false))\r
-               {\r
-                       ret = true;\r
-               }\r
-               el = el->parent();\r
-       }\r
-\r
-       return ret;\r
-}\r
-\r
-bool litehtml::html_tag::on_lbutton_down()\r
-{\r
-    bool ret = false;\r
-\r
-       element::ptr el = shared_from_this();\r
-    while (el)\r
-    {\r
-        if (el->set_pseudo_class(_t("active"), true))\r
-        {\r
-            ret = true;\r
-        }\r
-        el = el->parent();\r
-    }\r
-\r
-    return ret;\r
-}\r
-\r
-bool litehtml::html_tag::on_lbutton_up()\r
-{\r
-       bool ret = false;\r
-\r
-       element::ptr el = shared_from_this();\r
-    while (el)\r
-    {\r
-        if (el->set_pseudo_class(_t("active"), false))\r
-        {\r
-            ret = true;\r
-        }\r
-        el = el->parent();\r
-    }\r
-\r
-    on_click();\r
-\r
-       return ret;\r
-}\r
-\r
-void litehtml::html_tag::on_click()\r
-{\r
-       if (have_parent())\r
-       {\r
-               element::ptr el_parent = parent();\r
-               if (el_parent)\r
-               {\r
-                       el_parent->on_click();\r
-               }\r
-       }\r
-}\r
-\r
-const litehtml::tchar_t* litehtml::html_tag::get_cursor()\r
-{\r
-       return get_style_property(_t("cursor"), true, 0);\r
-}\r
-\r
-static const int font_size_table[8][7] =\r
-{\r
-       { 9,    9,     9,     9,    11,    14,    18},\r
-       { 9,    9,     9,    10,    12,    15,    20},\r
-       { 9,    9,     9,    11,    13,    17,    22},\r
-       { 9,    9,    10,    12,    14,    18,    24},\r
-       { 9,    9,    10,    13,    16,    20,    26},\r
-       { 9,    9,    11,    14,    17,    21,    28},\r
-       { 9,   10,    12,    15,    17,    23,    30},\r
-       { 9,   10,    13,    16,    18,    24,    32}\r
-};\r
-\r
-\r
-void litehtml::html_tag::init_font()\r
-{\r
-       // initialize font size\r
-       const tchar_t* str = get_style_property(_t("font-size"), false, 0);\r
-\r
-       int parent_sz = 0;\r
-       int doc_font_size = get_document()->container()->get_default_font_size();\r
-       element::ptr el_parent = parent();\r
-       if (el_parent)\r
-       {\r
-               parent_sz = el_parent->get_font_size();\r
-       } else\r
-       {\r
-               parent_sz = doc_font_size;\r
-       }\r
-\r
-\r
-       if(!str)\r
-       {\r
-               m_font_size = parent_sz;\r
-       } else\r
-       {\r
-               m_font_size = parent_sz;\r
-\r
-               css_length sz;\r
-               sz.fromString(str, font_size_strings);\r
-               if(sz.is_predefined())\r
-               {\r
-                       int idx_in_table = doc_font_size - 9;\r
-                       if(idx_in_table >= 0 && idx_in_table <= 7)\r
-                       {\r
-                               if(sz.predef() >= fontSize_xx_small && sz.predef() <= fontSize_xx_large)\r
-                               {\r
-                                       m_font_size = font_size_table[idx_in_table][sz.predef()];\r
-                               } else\r
-                               {\r
-                                       m_font_size = doc_font_size;\r
-                               }\r
-                       } else                  \r
-                       {\r
-                               switch(sz.predef())\r
-                               {\r
-                               case fontSize_xx_small:\r
-                                       m_font_size = doc_font_size * 3 / 5;\r
-                                       break;\r
-                               case fontSize_x_small:\r
-                                       m_font_size = doc_font_size * 3 / 4;\r
-                                       break;\r
-                               case fontSize_small:\r
-                                       m_font_size = doc_font_size * 8 / 9;\r
-                                       break;\r
-                               case fontSize_large:\r
-                                       m_font_size = doc_font_size * 6 / 5;\r
-                                       break;\r
-                               case fontSize_x_large:\r
-                                       m_font_size = doc_font_size * 3 / 2;\r
-                                       break;\r
-                               case fontSize_xx_large:\r
-                                       m_font_size = doc_font_size * 2;\r
-                                       break;\r
-                               default:\r
-                                       m_font_size = doc_font_size;\r
-                                       break;\r
-                               }\r
-                       }\r
-               } else\r
-               {\r
-                       if(sz.units() == css_units_percentage)\r
-                       {\r
-                               m_font_size = sz.calc_percent(parent_sz);\r
-                       } else if(sz.units() == css_units_none)\r
-                       {\r
-                               m_font_size = parent_sz;\r
-                       } else\r
-                       {\r
-                               m_font_size = get_document()->cvt_units(sz, parent_sz);\r
-                       }\r
-               }\r
-       }\r
-\r
-       // initialize font\r
-       const tchar_t* name                     = get_style_property(_t("font-family"),         true,   _t("inherit"));\r
-       const tchar_t* weight           = get_style_property(_t("font-weight"),         true,   _t("normal"));\r
-       const tchar_t* style            = get_style_property(_t("font-style"),          true,   _t("normal"));\r
-       const tchar_t* decoration       = get_style_property(_t("text-decoration"),     true,   _t("none"));\r
-\r
-       m_font = get_document()->get_font(name, m_font_size, weight, style, decoration, &m_font_metrics);\r
-}\r
-\r
-bool litehtml::html_tag::is_break() const\r
-{\r
-       return false;\r
-}\r
-\r
-void litehtml::html_tag::set_tagName( const tchar_t* tag )\r
-{\r
-       tstring s_val = tag;\r
-       std::locale lc = std::locale::global(std::locale::classic());\r
-       for(size_t i = 0; i < s_val.length(); i++)\r
-       {\r
-               s_val[i] = std::tolower(s_val[i], lc);\r
-       }\r
-       m_tag = s_val;\r
-}\r
-\r
-void litehtml::html_tag::draw_background( uint_ptr hdc, int x, int y, const position* clip )\r
-{\r
-       position pos = m_pos;\r
-       pos.x   += x;\r
-       pos.y   += y;\r
-\r
-       position el_pos = pos;\r
-       el_pos += m_padding;\r
-       el_pos += m_borders;\r
-\r
-       if(m_display != display_inline && m_display != display_table_row)\r
-       {\r
-               if(el_pos.does_intersect(clip))\r
-               {\r
-                       const background* bg = get_background();\r
-                       if(bg)\r
-                       {\r
-                               background_paint bg_paint;\r
-                               init_background_paint(pos, bg_paint, bg);\r
-\r
-                               get_document()->container()->draw_background(hdc, bg_paint);\r
-                       }\r
-                       position border_box = pos;\r
-                       border_box += m_padding;\r
-                       border_box += m_borders;\r
-\r
-                       borders bdr = m_css_borders;\r
-                       bdr.radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);\r
-\r
-                       get_document()->container()->draw_borders(hdc, bdr, border_box, have_parent() ? false : true);\r
-               }\r
-       } else\r
-       {\r
-               const background* bg = get_background();\r
-\r
-               position::vector boxes;\r
-               get_inline_boxes(boxes);\r
-\r
-               background_paint bg_paint;\r
-               position content_box;\r
-\r
-               for(position::vector::iterator box = boxes.begin(); box != boxes.end(); box++)\r
-               {\r
-                       box->x  += x;\r
-                       box->y  += y;\r
-\r
-                       if(box->does_intersect(clip))\r
-                       {\r
-                               content_box = *box;\r
-                               content_box -= m_borders;\r
-                               content_box -= m_padding;\r
-\r
-                               if(bg)\r
-                               {\r
-                                       init_background_paint(content_box, bg_paint, bg);\r
-                               }\r
-\r
-                               css_borders bdr;\r
-\r
-                               // set left borders radius for the first box\r
-                               if(box == boxes.begin())\r
-                               {\r
-                                       bdr.radius.bottom_left_x        = m_css_borders.radius.bottom_left_x;\r
-                                       bdr.radius.bottom_left_y        = m_css_borders.radius.bottom_left_y;\r
-                                       bdr.radius.top_left_x           = m_css_borders.radius.top_left_x;\r
-                                       bdr.radius.top_left_y           = m_css_borders.radius.top_left_y;\r
-                               }\r
-\r
-                               // set right borders radius for the last box\r
-                               if(box == boxes.end() - 1)\r
-                               {\r
-                                       bdr.radius.bottom_right_x       = m_css_borders.radius.bottom_right_x;\r
-                                       bdr.radius.bottom_right_y       = m_css_borders.radius.bottom_right_y;\r
-                                       bdr.radius.top_right_x          = m_css_borders.radius.top_right_x;\r
-                                       bdr.radius.top_right_y          = m_css_borders.radius.top_right_y;\r
-                               }\r
-\r
-                               \r
-                               bdr.top         = m_css_borders.top;\r
-                               bdr.bottom      = m_css_borders.bottom;\r
-                               if(box == boxes.begin())\r
-                               {\r
-                                       bdr.left        = m_css_borders.left;\r
-                               }\r
-                               if(box == boxes.end() - 1)\r
-                               {\r
-                                       bdr.right       = m_css_borders.right;\r
-                               }\r
-\r
-\r
-                               if(bg)\r
-                               {\r
-                                       bg_paint.border_radius = bdr.radius.calc_percents(bg_paint.border_box.width, bg_paint.border_box.width);\r
-                                       get_document()->container()->draw_background(hdc, bg_paint);\r
-                               }\r
-                               borders b = bdr;\r
-                               b.radius = bdr.radius.calc_percents(box->width, box->height);\r
-                               get_document()->container()->draw_borders(hdc, b, *box, false);\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-int litehtml::html_tag::render_inline(const element::ptr &container, int max_width)\r
-{\r
-       int ret_width = 0;\r
-       int rw = 0;\r
-\r
-       white_space ws = get_white_space();\r
-       bool skip_spaces = false;\r
-       if (ws == white_space_normal ||\r
-               ws == white_space_nowrap ||\r
-               ws == white_space_pre_line)\r
-       {\r
-               skip_spaces = true;\r
-       }\r
-       bool was_space = false;\r
-\r
-       for (auto& el : m_children)\r
-       {\r
-               // skip spaces to make rendering a bit faster\r
-               if (skip_spaces)\r
-               {\r
-                       if (el->is_white_space())\r
-                       {\r
-                               if (was_space)\r
-                               {\r
-                                       el->skip(true);\r
-                                       continue;\r
-                               }\r
-                               else\r
-                               {\r
-                                       was_space = true;\r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               was_space = false;\r
-                       }\r
-               }\r
-\r
-               rw = container->place_element( el, max_width );\r
-               if(rw > ret_width)\r
-               {\r
-                       ret_width = rw;\r
-               }\r
-       }\r
-       return ret_width;\r
-}\r
-\r
-int litehtml::html_tag::place_element(const element::ptr &el, int max_width)\r
-{\r
-       if(el->get_display() == display_none) return 0;\r
-\r
-       if(el->get_display() == display_inline)\r
-       {\r
-               return el->render_inline(shared_from_this(), max_width);\r
-       }\r
-\r
-       element_position el_position = el->get_element_position();\r
-\r
-       if(el_position == element_position_absolute || el_position == element_position_fixed)\r
-       {\r
-               int line_top = 0;\r
-               if(!m_boxes.empty())\r
-               {\r
-                       if(m_boxes.back()->get_type() == box_line)\r
-                       {\r
-                               line_top = m_boxes.back()->top();\r
-                               if(!m_boxes.back()->is_empty())\r
-                               {\r
-                                       line_top += line_height();\r
-                               }\r
-                       } else\r
-                       {\r
-                               line_top = m_boxes.back()->bottom();\r
-                       }\r
-               }\r
-\r
-               el->render(0, line_top, max_width);\r
-               el->m_pos.x     += el->content_margins_left();\r
-               el->m_pos.y     += el->content_margins_top();\r
-\r
-               return 0;\r
-       }\r
-\r
-       int ret_width = 0;\r
-\r
-       switch(el->get_float())\r
-       {\r
-       case float_left:\r
-               {\r
-                       int line_top = 0;\r
-                       if(!m_boxes.empty())\r
-                       {\r
-                               if(m_boxes.back()->get_type() == box_line)\r
-                               {\r
-                                       line_top = m_boxes.back()->top();\r
-                               } else\r
-                               {\r
-                                       line_top = m_boxes.back()->bottom();\r
-                               }\r
-                       }\r
-                       line_top                = get_cleared_top(el, line_top);\r
-                       int line_left   = 0;\r
-                       int line_right  = max_width;\r
-                       get_line_left_right(line_top, max_width, line_left, line_right);\r
-\r
-                       el->render(line_left, line_top, line_right);\r
-                       if(el->right() > line_right)\r
-                       {\r
-                               int new_top = find_next_line_top(el->top(), el->width(), max_width);\r
-                               el->m_pos.x = get_line_left(new_top) + el->content_margins_left();\r
-                               el->m_pos.y = new_top + el->content_margins_top();\r
-                       }\r
-                       add_float(el, 0, 0);\r
-                       ret_width = fix_line_width(max_width, float_left);\r
-                       if(!ret_width)\r
-                       {\r
-                               ret_width = el->right();\r
-                       }\r
-               }\r
-               break;\r
-       case float_right:\r
-               {\r
-                       int line_top = 0;\r
-                       if(!m_boxes.empty())\r
-                       {\r
-                               if(m_boxes.back()->get_type() == box_line)\r
-                               {\r
-                                       line_top = m_boxes.back()->top();\r
-                               } else\r
-                               {\r
-                                       line_top = m_boxes.back()->bottom();\r
-                               }\r
-                       }\r
-                       line_top                = get_cleared_top(el, line_top);\r
-                       int line_left   = 0;\r
-                       int line_right  = max_width;\r
-                       get_line_left_right(line_top, max_width, line_left, line_right);\r
-\r
-                       el->render(0, line_top, line_right);\r
-\r
-                       if(line_left + el->width() > line_right)\r
-                       {\r
-                               int new_top = find_next_line_top(el->top(), el->width(), max_width);\r
-                               el->m_pos.x = get_line_right(new_top, max_width) - el->width() + el->content_margins_left();\r
-                               el->m_pos.y = new_top + el->content_margins_top();\r
-                       } else\r
-                       {\r
-                               el->m_pos.x = line_right - el->width() + el->content_margins_left();\r
-                       }\r
-                       add_float(el, 0, 0);\r
-                       ret_width = fix_line_width(max_width, float_right);\r
-\r
-                       if(!ret_width)\r
-                       {\r
-                               line_left       = 0;\r
-                               line_right      = max_width;\r
-                               get_line_left_right(line_top, max_width, line_left, line_right);\r
-\r
-                               ret_width = ret_width + (max_width - line_right);\r
-                       }\r
-               }\r
-               break;\r
-       default:\r
-               {\r
-                       line_context line_ctx;\r
-                       line_ctx.top = 0;\r
-                       if (!m_boxes.empty())\r
-                       {\r
-                               line_ctx.top = m_boxes.back()->top();\r
-                       }\r
-                       line_ctx.left = 0;\r
-                       line_ctx.right = max_width;\r
-                       line_ctx.fix_top();\r
-                       get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);\r
-\r
-                       switch(el->get_display())\r
-                       {\r
-                       case display_inline_block:\r
-                               ret_width = el->render(line_ctx.left, line_ctx.top, line_ctx.right);\r
-                               break;\r
-                       case display_block:             \r
-                               if(el->is_replaced() || el->is_floats_holder())\r
-                               {\r
-                                       element::ptr el_parent = el->parent();\r
-                                       el->m_pos.width = el->get_css_width().calc_percent(line_ctx.right - line_ctx.left);\r
-                                       el->m_pos.height = el->get_css_height().calc_percent(el_parent ? el_parent->m_pos.height : 0);\r
-                               }\r
-                               el->calc_outlines(line_ctx.right - line_ctx.left);\r
-                               break;\r
-                       case display_inline_text:\r
-                               {\r
-                                       litehtml::size sz;\r
-                                       el->get_content_size(sz, line_ctx.right);\r
-                                       el->m_pos = sz;\r
-                               }\r
-                               break;\r
-                       default:\r
-                               ret_width = 0;\r
-                               break;\r
-                       }\r
-\r
-                       bool add_box = true;\r
-                       if(!m_boxes.empty())\r
-                       {\r
-                               if(m_boxes.back()->can_hold(el, m_white_space))\r
-                               {\r
-                                       add_box = false;\r
-                               }\r
-                       }\r
-                       if(add_box)\r
-                       {\r
-                               new_box(el, max_width, line_ctx);\r
-                       } else if(!m_boxes.empty())\r
-                       {\r
-                               line_ctx.top = m_boxes.back()->top();\r
-                       }\r
-\r
-                       if (line_ctx.top != line_ctx.calculatedTop)\r
-                       {\r
-                               line_ctx.left = 0;\r
-                               line_ctx.right = max_width;\r
-                               line_ctx.fix_top();\r
-                               get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);\r
-                       }\r
-\r
-                       if(!el->is_inline_box())\r
-                       {\r
-                               if(m_boxes.size() == 1)\r
-                               {\r
-                                       if(collapse_top_margin())\r
-                                       {\r
-                                               int shift = el->margin_top();\r
-                                               if(shift >= 0)\r
-                                               {\r
-                                                       line_ctx.top -= shift;\r
-                                                       m_boxes.back()->y_shift(-shift);\r
-                                               }\r
-                                       }\r
-                               } else\r
-                               {\r
-                                       int shift = 0;\r
-                                       int prev_margin = m_boxes[m_boxes.size() - 2]->bottom_margin();\r
-\r
-                                       if(prev_margin > el->margin_top())\r
-                                       {\r
-                                               shift = el->margin_top();\r
-                                       } else\r
-                                       {\r
-                                               shift = prev_margin;\r
-                                       }\r
-                                       if(shift >= 0)\r
-                                       {\r
-                                               line_ctx.top -= shift;\r
-                                               m_boxes.back()->y_shift(-shift);\r
-                                       }\r
-                               }\r
-                       }\r
-\r
-                       switch(el->get_display())\r
-                       {\r
-                       case display_table:\r
-                       case display_list_item:\r
-                               ret_width = el->render(line_ctx.left, line_ctx.top, line_ctx.width());\r
-                               break;\r
-                       case display_block:\r
-                       case display_table_cell:\r
-                       case display_table_caption:\r
-                       case display_table_row:\r
-                               if(el->is_replaced() || el->is_floats_holder())\r
-                               {\r
-                                       ret_width = el->render(line_ctx.left, line_ctx.top, line_ctx.width()) + line_ctx.left + (max_width - line_ctx.right);\r
-                               } else\r
-                               {\r
-                                       ret_width = el->render(0, line_ctx.top, max_width);\r
-                               }\r
-                               break;\r
-                       default:\r
-                               ret_width = 0;\r
-                               break;\r
-                       }\r
-\r
-                       m_boxes.back()->add_element(el);\r
-\r
-                       if(el->is_inline_box() && !el->skip())\r
-                       {\r
-                               ret_width = el->right() + (max_width - line_ctx.right);\r
-                       }\r
-               }\r
-               break;\r
-       }\r
-\r
-       return ret_width;\r
-}\r
-\r
-bool litehtml::html_tag::set_pseudo_class( const tchar_t* pclass, bool add )\r
-{\r
-       bool ret = false;\r
-       if(add)\r
-       {\r
-               if(std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), pclass) == m_pseudo_classes.end())\r
-               {\r
-                       m_pseudo_classes.push_back(pclass);\r
-                       ret = true;\r
-               }\r
-       } else\r
-       {\r
-               string_vector::iterator pi = std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), pclass);\r
-               if(pi != m_pseudo_classes.end())\r
-               {\r
-                       m_pseudo_classes.erase(pi);\r
-                       ret = true;\r
-               }\r
-       }\r
-       return ret;\r
-}\r
-\r
-bool litehtml::html_tag::set_class( const tchar_t* pclass, bool add )\r
-{\r
-       string_vector classes;\r
-       bool changed = false;\r
-\r
-       split_string( pclass, classes, _t(" ") );\r
-\r
-       if(add)\r
-       {\r
-               for( auto & _class : classes  )\r
-               {\r
-                       if(std::find(m_class_values.begin(), m_class_values.end(), _class) == m_class_values.end())\r
-                       {\r
-                               m_class_values.push_back( std::move( _class ) );\r
-                               changed = true;\r
-                       }\r
-               }\r
-       } else\r
-       {\r
-               for( const auto & _class : classes )\r
-               {\r
-                       auto end = std::remove(m_class_values.begin(), m_class_values.end(), _class);\r
-\r
-                       if(end != m_class_values.end())\r
-                       {\r
-                               m_class_values.erase(end, m_class_values.end());\r
-                               changed = true;\r
-                       }\r
-               }\r
-       }\r
-\r
-       if( changed )\r
-       {\r
-               tstring class_string;\r
-               join_string(class_string, m_class_values, _t(" "));\r
-               set_attr(_t("class"), class_string.c_str());\r
-\r
-               return true;\r
-       }\r
-       else\r
-       {\r
-               return false;\r
-       }\r
-\r
-}\r
-\r
-int litehtml::html_tag::line_height() const\r
-{\r
-       return m_line_height;\r
-}\r
-\r
-bool litehtml::html_tag::is_replaced() const\r
-{\r
-       return false;\r
-}\r
-\r
-int litehtml::html_tag::finish_last_box(bool end_of_render)\r
-{\r
-       int line_top = 0;\r
-\r
-       if(!m_boxes.empty())\r
-       {\r
-               m_boxes.back()->finish(end_of_render);\r
-\r
-               if(m_boxes.back()->is_empty())\r
-               {\r
-                       line_top = m_boxes.back()->top();\r
-                       m_boxes.pop_back();\r
-               }\r
-\r
-               if(!m_boxes.empty())\r
-               {\r
-                       line_top = m_boxes.back()->bottom();\r
-               }\r
-       }\r
-       return line_top;\r
-}\r
-\r
-int litehtml::html_tag::new_box(const element::ptr &el, int max_width, line_context& line_ctx)\r
-{\r
-       line_ctx.top = get_cleared_top(el, finish_last_box());\r
-\r
-       line_ctx.left = 0;\r
-       line_ctx.right = max_width;\r
-       line_ctx.fix_top();\r
-       get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);\r
-\r
-       if(el->is_inline_box() || el->is_floats_holder())\r
-       {\r
-               if (el->width() > line_ctx.right - line_ctx.left)\r
-               {\r
-                       line_ctx.top = find_next_line_top(line_ctx.top, el->width(), max_width);\r
-                       line_ctx.left = 0;\r
-                       line_ctx.right = max_width;\r
-                       line_ctx.fix_top();\r
-                       get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);\r
-               }\r
-       }\r
-\r
-       int first_line_margin = 0;\r
-       if(m_boxes.empty() && m_list_style_type != list_style_type_none && m_list_style_position == list_style_position_inside)\r
-       {\r
-               int sz_font = get_font_size();\r
-               first_line_margin = sz_font;\r
-       }\r
-\r
-       if(el->is_inline_box())\r
-       {\r
-               int text_indent = 0;\r
-               if(m_css_text_indent.val() != 0)\r
-               {\r
-                       bool line_box_found = false;\r
-                       for(box::vector::iterator iter = m_boxes.begin(); iter != m_boxes.end(); iter++)\r
-                       {\r
-                               if((*iter)->get_type() == box_line)\r
-                               {\r
-                                       line_box_found = true;\r
-                                       break;\r
-                               }\r
-                       }\r
-                       if(!line_box_found)\r
-                       {\r
-                               text_indent = m_css_text_indent.calc_percent(max_width);\r
-                       }\r
-               }\r
-\r
-               font_metrics fm;\r
-               get_font(&fm);\r
-               m_boxes.emplace_back(std::unique_ptr<line_box>(new line_box(line_ctx.top, line_ctx.left + first_line_margin + text_indent, line_ctx.right, line_height(), fm, m_text_align)));\r
-       } else\r
-       {\r
-               m_boxes.emplace_back(std::unique_ptr<block_box>(new block_box(line_ctx.top, line_ctx.left, line_ctx.right)));\r
-       }\r
-\r
-       return line_ctx.top;\r
-}\r
-\r
-int litehtml::html_tag::get_cleared_top(const element::ptr &el, int line_top) const\r
-{\r
-       switch(el->get_clear())\r
-       {\r
-       case clear_left:\r
-               {\r
-                       int fh = get_left_floats_height();\r
-                       if(fh && fh > line_top)\r
-                       {\r
-                               line_top = fh;\r
-                       }\r
-               }\r
-               break;\r
-       case clear_right:\r
-               {\r
-                       int fh = get_right_floats_height();\r
-                       if(fh && fh > line_top)\r
-                       {\r
-                               line_top = fh;\r
-                       }\r
-               }\r
-               break;\r
-       case clear_both:\r
-               {\r
-                       int fh = get_floats_height();\r
-                       if(fh && fh > line_top)\r
-                       {\r
-                               line_top = fh;\r
-                       }\r
-               }\r
-               break;\r
-       default:\r
-               if(el->get_float() != float_none)\r
-               {\r
-                       int fh = get_floats_height(el->get_float());\r
-                       if(fh && fh > line_top)\r
-                       {\r
-                               line_top = fh;\r
-                       }\r
-               }\r
-               break;\r
-       }\r
-       return line_top;\r
-}\r
-\r
-litehtml::style_display litehtml::html_tag::get_display() const\r
-{\r
-       return m_display;\r
-}\r
-\r
-litehtml::element_float litehtml::html_tag::get_float() const\r
-{\r
-       return m_float;\r
-}\r
-\r
-bool litehtml::html_tag::is_floats_holder() const\r
-{\r
-       if(     m_display == display_inline_block || \r
-               m_display == display_table_cell || \r
-               !have_parent() ||\r
-               is_body() || \r
-               m_float != float_none ||\r
-               m_el_position == element_position_absolute ||\r
-               m_el_position == element_position_fixed ||\r
-               m_overflow > overflow_visible)\r
-       {\r
-               return true;\r
-       }\r
-       return false;\r
-}\r
-\r
-bool litehtml::html_tag::is_first_child_inline(const element::ptr& el) const\r
-{\r
-       if(!m_children.empty())\r
-       {\r
-               for (const auto& this_el : m_children)\r
-               {\r
-                       if (!this_el->is_white_space())\r
-                       {\r
-                               if (el == this_el)\r
-                               {\r
-                                       return true;\r
-                               }\r
-                               if (this_el->get_display() == display_inline)\r
-                               {\r
-                                       if (this_el->have_inline_child())\r
-                                       {\r
-                                               return false;\r
-                                       }\r
-                               } else\r
-                               {\r
-                                       return false;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       return false;\r
-}\r
-\r
-bool litehtml::html_tag::is_last_child_inline(const element::ptr& el)\r
-{\r
-       if(!m_children.empty())\r
-       {\r
-               for (auto this_el = m_children.rbegin(); this_el < m_children.rend(); ++this_el)\r
-               {\r
-                       if (!(*this_el)->is_white_space())\r
-                       {\r
-                               if (el == (*this_el))\r
-                               {\r
-                                       return true;\r
-                               }\r
-                               if ((*this_el)->get_display() == display_inline)\r
-                               {\r
-                                       if ((*this_el)->have_inline_child())\r
-                                       {\r
-                                               return false;\r
-                                       }\r
-                               } else\r
-                               {\r
-                                       return false;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       return false;\r
-}\r
-\r
-litehtml::white_space litehtml::html_tag::get_white_space() const\r
-{\r
-       return m_white_space;\r
-}\r
-\r
-litehtml::vertical_align litehtml::html_tag::get_vertical_align() const\r
-{\r
-       return m_vertical_align;\r
-}\r
-\r
-litehtml::css_length litehtml::html_tag::get_css_left() const\r
-{\r
-       return m_css_offsets.left;\r
-}\r
-\r
-litehtml::css_length litehtml::html_tag::get_css_right() const\r
-{\r
-       return m_css_offsets.right;\r
-}\r
-\r
-litehtml::css_length litehtml::html_tag::get_css_top() const\r
-{\r
-       return m_css_offsets.top;\r
-}\r
-\r
-litehtml::css_length litehtml::html_tag::get_css_bottom() const\r
-{\r
-       return m_css_offsets.bottom;\r
-}\r
-\r
-\r
-litehtml::css_offsets litehtml::html_tag::get_css_offsets() const\r
-{\r
-       return m_css_offsets;\r
-}\r
-\r
-litehtml::element_clear litehtml::html_tag::get_clear() const\r
-{\r
-       return m_clear;\r
-}\r
-\r
-litehtml::css_length litehtml::html_tag::get_css_width() const\r
-{\r
-       return m_css_width;\r
-}\r
-\r
-litehtml::css_length litehtml::html_tag::get_css_height() const\r
-{\r
-       return m_css_height;\r
-}\r
-\r
-size_t litehtml::html_tag::get_children_count() const\r
-{\r
-       return m_children.size();\r
-}\r
-\r
-litehtml::element::ptr litehtml::html_tag::get_child( int idx ) const\r
-{\r
-       return m_children[idx];\r
-}\r
-\r
-void litehtml::html_tag::set_css_width( css_length& w )\r
-{\r
-       m_css_width = w;\r
-}\r
-\r
-void litehtml::html_tag::apply_vertical_align()\r
-{\r
-       if(!m_boxes.empty())\r
-       {\r
-               int add = 0;\r
-               int content_height      = m_boxes.back()->bottom();\r
-\r
-               if(m_pos.height > content_height)\r
-               {\r
-                       switch(m_vertical_align)\r
-                       {\r
-                       case va_middle:\r
-                               add = (m_pos.height - content_height) / 2;\r
-                               break;\r
-                       case va_bottom:\r
-                               add = m_pos.height - content_height;\r
-                               break;\r
-                       default:\r
-                               add = 0;\r
-                               break;\r
-                       }\r
-               }\r
-\r
-               if(add)\r
-               {\r
-                       for(size_t i = 0; i < m_boxes.size(); i++)\r
-                       {\r
-                               m_boxes[i]->y_shift(add);\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-litehtml::element_position litehtml::html_tag::get_element_position(css_offsets* offsets) const\r
-{\r
-       if(offsets && m_el_position != element_position_static)\r
-       {\r
-               *offsets = m_css_offsets;\r
-       }\r
-       return m_el_position;\r
-}\r
-\r
-void litehtml::html_tag::init_background_paint(position pos, background_paint &bg_paint, const background* bg)\r
-{\r
-       if(!bg) return;\r
-\r
-       bg_paint = *bg;\r
-       position content_box    = pos;\r
-       position padding_box    = pos;\r
-       padding_box += m_padding;\r
-       position border_box             = padding_box;\r
-       border_box += m_borders;\r
-\r
-       switch(bg->m_clip)\r
-       {\r
-       case litehtml::background_box_padding:\r
-               bg_paint.clip_box = padding_box;\r
-               break;\r
-       case litehtml::background_box_content:\r
-               bg_paint.clip_box = content_box;\r
-               break;\r
-       default:\r
-               bg_paint.clip_box = border_box;\r
-               break;\r
-       }\r
-\r
-       switch(bg->m_origin)\r
-       {\r
-       case litehtml::background_box_border:\r
-               bg_paint.origin_box = border_box;\r
-               break;\r
-       case litehtml::background_box_content:\r
-               bg_paint.origin_box = content_box;\r
-               break;\r
-       default:\r
-               bg_paint.origin_box = padding_box;\r
-               break;\r
-       }\r
-\r
-       if(!bg_paint.image.empty())\r
-       {\r
-               get_document()->container()->get_image_size(bg_paint.image.c_str(), bg_paint.baseurl.c_str(), bg_paint.image_size);\r
-               if(bg_paint.image_size.width && bg_paint.image_size.height)\r
-               {\r
-                       litehtml::size img_new_sz = bg_paint.image_size;\r
-                       double img_ar_width             = (double) bg_paint.image_size.width / (double) bg_paint.image_size.height;\r
-                       double img_ar_height    = (double) bg_paint.image_size.height / (double) bg_paint.image_size.width;\r
-\r
-\r
-                       if(bg->m_position.width.is_predefined())\r
-                       {\r
-                               switch(bg->m_position.width.predef())\r
-                               {\r
-                               case litehtml::background_size_contain:\r
-                                       if( (int) ((double) bg_paint.origin_box.width * img_ar_height) <= bg_paint.origin_box.height )\r
-                                       {\r
-                                               img_new_sz.width = bg_paint.origin_box.width;\r
-                                               img_new_sz.height       = (int) ((double) bg_paint.origin_box.width * img_ar_height);\r
-                                       } else\r
-                                       {\r
-                                               img_new_sz.height = bg_paint.origin_box.height;\r
-                                               img_new_sz.width        = (int) ((double) bg_paint.origin_box.height * img_ar_width);\r
-                                       }\r
-                                       break;\r
-                               case litehtml::background_size_cover:\r
-                                       if( (int) ((double) bg_paint.origin_box.width * img_ar_height) >= bg_paint.origin_box.height )\r
-                                       {\r
-                                               img_new_sz.width = bg_paint.origin_box.width;\r
-                                               img_new_sz.height       = (int) ((double) bg_paint.origin_box.width * img_ar_height);\r
-                                       } else\r
-                                       {\r
-                                               img_new_sz.height = bg_paint.origin_box.height;\r
-                                               img_new_sz.width        = (int) ((double) bg_paint.origin_box.height * img_ar_width);\r
-                                       }\r
-                                       break;\r
-                                       break;\r
-                               case litehtml::background_size_auto:\r
-                                       if(!bg->m_position.height.is_predefined())\r
-                                       {\r
-                                               img_new_sz.height       = bg->m_position.height.calc_percent(bg_paint.origin_box.height);\r
-                                               img_new_sz.width        = (int) ((double) img_new_sz.height * img_ar_width);\r
-                                       }\r
-                                       break;\r
-                               }\r
-                       } else\r
-                       {\r
-                               img_new_sz.width = bg->m_position.width.calc_percent(bg_paint.origin_box.width);\r
-                               if(bg->m_position.height.is_predefined())\r
-                               {\r
-                                       img_new_sz.height = (int) ((double) img_new_sz.width * img_ar_height);\r
-                               } else\r
-                               {\r
-                                       img_new_sz.height = bg->m_position.height.calc_percent(bg_paint.origin_box.height);\r
-                               }\r
-                       }\r
-\r
-                       bg_paint.image_size = img_new_sz;\r
-                       bg_paint.position_x = bg_paint.origin_box.x + (int) bg->m_position.x.calc_percent(bg_paint.origin_box.width - bg_paint.image_size.width);\r
-                       bg_paint.position_y = bg_paint.origin_box.y + (int) bg->m_position.y.calc_percent(bg_paint.origin_box.height - bg_paint.image_size.height);\r
-               }\r
-\r
-       }\r
-       bg_paint.border_radius  = m_css_borders.radius.calc_percents(border_box.width, border_box.height);;\r
-       bg_paint.border_box             = border_box;\r
-       bg_paint.is_root                = have_parent() ? false : true;\r
-}\r
-\r
-litehtml::visibility litehtml::html_tag::get_visibility() const\r
-{\r
-       return m_visibility;\r
-}\r
-\r
-void litehtml::html_tag::draw_list_marker( uint_ptr hdc, const position &pos )\r
-{\r
-       list_marker lm;\r
-\r
-       const tchar_t* list_image = get_style_property(_t("list-style-image"), true, 0);\r
-       size img_size;\r
-       if(list_image)\r
-       {\r
-               css::parse_css_url(list_image, lm.image);\r
-               lm.baseurl = get_style_property(_t("list-style-image-baseurl"), true, 0);\r
-               get_document()->container()->get_image_size(lm.image.c_str(), lm.baseurl, img_size);\r
-       } else\r
-       {\r
-               lm.baseurl = 0;\r
-       }\r
-\r
-\r
-       int ln_height   = line_height();\r
-       int sz_font             = get_font_size();\r
-       lm.pos.x                = pos.x;\r
-       lm.pos.width    = sz_font       - sz_font * 2 / 3;\r
-       lm.pos.height   = sz_font       - sz_font * 2 / 3;\r
-       lm.pos.y                = pos.y         + ln_height / 2 - lm.pos.height / 2;\r
-\r
-       if(img_size.width && img_size.height)\r
-       {\r
-               if(lm.pos.y + img_size.height > pos.y + pos.height)\r
-               {\r
-                       lm.pos.y = pos.y + pos.height - img_size.height;\r
-               }\r
-               if(img_size.width > lm.pos.width)\r
-               {\r
-                       lm.pos.x -= img_size.width - lm.pos.width;\r
-               }\r
-\r
-               lm.pos.width    = img_size.width;\r
-               lm.pos.height   = img_size.height;\r
-       }\r
-       if(m_list_style_position == list_style_position_outside)\r
-       {\r
-               lm.pos.x -= sz_font;\r
-       }\r
-\r
-       lm.color = get_color(_t("color"), true, web_color(0, 0, 0));\r
-       lm.marker_type = m_list_style_type;\r
-       get_document()->container()->draw_list_marker(hdc, lm);\r
-}\r
-\r
-void litehtml::html_tag::draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex )\r
-{\r
-       if (m_display == display_table || m_display == display_inline_table)\r
-       {\r
-               draw_children_table(hdc, x, y, clip, flag, zindex);\r
-       }\r
-       else\r
-       {\r
-               draw_children_box(hdc, x, y, clip, flag, zindex);\r
-       }\r
-}\r
-\r
-bool litehtml::html_tag::fetch_positioned()\r
-{\r
-       bool ret = false;\r
-\r
-       m_positioned.clear();\r
-\r
-       litehtml::element_position el_pos;\r
-\r
-       for(auto& el : m_children)\r
-       {\r
-               el_pos = el->get_element_position();\r
-               if (el_pos != element_position_static)\r
-               {\r
-                       add_positioned(el);\r
-               }\r
-               if (!ret && (el_pos == element_position_absolute || el_pos == element_position_fixed))\r
-               {\r
-                       ret = true;\r
-               }\r
-               if(el->fetch_positioned())\r
-               {\r
-                       ret = true;\r
-               }\r
-       }\r
-       return ret;\r
-}\r
-\r
-int litehtml::html_tag::get_zindex() const\r
-{\r
-       return m_z_index;\r
-}\r
-\r
-void litehtml::html_tag::render_positioned(render_type rt)\r
-{\r
-       position wnd_position;\r
-       get_document()->container()->get_client_rect(wnd_position);\r
-\r
-       element_position el_position;\r
-       bool process;\r
-       for (auto& el : m_positioned)\r
-       {\r
-               el_position = el->get_element_position();\r
-\r
-               process = false;\r
-               if(el->get_display() != display_none)\r
-               {\r
-                       if(el_position == element_position_absolute)\r
-                       {\r
-                               if(rt != render_fixed_only)\r
-                               {\r
-                                       process = true;\r
-                               }\r
-                       } else if(el_position == element_position_fixed)\r
-                       {\r
-                               if(rt != render_no_fixed)\r
-                               {\r
-                                       process = true;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               if(process)\r
-               {\r
-                       int parent_height       = 0;\r
-                       int parent_width        = 0;\r
-                       int client_x            = 0;\r
-                       int client_y            = 0;\r
-                       if(el_position == element_position_fixed)\r
-                       {\r
-                               parent_height   = wnd_position.height;\r
-                               parent_width    = wnd_position.width;\r
-                               client_x                = wnd_position.left();\r
-                               client_y                = wnd_position.top();\r
-                       } else\r
-                       {\r
-                               element::ptr el_parent = el->parent();\r
-                               if(el_parent)\r
-                               {\r
-                                       parent_height   = el_parent->height();\r
-                                       parent_width    = el_parent->width();\r
-                               }\r
-                       }\r
-\r
-                       css_length      css_left        = el->get_css_left();\r
-                       css_length      css_right       = el->get_css_right();\r
-                       css_length      css_top         = el->get_css_top();\r
-                       css_length      css_bottom      = el->get_css_bottom();\r
-\r
-                       bool need_render = false;\r
-\r
-                       css_length el_w = el->get_css_width();\r
-                       css_length el_h = el->get_css_height();\r
-\r
-            int new_width = -1;\r
-            int new_height = -1;\r
-                       if(el_w.units() == css_units_percentage && parent_width)\r
-                       {\r
-                new_width = el_w.calc_percent(parent_width);\r
-                if(el->m_pos.width != new_width)\r
-                               {\r
-                                       need_render = true;\r
-                    el->m_pos.width = new_width;\r
-                               }\r
-                       }\r
-\r
-                       if(el_h.units() == css_units_percentage && parent_height)\r
-                       {\r
-                new_height = el_h.calc_percent(parent_height);\r
-                if(el->m_pos.height != new_height)\r
-                               {\r
-                                       need_render = true;\r
-                    el->m_pos.height = new_height;\r
-                               }\r
-                       }\r
-\r
-                       bool cvt_x = false;\r
-                       bool cvt_y = false;\r
-\r
-                       if(el_position == element_position_fixed)\r
-                       {\r
-                               if(!css_left.is_predefined() || !css_right.is_predefined())\r
-                               {\r
-                                       if(!css_left.is_predefined() && css_right.is_predefined())\r
-                                       {\r
-                                               el->m_pos.x = css_left.calc_percent(parent_width) + el->content_margins_left();\r
-                                       } else if(css_left.is_predefined() && !css_right.is_predefined())\r
-                                       {\r
-                                               el->m_pos.x = parent_width - css_right.calc_percent(parent_width) - el->m_pos.width - el->content_margins_right();\r
-                                       } else\r
-                                       {\r
-                                               el->m_pos.x             = css_left.calc_percent(parent_width) + el->content_margins_left();\r
-                                               el->m_pos.width = parent_width - css_left.calc_percent(parent_width) - css_right.calc_percent(parent_width) - (el->content_margins_left() + el->content_margins_right());\r
-                                               need_render = true;\r
-                                       }\r
-                               }\r
-\r
-                               if(!css_top.is_predefined() || !css_bottom.is_predefined())\r
-                               {\r
-                                       if(!css_top.is_predefined() && css_bottom.is_predefined())\r
-                                       {\r
-                                               el->m_pos.y = css_top.calc_percent(parent_height) + el->content_margins_top();\r
-                                       } else if(css_top.is_predefined() && !css_bottom.is_predefined())\r
-                                       {\r
-                                               el->m_pos.y = parent_height - css_bottom.calc_percent(parent_height) - el->m_pos.height - el->content_margins_bottom();\r
-                                       } else\r
-                                       {\r
-                                               el->m_pos.y                     = css_top.calc_percent(parent_height) + el->content_margins_top();\r
-                                               el->m_pos.height        = parent_height - css_top.calc_percent(parent_height) - css_bottom.calc_percent(parent_height) - (el->content_margins_top() + el->content_margins_bottom());\r
-                                               need_render = true;\r
-                                       }\r
-                               }\r
-                       } else \r
-                       {\r
-                               if(!css_left.is_predefined() || !css_right.is_predefined())\r
-                               {\r
-                                       if(!css_left.is_predefined() && css_right.is_predefined())\r
-                                       {\r
-                                               el->m_pos.x = css_left.calc_percent(parent_width) + el->content_margins_left() - m_padding.left;\r
-                                       } else if(css_left.is_predefined() && !css_right.is_predefined())\r
-                                       {\r
-                                               el->m_pos.x = m_pos.width + m_padding.right - css_right.calc_percent(parent_width) - el->m_pos.width - el->content_margins_right();\r
-                                       } else\r
-                                       {\r
-                                               el->m_pos.x             = css_left.calc_percent(parent_width) + el->content_margins_left() - m_padding.left;\r
-                                               el->m_pos.width = m_pos.width + m_padding.left + m_padding.right - css_left.calc_percent(parent_width) - css_right.calc_percent(parent_width) - (el->content_margins_left() + el->content_margins_right());\r
-                        if (new_width != -1)\r
-                        {\r
-                            el->m_pos.x += (el->m_pos.width - new_width) / 2;\r
-                            el->m_pos.width = new_width;\r
-                        }\r
-                        need_render = true;\r
-                                       }\r
-                                       cvt_x = true;\r
-                               }\r
-\r
-                               if(!css_top.is_predefined() || !css_bottom.is_predefined())\r
-                               {\r
-                                       if(!css_top.is_predefined() && css_bottom.is_predefined())\r
-                                       {\r
-                                               el->m_pos.y = css_top.calc_percent(parent_height) + el->content_margins_top() - m_padding.top;\r
-                                       } else if(css_top.is_predefined() && !css_bottom.is_predefined())\r
-                                       {\r
-                                               el->m_pos.y = m_pos.height + m_padding.bottom - css_bottom.calc_percent(parent_height) - el->m_pos.height - el->content_margins_bottom();\r
-                                       } else\r
-                                       {\r
-                                               el->m_pos.y                     = css_top.calc_percent(parent_height) + el->content_margins_top() - m_padding.top;\r
-                                               el->m_pos.height        = m_pos.height + m_padding.top + m_padding.bottom - css_top.calc_percent(parent_height) - css_bottom.calc_percent(parent_height) - (el->content_margins_top() + el->content_margins_bottom());\r
-                        if (new_height != -1)\r
-                        {\r
-                            el->m_pos.y += (el->m_pos.height - new_height) / 2;\r
-                            el->m_pos.height = new_height;\r
-                        }\r
-                        need_render = true;\r
-                                       }\r
-                                       cvt_y = true;\r
-                               }\r
-                       }\r
-\r
-                       if(cvt_x || cvt_y)\r
-                       {\r
-                               int offset_x = 0;\r
-                               int offset_y = 0;\r
-                               element::ptr cur_el = el->parent();\r
-                               element::ptr this_el = shared_from_this();\r
-                               while(cur_el && cur_el != this_el)\r
-                               {\r
-                                       offset_x += cur_el->m_pos.x;\r
-                                       offset_y += cur_el->m_pos.y;\r
-                                       cur_el = cur_el->parent();\r
-                               }\r
-                               if(cvt_x)       el->m_pos.x -= offset_x;\r
-                               if(cvt_y)       el->m_pos.y -= offset_y;\r
-                       }\r
-\r
-                       if(need_render)\r
-                       {\r
-                               position pos = el->m_pos;\r
-                               el->render(el->left(), el->top(), el->width(), true);\r
-                               el->m_pos = pos;\r
-                       }\r
-\r
-                       if(el_position == element_position_fixed)\r
-                       {\r
-                               position fixed_pos;\r
-                               el->get_redraw_box(fixed_pos);\r
-                               get_document()->add_fixed_box(fixed_pos);\r
-                       }\r
-               }\r
-\r
-               el->render_positioned();\r
-       }\r
-\r
-       if(!m_positioned.empty())\r
-       {\r
-               std::stable_sort(m_positioned.begin(), m_positioned.end(), [](const litehtml::element::ptr& _Left, const litehtml::element::ptr& _Right)\r
-               {\r
-                       return (_Left->get_zindex() < _Right->get_zindex());\r
-               });\r
-       }\r
-}\r
-\r
-void litehtml::html_tag::draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned )\r
-{\r
-       if(!is_visible()) return;\r
-\r
-       std::map<int, bool> zindexes;\r
-       if(with_positioned)\r
-       {\r
-               for(elements_vector::iterator i = m_positioned.begin(); i != m_positioned.end(); i++)\r
-               {\r
-                       zindexes[(*i)->get_zindex()];\r
-               }\r
-\r
-               for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end(); idx++)\r
-               {\r
-                       if(idx->first < 0)\r
-                       {\r
-                               draw_children(hdc, x, y, clip, draw_positioned, idx->first);\r
-                       }\r
-               }\r
-       }\r
-       draw_children(hdc, x, y, clip, draw_block, 0);\r
-       draw_children(hdc, x, y, clip, draw_floats, 0);\r
-       draw_children(hdc, x, y, clip, draw_inlines, 0);\r
-       if(with_positioned)\r
-       {\r
-               for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end(); idx++)\r
-               {\r
-                       if(idx->first == 0)\r
-                       {\r
-                               draw_children(hdc, x, y, clip, draw_positioned, idx->first);\r
-                       }\r
-               }\r
-\r
-               for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end(); idx++)\r
-               {\r
-                       if(idx->first > 0)\r
-                       {\r
-                               draw_children(hdc, x, y, clip, draw_positioned, idx->first);\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-litehtml::overflow litehtml::html_tag::get_overflow() const\r
-{\r
-       return m_overflow;\r
-}\r
-\r
-bool litehtml::html_tag::is_nth_child(const element::ptr& el, int num, int off, bool of_type) const\r
-{\r
-       int idx = 1;\r
-       for(const auto& child : m_children)\r
-       {\r
-               if(child->get_display() != display_inline_text)\r
-               {\r
-                       if( (!of_type) || (of_type && !t_strcmp(el->get_tagName(), child->get_tagName())) )\r
-                       {\r
-                               if(el == child)\r
-                               {\r
-                                       if(num != 0)\r
-                                       {\r
-                                               if((idx - off) >= 0 && (idx - off) % num == 0)\r
-                                               {\r
-                                                       return true;\r
-                                               }\r
-\r
-                                       } else if(idx == off)\r
-                                       {\r
-                                               return true;\r
-                                       }\r
-                                       return false;\r
-                               }\r
-                               idx++;\r
-                       }\r
-                       if(el == child) break;\r
-               }\r
-       }\r
-       return false;\r
-}\r
-\r
-bool litehtml::html_tag::is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const\r
-{\r
-       int idx = 1;\r
-       for(elements_vector::const_reverse_iterator child = m_children.rbegin(); child != m_children.rend(); child++)\r
-       {\r
-               if((*child)->get_display() != display_inline_text)\r
-               {\r
-                       if( !of_type || (of_type && !t_strcmp(el->get_tagName(), (*child)->get_tagName())) )\r
-                       {\r
-                               if(el == (*child))\r
-                               {\r
-                                       if(num != 0)\r
-                                       {\r
-                                               if((idx - off) >= 0 && (idx - off) % num == 0)\r
-                                               {\r
-                                                       return true;\r
-                                               }\r
-\r
-                                       } else if(idx == off)\r
-                                       {\r
-                                               return true;\r
-                                       }\r
-                                       return false;\r
-                               }\r
-                               idx++;\r
-                       }\r
-                       if(el == (*child)) break;\r
-               }\r
-       }\r
-       return false;\r
-}\r
-\r
-void litehtml::html_tag::parse_nth_child_params( tstring param, int &num, int &off )\r
-{\r
-       if(param == _t("odd"))\r
-       {\r
-               num = 2;\r
-               off = 1;\r
-       } else if(param == _t("even"))\r
-       {\r
-               num = 2;\r
-               off = 0;\r
-       } else\r
-       {\r
-               string_vector tokens;\r
-               split_string(param, tokens, _t(" n"), _t("n"));\r
-\r
-               tstring s_num;\r
-               tstring s_off;\r
-\r
-               tstring s_int;\r
-               for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)\r
-               {\r
-                       if((*tok) == _t("n"))\r
-                       {\r
-                               s_num = s_int;\r
-                               s_int.clear();\r
-                       } else\r
-                       {\r
-                               s_int += (*tok);\r
-                       }\r
-               }\r
-               s_off = s_int;\r
-\r
-               num = t_atoi(s_num.c_str());\r
-               off = t_atoi(s_off.c_str());\r
-       }\r
-}\r
-\r
-void litehtml::html_tag::calc_document_size( litehtml::size& sz, int x /*= 0*/, int y /*= 0*/ )\r
-{\r
-       if(is_visible() && m_el_position != element_position_fixed)\r
-       {\r
-               element::calc_document_size(sz, x, y);\r
-\r
-               if(m_overflow == overflow_visible)\r
-               {\r
-                       for(auto& el : m_children)\r
-                       {\r
-                               el->calc_document_size(sz, x + m_pos.x, y + m_pos.y);\r
-                       }\r
-               }\r
-\r
-               // root element (<html>) must to cover entire window\r
-               if(!have_parent())\r
-               {\r
-                       position client_pos;\r
-                       get_document()->container()->get_client_rect(client_pos);\r
-                       m_pos.height = std::max(sz.height, client_pos.height) - content_margins_top() - content_margins_bottom();\r
-                       m_pos.width      = std::max(sz.width, client_pos.width) - content_margins_left() - content_margins_right();\r
-               }\r
-       }\r
-}\r
-\r
-\r
-void litehtml::html_tag::get_redraw_box(litehtml::position& pos, int x /*= 0*/, int y /*= 0*/)\r
-{\r
-       if(is_visible())\r
-       {\r
-               element::get_redraw_box(pos, x, y);\r
-\r
-               if(m_overflow == overflow_visible)\r
-               {\r
-                       for(auto& el : m_children)\r
-                       {\r
-                               if(el->get_element_position() != element_position_fixed)\r
-                               {\r
-                                       el->get_redraw_box(pos, x + m_pos.x, y + m_pos.y);\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-litehtml::element::ptr litehtml::html_tag::find_adjacent_sibling( const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/ )\r
-{\r
-       element::ptr ret;\r
-       for(auto& e : m_children)\r
-       {\r
-               if(e->get_display() != display_inline_text)\r
-               {\r
-                       if(e == el)\r
-                       {\r
-                               if(ret)\r
-                               {\r
-                                       int res = ret->select(selector, apply_pseudo);\r
-                                       if(res != select_no_match)\r
-                                       {\r
-                                               if(is_pseudo)\r
-                                               {\r
-                                                       if(res & select_match_pseudo_class)\r
-                                                       {\r
-                                                               *is_pseudo = true;\r
-                                                       } else\r
-                                                       {\r
-                                                               *is_pseudo = false;\r
-                                                       }\r
-                                               }\r
-                                               return ret;\r
-                                       }\r
-                               }\r
-                               return 0;\r
-                       } else\r
-                       {\r
-                               ret = e;\r
-                       }\r
-               }\r
-       }\r
-       return 0;\r
-}\r
-\r
-litehtml::element::ptr litehtml::html_tag::find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/)\r
-{\r
-       element::ptr ret = 0;\r
-       for(auto& e : m_children)\r
-       {\r
-               if(e->get_display() != display_inline_text)\r
-               {\r
-                       if(e == el)\r
-                       {\r
-                               return ret;\r
-                       } else if(!ret)\r
-                       {\r
-                               int res = e->select(selector, apply_pseudo);\r
-                               if(res != select_no_match)\r
-                               {\r
-                                       if(is_pseudo)\r
-                                       {\r
-                                               if(res & select_match_pseudo_class)\r
-                                               {\r
-                                                       *is_pseudo = true;\r
-                                               } else\r
-                                               {\r
-                                                       *is_pseudo = false;\r
-                                               }\r
-                                       }\r
-                                       ret = e;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       return 0;\r
-}\r
-\r
-bool litehtml::html_tag::is_only_child(const element::ptr& el, bool of_type) const\r
-{\r
-       int child_count = 0;\r
-       for(const auto& child : m_children)\r
-       {\r
-               if(child->get_display() != display_inline_text)\r
-               {\r
-                       if( !of_type || (of_type && !t_strcmp(el->get_tagName(), child->get_tagName())) )\r
-                       {\r
-                               child_count++;\r
-                       }\r
-                       if(child_count > 1) break;\r
-               }\r
-       }\r
-       if(child_count > 1)\r
-       {\r
-               return false;\r
-       }\r
-       return true;\r
-}\r
-\r
-void litehtml::html_tag::update_floats(int dy, const element::ptr &parent)\r
-{\r
-       if(is_floats_holder())\r
-       {\r
-               bool reset_cache = false;\r
-               for(floated_box::vector::reverse_iterator fb = m_floats_left.rbegin(); fb != m_floats_left.rend(); fb++)\r
-               {\r
-                       if(fb->el->is_ancestor(parent))\r
-                       {\r
-                               reset_cache     = true;\r
-                               fb->pos.y       += dy;\r
-                       }\r
-               }\r
-               if(reset_cache)\r
-               {\r
-                       m_cahe_line_left.invalidate();\r
-               }\r
-               reset_cache = false;\r
-               for(floated_box::vector::reverse_iterator fb = m_floats_right.rbegin(); fb != m_floats_right.rend(); fb++)\r
-               {\r
-                       if(fb->el->is_ancestor(parent))\r
-                       {\r
-                               reset_cache     = true;\r
-                               fb->pos.y       += dy;\r
-                       }\r
-               }\r
-               if(reset_cache)\r
-               {\r
-                       m_cahe_line_right.invalidate();\r
-               }\r
-       } else\r
-       {\r
-               element::ptr el_parent = this->parent();\r
-               if (el_parent)\r
-               {\r
-                       el_parent->update_floats(dy, parent);\r
-               }\r
-       }\r
-}\r
-\r
-void litehtml::html_tag::remove_before_after()\r
-{\r
-       if(!m_children.empty())\r
-       {\r
-               if( !t_strcmp(m_children.front()->get_tagName(), _t("::before")) )\r
-               {\r
-                       m_children.erase(m_children.begin());\r
-               }\r
-       }\r
-       if(!m_children.empty())\r
-       {\r
-               if( !t_strcmp(m_children.back()->get_tagName(), _t("::after")) )\r
-               {\r
-                       m_children.erase(m_children.end() - 1);\r
-               }\r
-       }\r
-}\r
-\r
-litehtml::element::ptr litehtml::html_tag::get_element_before()\r
-{\r
-       if(!m_children.empty())\r
-       {\r
-               if( !t_strcmp(m_children.front()->get_tagName(), _t("::before")) )\r
-               {\r
-                       return m_children.front();\r
-               }\r
-       }\r
-       element::ptr el = std::make_shared<el_before>(get_document());\r
-       el->parent(shared_from_this());\r
-       m_children.insert(m_children.begin(), el);\r
-       return el;\r
-}\r
-\r
-litehtml::element::ptr litehtml::html_tag::get_element_after()\r
-{\r
-       if(!m_children.empty())\r
-       {\r
-               if( !t_strcmp(m_children.back()->get_tagName(), _t("::after")) )\r
-               {\r
-                       return m_children.back();\r
-               }\r
-       }\r
-       element::ptr el = std::make_shared<el_after>(get_document());\r
-       appendChild(el);\r
-       return el;\r
-}\r
-\r
-void litehtml::html_tag::add_style( const litehtml::style& st )\r
-{\r
-       m_style.combine(st);\r
-}\r
-\r
-bool litehtml::html_tag::have_inline_child() const\r
-{\r
-       if(!m_children.empty())\r
-       {\r
-               for(const auto& el : m_children)\r
-               {\r
-                       if(!el->is_white_space())\r
-                       {\r
-                               return true;\r
-                       }\r
-               }\r
-       }\r
-       return false;\r
-}\r
-\r
-void litehtml::html_tag::refresh_styles()\r
-{\r
-       remove_before_after();\r
-\r
-       for (auto& el : m_children)\r
-       {\r
-               if(el->get_display() != display_inline_text)\r
-               {\r
-                       el->refresh_styles();\r
-               }\r
-       }\r
-\r
-       m_style.clear();\r
-\r
-       for (auto& usel : m_used_styles)\r
-       {\r
-               usel->m_used = false;\r
-\r
-               if(usel->m_selector->is_media_valid())\r
-               {\r
-                       int apply = select(*usel->m_selector, false);\r
-\r
-                       if(apply != select_no_match)\r
-                       {\r
-                               if(apply & select_match_pseudo_class)\r
-                               {\r
-                                       if(select(*usel->m_selector, true))\r
-                                       {\r
-                                               if(apply & select_match_with_after)\r
-                                               {\r
-                                                       element::ptr el = get_element_after();\r
-                                                       if(el)\r
-                                                       {\r
-                                                               el->add_style(*usel->m_selector->m_style);\r
-                                                       }\r
-                                               } else if(apply & select_match_with_before)\r
-                                               {\r
-                                                       element::ptr el = get_element_before();\r
-                                                       if(el)\r
-                                                       {\r
-                                                               el->add_style(*usel->m_selector->m_style);\r
-                                                       }\r
-                                               }\r
-                                               else\r
-                                               {\r
-                                                       add_style(*usel->m_selector->m_style);\r
-                                                       usel->m_used = true;\r
-                                               }\r
-                                       }\r
-                               } else if(apply & select_match_with_after)\r
-                               {\r
-                                       element::ptr el = get_element_after();\r
-                                       if(el)\r
-                                       {\r
-                                               el->add_style(*usel->m_selector->m_style);\r
-                                       }\r
-                               } else if(apply & select_match_with_before)\r
-                               {\r
-                                       element::ptr el = get_element_before();\r
-                                       if(el)\r
-                                       {\r
-                                               el->add_style(*usel->m_selector->m_style);\r
-                                       }\r
-                               } else\r
-                               {\r
-                                       add_style(*usel->m_selector->m_style);\r
-                                       usel->m_used = true;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-litehtml::element::ptr litehtml::html_tag::get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex)\r
-{\r
-       element::ptr ret = 0;\r
-\r
-       if(m_overflow > overflow_visible)\r
-       {\r
-               if(!m_pos.is_point_inside(x, y))\r
-               {\r
-                       return ret;\r
-               }\r
-       }\r
-\r
-       position pos = m_pos;\r
-       pos.x   = x - pos.x;\r
-       pos.y   = y - pos.y;\r
-\r
-       for(elements_vector::reverse_iterator i = m_children.rbegin(); i != m_children.rend() && !ret; i++)\r
-       {\r
-               element::ptr el = (*i);\r
-\r
-               if(el->is_visible() && el->get_display() != display_inline_text)\r
-               {\r
-                       switch(flag)\r
-                       {\r
-                       case draw_positioned:\r
-                               if(el->is_positioned() && el->get_zindex() == zindex)\r
-                               {\r
-                                       if(el->get_element_position() == element_position_fixed)\r
-                                       {\r
-                                               ret = el->get_element_by_point(client_x, client_y, client_x, client_y);\r
-                                               if(!ret && (*i)->is_point_inside(client_x, client_y))\r
-                                               {\r
-                                                       ret = (*i);\r
-                                               }\r
-                                       } else\r
-                                       {\r
-                                               ret = el->get_element_by_point(pos.x, pos.y, client_x, client_y);\r
-                                               if(!ret && (*i)->is_point_inside(pos.x, pos.y))\r
-                                               {\r
-                                                       ret = (*i);\r
-                                               }\r
-                                       }\r
-                                       el = 0;\r
-                               }\r
-                               break;\r
-                       case draw_block:\r
-                               if(!el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())\r
-                               {\r
-                                       if(el->is_point_inside(pos.x, pos.y))\r
-                                       {\r
-                                               ret = el;\r
-                                       }\r
-                               }\r
-                               break;\r
-                       case draw_floats:\r
-                               if(el->get_float() != float_none && !el->is_positioned())\r
-                               {\r
-                                       ret = el->get_element_by_point(pos.x, pos.y, client_x, client_y);\r
-\r
-                                       if(!ret && (*i)->is_point_inside(pos.x, pos.y))\r
-                                       {\r
-                                               ret = (*i);\r
-                                       }\r
-                                       el = 0;\r
-                               }\r
-                               break;\r
-                       case draw_inlines:\r
-                               if(el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())\r
-                               {\r
-                                       if(el->get_display() == display_inline_block)\r
-                                       {\r
-                                               ret = el->get_element_by_point(pos.x, pos.y, client_x, client_y);\r
-                                               el = 0;\r
-                                       }\r
-                                       if(!ret && (*i)->is_point_inside(pos.x, pos.y))\r
-                                       {\r
-                                               ret = (*i);\r
-                                       }\r
-                               }\r
-                               break;\r
-                       default:\r
-                               break;\r
-                       }\r
-\r
-                       if(el && !el->is_positioned())\r
-                       {\r
-                               if(flag == draw_positioned)\r
-                               {\r
-                                       element::ptr child = el->get_child_by_point(pos.x, pos.y, client_x, client_y, flag, zindex);\r
-                                       if(child)\r
-                                       {\r
-                                               ret = child;\r
-                                       }\r
-                               } else\r
-                               {\r
-                                       if(     el->get_float() == float_none &&\r
-                                               el->get_display() != display_inline_block)\r
-                                       {\r
-                                               element::ptr child = el->get_child_by_point(pos.x, pos.y, client_x, client_y, flag, zindex);\r
-                                               if(child)\r
-                                               {\r
-                                                       ret = child;\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       return ret;\r
-}\r
-\r
-litehtml::element::ptr litehtml::html_tag::get_element_by_point(int x, int y, int client_x, int client_y)\r
-{\r
-       if(!is_visible()) return 0;\r
-\r
-       element::ptr ret;\r
-\r
-       std::map<int, bool> zindexes;\r
-\r
-       for(elements_vector::iterator i = m_positioned.begin(); i != m_positioned.end(); i++)\r
-       {\r
-               zindexes[(*i)->get_zindex()];\r
-       }\r
-\r
-       for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end() && !ret; idx++)\r
-       {\r
-               if(idx->first > 0)\r
-               {\r
-                       ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, idx->first);\r
-               }\r
-       }\r
-       if(ret) return ret;\r
-\r
-       for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end() && !ret; idx++)\r
-       {\r
-               if(idx->first == 0)\r
-               {\r
-                       ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, idx->first);\r
-               }\r
-       }\r
-       if(ret) return ret;\r
-\r
-       ret = get_child_by_point(x, y, client_x, client_y, draw_inlines, 0);\r
-       if(ret) return ret;\r
-\r
-       ret = get_child_by_point(x, y, client_x, client_y, draw_floats, 0);\r
-       if(ret) return ret;\r
-\r
-       ret = get_child_by_point(x, y, client_x, client_y, draw_block, 0);\r
-       if(ret) return ret;\r
-\r
-\r
-       for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end() && !ret; idx++)\r
-       {\r
-               if(idx->first < 0)\r
-               {\r
-                       ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, idx->first);\r
-               }\r
-       }\r
-       if(ret) return ret;\r
-\r
-       if(m_el_position == element_position_fixed)\r
-       {\r
-               if(is_point_inside(client_x, client_y))\r
-               {\r
-                       ret = shared_from_this();\r
-               }\r
-       } else\r
-       {\r
-               if(is_point_inside(x, y))\r
-               {\r
-                       ret = shared_from_this();\r
-               }\r
-       }\r
-\r
-       return ret;\r
-}\r
-\r
-const litehtml::background* litehtml::html_tag::get_background(bool own_only)\r
-{\r
-       if(own_only)\r
-       {\r
-               // return own background with check for empty one\r
-               if(m_bg.m_image.empty() && !m_bg.m_color.alpha)\r
-               {\r
-                       return 0;\r
-               }\r
-               return &m_bg;\r
-       }\r
-\r
-       if(m_bg.m_image.empty() && !m_bg.m_color.alpha)\r
-       {\r
-               // if this is root element (<html>) try to get background from body\r
-               if (!have_parent())\r
-               {\r
-                       for (const auto& el : m_children)\r
-                       {\r
-                               if( el->is_body() )\r
-                               {\r
-                                       // return own body background\r
-                                       return el->get_background(true);\r
-                               }\r
-                       }\r
-               }\r
-               return 0;\r
-       }\r
-       \r
-       if(is_body())\r
-       {\r
-               element::ptr el_parent = parent();\r
-               if (el_parent)\r
-               {\r
-                       if (!el_parent->get_background(true))\r
-                       {\r
-                               // parent of body will draw background for body\r
-                               return 0;\r
-                       }\r
-               }\r
-       }\r
-\r
-       return &m_bg;\r
-}\r
-\r
-int litehtml::html_tag::render_box(int x, int y, int max_width, bool second_pass /*= false*/)\r
-{\r
-       int parent_width = max_width;\r
-\r
-       calc_outlines(parent_width);\r
-\r
-       m_pos.clear();\r
-       m_pos.move_to(x, y);\r
-\r
-       m_pos.x += content_margins_left();\r
-       m_pos.y += content_margins_top();\r
-\r
-       int ret_width = 0;\r
-\r
-       def_value<int>  block_width(0);\r
-\r
-       if (m_display != display_table_cell && !m_css_width.is_predefined())\r
-       {\r
-               int w = calc_width(parent_width);\r
-               \r
-               if (m_box_sizing == box_sizing_border_box)\r
-               {\r
-                       w -= m_padding.width() + m_borders.width();\r
-               }\r
-               ret_width = max_width = block_width = w;\r
-       }\r
-       else\r
-       {\r
-               if (max_width)\r
-               {\r
-                       max_width -= content_margins_left() + content_margins_right();\r
-               }\r
-       }\r
-\r
-       // check for max-width (on the first pass only)\r
-       if (!m_css_max_width.is_predefined() && !second_pass)\r
-       {\r
-               int mw = get_document()->cvt_units(m_css_max_width, m_font_size, parent_width);\r
-               if (m_box_sizing == box_sizing_border_box)\r
-               {\r
-                       mw -= m_padding.left + m_borders.left + m_padding.right + m_borders.right;\r
-               }\r
-               if (max_width > mw)\r
-               {\r
-                       max_width = mw;\r
-               }\r
-       }\r
-\r
-       m_floats_left.clear();\r
-       m_floats_right.clear();\r
-       m_boxes.clear();\r
-       m_cahe_line_left.invalidate();\r
-       m_cahe_line_right.invalidate();\r
-\r
-       element_position el_position;\r
-\r
-       int block_height = 0;\r
-\r
-       m_pos.height = 0;\r
-\r
-       if (get_predefined_height(block_height))\r
-       {\r
-               m_pos.height = block_height;\r
-       }\r
-\r
-       white_space ws = get_white_space();\r
-       bool skip_spaces = false;\r
-       if (ws == white_space_normal ||\r
-               ws == white_space_nowrap ||\r
-               ws == white_space_pre_line)\r
-       {\r
-               skip_spaces = true;\r
-       }\r
-\r
-       bool was_space = false;\r
-\r
-       for (auto el : m_children)\r
-       {\r
-               // we don't need process absolute and fixed positioned element on the second pass\r
-               if (second_pass)\r
-               {\r
-                       el_position = el->get_element_position();\r
-                       if ((el_position == element_position_absolute || el_position == element_position_fixed)) continue;\r
-               }\r
-\r
-               // skip spaces to make rendering a bit faster\r
-               if (skip_spaces)\r
-               {\r
-                       if (el->is_white_space())\r
-                       {\r
-                               if (was_space)\r
-                               {\r
-                                       el->skip(true);\r
-                                       continue;\r
-                               }\r
-                               else\r
-                               {\r
-                                       was_space = true;\r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               was_space = false;\r
-                       }\r
-               }\r
-\r
-               // place element into rendering flow\r
-               int rw = place_element(el, max_width);\r
-               if (rw > ret_width)\r
-               {\r
-                       ret_width = rw;\r
-               }\r
-       }\r
-\r
-       finish_last_box(true);\r
-\r
-       if (block_width.is_default() && is_inline_box())\r
-       {\r
-               m_pos.width = ret_width;\r
-       }\r
-       else\r
-       {\r
-               m_pos.width = max_width;\r
-       }\r
-       calc_auto_margins(parent_width);\r
-\r
-       if (!m_boxes.empty())\r
-       {\r
-               if (collapse_top_margin())\r
-               {\r
-                       int old_top = m_margins.top;\r
-                       m_margins.top = std::max(m_boxes.front()->top_margin(), m_margins.top);\r
-                       if (m_margins.top != old_top)\r
-                       {\r
-                               update_floats(m_margins.top - old_top, shared_from_this());\r
-                       }\r
-               }\r
-               if (collapse_bottom_margin())\r
-               {\r
-                       m_margins.bottom = std::max(m_boxes.back()->bottom_margin(), m_margins.bottom);\r
-                       m_pos.height = m_boxes.back()->bottom() - m_boxes.back()->bottom_margin();\r
-               }\r
-               else\r
-               {\r
-                       m_pos.height = m_boxes.back()->bottom();\r
-               }\r
-       }\r
-\r
-       // add the floats height to the block height\r
-       if (is_floats_holder())\r
-       {\r
-               int floats_height = get_floats_height();\r
-               if (floats_height > m_pos.height)\r
-               {\r
-                       m_pos.height = floats_height;\r
-               }\r
-       }\r
-\r
-       // calculate the final position\r
-\r
-       m_pos.move_to(x, y);\r
-       m_pos.x += content_margins_left();\r
-       m_pos.y += content_margins_top();\r
-\r
-       if (get_predefined_height(block_height))\r
-       {\r
-               m_pos.height = block_height;\r
-       }\r
-\r
-       int min_height = 0;\r
-       if (!m_css_min_height.is_predefined() && m_css_min_height.units() == css_units_percentage)\r
-       {\r
-               element::ptr el_parent = parent();\r
-               if (el_parent)\r
-               {\r
-                       if (el_parent->get_predefined_height(block_height))\r
-                       {\r
-                               min_height = m_css_min_height.calc_percent(block_height);\r
-                       }\r
-               }\r
-       }\r
-       else\r
-       {\r
-               min_height = (int)m_css_min_height.val();\r
-       }\r
-       if (min_height != 0 && m_box_sizing == box_sizing_border_box)\r
-       {\r
-               min_height -= m_padding.top + m_borders.top + m_padding.bottom + m_borders.bottom;\r
-               if (min_height < 0) min_height = 0;\r
-       }\r
-\r
-       if (m_display == display_list_item)\r
-       {\r
-               const tchar_t* list_image = get_style_property(_t("list-style-image"), true, 0);\r
-               if (list_image)\r
-               {\r
-                       tstring url;\r
-                       css::parse_css_url(list_image, url);\r
-\r
-                       size sz;\r
-                       const tchar_t* list_image_baseurl = get_style_property(_t("list-style-image-baseurl"), true, 0);\r
-                       get_document()->container()->get_image_size(url.c_str(), list_image_baseurl, sz);\r
-                       if (min_height < sz.height)\r
-                       {\r
-                               min_height = sz.height;\r
-                       }\r
-               }\r
-\r
-       }\r
-\r
-       if (min_height > m_pos.height)\r
-       {\r
-               m_pos.height = min_height;\r
-       }\r
-\r
-       int min_width = m_css_min_width.calc_percent(parent_width);\r
-\r
-       if (min_width != 0 && m_box_sizing == box_sizing_border_box)\r
-       {\r
-               min_width -= m_padding.left + m_borders.left + m_padding.right + m_borders.right;\r
-               if (min_width < 0) min_width = 0;\r
-       }\r
-\r
-       if (min_width != 0)\r
-       {\r
-               if (min_width > m_pos.width)\r
-               {\r
-                       m_pos.width = min_width;\r
-               }\r
-               if (min_width > ret_width)\r
-               {\r
-                       ret_width = min_width;\r
-               }\r
-       }\r
-\r
-       ret_width += content_margins_left() + content_margins_right();\r
-\r
-       // re-render with new width\r
-       if (ret_width < max_width && !second_pass && have_parent())\r
-       {\r
-               if (m_display == display_inline_block ||\r
-                       m_css_width.is_predefined() &&\r
-                       (m_float != float_none ||\r
-                       m_display == display_table ||\r
-                       m_el_position == element_position_absolute ||\r
-                       m_el_position == element_position_fixed\r
-                       )\r
-                       )\r
-               {\r
-                       render(x, y, ret_width, true);\r
-                       m_pos.width = ret_width - (content_margins_left() + content_margins_right());\r
-               }\r
-       }\r
-\r
-       if (is_floats_holder() && !second_pass)\r
-       {\r
-               for (const auto& fb : m_floats_left)\r
-               {\r
-                       fb.el->apply_relative_shift(fb.el->parent()->calc_width(m_pos.width));\r
-               }\r
-       }\r
-\r
-\r
-       return ret_width;\r
-}\r
-\r
-int litehtml::html_tag::render_table(int x, int y, int max_width, bool second_pass /*= false*/)\r
-{\r
-       if (!m_grid) return 0;\r
-\r
-       int parent_width = max_width;\r
-\r
-       calc_outlines(parent_width);\r
-\r
-       m_pos.clear();\r
-       m_pos.move_to(x, y);\r
-\r
-       m_pos.x += content_margins_left();\r
-       m_pos.y += content_margins_top();\r
-\r
-       def_value<int>  block_width(0);\r
-\r
-       if (!m_css_width.is_predefined())\r
-       {\r
-               max_width = block_width = calc_width(parent_width) - m_padding.width() - m_borders.width();\r
-       }\r
-       else\r
-       {\r
-               if (max_width)\r
-               {\r
-                       max_width -= content_margins_left() + content_margins_right();\r
-               }\r
-       }\r
-\r
-       // Calculate table spacing\r
-       int table_width_spacing = 0;\r
-       if (m_border_collapse == border_collapse_separate)\r
-       {\r
-               table_width_spacing = m_border_spacing_x * (m_grid->cols_count() + 1);\r
-       }\r
-       else\r
-       {\r
-               table_width_spacing = 0;\r
-\r
-               if (m_grid->cols_count())\r
-               {\r
-                       table_width_spacing -= std::min(border_left(), m_grid->column(0).border_left);\r
-                       table_width_spacing -= std::min(border_right(), m_grid->column(m_grid->cols_count() - 1).border_right);\r
-               }\r
-\r
-               for (int col = 1; col < m_grid->cols_count(); col++)\r
-               {\r
-                       table_width_spacing -= std::min(m_grid->column(col).border_left, m_grid->column(col - 1).border_right);\r
-               }\r
-       }\r
-\r
-\r
-       // Calculate the minimum content width (MCW) of each cell: the formatted content may span any number of lines but may not overflow the cell box. \r
-       // If the specified 'width' (W) of the cell is greater than MCW, W is the minimum cell width. A value of 'auto' means that MCW is the minimum \r
-       // cell width.\r
-       // \r
-       // Also, calculate the "maximum" cell width of each cell: formatting the content without breaking lines other than where explicit line breaks occur.\r
-\r
-       if (m_grid->cols_count() == 1 && !block_width.is_default())\r
-       {\r
-               for (int row = 0; row < m_grid->rows_count(); row++)\r
-               {\r
-                       table_cell* cell = m_grid->cell(0, row);\r
-                       if (cell && cell->el)\r
-                       {\r
-                               cell->min_width = cell->max_width = cell->el->render(0, 0, max_width - table_width_spacing);\r
-                               cell->el->m_pos.width = cell->min_width - cell->el->content_margins_left() - cell->el->content_margins_right();\r
-                       }\r
-               }\r
-       }\r
-       else\r
-       {\r
-               for (int row = 0; row < m_grid->rows_count(); row++)\r
-               {\r
-                       for (int col = 0; col < m_grid->cols_count(); col++)\r
-                       {\r
-                               table_cell* cell = m_grid->cell(col, row);\r
-                               if (cell && cell->el)\r
-                               {\r
-                                       if (!m_grid->column(col).css_width.is_predefined() && m_grid->column(col).css_width.units() != css_units_percentage)\r
-                                       {\r
-                                               int css_w = m_grid->column(col).css_width.calc_percent(block_width);\r
-                                               int el_w = cell->el->render(0, 0, css_w);\r
-                                               cell->min_width = cell->max_width = std::max(css_w, el_w);\r
-                                               cell->el->m_pos.width = cell->min_width - cell->el->content_margins_left() - cell->el->content_margins_right();\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               // calculate minimum content width\r
-                                               cell->min_width = cell->el->render(0, 0, 1);\r
-                                               // calculate maximum content width\r
-                                               cell->max_width = cell->el->render(0, 0, max_width - table_width_spacing);\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       // For each column, determine a maximum and minimum column width from the cells that span only that column. \r
-       // The minimum is that required by the cell with the largest minimum cell width (or the column 'width', whichever is larger). \r
-       // The maximum is that required by the cell with the largest maximum cell width (or the column 'width', whichever is larger).\r
-\r
-       for (int col = 0; col < m_grid->cols_count(); col++)\r
-       {\r
-               m_grid->column(col).max_width = 0;\r
-               m_grid->column(col).min_width = 0;\r
-               for (int row = 0; row < m_grid->rows_count(); row++)\r
-               {\r
-                       if (m_grid->cell(col, row)->colspan <= 1)\r
-                       {\r
-                               m_grid->column(col).max_width = std::max(m_grid->column(col).max_width, m_grid->cell(col, row)->max_width);\r
-                               m_grid->column(col).min_width = std::max(m_grid->column(col).min_width, m_grid->cell(col, row)->min_width);\r
-                       }\r
-               }\r
-       }\r
-\r
-       // For each cell that spans more than one column, increase the minimum widths of the columns it spans so that together, \r
-       // they are at least as wide as the cell. Do the same for the maximum widths. \r
-       // If possible, widen all spanned columns by approximately the same amount.\r
-\r
-       for (int col = 0; col < m_grid->cols_count(); col++)\r
-       {\r
-               for (int row = 0; row < m_grid->rows_count(); row++)\r
-               {\r
-                       if (m_grid->cell(col, row)->colspan > 1)\r
-                       {\r
-                               int max_total_width = m_grid->column(col).max_width;\r
-                               int min_total_width = m_grid->column(col).min_width;\r
-                               for (int col2 = col + 1; col2 < col + m_grid->cell(col, row)->colspan; col2++)\r
-                               {\r
-                                       max_total_width += m_grid->column(col2).max_width;\r
-                                       min_total_width += m_grid->column(col2).min_width;\r
-                               }\r
-                               if (min_total_width < m_grid->cell(col, row)->min_width)\r
-                               {\r
-                                       m_grid->distribute_min_width(m_grid->cell(col, row)->min_width - min_total_width, col, col + m_grid->cell(col, row)->colspan - 1);\r
-                               }\r
-                               if (max_total_width < m_grid->cell(col, row)->max_width)\r
-                               {\r
-                                       m_grid->distribute_max_width(m_grid->cell(col, row)->max_width - max_total_width, col, col + m_grid->cell(col, row)->colspan - 1);\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       // If the 'table' or 'inline-table' element's 'width' property has a computed value (W) other than 'auto', the used width is the \r
-       // greater of W, CAPMIN, and the minimum width required by all the columns plus cell spacing or borders (MIN). \r
-       // If the used width is greater than MIN, the extra width should be distributed over the columns.\r
-       //\r
-       // If the 'table' or 'inline-table' element has 'width: auto', the used width is the greater of the table's containing block width, \r
-       // CAPMIN, and MIN. However, if either CAPMIN or the maximum width required by the columns plus cell spacing or borders (MAX) is \r
-       // less than that of the containing block, use max(MAX, CAPMIN).\r
-\r
-\r
-       int table_width = 0;\r
-       int min_table_width = 0;\r
-       int max_table_width = 0;\r
-\r
-       if (!block_width.is_default())\r
-       {\r
-               table_width = m_grid->calc_table_width(block_width - table_width_spacing, false, min_table_width, max_table_width);\r
-       }\r
-       else\r
-       {\r
-               table_width = m_grid->calc_table_width(max_width - table_width_spacing, true, min_table_width, max_table_width);\r
-       }\r
-\r
-       min_table_width += table_width_spacing;\r
-       max_table_width += table_width_spacing;\r
-       table_width += table_width_spacing;\r
-       m_grid->calc_horizontal_positions(m_borders, m_border_collapse, m_border_spacing_x);\r
-\r
-       bool row_span_found = false;\r
-\r
-       // render cells with computed width\r
-       for (int row = 0; row < m_grid->rows_count(); row++)\r
-       {\r
-               m_grid->row(row).height = 0;\r
-               for (int col = 0; col < m_grid->cols_count(); col++)\r
-               {\r
-                       table_cell* cell = m_grid->cell(col, row);\r
-                       if (cell->el)\r
-                       {\r
-                               int span_col = col + cell->colspan - 1;\r
-                               if (span_col >= m_grid->cols_count())\r
-                               {\r
-                                       span_col = m_grid->cols_count() - 1;\r
-                               }\r
-                               int cell_width = m_grid->column(span_col).right - m_grid->column(col).left;\r
-\r
-                               if (cell->el->m_pos.width != cell_width - cell->el->content_margins_left() - cell->el->content_margins_right())\r
-                               {\r
-                                       cell->el->render(m_grid->column(col).left, 0, cell_width);\r
-                                       cell->el->m_pos.width = cell_width - cell->el->content_margins_left() - cell->el->content_margins_right();\r
-                               }\r
-                               else\r
-                               {\r
-                                       cell->el->m_pos.x = m_grid->column(col).left + cell->el->content_margins_left();\r
-                               }\r
-\r
-                               if (cell->rowspan <= 1)\r
-                               {\r
-                                       m_grid->row(row).height = std::max(m_grid->row(row).height, cell->el->height());\r
-                               }\r
-                               else\r
-                               {\r
-                                       row_span_found = true;\r
-                               }\r
-\r
-                       }\r
-               }\r
-       }\r
-\r
-       if (row_span_found)\r
-       {\r
-               for (int col = 0; col < m_grid->cols_count(); col++)\r
-               {\r
-                       for (int row = 0; row < m_grid->rows_count(); row++)\r
-                       {\r
-                               table_cell* cell = m_grid->cell(col, row);\r
-                               if (cell->el)\r
-                               {\r
-                                       int span_row = row + cell->rowspan - 1;\r
-                                       if (span_row >= m_grid->rows_count())\r
-                                       {\r
-                                               span_row = m_grid->rows_count() - 1;\r
-                                       }\r
-                                       if (span_row != row)\r
-                                       {\r
-                                               int h = 0;\r
-                                               for (int i = row; i <= span_row; i++)\r
-                                               {\r
-                                                       h += m_grid->row(i).height;\r
-                                               }\r
-                                               if (h < cell->el->height())\r
-                                               {\r
-                                                       m_grid->row(span_row).height += cell->el->height() - h;\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       // Calculate vertical table spacing\r
-       int table_height_spacing = 0;\r
-       if (m_border_collapse == border_collapse_separate)\r
-       {\r
-               table_height_spacing = m_border_spacing_y * (m_grid->rows_count() + 1);\r
-       }\r
-       else\r
-       {\r
-               table_height_spacing = 0;\r
-\r
-               if (m_grid->rows_count())\r
-               {\r
-                       table_height_spacing -= std::min(border_top(), m_grid->row(0).border_top);\r
-                       table_height_spacing -= std::min(border_bottom(), m_grid->row(m_grid->rows_count() - 1).border_bottom);\r
-               }\r
-\r
-               for (int row = 1; row < m_grid->rows_count(); row++)\r
-               {\r
-                       table_height_spacing -= std::min(m_grid->row(row).border_top, m_grid->row(row - 1).border_bottom);\r
-               }\r
-       }\r
-\r
-\r
-       // calculate block height\r
-       int block_height = 0;\r
-       if (get_predefined_height(block_height))\r
-       {\r
-               block_height -= m_padding.height() + m_borders.height();\r
-       }\r
-\r
-       // calculate minimum height from m_css_min_height\r
-       int min_height = 0;\r
-       if (!m_css_min_height.is_predefined() && m_css_min_height.units() == css_units_percentage)\r
-       {\r
-               element::ptr el_parent = parent();\r
-               if (el_parent)\r
-               {\r
-                       int parent_height = 0;\r
-                       if (el_parent->get_predefined_height(parent_height))\r
-                       {\r
-                               min_height = m_css_min_height.calc_percent(parent_height);\r
-                       }\r
-               }\r
-       }\r
-       else\r
-       {\r
-               min_height = (int)m_css_min_height.val();\r
-       }\r
-\r
-       int extra_row_height = 0;\r
-       int minimum_table_height = std::max(block_height, min_height);\r
-\r
-       m_grid->calc_rows_height(minimum_table_height - table_height_spacing, m_border_spacing_y);\r
-       m_grid->calc_vertical_positions(m_borders, m_border_collapse, m_border_spacing_y);\r
-\r
-       int table_height = 0;\r
-\r
-       // place cells vertically\r
-       for (int col = 0; col < m_grid->cols_count(); col++)\r
-       {\r
-               for (int row = 0; row < m_grid->rows_count(); row++)\r
-               {\r
-                       table_cell* cell = m_grid->cell(col, row);\r
-                       if (cell->el)\r
-                       {\r
-                               int span_row = row + cell->rowspan - 1;\r
-                               if (span_row >= m_grid->rows_count())\r
-                               {\r
-                                       span_row = m_grid->rows_count() - 1;\r
-                               }\r
-                               cell->el->m_pos.y = m_grid->row(row).top + cell->el->content_margins_top();\r
-                               cell->el->m_pos.height = m_grid->row(span_row).bottom - m_grid->row(row).top - cell->el->content_margins_top() - cell->el->content_margins_bottom();\r
-                               table_height = std::max(table_height, m_grid->row(span_row).bottom);\r
-                               cell->el->apply_vertical_align();\r
-                       }\r
-               }\r
-       }\r
-\r
-       if (m_border_collapse == border_collapse_collapse)\r
-       {\r
-               if (m_grid->rows_count())\r
-               {\r
-                       table_height -= std::min(border_bottom(), m_grid->row(m_grid->rows_count() - 1).border_bottom);\r
-               }\r
-       }\r
-       else\r
-       {\r
-               table_height += m_border_spacing_y;\r
-       }\r
-\r
-       m_pos.width = table_width;\r
-\r
-       calc_auto_margins(parent_width);\r
-\r
-       m_pos.move_to(x, y);\r
-       m_pos.x += content_margins_left();\r
-       m_pos.y += content_margins_top();\r
-       m_pos.width = table_width;\r
-       m_pos.height = table_height;\r
-\r
-       return max_table_width;\r
-}\r
-\r
-void litehtml::html_tag::draw_children_box(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex)\r
-{\r
-       position pos = m_pos;\r
-       pos.x += x;\r
-       pos.y += y;\r
-\r
-       document::ptr doc = get_document();\r
-\r
-       if (m_overflow > overflow_visible)\r
-       {\r
-               position border_box = pos;\r
-               border_box += m_padding;\r
-               border_box += m_borders;\r
-\r
-               border_radiuses bdr_radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);\r
-\r
-               bdr_radius -= m_borders;\r
-               bdr_radius -= m_padding;\r
-\r
-               doc->container()->set_clip(pos, bdr_radius, true, true);\r
-       }\r
-\r
-       position browser_wnd;\r
-       doc->container()->get_client_rect(browser_wnd);\r
-\r
-       element::ptr el;\r
-       for (auto& item : m_children)\r
-       {\r
-               el = item;\r
-               if (el->is_visible())\r
-               {\r
-                       switch (flag)\r
-                       {\r
-                       case draw_positioned:\r
-                               if (el->is_positioned() && el->get_zindex() == zindex)\r
-                               {\r
-                                       if (el->get_element_position() == element_position_fixed)\r
-                                       {\r
-                                               el->draw(hdc, browser_wnd.x, browser_wnd.y, clip);\r
-                                               el->draw_stacking_context(hdc, browser_wnd.x, browser_wnd.y, clip, true);\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               el->draw(hdc, pos.x, pos.y, clip);\r
-                                               el->draw_stacking_context(hdc, pos.x, pos.y, clip, true);\r
-                                       }\r
-                                       el = 0;\r
-                               }\r
-                               break;\r
-                       case draw_block:\r
-                               if (!el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())\r
-                               {\r
-                                       el->draw(hdc, pos.x, pos.y, clip);\r
-                               }\r
-                               break;\r
-                       case draw_floats:\r
-                               if (el->get_float() != float_none && !el->is_positioned())\r
-                               {\r
-                                       el->draw(hdc, pos.x, pos.y, clip);\r
-                                       el->draw_stacking_context(hdc, pos.x, pos.y, clip, false);\r
-                                       el = 0;\r
-                               }\r
-                               break;\r
-                       case draw_inlines:\r
-                               if (el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())\r
-                               {\r
-                                       el->draw(hdc, pos.x, pos.y, clip);\r
-                                       if (el->get_display() == display_inline_block)\r
-                                       {\r
-                                               el->draw_stacking_context(hdc, pos.x, pos.y, clip, false);\r
-                                               el = 0;\r
-                                       }\r
-                               }\r
-                               break;\r
-                       default:\r
-                               break;\r
-                       }\r
-\r
-                       if (el)\r
-                       {\r
-                               if (flag == draw_positioned)\r
-                               {\r
-                                       if (!el->is_positioned())\r
-                                       {\r
-                                               el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);\r
-                                       }\r
-                               }\r
-                               else\r
-                               {\r
-                                       if (el->get_float() == float_none &&\r
-                                               el->get_display() != display_inline_block &&\r
-                                               !el->is_positioned())\r
-                                       {\r
-                                               el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       if (m_overflow > overflow_visible)\r
-       {\r
-               doc->container()->del_clip();\r
-       }\r
-}\r
-\r
-void litehtml::html_tag::draw_children_table(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex)\r
-{\r
-       if (!m_grid) return;\r
-\r
-       position pos = m_pos;\r
-       pos.x += x;\r
-       pos.y += y;\r
-       for (int row = 0; row < m_grid->rows_count(); row++)\r
-       {\r
-               if (flag == draw_block)\r
-               {\r
-                       m_grid->row(row).el_row->draw_background(hdc, pos.x, pos.y, clip);\r
-               }\r
-               for (int col = 0; col < m_grid->cols_count(); col++)\r
-               {\r
-                       table_cell* cell = m_grid->cell(col, row);\r
-                       if (cell->el)\r
-                       {\r
-                               if (flag == draw_block)\r
-                               {\r
-                                       cell->el->draw(hdc, pos.x, pos.y, clip);\r
-                               }\r
-                               cell->el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);\r
-                       }\r
-               }\r
-       }\r
-}\r
+#include "html.h"
+#include "html_tag.h"
+#include "document.h"
+#include "iterators.h"
+#include "stylesheet.h"
+#include "table.h"
+#include <algorithm>
+#include <locale>
+#include "el_before_after.h"
+
+litehtml::html_tag::html_tag(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
+{
+       m_box_sizing                    = box_sizing_content_box;
+       m_z_index                               = 0;
+       m_overflow                              = overflow_visible;
+       m_box                                   = 0;
+       m_text_align                    = text_align_left;
+       m_el_position                   = element_position_static;
+       m_display                               = display_inline;
+       m_vertical_align                = va_baseline;
+       m_list_style_type               = list_style_type_none;
+       m_list_style_position   = list_style_position_outside;
+       m_float                                 = float_none;
+       m_clear                                 = clear_none;
+       m_font                                  = 0;
+       m_font_size                             = 0;
+       m_white_space                   = white_space_normal;
+       m_lh_predefined                 = false;
+       m_line_height                   = 0;
+       m_visibility                    = visibility_visible;
+       m_border_spacing_x              = 0;
+       m_border_spacing_y              = 0;
+       m_border_collapse               = border_collapse_separate;
+}
+
+litehtml::html_tag::~html_tag()
+{
+
+}
+
+bool litehtml::html_tag::appendChild(const element::ptr &el)
+{
+       if(el)
+       {
+               el->parent(shared_from_this());
+               m_children.push_back(el);
+               return true;
+       }
+       return false;
+}
+
+bool litehtml::html_tag::removeChild(const element::ptr &el)
+{
+       if(el && el->parent() == shared_from_this())
+       {
+               el->parent(nullptr);
+               m_children.erase(std::remove(m_children.begin(), m_children.end(), el), m_children.end());
+               return true;
+       }
+       return false;
+}
+
+void litehtml::html_tag::clearRecursive()
+{
+       for(auto& el : m_children)
+       {
+               el->clearRecursive();
+               el->parent(nullptr);
+       }
+       m_children.clear();
+}
+
+
+const litehtml::tchar_t* litehtml::html_tag::get_tagName() const
+{
+       return m_tag.c_str();
+}
+
+void litehtml::html_tag::set_attr( const tchar_t* name, const tchar_t* val )
+{
+       if(name && val)
+       {
+               tstring s_val = name;
+               std::locale lc = std::locale::global(std::locale::classic());
+               for(size_t i = 0; i < s_val.length(); i++)
+               {
+                       s_val[i] = std::tolower(s_val[i], lc);
+               }
+               m_attrs[s_val] = val;
+
+               if( t_strcasecmp( name, _t("class") ) == 0 )
+               {
+                       m_class_values.resize( 0 );
+                       split_string( val, m_class_values, _t(" ") );
+               }
+       }
+}
+
+const litehtml::tchar_t* litehtml::html_tag::get_attr( const tchar_t* name, const tchar_t* def )
+{
+       string_map::const_iterator attr = m_attrs.find(name);
+       if(attr != m_attrs.end())
+       {
+               return attr->second.c_str();
+       }
+       return def;
+}
+
+litehtml::elements_vector litehtml::html_tag::select_all( const tstring& selector )
+{
+       css_selector sel(media_query_list::ptr(0));
+       sel.parse(selector);
+       
+       return select_all(sel);
+}
+
+litehtml::elements_vector litehtml::html_tag::select_all( const css_selector& selector )
+{
+       litehtml::elements_vector res;
+       select_all(selector, res);
+       return res;
+}
+
+void litehtml::html_tag::select_all(const css_selector& selector, elements_vector& res)
+{
+       if(select(selector))
+       {
+               res.push_back(shared_from_this());
+       }
+       
+       for(auto& el : m_children)
+       {
+               el->select_all(selector, res);
+       }
+}
+
+
+litehtml::element::ptr litehtml::html_tag::select_one( const tstring& selector )
+{
+       css_selector sel(media_query_list::ptr(0));
+       sel.parse(selector);
+
+       return select_one(sel);
+}
+
+litehtml::element::ptr litehtml::html_tag::select_one( const css_selector& selector )
+{
+       if(select(selector))
+       {
+               return shared_from_this();
+       }
+
+       for(auto& el : m_children)
+       {
+               element::ptr res = el->select_one(selector);
+               if(res)
+               {
+                       return res;
+               }
+       }
+       return 0;
+}
+
+void litehtml::html_tag::apply_stylesheet( const litehtml::css& stylesheet )
+{
+       remove_before_after();
+
+       for(const auto& sel : stylesheet.selectors())
+       {
+               int apply = select(*sel, false);
+
+               if(apply != select_no_match)
+               {
+                       used_selector::ptr us = std::unique_ptr<used_selector>(new used_selector(sel, false));
+
+                       if(sel->is_media_valid())
+                       {
+                               if(apply & select_match_pseudo_class)
+                               {
+                                       if(select(*sel, true))
+                                       {
+                                               if(apply & select_match_with_after)
+                                               {
+                                                       element::ptr el = get_element_after();
+                                                       if(el)
+                                                       {
+                                                               el->add_style(*sel->m_style);
+                                                       }
+                                               } else if(apply & select_match_with_before)
+                                               {
+                                                       element::ptr el = get_element_before();
+                                                       if(el)
+                                                       {
+                                                               el->add_style(*sel->m_style);
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       add_style(*sel->m_style);
+                                                       us->m_used = true;
+                                               }
+                                       }
+                               } else if(apply & select_match_with_after)
+                               {
+                                       element::ptr el = get_element_after();
+                                       if(el)
+                                       {
+                                               el->add_style(*sel->m_style);
+                                       }
+                               } else if(apply & select_match_with_before)
+                               {
+                                       element::ptr el = get_element_before();
+                                       if(el)
+                                       {
+                                               el->add_style(*sel->m_style);
+                                       }
+                               } else
+                               {
+                                       add_style(*sel->m_style);
+                                       us->m_used = true;
+                               }
+                       }
+                       m_used_styles.push_back(std::move(us));
+               }
+       }
+
+       for(auto& el : m_children)
+       {
+               if(el->get_display() != display_inline_text)
+               {
+                       el->apply_stylesheet(stylesheet);
+               }
+       }
+}
+
+void litehtml::html_tag::get_content_size( size& sz, int max_width )
+{
+       sz.height       = 0;
+       if(m_display == display_block)
+       {
+               sz.width        = max_width;
+       } else
+       {
+               sz.width        = 0;
+       }
+}
+
+void litehtml::html_tag::draw( uint_ptr hdc, int x, int y, const position* clip )
+{
+       position pos = m_pos;
+       pos.x   += x;
+       pos.y   += y;
+
+       draw_background(hdc, x, y, clip);
+
+       if(m_display == display_list_item && m_list_style_type != list_style_type_none)
+       {
+               if(m_overflow > overflow_visible)
+               {
+                       position border_box = pos;
+                       border_box += m_padding;
+                       border_box += m_borders;
+
+                       border_radiuses bdr_radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
+
+                       bdr_radius -= m_borders;
+                       bdr_radius -= m_padding;
+
+                       get_document()->container()->set_clip(pos, bdr_radius, true, true);
+               }
+
+               draw_list_marker(hdc, pos);
+
+               if(m_overflow > overflow_visible)
+               {
+                       get_document()->container()->del_clip();
+               }
+       }
+}
+
+litehtml::uint_ptr litehtml::html_tag::get_font(font_metrics* fm)
+{
+       if(fm)
+       {
+               *fm = m_font_metrics;
+       }
+       return m_font;
+}
+
+const litehtml::tchar_t* litehtml::html_tag::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ )
+{
+       const tchar_t* ret = m_style.get_property(name);
+       element::ptr el_parent = parent();
+       if (el_parent)
+       {
+               if ( ( ret && !t_strcasecmp(ret, _t("inherit")) ) || (!ret && inherited) )
+               {
+                       ret = el_parent->get_style_property(name, inherited, def);
+               }
+       }
+
+       if(!ret)
+       {
+               ret = def;
+       }
+
+       return ret;
+}
+
+void litehtml::html_tag::parse_styles(bool is_reparse)
+{
+       const tchar_t* style = get_attr(_t("style"));
+
+       if(style)
+       {
+               m_style.add(style, NULL);
+       }
+
+       init_font();
+       document::ptr doc = get_document();
+
+       m_el_position   = (element_position)    value_index(get_style_property(_t("position"),          false,  _t("static")),          element_position_strings,       element_position_fixed);
+       m_text_align    = (text_align)                  value_index(get_style_property(_t("text-align"),                true,   _t("left")),            text_align_strings,                     text_align_left);
+       m_overflow              = (overflow)                    value_index(get_style_property(_t("overflow"),          false,  _t("visible")),         overflow_strings,                       overflow_visible);
+       m_white_space   = (white_space)                 value_index(get_style_property(_t("white-space"),       true,   _t("normal")),          white_space_strings,            white_space_normal);
+       m_display               = (style_display)               value_index(get_style_property(_t("display"),           false,  _t("inline")),          style_display_strings,          display_inline);
+       m_visibility    = (visibility)                  value_index(get_style_property(_t("visibility"),        true,   _t("visible")),         visibility_strings,                     visibility_visible);
+       m_box_sizing    = (box_sizing)                  value_index(get_style_property(_t("box-sizing"),                false,  _t("content-box")),     box_sizing_strings,                     box_sizing_content_box);
+
+       if(m_el_position != element_position_static)
+       {
+               const tchar_t* val = get_style_property(_t("z-index"), false, 0);
+               if(val)
+               {
+                       m_z_index = t_atoi(val);
+               }
+       }
+
+       const tchar_t* va       = get_style_property(_t("vertical-align"), true,        _t("baseline"));
+       m_vertical_align = (vertical_align) value_index(va, vertical_align_strings, va_baseline);
+
+       const tchar_t* fl       = get_style_property(_t("float"), false,        _t("none"));
+       m_float = (element_float) value_index(fl, element_float_strings, float_none);
+
+       m_clear = (element_clear) value_index(get_style_property(_t("clear"), false, _t("none")), element_clear_strings, clear_none);
+
+       if (m_float != float_none)
+       {
+               // reset display in to block for floating elements
+               if (m_display != display_none)
+               {
+                       m_display = display_block;
+               }
+       }
+       else if (m_display == display_table ||
+               m_display == display_table_caption ||
+               m_display == display_table_cell ||
+               m_display == display_table_column ||
+               m_display == display_table_column_group ||
+               m_display == display_table_footer_group ||
+               m_display == display_table_header_group ||
+               m_display == display_table_row ||
+               m_display == display_table_row_group)
+       {
+               doc->add_tabular(shared_from_this());
+       }
+       // fix inline boxes with absolute/fixed positions
+       else if (m_display != display_none && is_inline_box())
+       {
+               if (m_el_position == element_position_absolute || m_el_position == element_position_fixed)
+               {
+                       m_display = display_block;
+               }
+       }
+
+       m_css_text_indent.fromString(   get_style_property(_t("text-indent"),   true,   _t("0")),       _t("0"));
+
+       m_css_width.fromString(                 get_style_property(_t("width"),                 false,  _t("auto")), _t("auto"));
+       m_css_height.fromString(                get_style_property(_t("height"),                false,  _t("auto")), _t("auto"));
+
+       doc->cvt_units(m_css_width, m_font_size);
+       doc->cvt_units(m_css_height, m_font_size);
+
+       m_css_min_width.fromString(             get_style_property(_t("min-width"),             false,  _t("0")));
+       m_css_min_height.fromString(    get_style_property(_t("min-height"),            false,  _t("0")));
+
+       m_css_max_width.fromString(             get_style_property(_t("max-width"),             false,  _t("none")),    _t("none"));
+       m_css_max_height.fromString(    get_style_property(_t("max-height"),            false,  _t("none")),    _t("none"));
+       
+       doc->cvt_units(m_css_min_width, m_font_size);
+       doc->cvt_units(m_css_min_height, m_font_size);
+
+       m_css_offsets.left.fromString(          get_style_property(_t("left"),                          false,  _t("auto")), _t("auto"));
+       m_css_offsets.right.fromString(         get_style_property(_t("right"),                         false,  _t("auto")), _t("auto"));
+       m_css_offsets.top.fromString(           get_style_property(_t("top"),                           false,  _t("auto")), _t("auto"));
+       m_css_offsets.bottom.fromString(        get_style_property(_t("bottom"),                        false,  _t("auto")), _t("auto"));
+
+       doc->cvt_units(m_css_offsets.left, m_font_size);
+       doc->cvt_units(m_css_offsets.right, m_font_size);
+       doc->cvt_units(m_css_offsets.top,               m_font_size);
+       doc->cvt_units(m_css_offsets.bottom,    m_font_size);
+
+       m_css_margins.left.fromString(          get_style_property(_t("margin-left"),           false,  _t("0")), _t("auto"));
+       m_css_margins.right.fromString(         get_style_property(_t("margin-right"),          false,  _t("0")), _t("auto"));
+       m_css_margins.top.fromString(           get_style_property(_t("margin-top"),                    false,  _t("0")), _t("auto"));
+       m_css_margins.bottom.fromString(        get_style_property(_t("margin-bottom"),         false,  _t("0")), _t("auto"));
+
+       m_css_padding.left.fromString(          get_style_property(_t("padding-left"),          false,  _t("0")), _t(""));
+       m_css_padding.right.fromString(         get_style_property(_t("padding-right"),         false,  _t("0")), _t(""));
+       m_css_padding.top.fromString(           get_style_property(_t("padding-top"),           false,  _t("0")), _t(""));
+       m_css_padding.bottom.fromString(        get_style_property(_t("padding-bottom"),                false,  _t("0")), _t(""));
+
+       m_css_borders.left.width.fromString(    get_style_property(_t("border-left-width"),             false,  _t("medium")), border_width_strings);
+       m_css_borders.right.width.fromString(   get_style_property(_t("border-right-width"),            false,  _t("medium")), border_width_strings);
+       m_css_borders.top.width.fromString(             get_style_property(_t("border-top-width"),              false,  _t("medium")), border_width_strings);
+       m_css_borders.bottom.width.fromString(  get_style_property(_t("border-bottom-width"),   false,  _t("medium")), border_width_strings);
+
+       m_css_borders.left.color = web_color::from_string(get_style_property(_t("border-left-color"),   false,  _t("")), doc->container());
+       m_css_borders.left.style = (border_style) value_index(get_style_property(_t("border-left-style"), false, _t("none")), border_style_strings, border_style_none);
+
+    m_css_borders.right.color = web_color::from_string(get_style_property(_t("border-right-color"), false, _t("")), doc->container());
+       m_css_borders.right.style = (border_style) value_index(get_style_property(_t("border-right-style"), false, _t("none")), border_style_strings, border_style_none);
+
+    m_css_borders.top.color = web_color::from_string(get_style_property(_t("border-top-color"), false, _t("")), doc->container());
+       m_css_borders.top.style = (border_style) value_index(get_style_property(_t("border-top-style"), false, _t("none")), border_style_strings, border_style_none);
+
+    m_css_borders.bottom.color = web_color::from_string(get_style_property(_t("border-bottom-color"), false, _t("")), doc->container());
+       m_css_borders.bottom.style = (border_style) value_index(get_style_property(_t("border-bottom-style"), false, _t("none")), border_style_strings, border_style_none);
+
+       m_css_borders.radius.top_left_x.fromString(get_style_property(_t("border-top-left-radius-x"), false, _t("0")));
+       m_css_borders.radius.top_left_y.fromString(get_style_property(_t("border-top-left-radius-y"), false, _t("0")));
+
+       m_css_borders.radius.top_right_x.fromString(get_style_property(_t("border-top-right-radius-x"), false, _t("0")));
+       m_css_borders.radius.top_right_y.fromString(get_style_property(_t("border-top-right-radius-y"), false, _t("0")));
+
+       m_css_borders.radius.bottom_right_x.fromString(get_style_property(_t("border-bottom-right-radius-x"), false, _t("0")));
+       m_css_borders.radius.bottom_right_y.fromString(get_style_property(_t("border-bottom-right-radius-y"), false, _t("0")));
+
+       m_css_borders.radius.bottom_left_x.fromString(get_style_property(_t("border-bottom-left-radius-x"), false, _t("0")));
+       m_css_borders.radius.bottom_left_y.fromString(get_style_property(_t("border-bottom-left-radius-y"), false, _t("0")));
+
+       doc->cvt_units(m_css_borders.radius.bottom_left_x,                      m_font_size);
+       doc->cvt_units(m_css_borders.radius.bottom_left_y,                      m_font_size);
+       doc->cvt_units(m_css_borders.radius.bottom_right_x,                     m_font_size);
+       doc->cvt_units(m_css_borders.radius.bottom_right_y,                     m_font_size);
+       doc->cvt_units(m_css_borders.radius.top_left_x,                         m_font_size);
+       doc->cvt_units(m_css_borders.radius.top_left_y,                         m_font_size);
+       doc->cvt_units(m_css_borders.radius.top_right_x,                                m_font_size);
+       doc->cvt_units(m_css_borders.radius.top_right_y,                                m_font_size);
+
+       doc->cvt_units(m_css_text_indent,                                                               m_font_size);
+
+       m_margins.left          = doc->cvt_units(m_css_margins.left,            m_font_size);
+       m_margins.right         = doc->cvt_units(m_css_margins.right,           m_font_size);
+       m_margins.top           = doc->cvt_units(m_css_margins.top,             m_font_size);
+       m_margins.bottom        = doc->cvt_units(m_css_margins.bottom,  m_font_size);
+
+       m_padding.left          = doc->cvt_units(m_css_padding.left,            m_font_size);
+       m_padding.right         = doc->cvt_units(m_css_padding.right,           m_font_size);
+       m_padding.top           = doc->cvt_units(m_css_padding.top,             m_font_size);
+       m_padding.bottom        = doc->cvt_units(m_css_padding.bottom,  m_font_size);
+
+       m_borders.left          = doc->cvt_units(m_css_borders.left.width,      m_font_size);
+       m_borders.right         = doc->cvt_units(m_css_borders.right.width,     m_font_size);
+       m_borders.top           = doc->cvt_units(m_css_borders.top.width,               m_font_size);
+       m_borders.bottom        = doc->cvt_units(m_css_borders.bottom.width,    m_font_size);
+
+       css_length line_height;
+       line_height.fromString(get_style_property(_t("line-height"),    true,   _t("normal")), _t("normal"));
+       if(line_height.is_predefined())
+       {
+               m_line_height = m_font_metrics.height;
+               m_lh_predefined = true;
+       } else if(line_height.units() == css_units_none)
+       {
+               m_line_height = (int) (line_height.val() * m_font_size);
+               m_lh_predefined = false;
+       } else
+       {
+               m_line_height =  doc->cvt_units(line_height,    m_font_size, m_font_size);
+               m_lh_predefined = false;
+       }
+
+
+       if(m_display == display_list_item)
+       {
+               const tchar_t* list_type = get_style_property(_t("list-style-type"), true, _t("disc"));
+               m_list_style_type = (list_style_type) value_index(list_type, list_style_type_strings, list_style_type_disc);
+
+               const tchar_t* list_pos = get_style_property(_t("list-style-position"), true, _t("outside"));
+               m_list_style_position = (list_style_position) value_index(list_pos, list_style_position_strings, list_style_position_outside);
+
+               const tchar_t* list_image = get_style_property(_t("list-style-image"), true, 0);
+               if(list_image && list_image[0])
+               {
+                       tstring url;
+                       css::parse_css_url(list_image, url);
+
+                       const tchar_t* list_image_baseurl = get_style_property(_t("list-style-image-baseurl"), true, 0);
+                       doc->container()->load_image(url.c_str(), list_image_baseurl, true);
+               }
+
+       }
+
+       parse_background();
+
+       if(!is_reparse)
+       {
+               for(auto& el : m_children)
+               {
+                       el->parse_styles();
+               }
+       }
+}
+
+int litehtml::html_tag::render( int x, int y, int max_width, bool second_pass )
+{
+       if (m_display == display_table || m_display == display_inline_table)
+       {
+               return render_table(x, y, max_width, second_pass);
+       }
+
+       return render_box(x, y, max_width, second_pass);
+}
+
+bool litehtml::html_tag::is_white_space() const
+{
+       return false;
+}
+
+int litehtml::html_tag::get_font_size() const
+{
+       return m_font_size;
+}
+
+int litehtml::html_tag::get_base_line()
+{
+       if(is_replaced())
+       {
+               return 0;
+       }
+       int bl = 0;
+       if(!m_boxes.empty())
+       {
+               bl = m_boxes.back()->baseline() + content_margins_bottom();
+       }
+       return bl;
+}
+
+void litehtml::html_tag::init()
+{
+       if (m_display == display_table || m_display == display_inline_table)
+       {
+               if (m_grid)
+               {
+                       m_grid->clear();
+               }
+               else
+               {
+                       m_grid = std::unique_ptr<table_grid>(new table_grid());
+               }
+
+               go_inside_table                 table_selector;
+               table_rows_selector             row_selector;
+               table_cells_selector    cell_selector;
+
+               elements_iterator row_iter(shared_from_this(), &table_selector, &row_selector);
+
+               element::ptr row = row_iter.next(false);
+               while (row)
+               {
+                       m_grid->begin_row(row);
+
+                       elements_iterator cell_iter(row, &table_selector, &cell_selector);
+                       element::ptr cell = cell_iter.next();
+                       while (cell)
+                       {
+                               m_grid->add_cell(cell);
+
+                               cell = cell_iter.next(false);
+                       }
+                       row = row_iter.next(false);
+               }
+
+               m_grid->finish();
+       }
+
+       for (auto& el : m_children)
+       {
+               el->init();
+       }
+}
+
+int litehtml::html_tag::select(const css_selector& selector, bool apply_pseudo)
+{
+       int right_res = select(selector.m_right, apply_pseudo);
+       if(right_res == select_no_match)
+       {
+               return select_no_match;
+       }
+       element::ptr el_parent = parent();
+       if(selector.m_left)
+       {
+               if (!el_parent)
+               {
+                       return select_no_match;
+               }
+               switch(selector.m_combinator)
+               {
+               case combinator_descendant:
+                       {
+                               bool is_pseudo = false;
+                               element::ptr res = find_ancestor(*selector.m_left, apply_pseudo, &is_pseudo);
+                               if(!res)
+                               {
+                                       return select_no_match;
+                               } else
+                               {
+                                       if(is_pseudo)
+                                       {
+                                               right_res |= select_match_pseudo_class;
+                                       }
+                               }
+                       }
+                       break;
+               case combinator_child:
+                       {
+                               int res = el_parent->select(*selector.m_left, apply_pseudo);
+                               if(res == select_no_match)
+                               {
+                                       return select_no_match;
+                               } else
+                               {
+                                       if(right_res != select_match_pseudo_class)
+                                       {
+                                               right_res |= res;
+                                       }
+                               }
+                       }
+                       break;
+               case combinator_adjacent_sibling:
+                       {
+                               bool is_pseudo = false;
+                               element::ptr res = el_parent->find_adjacent_sibling(shared_from_this(), *selector.m_left, apply_pseudo, &is_pseudo);
+                               if(!res)
+                               {
+                                       return select_no_match;
+                               } else
+                               {
+                                       if(is_pseudo)
+                                       {
+                                               right_res |= select_match_pseudo_class;
+                                       }
+                               }
+                       }
+                       break;
+               case combinator_general_sibling:
+                       {
+                               bool is_pseudo = false;
+                               element::ptr res =  el_parent->find_sibling(shared_from_this(), *selector.m_left, apply_pseudo, &is_pseudo);
+                               if(!res)
+                               {
+                                       return select_no_match;
+                               } else
+                               {
+                                       if(is_pseudo)
+                                       {
+                                               right_res |= select_match_pseudo_class;
+                                       }
+                               }
+                       }
+                       break;
+               default:
+                       right_res = select_no_match;
+               }
+       }
+       return right_res;
+}
+
+int litehtml::html_tag::select(const css_element_selector& selector, bool apply_pseudo)
+{
+       if(!selector.m_tag.empty() && selector.m_tag != _t("*"))
+       {
+               if(selector.m_tag != m_tag)
+               {
+                       return select_no_match;
+               }
+       }
+
+       int res = select_match;
+       element::ptr el_parent = parent();
+
+       for(css_attribute_selector::vector::const_iterator i = selector.m_attrs.begin(); i != selector.m_attrs.end(); i++)
+       {
+               const tchar_t* attr_value = get_attr(i->attribute.c_str());
+               switch(i->condition)
+               {
+               case select_exists:
+                       if(!attr_value)
+                       {
+                               return select_no_match;
+                       }
+                       break;
+               case select_equal:
+                       if(!attr_value)
+                       {
+                               return select_no_match;
+                       } else 
+                       {
+                               if(i->attribute == _t("class"))
+                               {
+                                       const string_vector & tokens1 = m_class_values;
+                                       const string_vector & tokens2 = i->class_val;
+                                       bool found = true;
+                                       for(string_vector::const_iterator str1 = tokens2.begin(); str1 != tokens2.end() && found; str1++)
+                                       {
+                                               bool f = false;
+                                               for(string_vector::const_iterator str2 = tokens1.begin(); str2 != tokens1.end() && !f; str2++)
+                                               {
+                                                       if( !t_strcasecmp(str1->c_str(), str2->c_str()) )
+                                                       {
+                                                               f = true;
+                                                       }
+                                               }
+                                               if(!f)
+                                               {
+                                                       found = false;
+                                               }
+                                       }
+                                       if(!found)
+                                       {
+                                               return select_no_match;
+                                       }
+                               } else
+                               {
+                                       if( t_strcasecmp(i->val.c_str(), attr_value) )
+                                       {
+                                               return select_no_match;
+                                       }
+                               }
+                       }
+                       break;
+               case select_contain_str:
+                       if(!attr_value)
+                       {
+                               return select_no_match;
+                       } else if(!t_strstr(attr_value, i->val.c_str()))
+                       {
+                               return select_no_match;
+                       }
+                       break;
+               case select_start_str:
+                       if(!attr_value)
+                       {
+                               return select_no_match;
+                       } else if(t_strncmp(attr_value, i->val.c_str(), i->val.length()))
+                       {
+                               return select_no_match;
+                       }
+                       break;
+               case select_end_str:
+                       if(!attr_value)
+                       {
+                               return select_no_match;
+                       } else if(t_strncmp(attr_value, i->val.c_str(), i->val.length()))
+                       {
+                               const tchar_t* s = attr_value + t_strlen(attr_value) - i->val.length() - 1;
+                               if(s < attr_value)
+                               {
+                                       return select_no_match;
+                               }
+                               if(i->val != s)
+                               {
+                                       return select_no_match;
+                               }
+                       }
+                       break;
+               case select_pseudo_element:
+                       if(i->val == _t("after"))
+                       {
+                               res |= select_match_with_after;
+                       } else if(i->val == _t("before"))
+                       {
+                               res |= select_match_with_before;
+                       } else
+                       {
+                               return select_no_match;
+                       }
+                       break;
+               case select_pseudo_class:
+                       if(apply_pseudo)
+                       {
+                               if (!el_parent) return select_no_match;
+
+                               tstring selector_param;
+                               tstring selector_name;
+
+                               tstring::size_type begin        = i->val.find_first_of(_t('('));
+                               tstring::size_type end          = (begin == tstring::npos) ? tstring::npos : find_close_bracket(i->val, begin);
+                               if(begin != tstring::npos && end != tstring::npos)
+                               {
+                                       selector_param = i->val.substr(begin + 1, end - begin - 1);
+                               }
+                               if(begin != tstring::npos)
+                               {
+                                       selector_name = i->val.substr(0, begin);
+                                       litehtml::trim(selector_name);
+                               } else
+                               {
+                                       selector_name = i->val;
+                               }
+
+                               int selector = value_index(selector_name.c_str(), pseudo_class_strings);
+                               
+                               switch(selector)
+                               {
+                               case pseudo_class_only_child:
+                                       if (!el_parent->is_only_child(shared_from_this(), false))
+                                       {
+                                               return select_no_match;
+                                       }
+                                       break;
+                               case pseudo_class_only_of_type:
+                                       if (!el_parent->is_only_child(shared_from_this(), true))
+                                       {
+                                               return select_no_match;
+                                       }
+                                       break;
+                               case pseudo_class_first_child:
+                                       if (!el_parent->is_nth_child(shared_from_this(), 0, 1, false))
+                                       {
+                                               return select_no_match;
+                                       }
+                                       break;
+                               case pseudo_class_first_of_type:
+                                       if (!el_parent->is_nth_child(shared_from_this(), 0, 1, true))
+                                       {
+                                               return select_no_match;
+                                       }
+                                       break;
+                               case pseudo_class_last_child:
+                                       if (!el_parent->is_nth_last_child(shared_from_this(), 0, 1, false))
+                                       {
+                                               return select_no_match;
+                                       }
+                                       break;
+                               case pseudo_class_last_of_type:
+                                       if (!el_parent->is_nth_last_child(shared_from_this(), 0, 1, true))
+                                       {
+                                               return select_no_match;
+                                       }
+                                       break;
+                               case pseudo_class_nth_child:
+                               case pseudo_class_nth_of_type:
+                               case pseudo_class_nth_last_child:
+                               case pseudo_class_nth_last_of_type:
+                                       {
+                                               if(selector_param.empty()) return select_no_match;
+
+                                               int num = 0;
+                                               int off = 0;
+
+                                               parse_nth_child_params(selector_param, num, off);
+                                               if(!num && !off) return select_no_match;
+                                               switch(selector)
+                                               {
+                                               case pseudo_class_nth_child:
+                                                       if (!el_parent->is_nth_child(shared_from_this(), num, off, false))
+                                                       {
+                                                               return select_no_match;
+                                                       }
+                                                       break;
+                                               case pseudo_class_nth_of_type:
+                                                       if (!el_parent->is_nth_child(shared_from_this(), num, off, true))
+                                                       {
+                                                               return select_no_match;
+                                                       }
+                                                       break;
+                                               case pseudo_class_nth_last_child:
+                                                       if (!el_parent->is_nth_last_child(shared_from_this(), num, off, false))
+                                                       {
+                                                               return select_no_match;
+                                                       }
+                                                       break;
+                                               case pseudo_class_nth_last_of_type:
+                                                       if (!el_parent->is_nth_last_child(shared_from_this(), num, off, true))
+                                                       {
+                                                               return select_no_match;
+                                                       }
+                                                       break;
+                                               }
+
+                                       }
+                                       break;
+                               case pseudo_class_not:
+                                       {
+                                               css_element_selector sel;
+                                               sel.parse(selector_param);
+                                               if(select(sel, apply_pseudo))
+                                               {
+                                                       return select_no_match;
+                                               }
+                                       }
+                                       break;
+                               case pseudo_class_lang:
+                                       {
+                                               trim( selector_param );
+
+                                               if( !get_document()->match_lang( selector_param ) )
+                                               {
+                                                       return select_no_match;
+                                               }
+                                       }
+                                       break;
+                               default:
+                                       if(std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), i->val) == m_pseudo_classes.end())
+                                       {
+                                               return select_no_match;
+                                       }
+                                       break;
+                               }
+                       } else
+                       {
+                               res |= select_match_pseudo_class;
+                       }
+                       break;
+               }
+       }
+       return res;
+}
+
+litehtml::element::ptr litehtml::html_tag::find_ancestor(const css_selector& selector, bool apply_pseudo, bool* is_pseudo)
+{
+       element::ptr el_parent = parent();
+       if (!el_parent)
+       {
+               return nullptr;
+       }
+       int res = el_parent->select(selector, apply_pseudo);
+       if(res != select_no_match)
+       {
+               if(is_pseudo)
+               {
+                       if(res & select_match_pseudo_class)
+                       {
+                               *is_pseudo = true;
+                       } else
+                       {
+                               *is_pseudo = false;
+                       }
+               }
+               return el_parent;
+       }
+       return el_parent->find_ancestor(selector, apply_pseudo, is_pseudo);
+}
+
+int litehtml::html_tag::get_floats_height(element_float el_float) const
+{
+       if(is_floats_holder())
+       {
+               int h = 0;
+
+               bool process = false;
+
+               for(const auto& fb : m_floats_left)
+               {
+                       process = false;
+                       switch(el_float)
+                       {
+                       case float_none:
+                               process = true;
+                               break;
+                       case float_left:
+                               if (fb.clear_floats == clear_left || fb.clear_floats == clear_both)
+                               {
+                                       process = true;
+                               }
+                               break;
+                       case float_right:
+                               if (fb.clear_floats == clear_right || fb.clear_floats == clear_both)
+                               {
+                                       process = true;
+                               }
+                               break;
+                       }
+                       if(process)
+                       {
+                               if(el_float == float_none)
+                               {
+                                       h = std::max(h, fb.pos.bottom());
+                               } else
+                               {
+                                       h = std::max(h, fb.pos.top());
+                               }
+                       }
+               }
+
+
+               for(const auto fb : m_floats_right)
+               {
+                       process = false;
+                       switch(el_float)
+                       {
+                       case float_none:
+                               process = true;
+                               break;
+                       case float_left:
+                               if (fb.clear_floats == clear_left || fb.clear_floats == clear_both)
+                               {
+                                       process = true;
+                               }
+                               break;
+                       case float_right:
+                               if (fb.clear_floats == clear_right || fb.clear_floats == clear_both)
+                               {
+                                       process = true;
+                               }
+                               break;
+                       }
+                       if(process)
+                       {
+                               if(el_float == float_none)
+                               {
+                                       h = std::max(h, fb.pos.bottom());
+                               } else
+                               {
+                                       h = std::max(h, fb.pos.top());
+                               }
+                       }
+               }
+
+               return h;
+       }
+       element::ptr el_parent = parent();
+       if (el_parent)
+       {
+               int h = el_parent->get_floats_height(el_float);
+               return h - m_pos.y;
+       }
+       return 0;
+}
+
+int litehtml::html_tag::get_left_floats_height() const
+{
+       if(is_floats_holder())
+       {
+               int h = 0;
+               if(!m_floats_left.empty())
+               {
+                       for (const auto& fb : m_floats_left)
+                       {
+                               h = std::max(h, fb.pos.bottom());
+                       }
+               }
+               return h;
+       }
+       element::ptr el_parent = parent();
+       if (el_parent)
+       {
+               int h = el_parent->get_left_floats_height();
+               return h - m_pos.y;
+       }
+       return 0;
+}
+
+int litehtml::html_tag::get_right_floats_height() const
+{
+       if(is_floats_holder())
+       {
+               int h = 0;
+               if(!m_floats_right.empty())
+               {
+                       for(const auto& fb : m_floats_right)
+                       {
+                               h = std::max(h, fb.pos.bottom());
+                       }
+               }
+               return h;
+       }
+       element::ptr el_parent = parent();
+       if (el_parent)
+       {
+               int h = el_parent->get_right_floats_height();
+               return h - m_pos.y;
+       }
+       return 0;
+}
+
+int litehtml::html_tag::get_line_left( int y )
+{
+       if(is_floats_holder())
+       {
+               if(m_cahe_line_left.is_valid && m_cahe_line_left.hash == y)
+               {
+                       return m_cahe_line_left.val;
+               }
+
+               int w = 0;
+               for(const auto& fb : m_floats_left)
+               {
+                       if (y >= fb.pos.top() && y < fb.pos.bottom())
+                       {
+                               w = std::max(w, fb.pos.right());
+                               if (w < fb.pos.right())
+                               {
+                                       break;
+                               }
+                       }
+               }
+               m_cahe_line_left.set_value(y, w);
+               return w;
+       }
+       element::ptr el_parent = parent();
+       if (el_parent)
+       {
+               int w = el_parent->get_line_left(y + m_pos.y);
+               if (w < 0)
+               {
+                       w = 0;
+               }
+               return w - (w ? m_pos.x : 0);
+       }
+       return 0;
+}
+
+int litehtml::html_tag::get_line_right( int y, int def_right )
+{
+       if(is_floats_holder())
+       {
+               if(m_cahe_line_right.is_valid && m_cahe_line_right.hash == y)
+               {
+                       if(m_cahe_line_right.is_default)
+                       {
+                               return def_right;
+                       } else
+                       {
+                               return std::min(m_cahe_line_right.val, def_right);
+                       }
+               }
+
+               int w = def_right;
+               m_cahe_line_right.is_default = true;
+               for(const auto& fb : m_floats_right)
+               {
+                       if(y >= fb.pos.top() && y < fb.pos.bottom())
+                       {
+                               w = std::min(w, fb.pos.left());
+                               m_cahe_line_right.is_default = false;
+                               if(w > fb.pos.left())
+                               {
+                                       break;
+                               }
+                       }
+               }
+               m_cahe_line_right.set_value(y, w);
+               return w;
+       }
+       element::ptr el_parent = parent();
+       if (el_parent)
+       {
+               int w = el_parent->get_line_right(y + m_pos.y, def_right + m_pos.x);
+               return w - m_pos.x;
+       }
+       return 0;
+}
+
+
+void litehtml::html_tag::get_line_left_right( int y, int def_right, int& ln_left, int& ln_right )
+{
+       if(is_floats_holder())
+       {
+               ln_left         = get_line_left(y);
+               ln_right        = get_line_right(y, def_right);
+       } else
+       {
+               element::ptr el_parent = parent();
+               if (el_parent)
+               {
+                       el_parent->get_line_left_right(y + m_pos.y, def_right + m_pos.x, ln_left, ln_right);
+               }
+               ln_right -= m_pos.x;
+               ln_left -= m_pos.x;
+
+               if(ln_left < 0)
+               {
+                       ln_left = 0;
+               }
+       }
+}
+
+int litehtml::html_tag::fix_line_width( int max_width, element_float flt )
+{
+       int ret_width = 0;
+       if(!m_boxes.empty())
+       {
+               elements_vector els;
+               m_boxes.back()->get_elements(els);
+               bool was_cleared = false;
+               if(!els.empty() && els.front()->get_clear() != clear_none)
+               {
+                       if(els.front()->get_clear() == clear_both)
+                       {
+                               was_cleared = true;
+                       } else
+                       {
+                               if(     (flt == float_left      && els.front()->get_clear() == clear_left) ||
+                                       (flt == float_right     && els.front()->get_clear() == clear_right) )
+                               {
+                                       was_cleared = true;
+                               }
+                       }
+               }
+
+               if(!was_cleared)
+               {
+                       m_boxes.pop_back();
+
+                       for(elements_vector::iterator i = els.begin(); i != els.end(); i++)
+                       {
+                               int rw = place_element((*i), max_width);
+                               if(rw > ret_width)
+                               {
+                                       ret_width = rw;
+                               }
+                       }
+               } else
+               {
+                       int line_top = 0;
+                       if(m_boxes.back()->get_type() == box_line)
+                       {
+                               line_top = m_boxes.back()->top();
+                       } else
+                       {
+                               line_top = m_boxes.back()->bottom();
+                       }
+
+                       int line_left   = 0;
+                       int line_right  = max_width;
+                       get_line_left_right(line_top, max_width, line_left, line_right);
+
+                       if(m_boxes.back()->get_type() == box_line)
+                       {
+                               if(m_boxes.size() == 1 && m_list_style_type != list_style_type_none && m_list_style_position == list_style_position_inside)
+                               {
+                                       int sz_font = get_font_size();
+                                       line_left += sz_font;
+                               }
+
+                               if(m_css_text_indent.val() != 0)
+                               {
+                                       bool line_box_found = false;
+                                       for(box::vector::iterator iter = m_boxes.begin(); iter < m_boxes.end(); iter++)
+                                       {
+                                               if((*iter)->get_type() == box_line)
+                                               {
+                                                       line_box_found = true;
+                                                       break;
+                                               }
+                                       }
+                                       if(!line_box_found)
+                                       {
+                                               line_left += m_css_text_indent.calc_percent(max_width);
+                                       }
+                               }
+
+                       }
+
+                       elements_vector els;
+                       m_boxes.back()->new_width(line_left, line_right, els);
+                       for(auto& el : els)
+                       {
+                               int rw = place_element(el, max_width);
+                               if(rw > ret_width)
+                               {
+                                       ret_width = rw;
+                               }
+                       }
+               }
+       }
+
+       return ret_width;
+}
+
+void litehtml::html_tag::add_float(const element::ptr &el, int x, int y)
+{
+       if(is_floats_holder())
+       {
+               floated_box fb;
+               fb.pos.x                = el->left() + x;
+               fb.pos.y                = el->top()  + y;
+               fb.pos.width    = el->width();
+               fb.pos.height   = el->height();
+               fb.float_side   = el->get_float();
+               fb.clear_floats = el->get_clear();
+               fb.el                   = el;
+
+               if(fb.float_side == float_left)
+               {
+                       if(m_floats_left.empty())
+                       {
+                               m_floats_left.push_back(fb);
+                       } else
+                       {
+                               bool inserted = false;
+                               for(floated_box::vector::iterator i = m_floats_left.begin(); i != m_floats_left.end(); i++)
+                               {
+                                       if(fb.pos.right() > i->pos.right())
+                                       {
+                                               m_floats_left.insert(i, std::move(fb));
+                                               inserted = true;
+                                               break;
+                                       }
+                               }
+                               if(!inserted)
+                               {
+                                       m_floats_left.push_back(std::move(fb));
+                               }
+                       }
+                       m_cahe_line_left.invalidate();
+               } else if(fb.float_side == float_right)
+               {
+                       if(m_floats_right.empty())
+                       {
+                               m_floats_right.push_back(std::move(fb));
+                       } else
+                       {
+                               bool inserted = false;
+                               for(floated_box::vector::iterator i = m_floats_right.begin(); i != m_floats_right.end(); i++)
+                               {
+                                       if(fb.pos.left() < i->pos.left())
+                                       {
+                                               m_floats_right.insert(i, std::move(fb));
+                                               inserted = true;
+                                               break;
+                                       }
+                               }
+                               if(!inserted)
+                               {
+                                       m_floats_right.push_back(fb);
+                               }
+                       }
+                       m_cahe_line_right.invalidate();
+               }
+       } else
+       {
+               element::ptr el_parent = parent();
+               if (el_parent)
+               {
+                       el_parent->add_float(el, x + m_pos.x, y + m_pos.y);
+               }
+       }
+}
+
+int litehtml::html_tag::find_next_line_top( int top, int width, int def_right )
+{
+       if(is_floats_holder())
+       {
+               int new_top = top;
+               int_vector points;
+
+               for(const auto& fb : m_floats_left)
+               {
+                       if(fb.pos.top() >= top)
+                       {
+                               if(find(points.begin(), points.end(), fb.pos.top()) == points.end())
+                               {
+                                       points.push_back(fb.pos.top());
+                               }
+                       }
+                       if (fb.pos.bottom() >= top)
+                       {
+                               if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end())
+                               {
+                                       points.push_back(fb.pos.bottom());
+                               }
+                       }
+               }
+
+               for (const auto& fb : m_floats_right)
+               {
+                       if (fb.pos.top() >= top)
+                       {
+                               if (find(points.begin(), points.end(), fb.pos.top()) == points.end())
+                               {
+                                       points.push_back(fb.pos.top());
+                               }
+                       }
+                       if (fb.pos.bottom() >= top)
+                       {
+                               if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end())
+                               {
+                                       points.push_back(fb.pos.bottom());
+                               }
+                       }
+               }
+
+               if(!points.empty())
+               {
+                       sort(points.begin(), points.end(), std::less<int>( ));
+                       new_top = points.back();
+
+                       for(auto pt : points)
+                       {
+                               int pos_left    = 0;
+                               int pos_right   = def_right;
+                               get_line_left_right(pt, def_right, pos_left, pos_right);
+
+                               if(pos_right - pos_left >= width)
+                               {
+                                       new_top = pt;
+                                       break;
+                               }
+                       }
+               }
+               return new_top;
+       }
+       element::ptr el_parent = parent();
+       if (el_parent)
+       {
+               int new_top = el_parent->find_next_line_top(top + m_pos.y, width, def_right + m_pos.x);
+               return new_top - m_pos.y;
+       }
+       return 0;
+}
+
+void litehtml::html_tag::parse_background()
+{
+       // parse background-color
+       m_bg.m_color            = get_color(_t("background-color"), false, web_color(0, 0, 0, 0));
+
+       // parse background-position
+       const tchar_t* str = get_style_property(_t("background-position"), false, _t("0% 0%"));
+       if(str)
+       {
+               string_vector res;
+               split_string(str, res, _t(" \t"));
+               if(res.size() > 0)
+               {
+                       if(res.size() == 1)
+                       {
+                               if( value_in_list(res[0].c_str(), _t("left;right;center")) )
+                               {
+                                       m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
+                                       m_bg.m_position.y.set_value(50, css_units_percentage);
+                               } else if( value_in_list(res[0].c_str(), _t("top;bottom;center")) )
+                               {
+                                       m_bg.m_position.y.fromString(res[0], _t("top;bottom;center"));
+                                       m_bg.m_position.x.set_value(50, css_units_percentage);
+                               } else
+                               {
+                                       m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
+                                       m_bg.m_position.y.set_value(50, css_units_percentage);
+                               }
+                       } else
+                       {
+                               if(value_in_list(res[0].c_str(), _t("left;right")))
+                               {
+                                       m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
+                                       m_bg.m_position.y.fromString(res[1], _t("top;bottom;center"));
+                               } else if(value_in_list(res[0].c_str(), _t("top;bottom")))
+                               {
+                                       m_bg.m_position.x.fromString(res[1], _t("left;right;center"));
+                                       m_bg.m_position.y.fromString(res[0], _t("top;bottom;center"));
+                               } else if(value_in_list(res[1].c_str(), _t("left;right")))
+                               {
+                                       m_bg.m_position.x.fromString(res[1], _t("left;right;center"));
+                                       m_bg.m_position.y.fromString(res[0], _t("top;bottom;center"));
+                               }else if(value_in_list(res[1].c_str(), _t("top;bottom")))
+                               {
+                                       m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
+                                       m_bg.m_position.y.fromString(res[1], _t("top;bottom;center"));
+                               } else
+                               {
+                                       m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
+                                       m_bg.m_position.y.fromString(res[1], _t("top;bottom;center"));
+                               }
+                       }
+
+                       if(m_bg.m_position.x.is_predefined())
+                       {
+                               switch(m_bg.m_position.x.predef())
+                               {
+                               case 0:
+                                       m_bg.m_position.x.set_value(0, css_units_percentage);
+                                       break;
+                               case 1:
+                                       m_bg.m_position.x.set_value(100, css_units_percentage);
+                                       break;
+                               case 2:
+                                       m_bg.m_position.x.set_value(50, css_units_percentage);
+                                       break;
+                               }
+                       }
+                       if(m_bg.m_position.y.is_predefined())
+                       {
+                               switch(m_bg.m_position.y.predef())
+                               {
+                               case 0:
+                                       m_bg.m_position.y.set_value(0, css_units_percentage);
+                                       break;
+                               case 1:
+                                       m_bg.m_position.y.set_value(100, css_units_percentage);
+                                       break;
+                               case 2:
+                                       m_bg.m_position.y.set_value(50, css_units_percentage);
+                                       break;
+                               }
+                       }
+               } else
+               {
+                       m_bg.m_position.x.set_value(0, css_units_percentage);
+                       m_bg.m_position.y.set_value(0, css_units_percentage);
+               }
+       } else
+       {
+               m_bg.m_position.y.set_value(0, css_units_percentage);
+               m_bg.m_position.x.set_value(0, css_units_percentage);
+       }
+
+       str = get_style_property(_t("background-size"), false, _t("auto"));
+       if(str)
+       {
+               string_vector res;
+               split_string(str, res, _t(" \t"));
+               if(!res.empty())
+               {
+                       m_bg.m_position.width.fromString(res[0], background_size_strings);
+                       if(res.size() > 1)
+                       {
+                               m_bg.m_position.height.fromString(res[1], background_size_strings);
+                       } else
+                       {
+                               m_bg.m_position.height.predef(background_size_auto);
+                       }
+               } else
+               {
+                       m_bg.m_position.width.predef(background_size_auto);
+                       m_bg.m_position.height.predef(background_size_auto);
+               }
+       }
+
+       document::ptr doc = get_document();
+
+       doc->cvt_units(m_bg.m_position.x,               m_font_size);
+       doc->cvt_units(m_bg.m_position.y,               m_font_size);
+       doc->cvt_units(m_bg.m_position.width,   m_font_size);
+       doc->cvt_units(m_bg.m_position.height,  m_font_size);
+
+       // parse background_attachment
+       m_bg.m_attachment = (background_attachment) value_index(
+               get_style_property(_t("background-attachment"), false, _t("scroll")), 
+               background_attachment_strings, 
+               background_attachment_scroll);
+
+       // parse background_attachment
+       m_bg.m_repeat = (background_repeat) value_index(
+               get_style_property(_t("background-repeat"), false, _t("repeat")), 
+               background_repeat_strings, 
+               background_repeat_repeat);
+
+       // parse background_clip
+       m_bg.m_clip = (background_box) value_index(
+               get_style_property(_t("background-clip"), false, _t("border-box")), 
+               background_box_strings, 
+               background_box_border);
+
+       // parse background_origin
+       m_bg.m_origin = (background_box) value_index(
+               get_style_property(_t("background-origin"), false, _t("padding-box")), 
+               background_box_strings, 
+               background_box_content);
+
+       // parse background-image
+       css::parse_css_url(get_style_property(_t("background-image"), false, _t("")), m_bg.m_image);
+       m_bg.m_baseurl = get_style_property(_t("background-image-baseurl"), false, _t(""));
+
+       if(!m_bg.m_image.empty())
+       {
+               doc->container()->load_image(m_bg.m_image.c_str(), m_bg.m_baseurl.empty() ? 0 : m_bg.m_baseurl.c_str(), true);
+       }
+}
+
+void litehtml::html_tag::add_positioned(const element::ptr &el)
+{
+       if (m_el_position != element_position_static || (!have_parent()))
+       {
+               m_positioned.push_back(el);
+       } else
+       {
+               element::ptr el_parent = parent();
+               if (el_parent)
+               {
+                       el_parent->add_positioned(el);
+               }
+       }
+}
+
+void litehtml::html_tag::calc_outlines( int parent_width )
+{
+       m_padding.left  = m_css_padding.left.calc_percent(parent_width);
+       m_padding.right = m_css_padding.right.calc_percent(parent_width);
+
+       m_borders.left  = m_css_borders.left.width.calc_percent(parent_width);
+       m_borders.right = m_css_borders.right.width.calc_percent(parent_width);
+
+       m_margins.left  = m_css_margins.left.calc_percent(parent_width);
+       m_margins.right = m_css_margins.right.calc_percent(parent_width);
+
+       m_margins.top           = m_css_margins.top.calc_percent(parent_width);
+       m_margins.bottom        = m_css_margins.bottom.calc_percent(parent_width);
+
+       m_padding.top           = m_css_padding.top.calc_percent(parent_width);
+       m_padding.bottom        = m_css_padding.bottom.calc_percent(parent_width);
+}
+
+void litehtml::html_tag::calc_auto_margins(int parent_width)
+{
+       if (get_element_position() != element_position_absolute && (m_display == display_block || m_display == display_table))
+       {
+               if (m_css_margins.left.is_predefined() && m_css_margins.right.is_predefined())
+               {
+                       int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right;
+                       if (el_width <= parent_width)
+                       {
+                               m_margins.left = (parent_width - el_width) / 2;
+                               m_margins.right = (parent_width - el_width) - m_margins.left;
+                       }
+                       else
+                       {
+                               m_margins.left = 0;
+                               m_margins.right = 0;
+                       }
+               }
+               else if (m_css_margins.left.is_predefined() && !m_css_margins.right.is_predefined())
+               {
+                       int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right + m_margins.right;
+                       m_margins.left = parent_width - el_width;
+                       if (m_margins.left < 0) m_margins.left = 0;
+               }
+               else if (!m_css_margins.left.is_predefined() && m_css_margins.right.is_predefined())
+               {
+                       int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right + m_margins.left;
+                       m_margins.right = parent_width - el_width;
+                       if (m_margins.right < 0) m_margins.right = 0;
+               }
+       }
+}
+
+void litehtml::html_tag::parse_attributes()
+{
+       for(auto& el : m_children)
+       {
+               el->parse_attributes();
+       }
+}
+
+void litehtml::html_tag::get_text( tstring& text )
+{
+       for (auto& el : m_children)
+       {
+               el->get_text(text);
+       }
+}
+
+bool litehtml::html_tag::is_body()  const
+{
+       return false;
+}
+
+void litehtml::html_tag::set_data( const tchar_t* data )
+{
+
+}
+
+void litehtml::html_tag::get_inline_boxes( position::vector& boxes )
+{
+       litehtml::box* old_box = 0;
+       position pos;
+       for(auto& el : m_children)
+       {
+               if(!el->skip())
+               {
+                       if(el->m_box)
+                       {
+                               if(el->m_box != old_box)
+                               {
+                                       if(old_box)
+                                       {
+                                               if(boxes.empty())
+                                               {
+                                                       pos.x           -= m_padding.left + m_borders.left;
+                                                       pos.width       += m_padding.left + m_borders.left;
+                                               }
+                                               boxes.push_back(pos);
+                                       }
+                                       old_box         = el->m_box;
+                                       pos.x           = el->left() + el->margin_left();
+                                       pos.y           = el->top() - m_padding.top - m_borders.top;
+                                       pos.width       = 0;
+                                       pos.height      = 0;
+                               }
+                               pos.width       = el->right() - pos.x - el->margin_right() - el->margin_left();
+                               pos.height      = std::max(pos.height, el->height() + m_padding.top + m_padding.bottom + m_borders.top + m_borders.bottom);
+                       } else if(el->get_display() == display_inline)
+                       {
+                               position::vector sub_boxes;
+                               el->get_inline_boxes(sub_boxes);
+                               if(!sub_boxes.empty())
+                               {
+                                       sub_boxes.rbegin()->width += el->margin_right();
+                                       if(boxes.empty())
+                                       {
+                                               if(m_padding.left + m_borders.left > 0)
+                                               {
+                                                       position padding_box = (*sub_boxes.begin());
+                                                       padding_box.x           -= m_padding.left + m_borders.left + el->margin_left();
+                                                       padding_box.width       = m_padding.left + m_borders.left + el->margin_left();
+                                                       boxes.push_back(padding_box);
+                                               }
+                                       }
+
+                                       sub_boxes.rbegin()->width += el->margin_right();
+
+                                       boxes.insert(boxes.end(), sub_boxes.begin(), sub_boxes.end());
+                               }
+                       }
+               }
+       }
+       if(pos.width || pos.height)
+       {
+               if(boxes.empty())
+               {
+                       pos.x           -= m_padding.left + m_borders.left;
+                       pos.width       += m_padding.left + m_borders.left;
+               }
+               boxes.push_back(pos);
+       }
+       if(!boxes.empty())
+       {
+               if(m_padding.right + m_borders.right > 0)
+               {
+                       boxes.back().width += m_padding.right + m_borders.right;
+               }
+       }
+}
+
+bool litehtml::html_tag::on_mouse_over()
+{
+       bool ret = false;
+
+       element::ptr el = shared_from_this();
+       while(el)
+       {
+               if(el->set_pseudo_class(_t("hover"), true))
+               {
+                       ret = true;
+               }
+               el = el->parent();
+       }
+
+       return ret;
+}
+
+bool litehtml::html_tag::find_styles_changes( position::vector& redraw_boxes, int x, int y )
+{
+       if(m_display == display_inline_text)
+       {
+               return false;
+       }
+
+       bool ret = false;
+       bool apply = false;
+       for (used_selector::vector::iterator iter = m_used_styles.begin(); iter != m_used_styles.end() && !apply; iter++)
+       {
+               if((*iter)->m_selector->is_media_valid())
+               {
+                       int res = select(*((*iter)->m_selector), true);
+                       if( (res == select_no_match && (*iter)->m_used) || (res == select_match && !(*iter)->m_used) )
+                       {
+                               apply = true;
+                       }
+               }
+       }
+
+       if(apply)
+       {
+               if(m_display == display_inline ||  m_display == display_table_row)
+               {
+                       position::vector boxes;
+                       get_inline_boxes(boxes);
+                       for(position::vector::iterator pos = boxes.begin(); pos != boxes.end(); pos++)
+                       {
+                               pos->x  += x;
+                               pos->y  += y;
+                               redraw_boxes.push_back(*pos);
+                       }
+               } else
+               {
+                       position pos = m_pos;
+                       if(m_el_position != element_position_fixed)
+                       {
+                               pos.x += x;
+                               pos.y += y;
+                       }
+                       pos += m_padding;
+                       pos += m_borders;
+                       redraw_boxes.push_back(pos);
+               }
+
+               ret = true;
+               refresh_styles();
+               parse_styles();
+       }
+       for (auto& el : m_children)
+       {
+               if(!el->skip())
+               {
+                       if(m_el_position != element_position_fixed)
+                       {
+                               if(el->find_styles_changes(redraw_boxes, x + m_pos.x, y + m_pos.y))
+                               {
+                                       ret = true;
+                               }
+                       } else
+                       {
+                               if(el->find_styles_changes(redraw_boxes, m_pos.x, m_pos.y))
+                               {
+                                       ret = true;
+                               }
+                       }
+               }
+       }
+       return ret;
+}
+
+bool litehtml::html_tag::on_mouse_leave()
+{
+       bool ret = false;
+
+       element::ptr el = shared_from_this();
+       while(el)
+       {
+               if(el->set_pseudo_class(_t("hover"), false))
+               {
+                       ret = true;
+               }
+               if(el->set_pseudo_class(_t("active"), false))
+               {
+                       ret = true;
+               }
+               el = el->parent();
+       }
+
+       return ret;
+}
+
+bool litehtml::html_tag::on_lbutton_down()
+{
+    bool ret = false;
+
+       element::ptr el = shared_from_this();
+    while (el)
+    {
+        if (el->set_pseudo_class(_t("active"), true))
+        {
+            ret = true;
+        }
+        el = el->parent();
+    }
+
+    return ret;
+}
+
+bool litehtml::html_tag::on_lbutton_up()
+{
+       bool ret = false;
+
+       element::ptr el = shared_from_this();
+    while (el)
+    {
+        if (el->set_pseudo_class(_t("active"), false))
+        {
+            ret = true;
+        }
+        el = el->parent();
+    }
+
+    on_click();
+
+       return ret;
+}
+
+void litehtml::html_tag::on_click()
+{
+       if (have_parent())
+       {
+               element::ptr el_parent = parent();
+               if (el_parent)
+               {
+                       el_parent->on_click();
+               }
+       }
+}
+
+const litehtml::tchar_t* litehtml::html_tag::get_cursor()
+{
+       return get_style_property(_t("cursor"), true, 0);
+}
+
+static const int font_size_table[8][7] =
+{
+       { 9,    9,     9,     9,    11,    14,    18},
+       { 9,    9,     9,    10,    12,    15,    20},
+       { 9,    9,     9,    11,    13,    17,    22},
+       { 9,    9,    10,    12,    14,    18,    24},
+       { 9,    9,    10,    13,    16,    20,    26},
+       { 9,    9,    11,    14,    17,    21,    28},
+       { 9,   10,    12,    15,    17,    23,    30},
+       { 9,   10,    13,    16,    18,    24,    32}
+};
+
+
+void litehtml::html_tag::init_font()
+{
+       // initialize font size
+       const tchar_t* str = get_style_property(_t("font-size"), false, 0);
+
+       int parent_sz = 0;
+       int doc_font_size = get_document()->container()->get_default_font_size();
+       element::ptr el_parent = parent();
+       if (el_parent)
+       {
+               parent_sz = el_parent->get_font_size();
+       } else
+       {
+               parent_sz = doc_font_size;
+       }
+
+
+       if(!str)
+       {
+               m_font_size = parent_sz;
+       } else
+       {
+               m_font_size = parent_sz;
+
+               css_length sz;
+               sz.fromString(str, font_size_strings);
+               if(sz.is_predefined())
+               {
+                       int idx_in_table = doc_font_size - 9;
+                       if(idx_in_table >= 0 && idx_in_table <= 7)
+                       {
+                               if(sz.predef() >= fontSize_xx_small && sz.predef() <= fontSize_xx_large)
+                               {
+                                       m_font_size = font_size_table[idx_in_table][sz.predef()];
+                               } else
+                               {
+                                       m_font_size = doc_font_size;
+                               }
+                       } else                  
+                       {
+                               switch(sz.predef())
+                               {
+                               case fontSize_xx_small:
+                                       m_font_size = doc_font_size * 3 / 5;
+                                       break;
+                               case fontSize_x_small:
+                                       m_font_size = doc_font_size * 3 / 4;
+                                       break;
+                               case fontSize_small:
+                                       m_font_size = doc_font_size * 8 / 9;
+                                       break;
+                               case fontSize_large:
+                                       m_font_size = doc_font_size * 6 / 5;
+                                       break;
+                               case fontSize_x_large:
+                                       m_font_size = doc_font_size * 3 / 2;
+                                       break;
+                               case fontSize_xx_large:
+                                       m_font_size = doc_font_size * 2;
+                                       break;
+                               default:
+                                       m_font_size = doc_font_size;
+                                       break;
+                               }
+                       }
+               } else
+               {
+                       if(sz.units() == css_units_percentage)
+                       {
+                               m_font_size = sz.calc_percent(parent_sz);
+                       } else if(sz.units() == css_units_none)
+                       {
+                               m_font_size = parent_sz;
+                       } else
+                       {
+                               m_font_size = get_document()->cvt_units(sz, parent_sz);
+                       }
+               }
+       }
+
+       // initialize font
+       const tchar_t* name                     = get_style_property(_t("font-family"),         true,   _t("inherit"));
+       const tchar_t* weight           = get_style_property(_t("font-weight"),         true,   _t("normal"));
+       const tchar_t* style            = get_style_property(_t("font-style"),          true,   _t("normal"));
+       const tchar_t* decoration       = get_style_property(_t("text-decoration"),     true,   _t("none"));
+
+       m_font = get_document()->get_font(name, m_font_size, weight, style, decoration, &m_font_metrics);
+}
+
+bool litehtml::html_tag::is_break() const
+{
+       return false;
+}
+
+void litehtml::html_tag::set_tagName( const tchar_t* tag )
+{
+       tstring s_val = tag;
+       std::locale lc = std::locale::global(std::locale::classic());
+       for(size_t i = 0; i < s_val.length(); i++)
+       {
+               s_val[i] = std::tolower(s_val[i], lc);
+       }
+       m_tag = s_val;
+}
+
+void litehtml::html_tag::draw_background( uint_ptr hdc, int x, int y, const position* clip )
+{
+       position pos = m_pos;
+       pos.x   += x;
+       pos.y   += y;
+
+       position el_pos = pos;
+       el_pos += m_padding;
+       el_pos += m_borders;
+
+       if(m_display != display_inline && m_display != display_table_row)
+       {
+               if(el_pos.does_intersect(clip))
+               {
+                       const background* bg = get_background();
+                       if(bg)
+                       {
+                               background_paint bg_paint;
+                               init_background_paint(pos, bg_paint, bg);
+
+                               get_document()->container()->draw_background(hdc, bg_paint);
+                       }
+                       position border_box = pos;
+                       border_box += m_padding;
+                       border_box += m_borders;
+
+                       borders bdr = m_css_borders;
+                       bdr.radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
+
+                       get_document()->container()->draw_borders(hdc, bdr, border_box, have_parent() ? false : true);
+               }
+       } else
+       {
+               const background* bg = get_background();
+
+               position::vector boxes;
+               get_inline_boxes(boxes);
+
+               background_paint bg_paint;
+               position content_box;
+
+               for(position::vector::iterator box = boxes.begin(); box != boxes.end(); box++)
+               {
+                       box->x  += x;
+                       box->y  += y;
+
+                       if(box->does_intersect(clip))
+                       {
+                               content_box = *box;
+                               content_box -= m_borders;
+                               content_box -= m_padding;
+
+                               if(bg)
+                               {
+                                       init_background_paint(content_box, bg_paint, bg);
+                               }
+
+                               css_borders bdr;
+
+                               // set left borders radius for the first box
+                               if(box == boxes.begin())
+                               {
+                                       bdr.radius.bottom_left_x        = m_css_borders.radius.bottom_left_x;
+                                       bdr.radius.bottom_left_y        = m_css_borders.radius.bottom_left_y;
+                                       bdr.radius.top_left_x           = m_css_borders.radius.top_left_x;
+                                       bdr.radius.top_left_y           = m_css_borders.radius.top_left_y;
+                               }
+
+                               // set right borders radius for the last box
+                               if(box == boxes.end() - 1)
+                               {
+                                       bdr.radius.bottom_right_x       = m_css_borders.radius.bottom_right_x;
+                                       bdr.radius.bottom_right_y       = m_css_borders.radius.bottom_right_y;
+                                       bdr.radius.top_right_x          = m_css_borders.radius.top_right_x;
+                                       bdr.radius.top_right_y          = m_css_borders.radius.top_right_y;
+                               }
+
+                               
+                               bdr.top         = m_css_borders.top;
+                               bdr.bottom      = m_css_borders.bottom;
+                               if(box == boxes.begin())
+                               {
+                                       bdr.left        = m_css_borders.left;
+                               }
+                               if(box == boxes.end() - 1)
+                               {
+                                       bdr.right       = m_css_borders.right;
+                               }
+
+
+                               if(bg)
+                               {
+                                       bg_paint.border_radius = bdr.radius.calc_percents(bg_paint.border_box.width, bg_paint.border_box.width);
+                                       get_document()->container()->draw_background(hdc, bg_paint);
+                               }
+                               borders b = bdr;
+                               b.radius = bdr.radius.calc_percents(box->width, box->height);
+                               get_document()->container()->draw_borders(hdc, b, *box, false);
+                       }
+               }
+       }
+}
+
+int litehtml::html_tag::render_inline(const element::ptr &container, int max_width)
+{
+       int ret_width = 0;
+       int rw = 0;
+
+       white_space ws = get_white_space();
+       bool skip_spaces = false;
+       if (ws == white_space_normal ||
+               ws == white_space_nowrap ||
+               ws == white_space_pre_line)
+       {
+               skip_spaces = true;
+       }
+       bool was_space = false;
+
+       for (auto& el : m_children)
+       {
+               // skip spaces to make rendering a bit faster
+               if (skip_spaces)
+               {
+                       if (el->is_white_space())
+                       {
+                               if (was_space)
+                               {
+                                       el->skip(true);
+                                       continue;
+                               }
+                               else
+                               {
+                                       was_space = true;
+                               }
+                       }
+                       else
+                       {
+                               was_space = false;
+                       }
+               }
+
+               rw = container->place_element( el, max_width );
+               if(rw > ret_width)
+               {
+                       ret_width = rw;
+               }
+       }
+       return ret_width;
+}
+
+int litehtml::html_tag::place_element(const element::ptr &el, int max_width)
+{
+       if(el->get_display() == display_none) return 0;
+
+       if(el->get_display() == display_inline)
+       {
+               return el->render_inline(shared_from_this(), max_width);
+       }
+
+       element_position el_position = el->get_element_position();
+
+       if(el_position == element_position_absolute || el_position == element_position_fixed)
+       {
+               int line_top = 0;
+               if(!m_boxes.empty())
+               {
+                       if(m_boxes.back()->get_type() == box_line)
+                       {
+                               line_top = m_boxes.back()->top();
+                               if(!m_boxes.back()->is_empty())
+                               {
+                                       line_top += line_height();
+                               }
+                       } else
+                       {
+                               line_top = m_boxes.back()->bottom();
+                       }
+               }
+
+               el->render(0, line_top, max_width);
+               el->m_pos.x     += el->content_margins_left();
+               el->m_pos.y     += el->content_margins_top();
+
+               return 0;
+       }
+
+       int ret_width = 0;
+
+       switch(el->get_float())
+       {
+       case float_left:
+               {
+                       int line_top = 0;
+                       if(!m_boxes.empty())
+                       {
+                               if(m_boxes.back()->get_type() == box_line)
+                               {
+                                       line_top = m_boxes.back()->top();
+                               } else
+                               {
+                                       line_top = m_boxes.back()->bottom();
+                               }
+                       }
+                       line_top                = get_cleared_top(el, line_top);
+                       int line_left   = 0;
+                       int line_right  = max_width;
+                       get_line_left_right(line_top, max_width, line_left, line_right);
+
+                       el->render(line_left, line_top, line_right);
+                       if(el->right() > line_right)
+                       {
+                               int new_top = find_next_line_top(el->top(), el->width(), max_width);
+                               el->m_pos.x = get_line_left(new_top) + el->content_margins_left();
+                               el->m_pos.y = new_top + el->content_margins_top();
+                       }
+                       add_float(el, 0, 0);
+                       ret_width = fix_line_width(max_width, float_left);
+                       if(!ret_width)
+                       {
+                               ret_width = el->right();
+                       }
+               }
+               break;
+       case float_right:
+               {
+                       int line_top = 0;
+                       if(!m_boxes.empty())
+                       {
+                               if(m_boxes.back()->get_type() == box_line)
+                               {
+                                       line_top = m_boxes.back()->top();
+                               } else
+                               {
+                                       line_top = m_boxes.back()->bottom();
+                               }
+                       }
+                       line_top                = get_cleared_top(el, line_top);
+                       int line_left   = 0;
+                       int line_right  = max_width;
+                       get_line_left_right(line_top, max_width, line_left, line_right);
+
+                       el->render(0, line_top, line_right);
+
+                       if(line_left + el->width() > line_right)
+                       {
+                               int new_top = find_next_line_top(el->top(), el->width(), max_width);
+                               el->m_pos.x = get_line_right(new_top, max_width) - el->width() + el->content_margins_left();
+                               el->m_pos.y = new_top + el->content_margins_top();
+                       } else
+                       {
+                               el->m_pos.x = line_right - el->width() + el->content_margins_left();
+                       }
+                       add_float(el, 0, 0);
+                       ret_width = fix_line_width(max_width, float_right);
+
+                       if(!ret_width)
+                       {
+                               line_left       = 0;
+                               line_right      = max_width;
+                               get_line_left_right(line_top, max_width, line_left, line_right);
+
+                               ret_width = ret_width + (max_width - line_right);
+                       }
+               }
+               break;
+       default:
+               {
+                       line_context line_ctx;
+                       line_ctx.top = 0;
+                       if (!m_boxes.empty())
+                       {
+                               line_ctx.top = m_boxes.back()->top();
+                       }
+                       line_ctx.left = 0;
+                       line_ctx.right = max_width;
+                       line_ctx.fix_top();
+                       get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
+
+                       switch(el->get_display())
+                       {
+                       case display_inline_block:
+                               ret_width = el->render(line_ctx.left, line_ctx.top, line_ctx.right);
+                               break;
+                       case display_block:             
+                               if(el->is_replaced() || el->is_floats_holder())
+                               {
+                                       element::ptr el_parent = el->parent();
+                                       el->m_pos.width = el->get_css_width().calc_percent(line_ctx.right - line_ctx.left);
+                                       el->m_pos.height = el->get_css_height().calc_percent(el_parent ? el_parent->m_pos.height : 0);
+                               }
+                               el->calc_outlines(line_ctx.right - line_ctx.left);
+                               break;
+                       case display_inline_text:
+                               {
+                                       litehtml::size sz;
+                                       el->get_content_size(sz, line_ctx.right);
+                                       el->m_pos = sz;
+                               }
+                               break;
+                       default:
+                               ret_width = 0;
+                               break;
+                       }
+
+                       bool add_box = true;
+                       if(!m_boxes.empty())
+                       {
+                               if(m_boxes.back()->can_hold(el, m_white_space))
+                               {
+                                       add_box = false;
+                               }
+                       }
+                       if(add_box)
+                       {
+                               new_box(el, max_width, line_ctx);
+                       } else if(!m_boxes.empty())
+                       {
+                               line_ctx.top = m_boxes.back()->top();
+                       }
+
+                       if (line_ctx.top != line_ctx.calculatedTop)
+                       {
+                               line_ctx.left = 0;
+                               line_ctx.right = max_width;
+                               line_ctx.fix_top();
+                               get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
+                       }
+
+                       if(!el->is_inline_box())
+                       {
+                               if(m_boxes.size() == 1)
+                               {
+                                       if(collapse_top_margin())
+                                       {
+                                               int shift = el->margin_top();
+                                               if(shift >= 0)
+                                               {
+                                                       line_ctx.top -= shift;
+                                                       m_boxes.back()->y_shift(-shift);
+                                               }
+                                       }
+                               } else
+                               {
+                                       int shift = 0;
+                                       int prev_margin = m_boxes[m_boxes.size() - 2]->bottom_margin();
+
+                                       if(prev_margin > el->margin_top())
+                                       {
+                                               shift = el->margin_top();
+                                       } else
+                                       {
+                                               shift = prev_margin;
+                                       }
+                                       if(shift >= 0)
+                                       {
+                                               line_ctx.top -= shift;
+                                               m_boxes.back()->y_shift(-shift);
+                                       }
+                               }
+                       }
+
+                       switch(el->get_display())
+                       {
+                       case display_table:
+                       case display_list_item:
+                               ret_width = el->render(line_ctx.left, line_ctx.top, line_ctx.width());
+                               break;
+                       case display_block:
+                       case display_table_cell:
+                       case display_table_caption:
+                       case display_table_row:
+                               if(el->is_replaced() || el->is_floats_holder())
+                               {
+                                       ret_width = el->render(line_ctx.left, line_ctx.top, line_ctx.width()) + line_ctx.left + (max_width - line_ctx.right);
+                               } else
+                               {
+                                       ret_width = el->render(0, line_ctx.top, max_width);
+                               }
+                               break;
+                       default:
+                               ret_width = 0;
+                               break;
+                       }
+
+                       m_boxes.back()->add_element(el);
+
+                       if(el->is_inline_box() && !el->skip())
+                       {
+                               ret_width = el->right() + (max_width - line_ctx.right);
+                       }
+               }
+               break;
+       }
+
+       return ret_width;
+}
+
+bool litehtml::html_tag::set_pseudo_class( const tchar_t* pclass, bool add )
+{
+       bool ret = false;
+       if(add)
+       {
+               if(std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), pclass) == m_pseudo_classes.end())
+               {
+                       m_pseudo_classes.push_back(pclass);
+                       ret = true;
+               }
+       } else
+       {
+               string_vector::iterator pi = std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), pclass);
+               if(pi != m_pseudo_classes.end())
+               {
+                       m_pseudo_classes.erase(pi);
+                       ret = true;
+               }
+       }
+       return ret;
+}
+
+bool litehtml::html_tag::set_class( const tchar_t* pclass, bool add )
+{
+       string_vector classes;
+       bool changed = false;
+
+       split_string( pclass, classes, _t(" ") );
+
+       if(add)
+       {
+               for( auto & _class : classes  )
+               {
+                       if(std::find(m_class_values.begin(), m_class_values.end(), _class) == m_class_values.end())
+                       {
+                               m_class_values.push_back( std::move( _class ) );
+                               changed = true;
+                       }
+               }
+       } else
+       {
+               for( const auto & _class : classes )
+               {
+                       auto end = std::remove(m_class_values.begin(), m_class_values.end(), _class);
+
+                       if(end != m_class_values.end())
+                       {
+                               m_class_values.erase(end, m_class_values.end());
+                               changed = true;
+                       }
+               }
+       }
+
+       if( changed )
+       {
+               tstring class_string;
+               join_string(class_string, m_class_values, _t(" "));
+               set_attr(_t("class"), class_string.c_str());
+
+               return true;
+       }
+       else
+       {
+               return false;
+       }
+
+}
+
+int litehtml::html_tag::line_height() const
+{
+       return m_line_height;
+}
+
+bool litehtml::html_tag::is_replaced() const
+{
+       return false;
+}
+
+int litehtml::html_tag::finish_last_box(bool end_of_render)
+{
+       int line_top = 0;
+
+       if(!m_boxes.empty())
+       {
+               m_boxes.back()->finish(end_of_render);
+
+               if(m_boxes.back()->is_empty())
+               {
+                       line_top = m_boxes.back()->top();
+                       m_boxes.pop_back();
+               }
+
+               if(!m_boxes.empty())
+               {
+                       line_top = m_boxes.back()->bottom();
+               }
+       }
+       return line_top;
+}
+
+int litehtml::html_tag::new_box(const element::ptr &el, int max_width, line_context& line_ctx)
+{
+       line_ctx.top = get_cleared_top(el, finish_last_box());
+
+       line_ctx.left = 0;
+       line_ctx.right = max_width;
+       line_ctx.fix_top();
+       get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
+
+       if(el->is_inline_box() || el->is_floats_holder())
+       {
+               if (el->width() > line_ctx.right - line_ctx.left)
+               {
+                       line_ctx.top = find_next_line_top(line_ctx.top, el->width(), max_width);
+                       line_ctx.left = 0;
+                       line_ctx.right = max_width;
+                       line_ctx.fix_top();
+                       get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
+               }
+       }
+
+       int first_line_margin = 0;
+       if(m_boxes.empty() && m_list_style_type != list_style_type_none && m_list_style_position == list_style_position_inside)
+       {
+               int sz_font = get_font_size();
+               first_line_margin = sz_font;
+       }
+
+       if(el->is_inline_box())
+       {
+               int text_indent = 0;
+               if(m_css_text_indent.val() != 0)
+               {
+                       bool line_box_found = false;
+                       for(box::vector::iterator iter = m_boxes.begin(); iter != m_boxes.end(); iter++)
+                       {
+                               if((*iter)->get_type() == box_line)
+                               {
+                                       line_box_found = true;
+                                       break;
+                               }
+                       }
+                       if(!line_box_found)
+                       {
+                               text_indent = m_css_text_indent.calc_percent(max_width);
+                       }
+               }
+
+               font_metrics fm;
+               get_font(&fm);
+               m_boxes.emplace_back(std::unique_ptr<line_box>(new line_box(line_ctx.top, line_ctx.left + first_line_margin + text_indent, line_ctx.right, line_height(), fm, m_text_align)));
+       } else
+       {
+               m_boxes.emplace_back(std::unique_ptr<block_box>(new block_box(line_ctx.top, line_ctx.left, line_ctx.right)));
+       }
+
+       return line_ctx.top;
+}
+
+int litehtml::html_tag::get_cleared_top(const element::ptr &el, int line_top) const
+{
+       switch(el->get_clear())
+       {
+       case clear_left:
+               {
+                       int fh = get_left_floats_height();
+                       if(fh && fh > line_top)
+                       {
+                               line_top = fh;
+                       }
+               }
+               break;
+       case clear_right:
+               {
+                       int fh = get_right_floats_height();
+                       if(fh && fh > line_top)
+                       {
+                               line_top = fh;
+                       }
+               }
+               break;
+       case clear_both:
+               {
+                       int fh = get_floats_height();
+                       if(fh && fh > line_top)
+                       {
+                               line_top = fh;
+                       }
+               }
+               break;
+       default:
+               if(el->get_float() != float_none)
+               {
+                       int fh = get_floats_height(el->get_float());
+                       if(fh && fh > line_top)
+                       {
+                               line_top = fh;
+                       }
+               }
+               break;
+       }
+       return line_top;
+}
+
+litehtml::style_display litehtml::html_tag::get_display() const
+{
+       return m_display;
+}
+
+litehtml::element_float litehtml::html_tag::get_float() const
+{
+       return m_float;
+}
+
+bool litehtml::html_tag::is_floats_holder() const
+{
+       if(     m_display == display_inline_block || 
+               m_display == display_table_cell || 
+               !have_parent() ||
+               is_body() || 
+               m_float != float_none ||
+               m_el_position == element_position_absolute ||
+               m_el_position == element_position_fixed ||
+               m_overflow > overflow_visible)
+       {
+               return true;
+       }
+       return false;
+}
+
+bool litehtml::html_tag::is_first_child_inline(const element::ptr& el) const
+{
+       if(!m_children.empty())
+       {
+               for (const auto& this_el : m_children)
+               {
+                       if (!this_el->is_white_space())
+                       {
+                               if (el == this_el)
+                               {
+                                       return true;
+                               }
+                               if (this_el->get_display() == display_inline)
+                               {
+                                       if (this_el->have_inline_child())
+                                       {
+                                               return false;
+                                       }
+                               } else
+                               {
+                                       return false;
+                               }
+                       }
+               }
+       }
+       return false;
+}
+
+bool litehtml::html_tag::is_last_child_inline(const element::ptr& el)
+{
+       if(!m_children.empty())
+       {
+               for (auto this_el = m_children.rbegin(); this_el < m_children.rend(); ++this_el)
+               {
+                       if (!(*this_el)->is_white_space())
+                       {
+                               if (el == (*this_el))
+                               {
+                                       return true;
+                               }
+                               if ((*this_el)->get_display() == display_inline)
+                               {
+                                       if ((*this_el)->have_inline_child())
+                                       {
+                                               return false;
+                                       }
+                               } else
+                               {
+                                       return false;
+                               }
+                       }
+               }
+       }
+       return false;
+}
+
+litehtml::white_space litehtml::html_tag::get_white_space() const
+{
+       return m_white_space;
+}
+
+litehtml::vertical_align litehtml::html_tag::get_vertical_align() const
+{
+       return m_vertical_align;
+}
+
+litehtml::css_length litehtml::html_tag::get_css_left() const
+{
+       return m_css_offsets.left;
+}
+
+litehtml::css_length litehtml::html_tag::get_css_right() const
+{
+       return m_css_offsets.right;
+}
+
+litehtml::css_length litehtml::html_tag::get_css_top() const
+{
+       return m_css_offsets.top;
+}
+
+litehtml::css_length litehtml::html_tag::get_css_bottom() const
+{
+       return m_css_offsets.bottom;
+}
+
+
+litehtml::css_offsets litehtml::html_tag::get_css_offsets() const
+{
+       return m_css_offsets;
+}
+
+litehtml::element_clear litehtml::html_tag::get_clear() const
+{
+       return m_clear;
+}
+
+litehtml::css_length litehtml::html_tag::get_css_width() const
+{
+       return m_css_width;
+}
+
+litehtml::css_length litehtml::html_tag::get_css_height() const
+{
+       return m_css_height;
+}
+
+size_t litehtml::html_tag::get_children_count() const
+{
+       return m_children.size();
+}
+
+litehtml::element::ptr litehtml::html_tag::get_child( int idx ) const
+{
+       return m_children[idx];
+}
+
+void litehtml::html_tag::set_css_width( css_length& w )
+{
+       m_css_width = w;
+}
+
+void litehtml::html_tag::apply_vertical_align()
+{
+       if(!m_boxes.empty())
+       {
+               int add = 0;
+               int content_height      = m_boxes.back()->bottom();
+
+               if(m_pos.height > content_height)
+               {
+                       switch(m_vertical_align)
+                       {
+                       case va_middle:
+                               add = (m_pos.height - content_height) / 2;
+                               break;
+                       case va_bottom:
+                               add = m_pos.height - content_height;
+                               break;
+                       default:
+                               add = 0;
+                               break;
+                       }
+               }
+
+               if(add)
+               {
+                       for(size_t i = 0; i < m_boxes.size(); i++)
+                       {
+                               m_boxes[i]->y_shift(add);
+                       }
+               }
+       }
+}
+
+litehtml::element_position litehtml::html_tag::get_element_position(css_offsets* offsets) const
+{
+       if(offsets && m_el_position != element_position_static)
+       {
+               *offsets = m_css_offsets;
+       }
+       return m_el_position;
+}
+
+void litehtml::html_tag::init_background_paint(position pos, background_paint &bg_paint, const background* bg)
+{
+       if(!bg) return;
+
+       bg_paint = *bg;
+       position content_box    = pos;
+       position padding_box    = pos;
+       padding_box += m_padding;
+       position border_box             = padding_box;
+       border_box += m_borders;
+
+       switch(bg->m_clip)
+       {
+       case litehtml::background_box_padding:
+               bg_paint.clip_box = padding_box;
+               break;
+       case litehtml::background_box_content:
+               bg_paint.clip_box = content_box;
+               break;
+       default:
+               bg_paint.clip_box = border_box;
+               break;
+       }
+
+       switch(bg->m_origin)
+       {
+       case litehtml::background_box_border:
+               bg_paint.origin_box = border_box;
+               break;
+       case litehtml::background_box_content:
+               bg_paint.origin_box = content_box;
+               break;
+       default:
+               bg_paint.origin_box = padding_box;
+               break;
+       }
+
+       if(!bg_paint.image.empty())
+       {
+               get_document()->container()->get_image_size(bg_paint.image.c_str(), bg_paint.baseurl.c_str(), bg_paint.image_size);
+               if(bg_paint.image_size.width && bg_paint.image_size.height)
+               {
+                       litehtml::size img_new_sz = bg_paint.image_size;
+                       double img_ar_width             = (double) bg_paint.image_size.width / (double) bg_paint.image_size.height;
+                       double img_ar_height    = (double) bg_paint.image_size.height / (double) bg_paint.image_size.width;
+
+
+                       if(bg->m_position.width.is_predefined())
+                       {
+                               switch(bg->m_position.width.predef())
+                               {
+                               case litehtml::background_size_contain:
+                                       if( (int) ((double) bg_paint.origin_box.width * img_ar_height) <= bg_paint.origin_box.height )
+                                       {
+                                               img_new_sz.width = bg_paint.origin_box.width;
+                                               img_new_sz.height       = (int) ((double) bg_paint.origin_box.width * img_ar_height);
+                                       } else
+                                       {
+                                               img_new_sz.height = bg_paint.origin_box.height;
+                                               img_new_sz.width        = (int) ((double) bg_paint.origin_box.height * img_ar_width);
+                                       }
+                                       break;
+                               case litehtml::background_size_cover:
+                                       if( (int) ((double) bg_paint.origin_box.width * img_ar_height) >= bg_paint.origin_box.height )
+                                       {
+                                               img_new_sz.width = bg_paint.origin_box.width;
+                                               img_new_sz.height       = (int) ((double) bg_paint.origin_box.width * img_ar_height);
+                                       } else
+                                       {
+                                               img_new_sz.height = bg_paint.origin_box.height;
+                                               img_new_sz.width        = (int) ((double) bg_paint.origin_box.height * img_ar_width);
+                                       }
+                                       break;
+                                       break;
+                               case litehtml::background_size_auto:
+                                       if(!bg->m_position.height.is_predefined())
+                                       {
+                                               img_new_sz.height       = bg->m_position.height.calc_percent(bg_paint.origin_box.height);
+                                               img_new_sz.width        = (int) ((double) img_new_sz.height * img_ar_width);
+                                       }
+                                       break;
+                               }
+                       } else
+                       {
+                               img_new_sz.width = bg->m_position.width.calc_percent(bg_paint.origin_box.width);
+                               if(bg->m_position.height.is_predefined())
+                               {
+                                       img_new_sz.height = (int) ((double) img_new_sz.width * img_ar_height);
+                               } else
+                               {
+                                       img_new_sz.height = bg->m_position.height.calc_percent(bg_paint.origin_box.height);
+                               }
+                       }
+
+                       bg_paint.image_size = img_new_sz;
+                       bg_paint.position_x = bg_paint.origin_box.x + (int) bg->m_position.x.calc_percent(bg_paint.origin_box.width - bg_paint.image_size.width);
+                       bg_paint.position_y = bg_paint.origin_box.y + (int) bg->m_position.y.calc_percent(bg_paint.origin_box.height - bg_paint.image_size.height);
+               }
+
+       }
+       bg_paint.border_radius  = m_css_borders.radius.calc_percents(border_box.width, border_box.height);;
+       bg_paint.border_box             = border_box;
+       bg_paint.is_root                = have_parent() ? false : true;
+}
+
+litehtml::visibility litehtml::html_tag::get_visibility() const
+{
+       return m_visibility;
+}
+
+void litehtml::html_tag::draw_list_marker( uint_ptr hdc, const position &pos )
+{
+       list_marker lm;
+
+       const tchar_t* list_image = get_style_property(_t("list-style-image"), true, 0);
+       size img_size;
+       if(list_image)
+       {
+               css::parse_css_url(list_image, lm.image);
+               lm.baseurl = get_style_property(_t("list-style-image-baseurl"), true, 0);
+               get_document()->container()->get_image_size(lm.image.c_str(), lm.baseurl, img_size);
+       } else
+       {
+               lm.baseurl = 0;
+       }
+
+
+       int ln_height   = line_height();
+       int sz_font             = get_font_size();
+       lm.pos.x                = pos.x;
+       lm.pos.width    = sz_font       - sz_font * 2 / 3;
+       lm.pos.height   = sz_font       - sz_font * 2 / 3;
+       lm.pos.y                = pos.y         + ln_height / 2 - lm.pos.height / 2;
+
+       if(img_size.width && img_size.height)
+       {
+               if(lm.pos.y + img_size.height > pos.y + pos.height)
+               {
+                       lm.pos.y = pos.y + pos.height - img_size.height;
+               }
+               if(img_size.width > lm.pos.width)
+               {
+                       lm.pos.x -= img_size.width - lm.pos.width;
+               }
+
+               lm.pos.width    = img_size.width;
+               lm.pos.height   = img_size.height;
+       }
+       if(m_list_style_position == list_style_position_outside)
+       {
+               lm.pos.x -= sz_font;
+       }
+
+       lm.color = get_color(_t("color"), true, web_color(0, 0, 0));
+       lm.marker_type = m_list_style_type;
+       get_document()->container()->draw_list_marker(hdc, lm);
+}
+
+void litehtml::html_tag::draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex )
+{
+       if (m_display == display_table || m_display == display_inline_table)
+       {
+               draw_children_table(hdc, x, y, clip, flag, zindex);
+       }
+       else
+       {
+               draw_children_box(hdc, x, y, clip, flag, zindex);
+       }
+}
+
+bool litehtml::html_tag::fetch_positioned()
+{
+       bool ret = false;
+
+       m_positioned.clear();
+
+       litehtml::element_position el_pos;
+
+       for(auto& el : m_children)
+       {
+               el_pos = el->get_element_position();
+               if (el_pos != element_position_static)
+               {
+                       add_positioned(el);
+               }
+               if (!ret && (el_pos == element_position_absolute || el_pos == element_position_fixed))
+               {
+                       ret = true;
+               }
+               if(el->fetch_positioned())
+               {
+                       ret = true;
+               }
+       }
+       return ret;
+}
+
+int litehtml::html_tag::get_zindex() const
+{
+       return m_z_index;
+}
+
+void litehtml::html_tag::render_positioned(render_type rt)
+{
+       position wnd_position;
+       get_document()->container()->get_client_rect(wnd_position);
+
+       element_position el_position;
+       bool process;
+       for (auto& el : m_positioned)
+       {
+               el_position = el->get_element_position();
+
+               process = false;
+               if(el->get_display() != display_none)
+               {
+                       if(el_position == element_position_absolute)
+                       {
+                               if(rt != render_fixed_only)
+                               {
+                                       process = true;
+                               }
+                       } else if(el_position == element_position_fixed)
+                       {
+                               if(rt != render_no_fixed)
+                               {
+                                       process = true;
+                               }
+                       }
+               }
+
+               if(process)
+               {
+                       int parent_height       = 0;
+                       int parent_width        = 0;
+                       int client_x            = 0;
+                       int client_y            = 0;
+                       if(el_position == element_position_fixed)
+                       {
+                               parent_height   = wnd_position.height;
+                               parent_width    = wnd_position.width;
+                               client_x                = wnd_position.left();
+                               client_y                = wnd_position.top();
+                       } else
+                       {
+                               element::ptr el_parent = el->parent();
+                               if(el_parent)
+                               {
+                                       parent_height   = el_parent->height();
+                                       parent_width    = el_parent->width();
+                               }
+                       }
+
+                       css_length      css_left        = el->get_css_left();
+                       css_length      css_right       = el->get_css_right();
+                       css_length      css_top         = el->get_css_top();
+                       css_length      css_bottom      = el->get_css_bottom();
+
+                       bool need_render = false;
+
+                       css_length el_w = el->get_css_width();
+                       css_length el_h = el->get_css_height();
+
+            int new_width = -1;
+            int new_height = -1;
+                       if(el_w.units() == css_units_percentage && parent_width)
+                       {
+                new_width = el_w.calc_percent(parent_width);
+                if(el->m_pos.width != new_width)
+                               {
+                                       need_render = true;
+                    el->m_pos.width = new_width;
+                               }
+                       }
+
+                       if(el_h.units() == css_units_percentage && parent_height)
+                       {
+                new_height = el_h.calc_percent(parent_height);
+                if(el->m_pos.height != new_height)
+                               {
+                                       need_render = true;
+                    el->m_pos.height = new_height;
+                               }
+                       }
+
+                       bool cvt_x = false;
+                       bool cvt_y = false;
+
+                       if(el_position == element_position_fixed)
+                       {
+                               if(!css_left.is_predefined() || !css_right.is_predefined())
+                               {
+                                       if(!css_left.is_predefined() && css_right.is_predefined())
+                                       {
+                                               el->m_pos.x = css_left.calc_percent(parent_width) + el->content_margins_left();
+                                       } else if(css_left.is_predefined() && !css_right.is_predefined())
+                                       {
+                                               el->m_pos.x = parent_width - css_right.calc_percent(parent_width) - el->m_pos.width - el->content_margins_right();
+                                       } else
+                                       {
+                                               el->m_pos.x             = css_left.calc_percent(parent_width) + el->content_margins_left();
+                                               el->m_pos.width = parent_width - css_left.calc_percent(parent_width) - css_right.calc_percent(parent_width) - (el->content_margins_left() + el->content_margins_right());
+                                               need_render = true;
+                                       }
+                               }
+
+                               if(!css_top.is_predefined() || !css_bottom.is_predefined())
+                               {
+                                       if(!css_top.is_predefined() && css_bottom.is_predefined())
+                                       {
+                                               el->m_pos.y = css_top.calc_percent(parent_height) + el->content_margins_top();
+                                       } else if(css_top.is_predefined() && !css_bottom.is_predefined())
+                                       {
+                                               el->m_pos.y = parent_height - css_bottom.calc_percent(parent_height) - el->m_pos.height - el->content_margins_bottom();
+                                       } else
+                                       {
+                                               el->m_pos.y                     = css_top.calc_percent(parent_height) + el->content_margins_top();
+                                               el->m_pos.height        = parent_height - css_top.calc_percent(parent_height) - css_bottom.calc_percent(parent_height) - (el->content_margins_top() + el->content_margins_bottom());
+                                               need_render = true;
+                                       }
+                               }
+                       } else 
+                       {
+                               if(!css_left.is_predefined() || !css_right.is_predefined())
+                               {
+                                       if(!css_left.is_predefined() && css_right.is_predefined())
+                                       {
+                                               el->m_pos.x = css_left.calc_percent(parent_width) + el->content_margins_left() - m_padding.left;
+                                       } else if(css_left.is_predefined() && !css_right.is_predefined())
+                                       {
+                                               el->m_pos.x = m_pos.width + m_padding.right - css_right.calc_percent(parent_width) - el->m_pos.width - el->content_margins_right();
+                                       } else
+                                       {
+                                               el->m_pos.x             = css_left.calc_percent(parent_width) + el->content_margins_left() - m_padding.left;
+                                               el->m_pos.width = m_pos.width + m_padding.left + m_padding.right - css_left.calc_percent(parent_width) - css_right.calc_percent(parent_width) - (el->content_margins_left() + el->content_margins_right());
+                        if (new_width != -1)
+                        {
+                            el->m_pos.x += (el->m_pos.width - new_width) / 2;
+                            el->m_pos.width = new_width;
+                        }
+                        need_render = true;
+                                       }
+                                       cvt_x = true;
+                               }
+
+                               if(!css_top.is_predefined() || !css_bottom.is_predefined())
+                               {
+                                       if(!css_top.is_predefined() && css_bottom.is_predefined())
+                                       {
+                                               el->m_pos.y = css_top.calc_percent(parent_height) + el->content_margins_top() - m_padding.top;
+                                       } else if(css_top.is_predefined() && !css_bottom.is_predefined())
+                                       {
+                                               el->m_pos.y = m_pos.height + m_padding.bottom - css_bottom.calc_percent(parent_height) - el->m_pos.height - el->content_margins_bottom();
+                                       } else
+                                       {
+                                               el->m_pos.y                     = css_top.calc_percent(parent_height) + el->content_margins_top() - m_padding.top;
+                                               el->m_pos.height        = m_pos.height + m_padding.top + m_padding.bottom - css_top.calc_percent(parent_height) - css_bottom.calc_percent(parent_height) - (el->content_margins_top() + el->content_margins_bottom());
+                        if (new_height != -1)
+                        {
+                            el->m_pos.y += (el->m_pos.height - new_height) / 2;
+                            el->m_pos.height = new_height;
+                        }
+                        need_render = true;
+                                       }
+                                       cvt_y = true;
+                               }
+                       }
+
+                       if(cvt_x || cvt_y)
+                       {
+                               int offset_x = 0;
+                               int offset_y = 0;
+                               element::ptr cur_el = el->parent();
+                               element::ptr this_el = shared_from_this();
+                               while(cur_el && cur_el != this_el)
+                               {
+                                       offset_x += cur_el->m_pos.x;
+                                       offset_y += cur_el->m_pos.y;
+                                       cur_el = cur_el->parent();
+                               }
+                               if(cvt_x)       el->m_pos.x -= offset_x;
+                               if(cvt_y)       el->m_pos.y -= offset_y;
+                       }
+
+                       if(need_render)
+                       {
+                               position pos = el->m_pos;
+                               el->render(el->left(), el->top(), el->width(), true);
+                               el->m_pos = pos;
+                       }
+
+                       if(el_position == element_position_fixed)
+                       {
+                               position fixed_pos;
+                               el->get_redraw_box(fixed_pos);
+                               get_document()->add_fixed_box(fixed_pos);
+                       }
+               }
+
+               el->render_positioned();
+       }
+
+       if(!m_positioned.empty())
+       {
+               std::stable_sort(m_positioned.begin(), m_positioned.end(), [](const litehtml::element::ptr& _Left, const litehtml::element::ptr& _Right)
+               {
+                       return (_Left->get_zindex() < _Right->get_zindex());
+               });
+       }
+}
+
+void litehtml::html_tag::draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned )
+{
+       if(!is_visible()) return;
+
+       std::map<int, bool> zindexes;
+       if(with_positioned)
+       {
+               for(elements_vector::iterator i = m_positioned.begin(); i != m_positioned.end(); i++)
+               {
+                       zindexes[(*i)->get_zindex()];
+               }
+
+               for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end(); idx++)
+               {
+                       if(idx->first < 0)
+                       {
+                               draw_children(hdc, x, y, clip, draw_positioned, idx->first);
+                       }
+               }
+       }
+       draw_children(hdc, x, y, clip, draw_block, 0);
+       draw_children(hdc, x, y, clip, draw_floats, 0);
+       draw_children(hdc, x, y, clip, draw_inlines, 0);
+       if(with_positioned)
+       {
+               for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end(); idx++)
+               {
+                       if(idx->first == 0)
+                       {
+                               draw_children(hdc, x, y, clip, draw_positioned, idx->first);
+                       }
+               }
+
+               for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end(); idx++)
+               {
+                       if(idx->first > 0)
+                       {
+                               draw_children(hdc, x, y, clip, draw_positioned, idx->first);
+                       }
+               }
+       }
+}
+
+litehtml::overflow litehtml::html_tag::get_overflow() const
+{
+       return m_overflow;
+}
+
+bool litehtml::html_tag::is_nth_child(const element::ptr& el, int num, int off, bool of_type) const
+{
+       int idx = 1;
+       for(const auto& child : m_children)
+       {
+               if(child->get_display() != display_inline_text)
+               {
+                       if( (!of_type) || (of_type && !t_strcmp(el->get_tagName(), child->get_tagName())) )
+                       {
+                               if(el == child)
+                               {
+                                       if(num != 0)
+                                       {
+                                               if((idx - off) >= 0 && (idx - off) % num == 0)
+                                               {
+                                                       return true;
+                                               }
+
+                                       } else if(idx == off)
+                                       {
+                                               return true;
+                                       }
+                                       return false;
+                               }
+                               idx++;
+                       }
+                       if(el == child) break;
+               }
+       }
+       return false;
+}
+
+bool litehtml::html_tag::is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const
+{
+       int idx = 1;
+       for(elements_vector::const_reverse_iterator child = m_children.rbegin(); child != m_children.rend(); child++)
+       {
+               if((*child)->get_display() != display_inline_text)
+               {
+                       if( !of_type || (of_type && !t_strcmp(el->get_tagName(), (*child)->get_tagName())) )
+                       {
+                               if(el == (*child))
+                               {
+                                       if(num != 0)
+                                       {
+                                               if((idx - off) >= 0 && (idx - off) % num == 0)
+                                               {
+                                                       return true;
+                                               }
+
+                                       } else if(idx == off)
+                                       {
+                                               return true;
+                                       }
+                                       return false;
+                               }
+                               idx++;
+                       }
+                       if(el == (*child)) break;
+               }
+       }
+       return false;
+}
+
+void litehtml::html_tag::parse_nth_child_params( tstring param, int &num, int &off )
+{
+       if(param == _t("odd"))
+       {
+               num = 2;
+               off = 1;
+       } else if(param == _t("even"))
+       {
+               num = 2;
+               off = 0;
+       } else
+       {
+               string_vector tokens;
+               split_string(param, tokens, _t(" n"), _t("n"));
+
+               tstring s_num;
+               tstring s_off;
+
+               tstring s_int;
+               for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+               {
+                       if((*tok) == _t("n"))
+                       {
+                               s_num = s_int;
+                               s_int.clear();
+                       } else
+                       {
+                               s_int += (*tok);
+                       }
+               }
+               s_off = s_int;
+
+               num = t_atoi(s_num.c_str());
+               off = t_atoi(s_off.c_str());
+       }
+}
+
+void litehtml::html_tag::calc_document_size( litehtml::size& sz, int x /*= 0*/, int y /*= 0*/ )
+{
+       if(is_visible() && m_el_position != element_position_fixed)
+       {
+               element::calc_document_size(sz, x, y);
+
+               if(m_overflow == overflow_visible)
+               {
+                       for(auto& el : m_children)
+                       {
+                               el->calc_document_size(sz, x + m_pos.x, y + m_pos.y);
+                       }
+               }
+
+               // root element (<html>) must to cover entire window
+               if(!have_parent())
+               {
+                       position client_pos;
+                       get_document()->container()->get_client_rect(client_pos);
+                       m_pos.height = std::max(sz.height, client_pos.height) - content_margins_top() - content_margins_bottom();
+                       m_pos.width      = std::max(sz.width, client_pos.width) - content_margins_left() - content_margins_right();
+               }
+       }
+}
+
+
+void litehtml::html_tag::get_redraw_box(litehtml::position& pos, int x /*= 0*/, int y /*= 0*/)
+{
+       if(is_visible())
+       {
+               element::get_redraw_box(pos, x, y);
+
+               if(m_overflow == overflow_visible)
+               {
+                       for(auto& el : m_children)
+                       {
+                               if(el->get_element_position() != element_position_fixed)
+                               {
+                                       el->get_redraw_box(pos, x + m_pos.x, y + m_pos.y);
+                               }
+                       }
+               }
+       }
+}
+
+litehtml::element::ptr litehtml::html_tag::find_adjacent_sibling( const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/ )
+{
+       element::ptr ret;
+       for(auto& e : m_children)
+       {
+               if(e->get_display() != display_inline_text)
+               {
+                       if(e == el)
+                       {
+                               if(ret)
+                               {
+                                       int res = ret->select(selector, apply_pseudo);
+                                       if(res != select_no_match)
+                                       {
+                                               if(is_pseudo)
+                                               {
+                                                       if(res & select_match_pseudo_class)
+                                                       {
+                                                               *is_pseudo = true;
+                                                       } else
+                                                       {
+                                                               *is_pseudo = false;
+                                                       }
+                                               }
+                                               return ret;
+                                       }
+                               }
+                               return 0;
+                       } else
+                       {
+                               ret = e;
+                       }
+               }
+       }
+       return 0;
+}
+
+litehtml::element::ptr litehtml::html_tag::find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/)
+{
+       element::ptr ret = 0;
+       for(auto& e : m_children)
+       {
+               if(e->get_display() != display_inline_text)
+               {
+                       if(e == el)
+                       {
+                               return ret;
+                       } else if(!ret)
+                       {
+                               int res = e->select(selector, apply_pseudo);
+                               if(res != select_no_match)
+                               {
+                                       if(is_pseudo)
+                                       {
+                                               if(res & select_match_pseudo_class)
+                                               {
+                                                       *is_pseudo = true;
+                                               } else
+                                               {
+                                                       *is_pseudo = false;
+                                               }
+                                       }
+                                       ret = e;
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
+bool litehtml::html_tag::is_only_child(const element::ptr& el, bool of_type) const
+{
+       int child_count = 0;
+       for(const auto& child : m_children)
+       {
+               if(child->get_display() != display_inline_text)
+               {
+                       if( !of_type || (of_type && !t_strcmp(el->get_tagName(), child->get_tagName())) )
+                       {
+                               child_count++;
+                       }
+                       if(child_count > 1) break;
+               }
+       }
+       if(child_count > 1)
+       {
+               return false;
+       }
+       return true;
+}
+
+void litehtml::html_tag::update_floats(int dy, const element::ptr &parent)
+{
+       if(is_floats_holder())
+       {
+               bool reset_cache = false;
+               for(floated_box::vector::reverse_iterator fb = m_floats_left.rbegin(); fb != m_floats_left.rend(); fb++)
+               {
+                       if(fb->el->is_ancestor(parent))
+                       {
+                               reset_cache     = true;
+                               fb->pos.y       += dy;
+                       }
+               }
+               if(reset_cache)
+               {
+                       m_cahe_line_left.invalidate();
+               }
+               reset_cache = false;
+               for(floated_box::vector::reverse_iterator fb = m_floats_right.rbegin(); fb != m_floats_right.rend(); fb++)
+               {
+                       if(fb->el->is_ancestor(parent))
+                       {
+                               reset_cache     = true;
+                               fb->pos.y       += dy;
+                       }
+               }
+               if(reset_cache)
+               {
+                       m_cahe_line_right.invalidate();
+               }
+       } else
+       {
+               element::ptr el_parent = this->parent();
+               if (el_parent)
+               {
+                       el_parent->update_floats(dy, parent);
+               }
+       }
+}
+
+void litehtml::html_tag::remove_before_after()
+{
+       if(!m_children.empty())
+       {
+               if( !t_strcmp(m_children.front()->get_tagName(), _t("::before")) )
+               {
+                       m_children.erase(m_children.begin());
+               }
+       }
+       if(!m_children.empty())
+       {
+               if( !t_strcmp(m_children.back()->get_tagName(), _t("::after")) )
+               {
+                       m_children.erase(m_children.end() - 1);
+               }
+       }
+}
+
+litehtml::element::ptr litehtml::html_tag::get_element_before()
+{
+       if(!m_children.empty())
+       {
+               if( !t_strcmp(m_children.front()->get_tagName(), _t("::before")) )
+               {
+                       return m_children.front();
+               }
+       }
+       element::ptr el = std::make_shared<el_before>(get_document());
+       el->parent(shared_from_this());
+       m_children.insert(m_children.begin(), el);
+       return el;
+}
+
+litehtml::element::ptr litehtml::html_tag::get_element_after()
+{
+       if(!m_children.empty())
+       {
+               if( !t_strcmp(m_children.back()->get_tagName(), _t("::after")) )
+               {
+                       return m_children.back();
+               }
+       }
+       element::ptr el = std::make_shared<el_after>(get_document());
+       appendChild(el);
+       return el;
+}
+
+void litehtml::html_tag::add_style( const litehtml::style& st )
+{
+       m_style.combine(st);
+}
+
+bool litehtml::html_tag::have_inline_child() const
+{
+       if(!m_children.empty())
+       {
+               for(const auto& el : m_children)
+               {
+                       if(!el->is_white_space())
+                       {
+                               return true;
+                       }
+               }
+       }
+       return false;
+}
+
+void litehtml::html_tag::refresh_styles()
+{
+       remove_before_after();
+
+       for (auto& el : m_children)
+       {
+               if(el->get_display() != display_inline_text)
+               {
+                       el->refresh_styles();
+               }
+       }
+
+       m_style.clear();
+
+       for (auto& usel : m_used_styles)
+       {
+               usel->m_used = false;
+
+               if(usel->m_selector->is_media_valid())
+               {
+                       int apply = select(*usel->m_selector, false);
+
+                       if(apply != select_no_match)
+                       {
+                               if(apply & select_match_pseudo_class)
+                               {
+                                       if(select(*usel->m_selector, true))
+                                       {
+                                               if(apply & select_match_with_after)
+                                               {
+                                                       element::ptr el = get_element_after();
+                                                       if(el)
+                                                       {
+                                                               el->add_style(*usel->m_selector->m_style);
+                                                       }
+                                               } else if(apply & select_match_with_before)
+                                               {
+                                                       element::ptr el = get_element_before();
+                                                       if(el)
+                                                       {
+                                                               el->add_style(*usel->m_selector->m_style);
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       add_style(*usel->m_selector->m_style);
+                                                       usel->m_used = true;
+                                               }
+                                       }
+                               } else if(apply & select_match_with_after)
+                               {
+                                       element::ptr el = get_element_after();
+                                       if(el)
+                                       {
+                                               el->add_style(*usel->m_selector->m_style);
+                                       }
+                               } else if(apply & select_match_with_before)
+                               {
+                                       element::ptr el = get_element_before();
+                                       if(el)
+                                       {
+                                               el->add_style(*usel->m_selector->m_style);
+                                       }
+                               } else
+                               {
+                                       add_style(*usel->m_selector->m_style);
+                                       usel->m_used = true;
+                               }
+                       }
+               }
+       }
+}
+
+litehtml::element::ptr litehtml::html_tag::get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex)
+{
+       element::ptr ret = 0;
+
+       if(m_overflow > overflow_visible)
+       {
+               if(!m_pos.is_point_inside(x, y))
+               {
+                       return ret;
+               }
+       }
+
+       position pos = m_pos;
+       pos.x   = x - pos.x;
+       pos.y   = y - pos.y;
+
+       for(elements_vector::reverse_iterator i = m_children.rbegin(); i != m_children.rend() && !ret; i++)
+       {
+               element::ptr el = (*i);
+
+               if(el->is_visible() && el->get_display() != display_inline_text)
+               {
+                       switch(flag)
+                       {
+                       case draw_positioned:
+                               if(el->is_positioned() && el->get_zindex() == zindex)
+                               {
+                                       if(el->get_element_position() == element_position_fixed)
+                                       {
+                                               ret = el->get_element_by_point(client_x, client_y, client_x, client_y);
+                                               if(!ret && (*i)->is_point_inside(client_x, client_y))
+                                               {
+                                                       ret = (*i);
+                                               }
+                                       } else
+                                       {
+                                               ret = el->get_element_by_point(pos.x, pos.y, client_x, client_y);
+                                               if(!ret && (*i)->is_point_inside(pos.x, pos.y))
+                                               {
+                                                       ret = (*i);
+                                               }
+                                       }
+                                       el = 0;
+                               }
+                               break;
+                       case draw_block:
+                               if(!el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
+                               {
+                                       if(el->is_point_inside(pos.x, pos.y))
+                                       {
+                                               ret = el;
+                                       }
+                               }
+                               break;
+                       case draw_floats:
+                               if(el->get_float() != float_none && !el->is_positioned())
+                               {
+                                       ret = el->get_element_by_point(pos.x, pos.y, client_x, client_y);
+
+                                       if(!ret && (*i)->is_point_inside(pos.x, pos.y))
+                                       {
+                                               ret = (*i);
+                                       }
+                                       el = 0;
+                               }
+                               break;
+                       case draw_inlines:
+                               if(el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
+                               {
+                                       if(el->get_display() == display_inline_block)
+                                       {
+                                               ret = el->get_element_by_point(pos.x, pos.y, client_x, client_y);
+                                               el = 0;
+                                       }
+                                       if(!ret && (*i)->is_point_inside(pos.x, pos.y))
+                                       {
+                                               ret = (*i);
+                                       }
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+
+                       if(el && !el->is_positioned())
+                       {
+                               if(flag == draw_positioned)
+                               {
+                                       element::ptr child = el->get_child_by_point(pos.x, pos.y, client_x, client_y, flag, zindex);
+                                       if(child)
+                                       {
+                                               ret = child;
+                                       }
+                               } else
+                               {
+                                       if(     el->get_float() == float_none &&
+                                               el->get_display() != display_inline_block)
+                                       {
+                                               element::ptr child = el->get_child_by_point(pos.x, pos.y, client_x, client_y, flag, zindex);
+                                               if(child)
+                                               {
+                                                       ret = child;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return ret;
+}
+
+litehtml::element::ptr litehtml::html_tag::get_element_by_point(int x, int y, int client_x, int client_y)
+{
+       if(!is_visible()) return 0;
+
+       element::ptr ret;
+
+       std::map<int, bool> zindexes;
+
+       for(elements_vector::iterator i = m_positioned.begin(); i != m_positioned.end(); i++)
+       {
+               zindexes[(*i)->get_zindex()];
+       }
+
+       for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end() && !ret; idx++)
+       {
+               if(idx->first > 0)
+               {
+                       ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, idx->first);
+               }
+       }
+       if(ret) return ret;
+
+       for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end() && !ret; idx++)
+       {
+               if(idx->first == 0)
+               {
+                       ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, idx->first);
+               }
+       }
+       if(ret) return ret;
+
+       ret = get_child_by_point(x, y, client_x, client_y, draw_inlines, 0);
+       if(ret) return ret;
+
+       ret = get_child_by_point(x, y, client_x, client_y, draw_floats, 0);
+       if(ret) return ret;
+
+       ret = get_child_by_point(x, y, client_x, client_y, draw_block, 0);
+       if(ret) return ret;
+
+
+       for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end() && !ret; idx++)
+       {
+               if(idx->first < 0)
+               {
+                       ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, idx->first);
+               }
+       }
+       if(ret) return ret;
+
+       if(m_el_position == element_position_fixed)
+       {
+               if(is_point_inside(client_x, client_y))
+               {
+                       ret = shared_from_this();
+               }
+       } else
+       {
+               if(is_point_inside(x, y))
+               {
+                       ret = shared_from_this();
+               }
+       }
+
+       return ret;
+}
+
+const litehtml::background* litehtml::html_tag::get_background(bool own_only)
+{
+       if(own_only)
+       {
+               // return own background with check for empty one
+               if(m_bg.m_image.empty() && !m_bg.m_color.alpha)
+               {
+                       return 0;
+               }
+               return &m_bg;
+       }
+
+       if(m_bg.m_image.empty() && !m_bg.m_color.alpha)
+       {
+               // if this is root element (<html>) try to get background from body
+               if (!have_parent())
+               {
+                       for (const auto& el : m_children)
+                       {
+                               if( el->is_body() )
+                               {
+                                       // return own body background
+                                       return el->get_background(true);
+                               }
+                       }
+               }
+               return 0;
+       }
+       
+       if(is_body())
+       {
+               element::ptr el_parent = parent();
+               if (el_parent)
+               {
+                       if (!el_parent->get_background(true))
+                       {
+                               // parent of body will draw background for body
+                               return 0;
+                       }
+               }
+       }
+
+       return &m_bg;
+}
+
+int litehtml::html_tag::render_box(int x, int y, int max_width, bool second_pass /*= false*/)
+{
+       int parent_width = max_width;
+
+       calc_outlines(parent_width);
+
+       m_pos.clear();
+       m_pos.move_to(x, y);
+
+       m_pos.x += content_margins_left();
+       m_pos.y += content_margins_top();
+
+       int ret_width = 0;
+
+       def_value<int>  block_width(0);
+
+       if (m_display != display_table_cell && !m_css_width.is_predefined())
+       {
+               int w = calc_width(parent_width);
+               
+               if (m_box_sizing == box_sizing_border_box)
+               {
+                       w -= m_padding.width() + m_borders.width();
+               }
+               ret_width = max_width = block_width = w;
+       }
+       else
+       {
+               if (max_width)
+               {
+                       max_width -= content_margins_left() + content_margins_right();
+               }
+       }
+
+       // check for max-width (on the first pass only)
+       if (!m_css_max_width.is_predefined() && !second_pass)
+       {
+               int mw = get_document()->cvt_units(m_css_max_width, m_font_size, parent_width);
+               if (m_box_sizing == box_sizing_border_box)
+               {
+                       mw -= m_padding.left + m_borders.left + m_padding.right + m_borders.right;
+               }
+               if (max_width > mw)
+               {
+                       max_width = mw;
+               }
+       }
+
+       m_floats_left.clear();
+       m_floats_right.clear();
+       m_boxes.clear();
+       m_cahe_line_left.invalidate();
+       m_cahe_line_right.invalidate();
+
+       element_position el_position;
+
+       int block_height = 0;
+
+       m_pos.height = 0;
+
+       if (get_predefined_height(block_height))
+       {
+               m_pos.height = block_height;
+       }
+
+       white_space ws = get_white_space();
+       bool skip_spaces = false;
+       if (ws == white_space_normal ||
+               ws == white_space_nowrap ||
+               ws == white_space_pre_line)
+       {
+               skip_spaces = true;
+       }
+
+       bool was_space = false;
+
+       for (auto el : m_children)
+       {
+               // we don't need process absolute and fixed positioned element on the second pass
+               if (second_pass)
+               {
+                       el_position = el->get_element_position();
+                       if ((el_position == element_position_absolute || el_position == element_position_fixed)) continue;
+               }
+
+               // skip spaces to make rendering a bit faster
+               if (skip_spaces)
+               {
+                       if (el->is_white_space())
+                       {
+                               if (was_space)
+                               {
+                                       el->skip(true);
+                                       continue;
+                               }
+                               else
+                               {
+                                       was_space = true;
+                               }
+                       }
+                       else
+                       {
+                               was_space = false;
+                       }
+               }
+
+               // place element into rendering flow
+               int rw = place_element(el, max_width);
+               if (rw > ret_width)
+               {
+                       ret_width = rw;
+               }
+       }
+
+       finish_last_box(true);
+
+       if (block_width.is_default() && is_inline_box())
+       {
+               m_pos.width = ret_width;
+       }
+       else
+       {
+               m_pos.width = max_width;
+       }
+       calc_auto_margins(parent_width);
+
+       if (!m_boxes.empty())
+       {
+               if (collapse_top_margin())
+               {
+                       int old_top = m_margins.top;
+                       m_margins.top = std::max(m_boxes.front()->top_margin(), m_margins.top);
+                       if (m_margins.top != old_top)
+                       {
+                               update_floats(m_margins.top - old_top, shared_from_this());
+                       }
+               }
+               if (collapse_bottom_margin())
+               {
+                       m_margins.bottom = std::max(m_boxes.back()->bottom_margin(), m_margins.bottom);
+                       m_pos.height = m_boxes.back()->bottom() - m_boxes.back()->bottom_margin();
+               }
+               else
+               {
+                       m_pos.height = m_boxes.back()->bottom();
+               }
+       }
+
+       // add the floats height to the block height
+       if (is_floats_holder())
+       {
+               int floats_height = get_floats_height();
+               if (floats_height > m_pos.height)
+               {
+                       m_pos.height = floats_height;
+               }
+       }
+
+       // calculate the final position
+
+       m_pos.move_to(x, y);
+       m_pos.x += content_margins_left();
+       m_pos.y += content_margins_top();
+
+       if (get_predefined_height(block_height))
+       {
+               m_pos.height = block_height;
+       }
+
+       int min_height = 0;
+       if (!m_css_min_height.is_predefined() && m_css_min_height.units() == css_units_percentage)
+       {
+               element::ptr el_parent = parent();
+               if (el_parent)
+               {
+                       if (el_parent->get_predefined_height(block_height))
+                       {
+                               min_height = m_css_min_height.calc_percent(block_height);
+                       }
+               }
+       }
+       else
+       {
+               min_height = (int)m_css_min_height.val();
+       }
+       if (min_height != 0 && m_box_sizing == box_sizing_border_box)
+       {
+               min_height -= m_padding.top + m_borders.top + m_padding.bottom + m_borders.bottom;
+               if (min_height < 0) min_height = 0;
+       }
+
+       if (m_display == display_list_item)
+       {
+               const tchar_t* list_image = get_style_property(_t("list-style-image"), true, 0);
+               if (list_image)
+               {
+                       tstring url;
+                       css::parse_css_url(list_image, url);
+
+                       size sz;
+                       const tchar_t* list_image_baseurl = get_style_property(_t("list-style-image-baseurl"), true, 0);
+                       get_document()->container()->get_image_size(url.c_str(), list_image_baseurl, sz);
+                       if (min_height < sz.height)
+                       {
+                               min_height = sz.height;
+                       }
+               }
+
+       }
+
+       if (min_height > m_pos.height)
+       {
+               m_pos.height = min_height;
+       }
+
+       int min_width = m_css_min_width.calc_percent(parent_width);
+
+       if (min_width != 0 && m_box_sizing == box_sizing_border_box)
+       {
+               min_width -= m_padding.left + m_borders.left + m_padding.right + m_borders.right;
+               if (min_width < 0) min_width = 0;
+       }
+
+       if (min_width != 0)
+       {
+               if (min_width > m_pos.width)
+               {
+                       m_pos.width = min_width;
+               }
+               if (min_width > ret_width)
+               {
+                       ret_width = min_width;
+               }
+       }
+
+       ret_width += content_margins_left() + content_margins_right();
+
+       // re-render with new width
+       if (ret_width < max_width && !second_pass && have_parent())
+       {
+               if (m_display == display_inline_block ||
+                       m_css_width.is_predefined() &&
+                       (m_float != float_none ||
+                       m_display == display_table ||
+                       m_el_position == element_position_absolute ||
+                       m_el_position == element_position_fixed
+                       )
+                       )
+               {
+                       render(x, y, ret_width, true);
+                       m_pos.width = ret_width - (content_margins_left() + content_margins_right());
+               }
+       }
+
+       if (is_floats_holder() && !second_pass)
+       {
+               for (const auto& fb : m_floats_left)
+               {
+                       fb.el->apply_relative_shift(fb.el->parent()->calc_width(m_pos.width));
+               }
+       }
+
+
+       return ret_width;
+}
+
+int litehtml::html_tag::render_table(int x, int y, int max_width, bool second_pass /*= false*/)
+{
+       if (!m_grid) return 0;
+
+       int parent_width = max_width;
+
+       calc_outlines(parent_width);
+
+       m_pos.clear();
+       m_pos.move_to(x, y);
+
+       m_pos.x += content_margins_left();
+       m_pos.y += content_margins_top();
+
+       def_value<int>  block_width(0);
+
+       if (!m_css_width.is_predefined())
+       {
+               max_width = block_width = calc_width(parent_width) - m_padding.width() - m_borders.width();
+       }
+       else
+       {
+               if (max_width)
+               {
+                       max_width -= content_margins_left() + content_margins_right();
+               }
+       }
+
+       // Calculate table spacing
+       int table_width_spacing = 0;
+       if (m_border_collapse == border_collapse_separate)
+       {
+               table_width_spacing = m_border_spacing_x * (m_grid->cols_count() + 1);
+       }
+       else
+       {
+               table_width_spacing = 0;
+
+               if (m_grid->cols_count())
+               {
+                       table_width_spacing -= std::min(border_left(), m_grid->column(0).border_left);
+                       table_width_spacing -= std::min(border_right(), m_grid->column(m_grid->cols_count() - 1).border_right);
+               }
+
+               for (int col = 1; col < m_grid->cols_count(); col++)
+               {
+                       table_width_spacing -= std::min(m_grid->column(col).border_left, m_grid->column(col - 1).border_right);
+               }
+       }
+
+
+       // Calculate the minimum content width (MCW) of each cell: the formatted content may span any number of lines but may not overflow the cell box. 
+       // If the specified 'width' (W) of the cell is greater than MCW, W is the minimum cell width. A value of 'auto' means that MCW is the minimum 
+       // cell width.
+       // 
+       // Also, calculate the "maximum" cell width of each cell: formatting the content without breaking lines other than where explicit line breaks occur.
+
+       if (m_grid->cols_count() == 1 && !block_width.is_default())
+       {
+               for (int row = 0; row < m_grid->rows_count(); row++)
+               {
+                       table_cell* cell = m_grid->cell(0, row);
+                       if (cell && cell->el)
+                       {
+                               cell->min_width = cell->max_width = cell->el->render(0, 0, max_width - table_width_spacing);
+                               cell->el->m_pos.width = cell->min_width - cell->el->content_margins_left() - cell->el->content_margins_right();
+                       }
+               }
+       }
+       else
+       {
+               for (int row = 0; row < m_grid->rows_count(); row++)
+               {
+                       for (int col = 0; col < m_grid->cols_count(); col++)
+                       {
+                               table_cell* cell = m_grid->cell(col, row);
+                               if (cell && cell->el)
+                               {
+                                       if (!m_grid->column(col).css_width.is_predefined() && m_grid->column(col).css_width.units() != css_units_percentage)
+                                       {
+                                               int css_w = m_grid->column(col).css_width.calc_percent(block_width);
+                                               int el_w = cell->el->render(0, 0, css_w);
+                                               cell->min_width = cell->max_width = std::max(css_w, el_w);
+                                               cell->el->m_pos.width = cell->min_width - cell->el->content_margins_left() - cell->el->content_margins_right();
+                                       }
+                                       else
+                                       {
+                                               // calculate minimum content width
+                                               cell->min_width = cell->el->render(0, 0, 1);
+                                               // calculate maximum content width
+                                               cell->max_width = cell->el->render(0, 0, max_width - table_width_spacing);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       // For each column, determine a maximum and minimum column width from the cells that span only that column. 
+       // The minimum is that required by the cell with the largest minimum cell width (or the column 'width', whichever is larger). 
+       // The maximum is that required by the cell with the largest maximum cell width (or the column 'width', whichever is larger).
+
+       for (int col = 0; col < m_grid->cols_count(); col++)
+       {
+               m_grid->column(col).max_width = 0;
+               m_grid->column(col).min_width = 0;
+               for (int row = 0; row < m_grid->rows_count(); row++)
+               {
+                       if (m_grid->cell(col, row)->colspan <= 1)
+                       {
+                               m_grid->column(col).max_width = std::max(m_grid->column(col).max_width, m_grid->cell(col, row)->max_width);
+                               m_grid->column(col).min_width = std::max(m_grid->column(col).min_width, m_grid->cell(col, row)->min_width);
+                       }
+               }
+       }
+
+       // For each cell that spans more than one column, increase the minimum widths of the columns it spans so that together, 
+       // they are at least as wide as the cell. Do the same for the maximum widths. 
+       // If possible, widen all spanned columns by approximately the same amount.
+
+       for (int col = 0; col < m_grid->cols_count(); col++)
+       {
+               for (int row = 0; row < m_grid->rows_count(); row++)
+               {
+                       if (m_grid->cell(col, row)->colspan > 1)
+                       {
+                               int max_total_width = m_grid->column(col).max_width;
+                               int min_total_width = m_grid->column(col).min_width;
+                               for (int col2 = col + 1; col2 < col + m_grid->cell(col, row)->colspan; col2++)
+                               {
+                                       max_total_width += m_grid->column(col2).max_width;
+                                       min_total_width += m_grid->column(col2).min_width;
+                               }
+                               if (min_total_width < m_grid->cell(col, row)->min_width)
+                               {
+                                       m_grid->distribute_min_width(m_grid->cell(col, row)->min_width - min_total_width, col, col + m_grid->cell(col, row)->colspan - 1);
+                               }
+                               if (max_total_width < m_grid->cell(col, row)->max_width)
+                               {
+                                       m_grid->distribute_max_width(m_grid->cell(col, row)->max_width - max_total_width, col, col + m_grid->cell(col, row)->colspan - 1);
+                               }
+                       }
+               }
+       }
+
+       // If the 'table' or 'inline-table' element's 'width' property has a computed value (W) other than 'auto', the used width is the 
+       // greater of W, CAPMIN, and the minimum width required by all the columns plus cell spacing or borders (MIN). 
+       // If the used width is greater than MIN, the extra width should be distributed over the columns.
+       //
+       // If the 'table' or 'inline-table' element has 'width: auto', the used width is the greater of the table's containing block width, 
+       // CAPMIN, and MIN. However, if either CAPMIN or the maximum width required by the columns plus cell spacing or borders (MAX) is 
+       // less than that of the containing block, use max(MAX, CAPMIN).
+
+
+       int table_width = 0;
+       int min_table_width = 0;
+       int max_table_width = 0;
+
+       if (!block_width.is_default())
+       {
+               table_width = m_grid->calc_table_width(block_width - table_width_spacing, false, min_table_width, max_table_width);
+       }
+       else
+       {
+               table_width = m_grid->calc_table_width(max_width - table_width_spacing, true, min_table_width, max_table_width);
+       }
+
+       min_table_width += table_width_spacing;
+       max_table_width += table_width_spacing;
+       table_width += table_width_spacing;
+       m_grid->calc_horizontal_positions(m_borders, m_border_collapse, m_border_spacing_x);
+
+       bool row_span_found = false;
+
+       // render cells with computed width
+       for (int row = 0; row < m_grid->rows_count(); row++)
+       {
+               m_grid->row(row).height = 0;
+               for (int col = 0; col < m_grid->cols_count(); col++)
+               {
+                       table_cell* cell = m_grid->cell(col, row);
+                       if (cell->el)
+                       {
+                               int span_col = col + cell->colspan - 1;
+                               if (span_col >= m_grid->cols_count())
+                               {
+                                       span_col = m_grid->cols_count() - 1;
+                               }
+                               int cell_width = m_grid->column(span_col).right - m_grid->column(col).left;
+
+                               if (cell->el->m_pos.width != cell_width - cell->el->content_margins_left() - cell->el->content_margins_right())
+                               {
+                                       cell->el->render(m_grid->column(col).left, 0, cell_width);
+                                       cell->el->m_pos.width = cell_width - cell->el->content_margins_left() - cell->el->content_margins_right();
+                               }
+                               else
+                               {
+                                       cell->el->m_pos.x = m_grid->column(col).left + cell->el->content_margins_left();
+                               }
+
+                               if (cell->rowspan <= 1)
+                               {
+                                       m_grid->row(row).height = std::max(m_grid->row(row).height, cell->el->height());
+                               }
+                               else
+                               {
+                                       row_span_found = true;
+                               }
+
+                       }
+               }
+       }
+
+       if (row_span_found)
+       {
+               for (int col = 0; col < m_grid->cols_count(); col++)
+               {
+                       for (int row = 0; row < m_grid->rows_count(); row++)
+                       {
+                               table_cell* cell = m_grid->cell(col, row);
+                               if (cell->el)
+                               {
+                                       int span_row = row + cell->rowspan - 1;
+                                       if (span_row >= m_grid->rows_count())
+                                       {
+                                               span_row = m_grid->rows_count() - 1;
+                                       }
+                                       if (span_row != row)
+                                       {
+                                               int h = 0;
+                                               for (int i = row; i <= span_row; i++)
+                                               {
+                                                       h += m_grid->row(i).height;
+                                               }
+                                               if (h < cell->el->height())
+                                               {
+                                                       m_grid->row(span_row).height += cell->el->height() - h;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       // Calculate vertical table spacing
+       int table_height_spacing = 0;
+       if (m_border_collapse == border_collapse_separate)
+       {
+               table_height_spacing = m_border_spacing_y * (m_grid->rows_count() + 1);
+       }
+       else
+       {
+               table_height_spacing = 0;
+
+               if (m_grid->rows_count())
+               {
+                       table_height_spacing -= std::min(border_top(), m_grid->row(0).border_top);
+                       table_height_spacing -= std::min(border_bottom(), m_grid->row(m_grid->rows_count() - 1).border_bottom);
+               }
+
+               for (int row = 1; row < m_grid->rows_count(); row++)
+               {
+                       table_height_spacing -= std::min(m_grid->row(row).border_top, m_grid->row(row - 1).border_bottom);
+               }
+       }
+
+
+       // calculate block height
+       int block_height = 0;
+       if (get_predefined_height(block_height))
+       {
+               block_height -= m_padding.height() + m_borders.height();
+       }
+
+       // calculate minimum height from m_css_min_height
+       int min_height = 0;
+       if (!m_css_min_height.is_predefined() && m_css_min_height.units() == css_units_percentage)
+       {
+               element::ptr el_parent = parent();
+               if (el_parent)
+               {
+                       int parent_height = 0;
+                       if (el_parent->get_predefined_height(parent_height))
+                       {
+                               min_height = m_css_min_height.calc_percent(parent_height);
+                       }
+               }
+       }
+       else
+       {
+               min_height = (int)m_css_min_height.val();
+       }
+
+       int extra_row_height = 0;
+       int minimum_table_height = std::max(block_height, min_height);
+
+       m_grid->calc_rows_height(minimum_table_height - table_height_spacing, m_border_spacing_y);
+       m_grid->calc_vertical_positions(m_borders, m_border_collapse, m_border_spacing_y);
+
+       int table_height = 0;
+
+       // place cells vertically
+       for (int col = 0; col < m_grid->cols_count(); col++)
+       {
+               for (int row = 0; row < m_grid->rows_count(); row++)
+               {
+                       table_cell* cell = m_grid->cell(col, row);
+                       if (cell->el)
+                       {
+                               int span_row = row + cell->rowspan - 1;
+                               if (span_row >= m_grid->rows_count())
+                               {
+                                       span_row = m_grid->rows_count() - 1;
+                               }
+                               cell->el->m_pos.y = m_grid->row(row).top + cell->el->content_margins_top();
+                               cell->el->m_pos.height = m_grid->row(span_row).bottom - m_grid->row(row).top - cell->el->content_margins_top() - cell->el->content_margins_bottom();
+                               table_height = std::max(table_height, m_grid->row(span_row).bottom);
+                               cell->el->apply_vertical_align();
+                       }
+               }
+       }
+
+       if (m_border_collapse == border_collapse_collapse)
+       {
+               if (m_grid->rows_count())
+               {
+                       table_height -= std::min(border_bottom(), m_grid->row(m_grid->rows_count() - 1).border_bottom);
+               }
+       }
+       else
+       {
+               table_height += m_border_spacing_y;
+       }
+
+       m_pos.width = table_width;
+
+       calc_auto_margins(parent_width);
+
+       m_pos.move_to(x, y);
+       m_pos.x += content_margins_left();
+       m_pos.y += content_margins_top();
+       m_pos.width = table_width;
+       m_pos.height = table_height;
+
+       return max_table_width;
+}
+
+void litehtml::html_tag::draw_children_box(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex)
+{
+       position pos = m_pos;
+       pos.x += x;
+       pos.y += y;
+
+       document::ptr doc = get_document();
+
+       if (m_overflow > overflow_visible)
+       {
+               position border_box = pos;
+               border_box += m_padding;
+               border_box += m_borders;
+
+               border_radiuses bdr_radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
+
+               bdr_radius -= m_borders;
+               bdr_radius -= m_padding;
+
+               doc->container()->set_clip(pos, bdr_radius, true, true);
+       }
+
+       position browser_wnd;
+       doc->container()->get_client_rect(browser_wnd);
+
+       element::ptr el;
+       for (auto& item : m_children)
+       {
+               el = item;
+               if (el->is_visible())
+               {
+                       switch (flag)
+                       {
+                       case draw_positioned:
+                               if (el->is_positioned() && el->get_zindex() == zindex)
+                               {
+                                       if (el->get_element_position() == element_position_fixed)
+                                       {
+                                               el->draw(hdc, browser_wnd.x, browser_wnd.y, clip);
+                                               el->draw_stacking_context(hdc, browser_wnd.x, browser_wnd.y, clip, true);
+                                       }
+                                       else
+                                       {
+                                               el->draw(hdc, pos.x, pos.y, clip);
+                                               el->draw_stacking_context(hdc, pos.x, pos.y, clip, true);
+                                       }
+                                       el = 0;
+                               }
+                               break;
+                       case draw_block:
+                               if (!el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
+                               {
+                                       el->draw(hdc, pos.x, pos.y, clip);
+                               }
+                               break;
+                       case draw_floats:
+                               if (el->get_float() != float_none && !el->is_positioned())
+                               {
+                                       el->draw(hdc, pos.x, pos.y, clip);
+                                       el->draw_stacking_context(hdc, pos.x, pos.y, clip, false);
+                                       el = 0;
+                               }
+                               break;
+                       case draw_inlines:
+                               if (el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
+                               {
+                                       el->draw(hdc, pos.x, pos.y, clip);
+                                       if (el->get_display() == display_inline_block)
+                                       {
+                                               el->draw_stacking_context(hdc, pos.x, pos.y, clip, false);
+                                               el = 0;
+                                       }
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+
+                       if (el)
+                       {
+                               if (flag == draw_positioned)
+                               {
+                                       if (!el->is_positioned())
+                                       {
+                                               el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
+                                       }
+                               }
+                               else
+                               {
+                                       if (el->get_float() == float_none &&
+                                               el->get_display() != display_inline_block &&
+                                               !el->is_positioned())
+                                       {
+                                               el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if (m_overflow > overflow_visible)
+       {
+               doc->container()->del_clip();
+       }
+}
+
+void litehtml::html_tag::draw_children_table(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex)
+{
+       if (!m_grid) return;
+
+       position pos = m_pos;
+       pos.x += x;
+       pos.y += y;
+       for (int row = 0; row < m_grid->rows_count(); row++)
+       {
+               if (flag == draw_block)
+               {
+                       m_grid->row(row).el_row->draw_background(hdc, pos.x, pos.y, clip);
+               }
+               for (int col = 0; col < m_grid->cols_count(); col++)
+               {
+                       table_cell* cell = m_grid->cell(col, row);
+                       if (cell->el)
+                       {
+                               if (flag == draw_block)
+                               {
+                                       cell->el->draw(hdc, pos.x, pos.y, clip);
+                               }
+                               cell->el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
+                       }
+               }
+       }
+}
index f03bb6249d7248de73ebdd9c8a349107ab4f6e0b..460eb072dda93b6adbddef35eefef7f0c62fa7c5 100644 (file)
-#pragma once\r
-\r
-#include "element.h"\r
-#include "style.h"\r
-#include "background.h"\r
-#include "css_margins.h"\r
-#include "borders.h"\r
-#include "css_selector.h"\r
-#include "stylesheet.h"\r
-#include "box.h"\r
-#include "table.h"\r
-\r
-namespace litehtml\r
-{\r
-       struct line_context\r
-       {\r
-               int calculatedTop;\r
-               int top;\r
-               int left;\r
-               int right;\r
-\r
-               int width()\r
-               {\r
-                       return right - left;\r
-               }\r
-               void fix_top()\r
-               {\r
-                       calculatedTop = top;\r
-               }\r
-       };\r
-\r
-       class html_tag : public element\r
-       {\r
-               friend class elements_iterator;\r
-               friend class el_table;\r
-               friend class table_grid;\r
-               friend class block_box;\r
-               friend class line_box;\r
-       public:\r
-               typedef std::shared_ptr<litehtml::html_tag>     ptr;\r
-       protected:\r
-               box::vector                             m_boxes;\r
-               string_vector                   m_class_values;\r
-               tstring                                 m_tag;\r
-               litehtml::style                 m_style;\r
-               string_map                              m_attrs;\r
-               vertical_align                  m_vertical_align;\r
-               text_align                              m_text_align;\r
-               style_display                   m_display;\r
-               list_style_type                 m_list_style_type;\r
-               list_style_position             m_list_style_position;\r
-               white_space                             m_white_space;\r
-               element_float                   m_float;\r
-               element_clear                   m_clear;\r
-               floated_box::vector             m_floats_left;\r
-               floated_box::vector             m_floats_right;\r
-               elements_vector                 m_positioned;\r
-               background                              m_bg;\r
-               element_position                m_el_position;\r
-               int                                             m_line_height;\r
-               bool                                    m_lh_predefined;\r
-               string_vector                   m_pseudo_classes;\r
-               used_selector::vector   m_used_styles;          \r
-               \r
-               uint_ptr                                m_font;\r
-               int                                             m_font_size;\r
-               font_metrics                    m_font_metrics;\r
-\r
-               css_margins                             m_css_margins;\r
-               css_margins                             m_css_padding;\r
-               css_borders                             m_css_borders;\r
-               css_length                              m_css_width;\r
-               css_length                              m_css_height;\r
-               css_length                              m_css_min_width;\r
-               css_length                              m_css_min_height;\r
-               css_length                              m_css_max_width;\r
-               css_length                              m_css_max_height;\r
-               css_offsets                             m_css_offsets;\r
-               css_length                              m_css_text_indent;\r
-\r
-               overflow                                m_overflow;\r
-               visibility                              m_visibility;\r
-               int                                             m_z_index;\r
-               box_sizing                              m_box_sizing;\r
-\r
-               int_int_cache                   m_cahe_line_left;\r
-               int_int_cache                   m_cahe_line_right;\r
-\r
-               // data for table rendering\r
-               std::unique_ptr<table_grid>     m_grid;\r
-               css_length                              m_css_border_spacing_x;\r
-               css_length                              m_css_border_spacing_y;\r
-               int                                             m_border_spacing_x;\r
-               int                                             m_border_spacing_y;\r
-               border_collapse                 m_border_collapse;\r
-\r
-               virtual void                    select_all(const css_selector& selector, elements_vector& res);\r
-\r
-       public:\r
-               html_tag(const std::shared_ptr<litehtml::document>& doc);\r
-               virtual ~html_tag();\r
-\r
-               /* render functions */\r
-\r
-               virtual int                                     render(int x, int y, int max_width, bool second_pass = false) override;\r
-\r
-               virtual int                                     render_inline(const element::ptr &container, int max_width) override;\r
-               virtual int                                     place_element(const element::ptr &el, int max_width) override;\r
-               virtual bool                            fetch_positioned() override;\r
-               virtual void                            render_positioned(render_type rt = render_all) override;\r
-\r
-               int                                                     new_box(const element::ptr &el, int max_width, line_context& line_ctx);\r
-\r
-               int                                                     get_cleared_top(const element::ptr &el, int line_top) const;\r
-               int                                                     finish_last_box(bool end_of_render = false);\r
-\r
-               virtual bool                            appendChild(const element::ptr &el) override;\r
-               virtual bool                            removeChild(const element::ptr &el) override;\r
-               virtual void                            clearRecursive() override;\r
-               virtual const tchar_t*          get_tagName() const override;\r
-               virtual void                            set_tagName(const tchar_t* tag) override;\r
-               virtual void                            set_data(const tchar_t* data) override;\r
-               virtual element_float           get_float() const override;\r
-               virtual vertical_align          get_vertical_align() const override;\r
-               virtual css_length                      get_css_left() const override;\r
-               virtual css_length                      get_css_right() const override;\r
-               virtual css_length                      get_css_top() const override;\r
-               virtual css_length                      get_css_bottom() const override;\r
-               virtual css_length                      get_css_width() const override;\r
-               virtual css_offsets                     get_css_offsets() const override;\r
-               virtual void                            set_css_width(css_length& w) override;\r
-               virtual css_length                      get_css_height() const override;\r
-               virtual element_clear           get_clear() const override;\r
-               virtual size_t                          get_children_count() const override;\r
-               virtual element::ptr            get_child(int idx) const override;\r
-               virtual element_position        get_element_position(css_offsets* offsets = 0) const override;\r
-               virtual overflow                        get_overflow() const override;\r
-\r
-               virtual void                            set_attr(const tchar_t* name, const tchar_t* val) override;\r
-               virtual const tchar_t*          get_attr(const tchar_t* name, const tchar_t* def = 0) override;\r
-               virtual void                            apply_stylesheet(const litehtml::css& stylesheet) override;\r
-               virtual void                            refresh_styles() override;\r
-\r
-               virtual bool                            is_white_space() const override;\r
-               virtual bool                            is_body() const override;\r
-               virtual bool                            is_break() const override;\r
-               virtual int                                     get_base_line() override;\r
-               virtual bool                            on_mouse_over() override;\r
-               virtual bool                            on_mouse_leave() override;\r
-               virtual bool                            on_lbutton_down() override;\r
-               virtual bool                            on_lbutton_up() override;\r
-               virtual void                            on_click() override;\r
-               virtual bool                            find_styles_changes(position::vector& redraw_boxes, int x, int y) override;\r
-               virtual const tchar_t*          get_cursor() override;\r
-               virtual void                            init_font() override;\r
-               virtual bool                            set_pseudo_class(const tchar_t* pclass, bool add) override;\r
-               virtual bool                            set_class(const tchar_t* pclass, bool add) override;\r
-               virtual bool                            is_replaced() const override;\r
-               virtual int                                     line_height() const override;\r
-               virtual white_space                     get_white_space() const override;\r
-               virtual style_display           get_display() const override;\r
-               virtual visibility                      get_visibility() const override;\r
-               virtual void                            parse_styles(bool is_reparse = false) override;\r
-               virtual void                            draw(uint_ptr hdc, int x, int y, const position* clip) override;\r
-               virtual void                            draw_background(uint_ptr hdc, int x, int y, const position* clip) override;\r
-\r
-               virtual const tchar_t*          get_style_property(const tchar_t* name, bool inherited, const tchar_t* def = 0) override;\r
-               virtual uint_ptr                        get_font(font_metrics* fm = 0) override;\r
-               virtual int                                     get_font_size() const override;\r
-\r
-               elements_vector&                        children();\r
-               virtual void                            calc_outlines(int parent_width) override;\r
-               virtual void                            calc_auto_margins(int parent_width) override;\r
-\r
-               virtual int                                     select(const css_selector& selector, bool apply_pseudo = true) override;\r
-               virtual int                                     select(const css_element_selector& selector, bool apply_pseudo = true) override;\r
-\r
-               virtual elements_vector         select_all(const tstring& selector) override;\r
-               virtual elements_vector         select_all(const css_selector& selector) override;\r
-\r
-               virtual element::ptr            select_one(const tstring& selector) override;\r
-               virtual element::ptr            select_one(const css_selector& selector) override;\r
-\r
-               virtual element::ptr            find_ancestor(const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0) override;\r
-               virtual element::ptr            find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0) override;\r
-               virtual element::ptr            find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0) override;\r
-               virtual void                            get_text(tstring& text) override;\r
-               virtual void                            parse_attributes() override;\r
-\r
-               virtual bool                            is_first_child_inline(const element::ptr& el) const override;\r
-               virtual bool                            is_last_child_inline(const element::ptr& el) override;\r
-               virtual bool                            have_inline_child() const override;\r
-               virtual void                            get_content_size(size& sz, int max_width) override;\r
-               virtual void                            init() override;\r
-               virtual void                            get_inline_boxes(position::vector& boxes) override;\r
-               virtual bool                            is_floats_holder() const override;\r
-               virtual int                                     get_floats_height(element_float el_float = float_none) const override;\r
-               virtual int                                     get_left_floats_height() const override;\r
-               virtual int                                     get_right_floats_height() const override;\r
-               virtual int                                     get_line_left(int y) override;\r
-               virtual int                                     get_line_right(int y, int def_right) override;\r
-               virtual void                            get_line_left_right(int y, int def_right, int& ln_left, int& ln_right) override;\r
-               virtual void                            add_float(const element::ptr &el, int x, int y) override;\r
-               virtual void                            update_floats(int dy, const element::ptr &parent) override;\r
-               virtual void                            add_positioned(const element::ptr &el) override;\r
-               virtual int                                     find_next_line_top(int top, int width, int def_right) override;\r
-               virtual void                            apply_vertical_align() override;\r
-               virtual void                            draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override;\r
-               virtual int                                     get_zindex() const override;\r
-               virtual void                            draw_stacking_context(uint_ptr hdc, int x, int y, const position* clip, bool with_positioned) override;\r
-               virtual void                            calc_document_size(litehtml::size& sz, int x = 0, int y = 0) override;\r
-               virtual void                            get_redraw_box(litehtml::position& pos, int x = 0, int y = 0) override;\r
-               virtual void                            add_style(const litehtml::style& st) override;\r
-               virtual element::ptr            get_element_by_point(int x, int y, int client_x, int client_y) override;\r
-               virtual element::ptr            get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex) override;\r
-\r
-               virtual bool                            is_nth_child(const element::ptr& el, int num, int off, bool of_type) const override;\r
-               virtual bool                            is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const override;\r
-               virtual bool                            is_only_child(const element::ptr& el, bool of_type) const override;\r
-               virtual const background*       get_background(bool own_only = false) override;\r
-\r
-       protected:\r
-               void                                            draw_children_box(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex);\r
-               void                                            draw_children_table(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex);\r
-               int                                                     render_box(int x, int y, int max_width, bool second_pass = false);\r
-               int                                                     render_table(int x, int y, int max_width, bool second_pass = false);\r
-               int                                                     fix_line_width(int max_width, element_float flt);\r
-               void                                            parse_background();\r
-               void                                            init_background_paint( position pos, background_paint &bg_paint, const background* bg );\r
-               void                                            draw_list_marker( uint_ptr hdc, const position &pos );\r
-               void                                            parse_nth_child_params( tstring param, int &num, int &off );\r
-               void                                            remove_before_after();\r
-               litehtml::element::ptr          get_element_before();\r
-               litehtml::element::ptr          get_element_after();\r
-       };\r
-\r
-       /************************************************************************/\r
-       /*                        Inline Functions                              */\r
-       /************************************************************************/\r
-\r
-       inline elements_vector& litehtml::html_tag::children()\r
-       {\r
-               return m_children;\r
-       }\r
-}\r
-\r
+#ifndef LH_HTML_TAG_H
+#define LH_HTML_TAG_H
+
+#include "element.h"
+#include "style.h"
+#include "background.h"
+#include "css_margins.h"
+#include "borders.h"
+#include "css_selector.h"
+#include "stylesheet.h"
+#include "box.h"
+#include "table.h"
+
+namespace litehtml
+{
+       struct line_context
+       {
+               int calculatedTop;
+               int top;
+               int left;
+               int right;
+
+               int width()
+               {
+                       return right - left;
+               }
+               void fix_top()
+               {
+                       calculatedTop = top;
+               }
+       };
+
+       class html_tag : public element
+       {
+               friend class elements_iterator;
+               friend class el_table;
+               friend class table_grid;
+               friend class block_box;
+               friend class line_box;
+       public:
+               typedef std::shared_ptr<litehtml::html_tag>     ptr;
+       protected:
+               box::vector                             m_boxes;
+               string_vector                   m_class_values;
+               tstring                                 m_tag;
+               litehtml::style                 m_style;
+               string_map                              m_attrs;
+               vertical_align                  m_vertical_align;
+               text_align                              m_text_align;
+               style_display                   m_display;
+               list_style_type                 m_list_style_type;
+               list_style_position             m_list_style_position;
+               white_space                             m_white_space;
+               element_float                   m_float;
+               element_clear                   m_clear;
+               floated_box::vector             m_floats_left;
+               floated_box::vector             m_floats_right;
+               elements_vector                 m_positioned;
+               background                              m_bg;
+               element_position                m_el_position;
+               int                                             m_line_height;
+               bool                                    m_lh_predefined;
+               string_vector                   m_pseudo_classes;
+               used_selector::vector   m_used_styles;          
+               
+               uint_ptr                                m_font;
+               int                                             m_font_size;
+               font_metrics                    m_font_metrics;
+
+               css_margins                             m_css_margins;
+               css_margins                             m_css_padding;
+               css_borders                             m_css_borders;
+               css_length                              m_css_width;
+               css_length                              m_css_height;
+               css_length                              m_css_min_width;
+               css_length                              m_css_min_height;
+               css_length                              m_css_max_width;
+               css_length                              m_css_max_height;
+               css_offsets                             m_css_offsets;
+               css_length                              m_css_text_indent;
+
+               overflow                                m_overflow;
+               visibility                              m_visibility;
+               int                                             m_z_index;
+               box_sizing                              m_box_sizing;
+
+               int_int_cache                   m_cahe_line_left;
+               int_int_cache                   m_cahe_line_right;
+
+               // data for table rendering
+               std::unique_ptr<table_grid>     m_grid;
+               css_length                              m_css_border_spacing_x;
+               css_length                              m_css_border_spacing_y;
+               int                                             m_border_spacing_x;
+               int                                             m_border_spacing_y;
+               border_collapse                 m_border_collapse;
+
+               virtual void                    select_all(const css_selector& selector, elements_vector& res) override;
+
+       public:
+               html_tag(const std::shared_ptr<litehtml::document>& doc);
+               virtual ~html_tag();
+
+               /* render functions */
+
+               virtual int                                     render(int x, int y, int max_width, bool second_pass = false) override;
+
+               virtual int                                     render_inline(const element::ptr &container, int max_width) override;
+               virtual int                                     place_element(const element::ptr &el, int max_width) override;
+               virtual bool                            fetch_positioned() override;
+               virtual void                            render_positioned(render_type rt = render_all) override;
+
+               int                                                     new_box(const element::ptr &el, int max_width, line_context& line_ctx);
+
+               int                                                     get_cleared_top(const element::ptr &el, int line_top) const;
+               int                                                     finish_last_box(bool end_of_render = false);
+
+               virtual bool                            appendChild(const element::ptr &el) override;
+               virtual bool                            removeChild(const element::ptr &el) override;
+               virtual void                            clearRecursive() override;
+               virtual const tchar_t*          get_tagName() const override;
+               virtual void                            set_tagName(const tchar_t* tag) override;
+               virtual void                            set_data(const tchar_t* data) override;
+               virtual element_float           get_float() const override;
+               virtual vertical_align          get_vertical_align() const override;
+               virtual css_length                      get_css_left() const override;
+               virtual css_length                      get_css_right() const override;
+               virtual css_length                      get_css_top() const override;
+               virtual css_length                      get_css_bottom() const override;
+               virtual css_length                      get_css_width() const override;
+               virtual css_offsets                     get_css_offsets() const override;
+               virtual void                            set_css_width(css_length& w) override;
+               virtual css_length                      get_css_height() const override;
+               virtual element_clear           get_clear() const override;
+               virtual size_t                          get_children_count() const override;
+               virtual element::ptr            get_child(int idx) const override;
+               virtual element_position        get_element_position(css_offsets* offsets = 0) const override;
+               virtual overflow                        get_overflow() const override;
+
+               virtual void                            set_attr(const tchar_t* name, const tchar_t* val) override;
+               virtual const tchar_t*          get_attr(const tchar_t* name, const tchar_t* def = 0) override;
+               virtual void                            apply_stylesheet(const litehtml::css& stylesheet) override;
+               virtual void                            refresh_styles() override;
+
+               virtual bool                            is_white_space() const override;
+               virtual bool                            is_body() const override;
+               virtual bool                            is_break() const override;
+               virtual int                                     get_base_line() override;
+               virtual bool                            on_mouse_over() override;
+               virtual bool                            on_mouse_leave() override;
+               virtual bool                            on_lbutton_down() override;
+               virtual bool                            on_lbutton_up() override;
+               virtual void                            on_click() override;
+               virtual bool                            find_styles_changes(position::vector& redraw_boxes, int x, int y) override;
+               virtual const tchar_t*          get_cursor() override;
+               virtual void                            init_font() override;
+               virtual bool                            set_pseudo_class(const tchar_t* pclass, bool add) override;
+               virtual bool                            set_class(const tchar_t* pclass, bool add) override;
+               virtual bool                            is_replaced() const override;
+               virtual int                                     line_height() const override;
+               virtual white_space                     get_white_space() const override;
+               virtual style_display           get_display() const override;
+               virtual visibility                      get_visibility() const override;
+               virtual void                            parse_styles(bool is_reparse = false) override;
+               virtual void                            draw(uint_ptr hdc, int x, int y, const position* clip) override;
+               virtual void                            draw_background(uint_ptr hdc, int x, int y, const position* clip) override;
+
+               virtual const tchar_t*          get_style_property(const tchar_t* name, bool inherited, const tchar_t* def = 0) override;
+               virtual uint_ptr                        get_font(font_metrics* fm = 0) override;
+               virtual int                                     get_font_size() const override;
+
+               elements_vector&                        children();
+               virtual void                            calc_outlines(int parent_width) override;
+               virtual void                            calc_auto_margins(int parent_width) override;
+
+               virtual int                                     select(const css_selector& selector, bool apply_pseudo = true) override;
+               virtual int                                     select(const css_element_selector& selector, bool apply_pseudo = true) override;
+
+               virtual elements_vector         select_all(const tstring& selector) override;
+               virtual elements_vector         select_all(const css_selector& selector) override;
+
+               virtual element::ptr            select_one(const tstring& selector) override;
+               virtual element::ptr            select_one(const css_selector& selector) override;
+
+               virtual element::ptr            find_ancestor(const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0) override;
+               virtual element::ptr            find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0) override;
+               virtual element::ptr            find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0) override;
+               virtual void                            get_text(tstring& text) override;
+               virtual void                            parse_attributes() override;
+
+               virtual bool                            is_first_child_inline(const element::ptr& el) const override;
+               virtual bool                            is_last_child_inline(const element::ptr& el) override;
+               virtual bool                            have_inline_child() const override;
+               virtual void                            get_content_size(size& sz, int max_width) override;
+               virtual void                            init() override;
+               virtual void                            get_inline_boxes(position::vector& boxes) override;
+               virtual bool                            is_floats_holder() const override;
+               virtual int                                     get_floats_height(element_float el_float = float_none) const override;
+               virtual int                                     get_left_floats_height() const override;
+               virtual int                                     get_right_floats_height() const override;
+               virtual int                                     get_line_left(int y) override;
+               virtual int                                     get_line_right(int y, int def_right) override;
+               virtual void                            get_line_left_right(int y, int def_right, int& ln_left, int& ln_right) override;
+               virtual void                            add_float(const element::ptr &el, int x, int y) override;
+               virtual void                            update_floats(int dy, const element::ptr &parent) override;
+               virtual void                            add_positioned(const element::ptr &el) override;
+               virtual int                                     find_next_line_top(int top, int width, int def_right) override;
+               virtual void                            apply_vertical_align() override;
+               virtual void                            draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override;
+               virtual int                                     get_zindex() const override;
+               virtual void                            draw_stacking_context(uint_ptr hdc, int x, int y, const position* clip, bool with_positioned) override;
+               virtual void                            calc_document_size(litehtml::size& sz, int x = 0, int y = 0) override;
+               virtual void                            get_redraw_box(litehtml::position& pos, int x = 0, int y = 0) override;
+               virtual void                            add_style(const litehtml::style& st) override;
+               virtual element::ptr            get_element_by_point(int x, int y, int client_x, int client_y) override;
+               virtual element::ptr            get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex) override;
+
+               virtual bool                            is_nth_child(const element::ptr& el, int num, int off, bool of_type) const override;
+               virtual bool                            is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const override;
+               virtual bool                            is_only_child(const element::ptr& el, bool of_type) const override;
+               virtual const background*       get_background(bool own_only = false) override;
+
+       protected:
+               void                                            draw_children_box(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex);
+               void                                            draw_children_table(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex);
+               int                                                     render_box(int x, int y, int max_width, bool second_pass = false);
+               int                                                     render_table(int x, int y, int max_width, bool second_pass = false);
+               int                                                     fix_line_width(int max_width, element_float flt);
+               void                                            parse_background();
+               void                                            init_background_paint( position pos, background_paint &bg_paint, const background* bg );
+               void                                            draw_list_marker( uint_ptr hdc, const position &pos );
+               void                                            parse_nth_child_params( tstring param, int &num, int &off );
+               void                                            remove_before_after();
+               litehtml::element::ptr          get_element_before();
+               litehtml::element::ptr          get_element_after();
+       };
+
+       /************************************************************************/
+       /*                        Inline Functions                              */
+       /************************************************************************/
+
+       inline elements_vector& litehtml::html_tag::children()
+       {
+               return m_children;
+       }
+}
+
+#endif  // LH_HTML_TAG_H
index 3459f5c6f86ceaba857df267e43327f67ac2f39f..9d6a623d8b6253ad0515f6b05e6f2498d95b8567 100644 (file)
@@ -1,94 +1,94 @@
-#include "html.h"\r
-#include "iterators.h"\r
-#include "html_tag.h"\r
-\r
-litehtml::element::ptr litehtml::elements_iterator::next(bool ret_parent)\r
-{\r
-       next_idx();\r
-\r
-       while(m_idx < (int) m_el->get_children_count())\r
-       {\r
-               element::ptr el = m_el->get_child(m_idx);\r
-               if(     el->get_children_count() && m_go_inside && m_go_inside->select(el) )\r
-               {\r
-                       stack_item si;\r
-                       si.idx          = m_idx;\r
-                       si.el           = m_el;\r
-                       m_stack.push_back(si);\r
-                       m_el            = el;\r
-                       m_idx           = -1;\r
-                       if(ret_parent)\r
-                       {\r
-                               return el;\r
-                       }\r
-                       next_idx();\r
-               } else\r
-               {\r
-                       if( !m_select || (m_select && m_select->select(m_el->get_child(m_idx))) )\r
-                       {\r
-                               return m_el->get_child(m_idx);\r
-                       } else\r
-                       {\r
-                               next_idx();\r
-                       }\r
-               }\r
-       }\r
-\r
-       return 0;\r
-}\r
-\r
-void litehtml::elements_iterator::next_idx()\r
-{\r
-       m_idx++;\r
-       while(m_idx >= (int) m_el->get_children_count() && m_stack.size())\r
-       {\r
-               stack_item si = m_stack.back();\r
-               m_stack.pop_back();\r
-               m_idx   = si.idx;\r
-               m_el    = si.el;\r
-               m_idx++;\r
-               continue;\r
-       }\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////////\r
-//////////////////////////////////////////////////////////////////////////\r
-\r
-\r
-bool litehtml::go_inside_inline::select(const element::ptr& el)\r
-{\r
-       if(el->get_display() == display_inline || el->get_display() == display_inline_text)\r
-       {\r
-               return true;\r
-       }\r
-       return false;\r
-}\r
-\r
-bool litehtml::go_inside_table::select(const element::ptr& el)\r
-{\r
-       if(     el->get_display() == display_table_row_group ||\r
-               el->get_display() == display_table_header_group ||\r
-               el->get_display() == display_table_footer_group)\r
-       {\r
-               return true;\r
-       }\r
-       return false;\r
-}\r
-\r
-bool litehtml::table_rows_selector::select(const element::ptr& el)\r
-{\r
-       if(     el->get_display() == display_table_row)\r
-       {\r
-               return true;\r
-       }\r
-       return false;\r
-}\r
-\r
-bool litehtml::table_cells_selector::select(const element::ptr& el)\r
-{\r
-       if(     el->get_display() == display_table_cell)\r
-       {\r
-               return true;\r
-       }\r
-       return false;\r
-}\r
+#include "html.h"
+#include "iterators.h"
+#include "html_tag.h"
+
+litehtml::element::ptr litehtml::elements_iterator::next(bool ret_parent)
+{
+       next_idx();
+
+       while(m_idx < (int) m_el->get_children_count())
+       {
+               element::ptr el = m_el->get_child(m_idx);
+               if(     el->get_children_count() && m_go_inside && m_go_inside->select(el) )
+               {
+                       stack_item si;
+                       si.idx          = m_idx;
+                       si.el           = m_el;
+                       m_stack.push_back(si);
+                       m_el            = el;
+                       m_idx           = -1;
+                       if(ret_parent)
+                       {
+                               return el;
+                       }
+                       next_idx();
+               } else
+               {
+                       if( !m_select || (m_select && m_select->select(m_el->get_child(m_idx))) )
+                       {
+                               return m_el->get_child(m_idx);
+                       } else
+                       {
+                               next_idx();
+                       }
+               }
+       }
+
+       return 0;
+}
+
+void litehtml::elements_iterator::next_idx()
+{
+       m_idx++;
+       while(m_idx >= (int) m_el->get_children_count() && m_stack.size())
+       {
+               stack_item si = m_stack.back();
+               m_stack.pop_back();
+               m_idx   = si.idx;
+               m_el    = si.el;
+               m_idx++;
+               continue;
+       }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+
+bool litehtml::go_inside_inline::select(const element::ptr& el)
+{
+       if(el->get_display() == display_inline || el->get_display() == display_inline_text)
+       {
+               return true;
+       }
+       return false;
+}
+
+bool litehtml::go_inside_table::select(const element::ptr& el)
+{
+       if(     el->get_display() == display_table_row_group ||
+               el->get_display() == display_table_header_group ||
+               el->get_display() == display_table_footer_group)
+       {
+               return true;
+       }
+       return false;
+}
+
+bool litehtml::table_rows_selector::select(const element::ptr& el)
+{
+       if(     el->get_display() == display_table_row)
+       {
+               return true;
+       }
+       return false;
+}
+
+bool litehtml::table_cells_selector::select(const element::ptr& el)
+{
+       if(     el->get_display() == display_table_cell)
+       {
+               return true;
+       }
+       return false;
+}
index df60dc5b2f2c36adecb52f87c1a894debd5ee108..53f23c337a6e0cc392b4b5ab4a8f2a098926c5fb 100644 (file)
@@ -1,87 +1,90 @@
-#pragma once\r
-\r
-#include "types.h"\r
-\r
-namespace litehtml\r
-{\r
-       class element;\r
-\r
-       class iterator_selector\r
-       {\r
-       public:\r
-               virtual bool select(const element::ptr& el) = 0;\r
-       };\r
-\r
-       class elements_iterator\r
-       {\r
-       private:\r
-               struct stack_item\r
-               {\r
-                       int                             idx;\r
-                       element::ptr    el;\r
-                       stack_item()\r
-                       {\r
-\r
-                       }\r
-                       stack_item(const stack_item& val)\r
-                       {\r
-                               idx = val.idx;\r
-                               el = val.el;\r
-                       }\r
-                       stack_item(stack_item&& val)\r
-                       {\r
-                               idx = val.idx;\r
-                               el = std::move(val.el);\r
-                       }\r
-               };\r
-\r
-               std::vector<stack_item>         m_stack;\r
-               element::ptr                            m_el;\r
-               int                                                     m_idx;\r
-               iterator_selector*                      m_go_inside;\r
-               iterator_selector*                      m_select;\r
-       public:\r
-\r
-               elements_iterator(const element::ptr& el, iterator_selector* go_inside, iterator_selector* select)\r
-               { \r
-                       m_el                    = el;\r
-                       m_idx                   = -1; \r
-                       m_go_inside             = go_inside;\r
-                       m_select                = select;\r
-               }\r
-\r
-               ~elements_iterator()\r
-               {\r
-\r
-               }\r
-\r
-               element::ptr next(bool ret_parent = true);\r
-       \r
-       private:\r
-               void next_idx();\r
-       };\r
-\r
-       class go_inside_inline : public iterator_selector\r
-       {\r
-       public:\r
-               virtual bool select(const element::ptr& el);\r
-       };\r
-\r
-       class go_inside_table : public iterator_selector\r
-       {\r
-       public:\r
-               virtual bool select(const element::ptr& el);\r
-       };\r
-\r
-       class table_rows_selector : public iterator_selector\r
-       {\r
-       public:\r
-               virtual bool select(const element::ptr& el);\r
-       };\r
-\r
-       class table_cells_selector : public iterator_selector\r
-       {\r
-       public:\r
-               virtual bool select(const element::ptr& el);\r
-       };\r
-}\r
+#ifndef LH_ITERATORS_H
+#define LH_ITERATORS_H
+
+#include "types.h"
+
+namespace litehtml
+{
+       class element;
+
+       class iterator_selector
+       {
+       public:
+               virtual bool select(const element::ptr& el) = 0;
+       };
+
+       class elements_iterator
+       {
+       private:
+               struct stack_item
+               {
+                       int                             idx;
+                       element::ptr    el;
+                       stack_item()
+                       {
+
+                       }
+                       stack_item(const stack_item& val)
+                       {
+                               idx = val.idx;
+                               el = val.el;
+                       }
+                       stack_item(stack_item&& val)
+                       {
+                               idx = val.idx;
+                               el = std::move(val.el);
+                       }
+               };
+
+               std::vector<stack_item>         m_stack;
+               element::ptr                            m_el;
+               int                                                     m_idx;
+               iterator_selector*                      m_go_inside;
+               iterator_selector*                      m_select;
+       public:
+
+               elements_iterator(const element::ptr& el, iterator_selector* go_inside, iterator_selector* select)
+               { 
+                       m_el                    = el;
+                       m_idx                   = -1; 
+                       m_go_inside             = go_inside;
+                       m_select                = select;
+               }
+
+               ~elements_iterator()
+               {
+
+               }
+
+               element::ptr next(bool ret_parent = true);
+       
+       private:
+               void next_idx();
+       };
+
+       class go_inside_inline : public iterator_selector
+       {
+       public:
+               virtual bool select(const element::ptr& el);
+       };
+
+       class go_inside_table : public iterator_selector
+       {
+       public:
+               virtual bool select(const element::ptr& el);
+       };
+
+       class table_rows_selector : public iterator_selector
+       {
+       public:
+               virtual bool select(const element::ptr& el);
+       };
+
+       class table_cells_selector : public iterator_selector
+       {
+       public:
+               virtual bool select(const element::ptr& el);
+       };
+}
+
+#endif  // LH_ITERATORS_H
index 02e5b8d03fdbf3157116f5b65522f503df4fed66..75db8300e8ae2030718f20d00260e3fff97baf95 100644 (file)
@@ -1,10 +1,12 @@
-#pragma once
+#ifndef LITEHTML_H
+#define LITEHTML_H
 
-#include "litehtml/os_types.h"
-#include "litehtml/types.h"
 #include "litehtml/html.h"
-#include "litehtml/element.h"
 #include "litehtml/document.h"
-#include "litehtml/context.h"
+#include "litehtml/html_tag.h"
+#include "litehtml/stylesheet.h"
+#include "litehtml/stylesheet.h"
 #include "litehtml/element.h"
+#include "litehtml/html_tag.h"
 
+#endif  // LITEHTML_H
index 6cc66daf13d138ecaed9a6956a32dc52bd8a1f8d..41ff39ede98d5bf407c0c725d212c22d38f14d25 100644 (file)
-#include "html.h"\r
-#include "media_query.h"\r
-#include "document.h"\r
-\r
-\r
-litehtml::media_query::media_query()\r
-{\r
-       m_media_type    = media_type_all;\r
-       m_not                   = false;\r
-}\r
-\r
-litehtml::media_query::media_query( const media_query& val )\r
-{\r
-       m_not                   = val.m_not;\r
-       m_expressions   = val.m_expressions;\r
-       m_media_type    = val.m_media_type;\r
-}\r
-\r
-litehtml::media_query::ptr litehtml::media_query::create_from_string(const tstring& str, const std::shared_ptr<document>& doc)\r
-{\r
-       media_query::ptr query = std::make_shared<media_query>();\r
-\r
-       string_vector tokens;\r
-       split_string(str, tokens, _t(" \t\r\n"), _t(""), _t("("));\r
-\r
-       for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)\r
-       {\r
-               if((*tok) == _t("not"))\r
-               {\r
-                       query->m_not = true;\r
-               } else if(tok->at(0) == _t('('))\r
-               {\r
-                       tok->erase(0, 1);\r
-                       if(tok->at(tok->length() - 1) == _t(')'))\r
-                       {\r
-                               tok->erase(tok->length() - 1, 1);\r
-                       }\r
-                       media_query_expression expr;\r
-                       string_vector expr_tokens;\r
-                       split_string((*tok), expr_tokens, _t(":"));\r
-                       if(!expr_tokens.empty())\r
-                       {\r
-                               trim(expr_tokens[0]);\r
-                               expr.feature = (media_feature) value_index(expr_tokens[0], media_feature_strings, media_feature_none);\r
-                               if(expr.feature != media_feature_none)\r
-                               {\r
-                                       if(expr_tokens.size() == 1)\r
-                                       {\r
-                                               expr.check_as_bool = true;\r
-                                       } else\r
-                                       {\r
-                                               trim(expr_tokens[1]);\r
-                                               expr.check_as_bool = false;\r
-                                               if(expr.feature == media_feature_orientation)\r
-                                               {\r
-                                                       expr.val = value_index(expr_tokens[1], media_orientation_strings, media_orientation_landscape);\r
-                                               } else\r
-                                               {\r
-                                                       tstring::size_type slash_pos = expr_tokens[1].find(_t('/'));\r
-                                                       if( slash_pos != tstring::npos )\r
-                                                       {\r
-                                                               tstring val1 = expr_tokens[1].substr(0, slash_pos);\r
-                                                               tstring val2 = expr_tokens[1].substr(slash_pos + 1);\r
-                                                               trim(val1);\r
-                                                               trim(val2);\r
-                                                               expr.val = t_atoi(val1.c_str());\r
-                                                               expr.val2 = t_atoi(val2.c_str());\r
-                                                       } else\r
-                                                       {\r
-                                                               css_length length;\r
-                                                               length.fromString(expr_tokens[1]);\r
-                                                               if(length.units() == css_units_dpcm)\r
-                                                               {\r
-                                                                       expr.val = (int) (length.val() * 2.54);\r
-                                                               } else if(length.units() == css_units_dpi)\r
-                                                               {\r
-                                                                       expr.val = (int) (length.val() * 2.54);\r
-                                                               } else\r
-                                                               {\r
-                                                                       if(doc)\r
-                                                                       {\r
-                                                                               doc->cvt_units(length, doc->container()->get_default_font_size());\r
-                                                                       }\r
-                                                                       expr.val = (int) length.val();\r
-                                                               }\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                                       query->m_expressions.push_back(expr);\r
-                               }\r
-                       }\r
-               } else\r
-               {\r
-                       query->m_media_type = (media_type) value_index((*tok), media_type_strings, media_type_all);\r
-\r
-               }\r
-       }\r
-\r
-       return query;\r
-}\r
-\r
-bool litehtml::media_query::check( const media_features& features ) const\r
-{\r
-       bool res = false;\r
-       if(m_media_type == media_type_all || m_media_type == features.type)\r
-       {\r
-               res = true;\r
-               for(media_query_expression::vector::const_iterator expr = m_expressions.begin(); expr != m_expressions.end() && res; expr++)\r
-               {\r
-                       if(!expr->check(features))\r
-                       {\r
-                               res = false;\r
-                       }\r
-               }\r
-       }\r
-\r
-       if(m_not)\r
-       {\r
-               res = !res;\r
-       }\r
-\r
-       return res;\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////////\r
-\r
-litehtml::media_query_list::ptr litehtml::media_query_list::create_from_string(const tstring& str, const std::shared_ptr<document>& doc)\r
-{\r
-       media_query_list::ptr list = std::make_shared<media_query_list>();\r
-\r
-       string_vector tokens;\r
-       split_string(str, tokens, _t(","));\r
-\r
-       for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)\r
-       {\r
-               trim(*tok);\r
-               lcase(*tok);\r
-\r
-               litehtml::media_query::ptr query = media_query::create_from_string(*tok, doc);\r
-               if(query)\r
-               {\r
-                       list->m_queries.push_back(query);\r
-               }\r
-       }\r
-       if(list->m_queries.empty())\r
-       {\r
-               list = 0;\r
-       }\r
-\r
-       return list;\r
-}\r
-\r
-bool litehtml::media_query_list::apply_media_features( const media_features& features )\r
-{\r
-       bool apply = false;\r
-       \r
-       for(media_query::vector::iterator iter = m_queries.begin(); iter != m_queries.end() && !apply; iter++)\r
-       {\r
-               if((*iter)->check(features))\r
-               {\r
-                       apply = true;\r
-               }\r
-       }\r
-\r
-       bool ret = (apply != m_is_used);\r
-       m_is_used = apply;\r
-       return ret;\r
-}\r
-\r
-bool litehtml::media_query_expression::check( const media_features& features ) const\r
-{\r
-       switch(feature)\r
-       {\r
-       case media_feature_width:\r
-               if(check_as_bool)\r
-               {\r
-                       return (features.width != 0);\r
-               } else if(features.width == val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       case media_feature_min_width:\r
-               if(features.width >= val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       case media_feature_max_width:\r
-               if(features.width <= val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       case media_feature_height:\r
-               if(check_as_bool)\r
-               {\r
-                       return (features.height != 0);\r
-               } else if(features.height == val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       case media_feature_min_height:\r
-               if(features.height >= val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       case media_feature_max_height:\r
-               if(features.height <= val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-\r
-       case media_feature_device_width:\r
-               if(check_as_bool)\r
-               {\r
-                       return (features.device_width != 0);\r
-               } else if(features.device_width == val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       case media_feature_min_device_width:\r
-               if(features.device_width >= val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       case media_feature_max_device_width:\r
-               if(features.device_width <= val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       case media_feature_device_height:\r
-               if(check_as_bool)\r
-               {\r
-                       return (features.device_height != 0);\r
-               } else if(features.device_height == val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       case media_feature_min_device_height:\r
-               if(features.device_height <= val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       case media_feature_max_device_height:\r
-               if(features.device_height <= val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-\r
-       case media_feature_orientation:\r
-               if(features.height >= features.width)\r
-               {\r
-                       if(val == media_orientation_portrait)\r
-                       {\r
-                               return true;\r
-                       }\r
-               } else\r
-               {\r
-                       if(val == media_orientation_landscape)\r
-                       {\r
-                               return true;\r
-                       }\r
-               }\r
-               break;\r
-       case media_feature_aspect_ratio:\r
-               if(features.height && val2)\r
-               {\r
-                       int ratio_this = round_d( (double) val / (double) val2 * 100 );\r
-                       int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 );\r
-                       if(ratio_this == ratio_feat)\r
-                       {\r
-                               return true;\r
-                       }\r
-               }\r
-               break;\r
-       case media_feature_min_aspect_ratio:\r
-               if(features.height && val2)\r
-               {\r
-                       int ratio_this = round_d( (double) val / (double) val2 * 100 );\r
-                       int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 );\r
-                       if(ratio_feat >= ratio_this)\r
-                       {\r
-                               return true;\r
-                       }\r
-               }\r
-               break;\r
-       case media_feature_max_aspect_ratio:\r
-               if(features.height && val2)\r
-               {\r
-                       int ratio_this = round_d( (double) val / (double) val2 * 100 );\r
-                       int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 );\r
-                       if(ratio_feat <= ratio_this)\r
-                       {\r
-                               return true;\r
-                       }\r
-               }\r
-               break;\r
-\r
-       case media_feature_device_aspect_ratio:\r
-               if(features.device_height && val2)\r
-               {\r
-                       int ratio_this = round_d( (double) val / (double) val2 * 100 );\r
-                       int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 );\r
-                       if(ratio_feat == ratio_this)\r
-                       {\r
-                               return true;\r
-                       }\r
-               }\r
-               break;\r
-       case media_feature_min_device_aspect_ratio:\r
-               if(features.device_height && val2)\r
-               {\r
-                       int ratio_this = round_d( (double) val / (double) val2 * 100 );\r
-                       int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 );\r
-                       if(ratio_feat >= ratio_this)\r
-                       {\r
-                               return true;\r
-                       }\r
-               }\r
-               break;\r
-       case media_feature_max_device_aspect_ratio:\r
-               if(features.device_height && val2)\r
-               {\r
-                       int ratio_this = round_d( (double) val / (double) val2 * 100 );\r
-                       int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 );\r
-                       if(ratio_feat <= ratio_this)\r
-                       {\r
-                               return true;\r
-                       }\r
-               }\r
-               break;\r
-\r
-       case media_feature_color:\r
-               if(check_as_bool)\r
-               {\r
-                       return (features.color != 0);\r
-               } else if(features.color == val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       case media_feature_min_color:\r
-               if(features.color >= val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       case media_feature_max_color:\r
-               if(features.color <= val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-\r
-       case media_feature_color_index:\r
-               if(check_as_bool)\r
-               {\r
-                       return (features.color_index != 0);\r
-               } else if(features.color_index == val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       case media_feature_min_color_index:\r
-               if(features.color_index >= val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       case media_feature_max_color_index:\r
-               if(features.color_index <= val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-\r
-       case media_feature_monochrome:\r
-               if(check_as_bool)\r
-               {\r
-                       return (features.monochrome != 0);\r
-               } else if(features.monochrome == val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       case media_feature_min_monochrome:\r
-               if(features.monochrome >= val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       case media_feature_max_monochrome:\r
-               if(features.monochrome <= val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-\r
-       case media_feature_resolution:\r
-               if(features.resolution == val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       case media_feature_min_resolution:\r
-               if(features.resolution >= val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       case media_feature_max_resolution:\r
-               if(features.resolution <= val)\r
-               {\r
-                       return true;\r
-               }\r
-               break;\r
-       default:\r
-               return false;\r
-       }\r
-\r
-       return false;\r
-}\r
+#include "html.h"
+#include "media_query.h"
+#include "document.h"
+
+
+litehtml::media_query::media_query()
+{
+       m_media_type    = media_type_all;
+       m_not                   = false;
+}
+
+litehtml::media_query::media_query( const media_query& val )
+{
+       m_not                   = val.m_not;
+       m_expressions   = val.m_expressions;
+       m_media_type    = val.m_media_type;
+}
+
+litehtml::media_query::ptr litehtml::media_query::create_from_string(const tstring& str, const std::shared_ptr<document>& doc)
+{
+       media_query::ptr query = std::make_shared<media_query>();
+
+       string_vector tokens;
+       split_string(str, tokens, _t(" \t\r\n"), _t(""), _t("("));
+
+       for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+       {
+               if((*tok) == _t("not"))
+               {
+                       query->m_not = true;
+               } else if(tok->at(0) == _t('('))
+               {
+                       tok->erase(0, 1);
+                       if(tok->at(tok->length() - 1) == _t(')'))
+                       {
+                               tok->erase(tok->length() - 1, 1);
+                       }
+                       media_query_expression expr;
+                       string_vector expr_tokens;
+                       split_string((*tok), expr_tokens, _t(":"));
+                       if(!expr_tokens.empty())
+                       {
+                               trim(expr_tokens[0]);
+                               expr.feature = (media_feature) value_index(expr_tokens[0], media_feature_strings, media_feature_none);
+                               if(expr.feature != media_feature_none)
+                               {
+                                       if(expr_tokens.size() == 1)
+                                       {
+                                               expr.check_as_bool = true;
+                                       } else
+                                       {
+                                               trim(expr_tokens[1]);
+                                               expr.check_as_bool = false;
+                                               if(expr.feature == media_feature_orientation)
+                                               {
+                                                       expr.val = value_index(expr_tokens[1], media_orientation_strings, media_orientation_landscape);
+                                               } else
+                                               {
+                                                       tstring::size_type slash_pos = expr_tokens[1].find(_t('/'));
+                                                       if( slash_pos != tstring::npos )
+                                                       {
+                                                               tstring val1 = expr_tokens[1].substr(0, slash_pos);
+                                                               tstring val2 = expr_tokens[1].substr(slash_pos + 1);
+                                                               trim(val1);
+                                                               trim(val2);
+                                                               expr.val = t_atoi(val1.c_str());
+                                                               expr.val2 = t_atoi(val2.c_str());
+                                                       } else
+                                                       {
+                                                               css_length length;
+                                                               length.fromString(expr_tokens[1]);
+                                                               if(length.units() == css_units_dpcm)
+                                                               {
+                                                                       expr.val = (int) (length.val() * 2.54);
+                                                               } else if(length.units() == css_units_dpi)
+                                                               {
+                                                                       expr.val = (int) (length.val() * 2.54);
+                                                               } else
+                                                               {
+                                                                       if(doc)
+                                                                       {
+                                                                               doc->cvt_units(length, doc->container()->get_default_font_size());
+                                                                       }
+                                                                       expr.val = (int) length.val();
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       query->m_expressions.push_back(expr);
+                               }
+                       }
+               } else
+               {
+                       query->m_media_type = (media_type) value_index((*tok), media_type_strings, media_type_all);
+
+               }
+       }
+
+       return query;
+}
+
+bool litehtml::media_query::check( const media_features& features ) const
+{
+       bool res = false;
+       if(m_media_type == media_type_all || m_media_type == features.type)
+       {
+               res = true;
+               for(media_query_expression::vector::const_iterator expr = m_expressions.begin(); expr != m_expressions.end() && res; expr++)
+               {
+                       if(!expr->check(features))
+                       {
+                               res = false;
+                       }
+               }
+       }
+
+       if(m_not)
+       {
+               res = !res;
+       }
+
+       return res;
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+litehtml::media_query_list::ptr litehtml::media_query_list::create_from_string(const tstring& str, const std::shared_ptr<document>& doc)
+{
+       media_query_list::ptr list = std::make_shared<media_query_list>();
+
+       string_vector tokens;
+       split_string(str, tokens, _t(","));
+
+       for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+       {
+               trim(*tok);
+               lcase(*tok);
+
+               litehtml::media_query::ptr query = media_query::create_from_string(*tok, doc);
+               if(query)
+               {
+                       list->m_queries.push_back(query);
+               }
+       }
+       if(list->m_queries.empty())
+       {
+               list = 0;
+       }
+
+       return list;
+}
+
+bool litehtml::media_query_list::apply_media_features( const media_features& features )
+{
+       bool apply = false;
+       
+       for(media_query::vector::iterator iter = m_queries.begin(); iter != m_queries.end() && !apply; iter++)
+       {
+               if((*iter)->check(features))
+               {
+                       apply = true;
+               }
+       }
+
+       bool ret = (apply != m_is_used);
+       m_is_used = apply;
+       return ret;
+}
+
+bool litehtml::media_query_expression::check( const media_features& features ) const
+{
+       switch(feature)
+       {
+       case media_feature_width:
+               if(check_as_bool)
+               {
+                       return (features.width != 0);
+               } else if(features.width == val)
+               {
+                       return true;
+               }
+               break;
+       case media_feature_min_width:
+               if(features.width >= val)
+               {
+                       return true;
+               }
+               break;
+       case media_feature_max_width:
+               if(features.width <= val)
+               {
+                       return true;
+               }
+               break;
+       case media_feature_height:
+               if(check_as_bool)
+               {
+                       return (features.height != 0);
+               } else if(features.height == val)
+               {
+                       return true;
+               }
+               break;
+       case media_feature_min_height:
+               if(features.height >= val)
+               {
+                       return true;
+               }
+               break;
+       case media_feature_max_height:
+               if(features.height <= val)
+               {
+                       return true;
+               }
+               break;
+
+       case media_feature_device_width:
+               if(check_as_bool)
+               {
+                       return (features.device_width != 0);
+               } else if(features.device_width == val)
+               {
+                       return true;
+               }
+               break;
+       case media_feature_min_device_width:
+               if(features.device_width >= val)
+               {
+                       return true;
+               }
+               break;
+       case media_feature_max_device_width:
+               if(features.device_width <= val)
+               {
+                       return true;
+               }
+               break;
+       case media_feature_device_height:
+               if(check_as_bool)
+               {
+                       return (features.device_height != 0);
+               } else if(features.device_height == val)
+               {
+                       return true;
+               }
+               break;
+       case media_feature_min_device_height:
+               if(features.device_height <= val)
+               {
+                       return true;
+               }
+               break;
+       case media_feature_max_device_height:
+               if(features.device_height <= val)
+               {
+                       return true;
+               }
+               break;
+
+       case media_feature_orientation:
+               if(features.height >= features.width)
+               {
+                       if(val == media_orientation_portrait)
+                       {
+                               return true;
+                       }
+               } else
+               {
+                       if(val == media_orientation_landscape)
+                       {
+                               return true;
+                       }
+               }
+               break;
+       case media_feature_aspect_ratio:
+               if(features.height && val2)
+               {
+                       int ratio_this = round_d( (double) val / (double) val2 * 100 );
+                       int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 );
+                       if(ratio_this == ratio_feat)
+                       {
+                               return true;
+                       }
+               }
+               break;
+       case media_feature_min_aspect_ratio:
+               if(features.height && val2)
+               {
+                       int ratio_this = round_d( (double) val / (double) val2 * 100 );
+                       int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 );
+                       if(ratio_feat >= ratio_this)
+                       {
+                               return true;
+                       }
+               }
+               break;
+       case media_feature_max_aspect_ratio:
+               if(features.height && val2)
+               {
+                       int ratio_this = round_d( (double) val / (double) val2 * 100 );
+                       int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 );
+                       if(ratio_feat <= ratio_this)
+                       {
+                               return true;
+                       }
+               }
+               break;
+
+       case media_feature_device_aspect_ratio:
+               if(features.device_height && val2)
+               {
+                       int ratio_this = round_d( (double) val / (double) val2 * 100 );
+                       int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 );
+                       if(ratio_feat == ratio_this)
+                       {
+                               return true;
+                       }
+               }
+               break;
+       case media_feature_min_device_aspect_ratio:
+               if(features.device_height && val2)
+               {
+                       int ratio_this = round_d( (double) val / (double) val2 * 100 );
+                       int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 );
+                       if(ratio_feat >= ratio_this)
+                       {
+                               return true;
+                       }
+               }
+               break;
+       case media_feature_max_device_aspect_ratio:
+               if(features.device_height && val2)
+               {
+                       int ratio_this = round_d( (double) val / (double) val2 * 100 );
+                       int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 );
+                       if(ratio_feat <= ratio_this)
+                       {
+                               return true;
+                       }
+               }
+               break;
+
+       case media_feature_color:
+               if(check_as_bool)
+               {
+                       return (features.color != 0);
+               } else if(features.color == val)
+               {
+                       return true;
+               }
+               break;
+       case media_feature_min_color:
+               if(features.color >= val)
+               {
+                       return true;
+               }
+               break;
+       case media_feature_max_color:
+               if(features.color <= val)
+               {
+                       return true;
+               }
+               break;
+
+       case media_feature_color_index:
+               if(check_as_bool)
+               {
+                       return (features.color_index != 0);
+               } else if(features.color_index == val)
+               {
+                       return true;
+               }
+               break;
+       case media_feature_min_color_index:
+               if(features.color_index >= val)
+               {
+                       return true;
+               }
+               break;
+       case media_feature_max_color_index:
+               if(features.color_index <= val)
+               {
+                       return true;
+               }
+               break;
+
+       case media_feature_monochrome:
+               if(check_as_bool)
+               {
+                       return (features.monochrome != 0);
+               } else if(features.monochrome == val)
+               {
+                       return true;
+               }
+               break;
+       case media_feature_min_monochrome:
+               if(features.monochrome >= val)
+               {
+                       return true;
+               }
+               break;
+       case media_feature_max_monochrome:
+               if(features.monochrome <= val)
+               {
+                       return true;
+               }
+               break;
+
+       case media_feature_resolution:
+               if(features.resolution == val)
+               {
+                       return true;
+               }
+               break;
+       case media_feature_min_resolution:
+               if(features.resolution >= val)
+               {
+                       return true;
+               }
+               break;
+       case media_feature_max_resolution:
+               if(features.resolution <= val)
+               {
+                       return true;
+               }
+               break;
+       default:
+               return false;
+       }
+
+       return false;
+}
index 52c7f3f4f2f821bfb708a0b586bcdf4293af4a09..6a81bcb32ab9e426a19ec1a158523b1a71d74758 100644 (file)
@@ -1,74 +1,77 @@
-#pragma once\r
-\r
-namespace litehtml\r
-{\r
-       struct media_query_expression\r
-       {\r
-               typedef std::vector<media_query_expression>     vector;\r
-               media_feature   feature;\r
-               int                             val;\r
-               int                             val2;\r
-               bool                    check_as_bool;\r
-               \r
-               media_query_expression()\r
-               {\r
-                       check_as_bool   = false;\r
-                       feature                 = media_feature_none;\r
-                       val                             = 0;\r
-                       val2                    = 0;\r
-               }\r
-\r
-               bool check(const media_features& features) const;\r
-       };\r
-\r
-       class media_query\r
-       {\r
-       public:\r
-               typedef std::shared_ptr<media_query>    ptr;\r
-               typedef std::vector<media_query::ptr>   vector;\r
-       private:\r
-               media_query_expression::vector  m_expressions;\r
-               bool                                                    m_not;\r
-               media_type                                              m_media_type;\r
-       public:\r
-               media_query();\r
-               media_query(const media_query& val);\r
-\r
-               static media_query::ptr create_from_string(const tstring& str, const std::shared_ptr<document>& doc);\r
-               bool check(const media_features& features) const;\r
-       };\r
-\r
-       class media_query_list\r
-       {\r
-       public:\r
-               typedef std::shared_ptr<media_query_list>       ptr;\r
-               typedef std::vector<media_query_list::ptr>      vector;\r
-       private:\r
-               media_query::vector     m_queries;\r
-               bool                            m_is_used;\r
-       public:\r
-               media_query_list();\r
-               media_query_list(const media_query_list& val);\r
-\r
-               static media_query_list::ptr create_from_string(const tstring& str, const std::shared_ptr<document>& doc);\r
-               bool is_used() const;\r
-               bool apply_media_features(const media_features& features);      // returns true if the m_is_used changed\r
-       };\r
-\r
-       inline media_query_list::media_query_list(const media_query_list& val)\r
-       {\r
-               m_is_used       = val.m_is_used;\r
-               m_queries       = val.m_queries;\r
-       }\r
-\r
-       inline media_query_list::media_query_list()\r
-       {\r
-               m_is_used = false;\r
-       }\r
-\r
-       inline bool media_query_list::is_used() const\r
-       {\r
-               return m_is_used;\r
-       }\r
-\r
-}
\ No newline at end of file
+#ifndef LH_MEDIA_QUERY_H
+#define LH_MEDIA_QUERY_H
+
+namespace litehtml
+{
+       struct media_query_expression
+       {
+               typedef std::vector<media_query_expression>     vector;
+               media_feature   feature;
+               int                             val;
+               int                             val2;
+               bool                    check_as_bool;
+               
+               media_query_expression()
+               {
+                       check_as_bool   = false;
+                       feature                 = media_feature_none;
+                       val                             = 0;
+                       val2                    = 0;
+               }
+
+               bool check(const media_features& features) const;
+       };
+
+       class media_query
+       {
+       public:
+               typedef std::shared_ptr<media_query>    ptr;
+               typedef std::vector<media_query::ptr>   vector;
+       private:
+               media_query_expression::vector  m_expressions;
+               bool                                                    m_not;
+               media_type                                              m_media_type;
+       public:
+               media_query();
+               media_query(const media_query& val);
+
+               static media_query::ptr create_from_string(const tstring& str, const std::shared_ptr<document>& doc);
+               bool check(const media_features& features) const;
+       };
+
+       class media_query_list
+       {
+       public:
+               typedef std::shared_ptr<media_query_list>       ptr;
+               typedef std::vector<media_query_list::ptr>      vector;
+       private:
+               media_query::vector     m_queries;
+               bool                            m_is_used;
+       public:
+               media_query_list();
+               media_query_list(const media_query_list& val);
+
+               static media_query_list::ptr create_from_string(const tstring& str, const std::shared_ptr<document>& doc);
+               bool is_used() const;
+               bool apply_media_features(const media_features& features);      // returns true if the m_is_used changed
+       };
+
+       inline media_query_list::media_query_list(const media_query_list& val)
+       {
+               m_is_used       = val.m_is_used;
+               m_queries       = val.m_queries;
+       }
+
+       inline media_query_list::media_query_list()
+       {
+               m_is_used = false;
+       }
+
+       inline bool media_query_list::is_used() const
+       {
+               return m_is_used;
+       }
+
+}
+
+#endif  // LH_MEDIA_QUERY_H
index 4fb638f07d114a9a8c1954ed5a96219f55a945b2..39b027085d4ad3ce9dfd985fd02983a585ea99d1 100644 (file)
@@ -1,83 +1,86 @@
-#pragma once\r
-\r
-namespace litehtml\r
-{\r
-#if defined( WIN32 ) || defined( WINCE )\r
-\r
-#ifndef LITEHTML_UTF8\r
-\r
-       typedef std::wstring            tstring;\r
-       typedef wchar_t                         tchar_t;\r
-       typedef std::wstringstream      tstringstream;\r
-\r
-       #define _t(quote)                       L##quote\r
-\r
-       #define t_strlen                        wcslen\r
-       #define t_strcmp                        wcscmp\r
-       #define t_strncmp                       wcsncmp\r
-       #define t_strcasecmp            _wcsicmp\r
-       #define t_strncasecmp           _wcsnicmp\r
-       #define t_strtol                        wcstol\r
-       #define t_atoi                          _wtoi\r
-       #define t_strtod                        wcstod\r
-       #define t_itoa(value, buffer, size, radix)      _itow_s(value, buffer, size, radix)\r
-       #define t_strstr                        wcsstr\r
-       #define t_tolower                       towlower\r
-       #define t_isdigit                       iswdigit\r
-\r
-#else\r
-\r
-       typedef std::string                     tstring;\r
-       typedef char                            tchar_t;\r
-       typedef std::stringstream       tstringstream;\r
-\r
-       #define _t(quote)                       quote\r
-\r
-       #define t_strlen                        strlen\r
-       #define t_strcmp                        strcmp\r
-       #define t_strncmp                       strncmp\r
-       #define t_strcasecmp            _stricmp\r
-       #define t_strncasecmp           _strnicmp\r
-       #define t_strtol                        strtol\r
-       #define t_atoi                          atoi\r
-       #define t_strtod                        strtod\r
-       #define t_itoa(value, buffer, size, radix)      _itoa_s(value, buffer, size, radix)\r
-       #define t_strstr                        strstr\r
-       #define t_tolower                       tolower\r
-       #define t_isdigit                       isdigit\r
-\r
-#endif\r
-\r
-       #ifdef _WIN64\r
-               typedef unsigned __int64 uint_ptr;\r
-       #else\r
-               typedef unsigned int    uint_ptr;\r
-       #endif\r
-\r
-#else\r
-       #define LITEHTML_UTF8\r
-\r
-       typedef std::string                     tstring;\r
-       typedef char                            tchar_t;\r
-       typedef void*                           uint_ptr;\r
-       typedef std::stringstream       tstringstream;\r
-\r
-       #define _t(quote)                       quote\r
-\r
-       #define t_strlen                        strlen\r
-       #define t_strcmp                        strcmp\r
-       #define t_strncmp                       strncmp\r
-\r
-       #define t_strcasecmp            strcasecmp\r
-       #define t_strncasecmp           strncasecmp\r
-       #define t_itoa(value, buffer, size, radix)      snprintf(buffer, size, "%d", value)\r
-\r
-       #define t_strtol                        strtol\r
-       #define t_atoi                          atoi\r
-       #define t_strtod                        strtod\r
-       #define t_strstr                        strstr\r
-       #define t_tolower                       tolower\r
-       #define t_isdigit                       isdigit\r
-\r
-#endif\r
-}\r
+#ifndef LH_OS_TYPES_H
+#define LH_OS_TYPES_H
+
+namespace litehtml
+{
+#if defined( WIN32 ) || defined( WINCE )
+
+#ifndef LITEHTML_UTF8
+
+       typedef std::wstring            tstring;
+       typedef wchar_t                         tchar_t;
+       typedef std::wstringstream      tstringstream;
+
+       #define _t(quote)                       L##quote
+
+       #define t_strlen                        wcslen
+       #define t_strcmp                        wcscmp
+       #define t_strncmp                       wcsncmp
+       #define t_strcasecmp            _wcsicmp
+       #define t_strncasecmp           _wcsnicmp
+       #define t_strtol                        wcstol
+       #define t_atoi                          _wtoi
+       #define t_strtod                        wcstod
+       #define t_itoa(value, buffer, size, radix)      _itow_s(value, buffer, size, radix)
+       #define t_strstr                        wcsstr
+       #define t_tolower                       towlower
+       #define t_isdigit                       iswdigit
+
+#else
+
+       typedef std::string                     tstring;
+       typedef char                            tchar_t;
+       typedef std::stringstream       tstringstream;
+
+       #define _t(quote)                       quote
+
+       #define t_strlen                        strlen
+       #define t_strcmp                        strcmp
+       #define t_strncmp                       strncmp
+       #define t_strcasecmp            _stricmp
+       #define t_strncasecmp           _strnicmp
+       #define t_strtol                        strtol
+       #define t_atoi                          atoi
+       #define t_strtod                        strtod
+       #define t_itoa(value, buffer, size, radix)      _itoa_s(value, buffer, size, radix)
+       #define t_strstr                        strstr
+       #define t_tolower                       tolower
+       #define t_isdigit                       isdigit
+
+#endif
+
+       #ifdef _WIN64
+               typedef unsigned __int64 uint_ptr;
+       #else
+               typedef unsigned int    uint_ptr;
+       #endif
+
+#else
+       #define LITEHTML_UTF8
+
+       typedef std::string                     tstring;
+       typedef char                            tchar_t;
+       typedef void*                           uint_ptr;
+       typedef std::stringstream       tstringstream;
+
+       #define _t(quote)                       quote
+
+       #define t_strlen                        strlen
+       #define t_strcmp                        strcmp
+       #define t_strncmp                       strncmp
+
+       #define t_strcasecmp            strcasecmp
+       #define t_strncasecmp           strncasecmp
+       #define t_itoa(value, buffer, size, radix)      snprintf(buffer, size, "%d", value)
+
+       #define t_strtol                        strtol
+       #define t_atoi                          atoi
+       #define t_strtod                        strtod
+       #define t_strstr                        strstr
+       #define t_tolower                       tolower
+       #define t_isdigit                       isdigit
+
+#endif
+}
+
+#endif  // LH_OS_TYPES_H
index 60b873837976d43f69cddef1b171b7d431bdd153..be0687073a967a90f0a3bf5ad9ad83d91980560d 100644 (file)
-#include "html.h"\r
-#include "style.h"\r
-#include <functional>\r
-#include <algorithm>\r
-#ifndef WINCE\r
-#include <locale>\r
-#endif\r
-\r
-litehtml::string_map litehtml::style::m_valid_values =\r
-{\r
-       { _t("white-space"), white_space_strings }\r
-};\r
-\r
-litehtml::style::style()\r
-{\r
-}\r
-\r
-litehtml::style::style( const style& val )\r
-{\r
-       m_properties = val.m_properties;\r
-}\r
-\r
-litehtml::style::~style()\r
-{\r
-\r
-}\r
-\r
-void litehtml::style::parse( const tchar_t* txt, const tchar_t* baseurl )\r
-{\r
-       std::vector<tstring> properties;\r
-       split_string(txt, properties, _t(";"));\r
-\r
-       for(std::vector<tstring>::const_iterator i = properties.begin(); i != properties.end(); i++)\r
-       {\r
-               parse_property(*i, baseurl);\r
-       }\r
-}\r
-\r
-void litehtml::style::parse_property( const tstring& txt, const tchar_t* baseurl )\r
-{\r
-       tstring::size_type pos = txt.find_first_of(_t(":"));\r
-       if(pos != tstring::npos)\r
-       {\r
-               tstring name    = txt.substr(0, pos);\r
-               tstring val     = txt.substr(pos + 1);\r
-\r
-               trim(name);\r
-               trim(val);\r
-\r
-               lcase(name);\r
-\r
-               if(!name.empty() && !val.empty())\r
-               {\r
-                       string_vector vals;\r
-                       split_string(val, vals, _t("!"));\r
-                       if(vals.size() == 1)\r
-                       {\r
-                               add_property(name.c_str(), val.c_str(), baseurl, false);\r
-                       } else if(vals.size() > 1)\r
-                       {\r
-                               trim(vals[0]);\r
-                               lcase(vals[1]);\r
-                               if(vals[1] == _t("important"))\r
-                               {\r
-                                       add_property(name.c_str(), vals[0].c_str(), baseurl, true);\r
-                               } else\r
-                               {\r
-                                       add_property(name.c_str(), vals[0].c_str(), baseurl, false);\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-void litehtml::style::combine( const litehtml::style& src )\r
-{\r
-       for(props_map::const_iterator i = src.m_properties.begin(); i != src.m_properties.end(); i++)\r
-       {\r
-               add_parsed_property(i->first.c_str(), i->second.m_value.c_str(), i->second.m_important);\r
-       }\r
-}\r
-\r
-void litehtml::style::add_property( const tchar_t* name, const tchar_t* val, const tchar_t* baseurl, bool important )\r
-{\r
-       if(!name || !val)\r
-       {\r
-               return;\r
-       }\r
-\r
-       // Add baseurl for background image \r
-       if(     !t_strcmp(name, _t("background-image")))\r
-       {\r
-               add_parsed_property(name, val, important);\r
-               if(baseurl)\r
-               {\r
-                       add_parsed_property(_t("background-image-baseurl"), baseurl, important);\r
-               }\r
-       } else\r
-\r
-       // Parse border spacing properties \r
-       if(     !t_strcmp(name, _t("border-spacing")))\r
-       {\r
-               string_vector tokens;\r
-               split_string(val, tokens, _t(" "));\r
-               if(tokens.size() == 1)\r
-               {\r
-                       add_property(_t("-litehtml-border-spacing-x"), tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("-litehtml-border-spacing-y"), tokens[0].c_str(), baseurl, important);\r
-               } else if(tokens.size() == 2)\r
-               {\r
-                       add_property(_t("-litehtml-border-spacing-x"), tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("-litehtml-border-spacing-y"), tokens[1].c_str(), baseurl, important);\r
-               }\r
-       } else\r
-\r
-       // Parse borders shorthand properties \r
-\r
-       if(     !t_strcmp(name, _t("border")))\r
-       {\r
-               string_vector tokens;\r
-               split_string(val, tokens, _t(" "), _t(""), _t("("));\r
-               int idx;\r
-               tstring str;\r
-               for(string_vector::const_iterator tok = tokens.begin(); tok != tokens.end(); tok++)\r
-               {\r
-                       idx = value_index(tok->c_str(), border_style_strings, -1);\r
-                       if(idx >= 0)\r
-                       {\r
-                               add_property(_t("border-left-style"), tok->c_str(), baseurl, important);\r
-                               add_property(_t("border-right-style"), tok->c_str(), baseurl, important);\r
-                               add_property(_t("border-top-style"), tok->c_str(), baseurl, important);\r
-                               add_property(_t("border-bottom-style"), tok->c_str(), baseurl, important);\r
-                       } else\r
-                       {\r
-                               if(web_color::is_color(tok->c_str()))\r
-                               {\r
-                                       add_property(_t("border-left-color"), tok->c_str(), baseurl, important);\r
-                                       add_property(_t("border-right-color"), tok->c_str(), baseurl, important);\r
-                                       add_property(_t("border-top-color"), tok->c_str(), baseurl, important);\r
-                                       add_property(_t("border-bottom-color"), tok->c_str(), baseurl, important);\r
-                               } else\r
-                               {\r
-                                       add_property(_t("border-left-width"), tok->c_str(), baseurl, important);\r
-                                       add_property(_t("border-right-width"), tok->c_str(), baseurl, important);\r
-                                       add_property(_t("border-top-width"), tok->c_str(), baseurl, important);\r
-                                       add_property(_t("border-bottom-width"), tok->c_str(), baseurl, important);\r
-                               }\r
-                       }\r
-               }\r
-       } else if(      !t_strcmp(name, _t("border-left"))      ||\r
-               !t_strcmp(name, _t("border-right"))     ||\r
-               !t_strcmp(name, _t("border-top"))       ||\r
-               !t_strcmp(name, _t("border-bottom")) )\r
-       {\r
-               string_vector tokens;\r
-               split_string(val, tokens, _t(" "), _t(""), _t("("));\r
-               int idx;\r
-               tstring str;\r
-               for(string_vector::const_iterator tok = tokens.begin(); tok != tokens.end(); tok++)\r
-               {\r
-                       idx = value_index(tok->c_str(), border_style_strings, -1);\r
-                       if(idx >= 0)\r
-                       {\r
-                               str = name;\r
-                               str += _t("-style");\r
-                               add_property(str.c_str(), tok->c_str(), baseurl, important);\r
-                       } else\r
-                       {\r
-                               if(web_color::is_color(tok->c_str()))\r
-                               {\r
-                                       str = name;\r
-                                       str += _t("-color");\r
-                                       add_property(str.c_str(), tok->c_str(), baseurl, important);\r
-                               } else\r
-                               {\r
-                                       str = name;\r
-                                       str += _t("-width");\r
-                                       add_property(str.c_str(), tok->c_str(), baseurl, important);\r
-                               }\r
-                       }\r
-               }\r
-       } else \r
-\r
-       // Parse border radius shorthand properties \r
-       if(!t_strcmp(name, _t("border-bottom-left-radius")))\r
-       {\r
-               string_vector tokens;\r
-               split_string(val, tokens, _t(" "));\r
-               if(tokens.size() >= 2)\r
-               {\r
-                       add_property(_t("border-bottom-left-radius-x"), tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-left-radius-y"), tokens[1].c_str(), baseurl, important);\r
-               } else if(tokens.size() == 1)\r
-               {\r
-                       add_property(_t("border-bottom-left-radius-x"), tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-left-radius-y"), tokens[0].c_str(), baseurl, important);\r
-               }\r
-\r
-       } else if(!t_strcmp(name, _t("border-bottom-right-radius")))\r
-       {\r
-               string_vector tokens;\r
-               split_string(val, tokens, _t(" "));\r
-               if(tokens.size() >= 2)\r
-               {\r
-                       add_property(_t("border-bottom-right-radius-x"), tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-right-radius-y"), tokens[1].c_str(), baseurl, important);\r
-               } else if(tokens.size() == 1)\r
-               {\r
-                       add_property(_t("border-bottom-right-radius-x"), tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-right-radius-y"), tokens[0].c_str(), baseurl, important);\r
-               }\r
-\r
-       } else if(!t_strcmp(name, _t("border-top-right-radius")))\r
-       {\r
-               string_vector tokens;\r
-               split_string(val, tokens, _t(" "));\r
-               if(tokens.size() >= 2)\r
-               {\r
-                       add_property(_t("border-top-right-radius-x"), tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-top-right-radius-y"), tokens[1].c_str(), baseurl, important);\r
-               } else if(tokens.size() == 1)\r
-               {\r
-                       add_property(_t("border-top-right-radius-x"), tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-top-right-radius-y"), tokens[0].c_str(), baseurl, important);\r
-               }\r
-\r
-       } else if(!t_strcmp(name, _t("border-top-left-radius")))\r
-       {\r
-               string_vector tokens;\r
-               split_string(val, tokens, _t(" "));\r
-               if(tokens.size() >= 2)\r
-               {\r
-                       add_property(_t("border-top-left-radius-x"), tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-top-left-radius-y"), tokens[1].c_str(), baseurl, important);\r
-               } else if(tokens.size() == 1)\r
-               {\r
-                       add_property(_t("border-top-left-radius-x"), tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-top-left-radius-y"), tokens[0].c_str(), baseurl, important);\r
-               }\r
-\r
-       } else \r
-\r
-       // Parse border-radius shorthand properties \r
-       if(!t_strcmp(name, _t("border-radius")))\r
-       {\r
-               string_vector tokens;\r
-               split_string(val, tokens, _t("/"));\r
-               if(tokens.size() == 1)\r
-               {\r
-                       add_property(_t("border-radius-x"), tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-radius-y"), tokens[0].c_str(), baseurl, important);\r
-               } else if(tokens.size() >= 2)\r
-               {\r
-                       add_property(_t("border-radius-x"), tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-radius-y"), tokens[1].c_str(), baseurl, important);\r
-               }\r
-       } else if(!t_strcmp(name, _t("border-radius-x")))\r
-       {\r
-               string_vector tokens;\r
-               split_string(val, tokens, _t(" "));\r
-               if(tokens.size() == 1)\r
-               {\r
-                       add_property(_t("border-top-left-radius-x"),            tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-top-right-radius-x"),           tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-right-radius-x"),        tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-left-radius-x"), tokens[0].c_str(), baseurl, important);\r
-               } else if(tokens.size() == 2)\r
-               {\r
-                       add_property(_t("border-top-left-radius-x"),            tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-top-right-radius-x"),           tokens[1].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-right-radius-x"),        tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-left-radius-x"), tokens[1].c_str(), baseurl, important);\r
-               } else if(tokens.size() == 3)\r
-               {\r
-                       add_property(_t("border-top-left-radius-x"),            tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-top-right-radius-x"),           tokens[1].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-right-radius-x"),        tokens[2].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-left-radius-x"), tokens[1].c_str(), baseurl, important);\r
-               } else if(tokens.size() == 4)\r
-               {\r
-                       add_property(_t("border-top-left-radius-x"),            tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-top-right-radius-x"),           tokens[1].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-right-radius-x"),        tokens[2].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-left-radius-x"), tokens[3].c_str(), baseurl, important);\r
-               }\r
-       } else if(!t_strcmp(name, _t("border-radius-y")))\r
-       {\r
-               string_vector tokens;\r
-               split_string(val, tokens, _t(" "));\r
-               if(tokens.size() == 1)\r
-               {\r
-                       add_property(_t("border-top-left-radius-y"),            tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-top-right-radius-y"),           tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-right-radius-y"),        tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-left-radius-y"), tokens[0].c_str(), baseurl, important);\r
-               } else if(tokens.size() == 2)\r
-               {\r
-                       add_property(_t("border-top-left-radius-y"),            tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-top-right-radius-y"),           tokens[1].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-right-radius-y"),        tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-left-radius-y"), tokens[1].c_str(), baseurl, important);\r
-               } else if(tokens.size() == 3)\r
-               {\r
-                       add_property(_t("border-top-left-radius-y"),            tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-top-right-radius-y"),           tokens[1].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-right-radius-y"),        tokens[2].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-left-radius-y"), tokens[1].c_str(), baseurl, important);\r
-               } else if(tokens.size() == 4)\r
-               {\r
-                       add_property(_t("border-top-left-radius-y"),            tokens[0].c_str(), baseurl, important);\r
-                       add_property(_t("border-top-right-radius-y"),           tokens[1].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-right-radius-y"),        tokens[2].c_str(), baseurl, important);\r
-                       add_property(_t("border-bottom-left-radius-y"), tokens[3].c_str(), baseurl, important);\r
-               }\r
-       }\r
-       \r
-\r
-       // Parse list-style shorthand properties \r
-       if(!t_strcmp(name, _t("list-style")))\r
-       {\r
-               add_parsed_property(_t("list-style-type"),                      _t("disc"),             important);\r
-               add_parsed_property(_t("list-style-position"),          _t("outside"),  important);\r
-               add_parsed_property(_t("list-style-image"),                     _t(""),                 important);\r
-               add_parsed_property(_t("list-style-image-baseurl"),     _t(""),                 important);\r
-\r
-               string_vector tokens;\r
-               split_string(val, tokens, _t(" "), _t(""), _t("("));\r
-               for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)\r
-               {\r
-                       int idx = value_index(tok->c_str(), list_style_type_strings, -1);\r
-                       if(idx >= 0)\r
-                       {\r
-                               add_parsed_property(_t("list-style-type"), *tok, important);\r
-                       } else\r
-                       {\r
-                               idx = value_index(tok->c_str(), list_style_position_strings, -1);\r
-                               if(idx >= 0)\r
-                               {\r
-                                       add_parsed_property(_t("list-style-position"), *tok, important);\r
-                               } else if(!t_strncmp(val, _t("url"), 3))\r
-                               {\r
-                                       add_parsed_property(_t("list-style-image"), *tok, important);\r
-                                       if(baseurl)\r
-                                       {\r
-                                               add_parsed_property(_t("list-style-image-baseurl"), baseurl, important);\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       } else \r
-\r
-       // Add baseurl for background image \r
-       if(     !t_strcmp(name, _t("list-style-image")))\r
-       {\r
-               add_parsed_property(name, val, important);\r
-               if(baseurl)\r
-               {\r
-                       add_parsed_property(_t("list-style-image-baseurl"), baseurl, important);\r
-               }\r
-       } else\r
-               \r
-       // Parse background shorthand properties \r
-       if(!t_strcmp(name, _t("background")))\r
-       {\r
-               parse_short_background(val, baseurl, important);\r
-\r
-       } else \r
-               \r
-       // Parse margin and padding shorthand properties \r
-       if(!t_strcmp(name, _t("margin")) || !t_strcmp(name, _t("padding")))\r
-       {\r
-               string_vector tokens;\r
-               split_string(val, tokens, _t(" "));\r
-               if(tokens.size() >= 4)\r
-               {\r
-                       add_parsed_property(tstring(name) + _t("-top"),         tokens[0], important);\r
-                       add_parsed_property(tstring(name) + _t("-right"),               tokens[1], important);\r
-                       add_parsed_property(tstring(name) + _t("-bottom"),      tokens[2], important);\r
-                       add_parsed_property(tstring(name) + _t("-left"),                tokens[3], important);\r
-               } else if(tokens.size() == 3)\r
-               {\r
-                       add_parsed_property(tstring(name) + _t("-top"),         tokens[0], important);\r
-                       add_parsed_property(tstring(name) + _t("-right"),               tokens[1], important);\r
-                       add_parsed_property(tstring(name) + _t("-left"),                tokens[1], important);\r
-                       add_parsed_property(tstring(name) + _t("-bottom"),      tokens[2], important);\r
-               } else if(tokens.size() == 2)\r
-               {\r
-                       add_parsed_property(tstring(name) + _t("-top"),         tokens[0], important);\r
-                       add_parsed_property(tstring(name) + _t("-bottom"),      tokens[0], important);\r
-                       add_parsed_property(tstring(name) + _t("-right"),               tokens[1], important);\r
-                       add_parsed_property(tstring(name) + _t("-left"),                tokens[1], important);\r
-               } else if(tokens.size() == 1)\r
-               {\r
-                       add_parsed_property(tstring(name) + _t("-top"),         tokens[0], important);\r
-                       add_parsed_property(tstring(name) + _t("-bottom"),      tokens[0], important);\r
-                       add_parsed_property(tstring(name) + _t("-right"),               tokens[0], important);\r
-                       add_parsed_property(tstring(name) + _t("-left"),                tokens[0], important);\r
-               }\r
-       } else \r
-               \r
-               \r
-       // Parse border-* shorthand properties \r
-       if(     !t_strcmp(name, _t("border-left")) || \r
-               !t_strcmp(name, _t("border-right")) ||\r
-               !t_strcmp(name, _t("border-top"))  || \r
-               !t_strcmp(name, _t("border-bottom")))\r
-       {\r
-               parse_short_border(name, val, important);\r
-       } else \r
-               \r
-       // Parse border-width/style/color shorthand properties \r
-       if(     !t_strcmp(name, _t("border-width")) ||\r
-               !t_strcmp(name, _t("border-style"))  ||\r
-               !t_strcmp(name, _t("border-color")) )\r
-       {\r
-               string_vector nametokens;\r
-               split_string(name, nametokens, _t("-"));\r
-\r
-               string_vector tokens;\r
-               split_string(val, tokens, _t(" "));\r
-               if(tokens.size() >= 4)\r
-               {\r
-                       add_parsed_property(nametokens[0] + _t("-top-")         + nametokens[1],        tokens[0], important);\r
-                       add_parsed_property(nametokens[0] + _t("-right-")       + nametokens[1],        tokens[1], important);\r
-                       add_parsed_property(nametokens[0] + _t("-bottom-")      + nametokens[1],        tokens[2], important);\r
-                       add_parsed_property(nametokens[0] + _t("-left-")        + nametokens[1],        tokens[3], important);\r
-               } else if(tokens.size() == 3)\r
-               {\r
-                       add_parsed_property(nametokens[0] + _t("-top-")         + nametokens[1],        tokens[0], important);\r
-                       add_parsed_property(nametokens[0] + _t("-right-")       + nametokens[1],        tokens[1], important);\r
-                       add_parsed_property(nametokens[0] + _t("-left-")        + nametokens[1],        tokens[1], important);\r
-                       add_parsed_property(nametokens[0] + _t("-bottom-")      + nametokens[1],        tokens[2], important);\r
-               } else if(tokens.size() == 2)\r
-               {\r
-                       add_parsed_property(nametokens[0] + _t("-top-")         + nametokens[1],        tokens[0], important);\r
-                       add_parsed_property(nametokens[0] + _t("-bottom-")      + nametokens[1],        tokens[0], important);\r
-                       add_parsed_property(nametokens[0] + _t("-right-")       + nametokens[1],        tokens[1], important);\r
-                       add_parsed_property(nametokens[0] + _t("-left-")        + nametokens[1],        tokens[1], important);\r
-               } else if(tokens.size() == 1)\r
-               {\r
-                       add_parsed_property(nametokens[0] + _t("-top-")         + nametokens[1],        tokens[0], important);\r
-                       add_parsed_property(nametokens[0] + _t("-bottom-")      + nametokens[1],        tokens[0], important);\r
-                       add_parsed_property(nametokens[0] + _t("-right-")       + nametokens[1],        tokens[0], important);\r
-                       add_parsed_property(nametokens[0] + _t("-left-")        + nametokens[1],        tokens[0], important);\r
-               }\r
-       } else \r
-               \r
-       // Parse font shorthand properties \r
-       if(!t_strcmp(name, _t("font")))\r
-       {\r
-               parse_short_font(val, important);\r
-       } else \r
-       {\r
-               add_parsed_property(name, val, important);\r
-       }\r
-}\r
-\r
-void litehtml::style::parse_short_border( const tstring& prefix, const tstring& val, bool important )\r
-{\r
-       string_vector tokens;\r
-       split_string(val, tokens, _t(" "), _t(""), _t("("));\r
-       if(tokens.size() >= 3)\r
-       {\r
-               add_parsed_property(prefix + _t("-width"),      tokens[0], important);\r
-               add_parsed_property(prefix + _t("-style"),      tokens[1], important);\r
-               add_parsed_property(prefix + _t("-color"),      tokens[2], important);\r
-       } else if(tokens.size() == 2)\r
-       {\r
-               if(iswdigit(tokens[0][0]) || value_index(val.c_str(), border_width_strings) >= 0)\r
-               {\r
-                       add_parsed_property(prefix + _t("-width"),      tokens[0], important);\r
-                       add_parsed_property(prefix + _t("-style"),      tokens[1], important);\r
-               } else\r
-               {\r
-                       add_parsed_property(prefix + _t("-style"),      tokens[0], important);\r
-                       add_parsed_property(prefix + _t("-color"),      tokens[1], important);\r
-               }\r
-       }\r
-}\r
-\r
-void litehtml::style::parse_short_background( const tstring& val, const tchar_t* baseurl, bool important )\r
-{\r
-       add_parsed_property(_t("background-color"),                     _t("transparent"),      important);\r
-       add_parsed_property(_t("background-image"),                     _t(""),                         important);\r
-       add_parsed_property(_t("background-image-baseurl"), _t(""),                             important);\r
-       add_parsed_property(_t("background-repeat"),            _t("repeat"),           important);\r
-       add_parsed_property(_t("background-origin"),            _t("padding-box"),      important);\r
-       add_parsed_property(_t("background-clip"),                      _t("border-box"),       important);\r
-       add_parsed_property(_t("background-attachment"),        _t("scroll"),           important);\r
-\r
-       if(val == _t("none"))\r
-       {\r
-               return;\r
-       }\r
-\r
-       string_vector tokens;\r
-       split_string(val, tokens, _t(" "), _t(""), _t("("));\r
-       bool origin_found = false;\r
-       for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)\r
-       {\r
-               if(web_color::is_color(tok->c_str()))\r
-               {\r
-                       add_parsed_property(_t("background-color"), *tok, important);\r
-               } else if(tok->substr(0, 3) == _t("url"))\r
-               {\r
-                       add_parsed_property(_t("background-image"), *tok, important);\r
-                       if(baseurl)\r
-                       {\r
-                               add_parsed_property(_t("background-image-baseurl"), baseurl, important);\r
-                       }\r
-\r
-               } else if( value_in_list(tok->c_str(), background_repeat_strings) )\r
-               {\r
-                       add_parsed_property(_t("background-repeat"), *tok, important);\r
-               } else if( value_in_list(tok->c_str(), background_attachment_strings) )\r
-               {\r
-                       add_parsed_property(_t("background-attachment"), *tok, important);\r
-               } else if( value_in_list(tok->c_str(), background_box_strings) )\r
-               {\r
-                       if(!origin_found)\r
-                       {\r
-                               add_parsed_property(_t("background-origin"), *tok, important);\r
-                               origin_found = true;\r
-                       } else\r
-                       {\r
-                               add_parsed_property(_t("background-clip"),*tok, important);\r
-                       }\r
-               } else if(      value_in_list(tok->c_str(), _t("left;right;top;bottom;center")) ||\r
-                                       iswdigit((*tok)[0]) ||\r
-                                       (*tok)[0] == _t('-')    ||\r
-                                       (*tok)[0] == _t('.')    ||\r
-                                       (*tok)[0] == _t('+'))\r
-               {\r
-                       if(m_properties.find(_t("background-position")) != m_properties.end())\r
-                       {\r
-                               m_properties[_t("background-position")].m_value = m_properties[_t("background-position")].m_value + _t(" ") + *tok;\r
-                       } else\r
-                       {\r
-                               add_parsed_property(_t("background-position"), *tok, important);\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-void litehtml::style::parse_short_font( const tstring& val, bool important )\r
-{\r
-       add_parsed_property(_t("font-style"),   _t("normal"),   important);\r
-       add_parsed_property(_t("font-variant"), _t("normal"),   important);\r
-       add_parsed_property(_t("font-weight"),  _t("normal"),   important);\r
-       add_parsed_property(_t("font-size"),            _t("medium"),   important);\r
-       add_parsed_property(_t("line-height"),  _t("normal"),   important);\r
-\r
-       string_vector tokens;\r
-       split_string(val, tokens, _t(" "), _t(""), _t("\""));\r
-\r
-       int idx = 0;\r
-       bool was_normal = false;\r
-       bool is_family = false;\r
-       tstring font_family;\r
-       for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)\r
-       {\r
-               idx = value_index(tok->c_str(), font_style_strings);\r
-               if(!is_family)\r
-               {\r
-                       if(idx >= 0)\r
-                       {\r
-                               if(idx == 0 && !was_normal)\r
-                               {\r
-                                       add_parsed_property(_t("font-weight"),          *tok, important);\r
-                                       add_parsed_property(_t("font-variant"),         *tok, important);\r
-                                       add_parsed_property(_t("font-style"),           *tok, important);\r
-                               } else\r
-                               {\r
-                                       add_parsed_property(_t("font-style"),           *tok, important);\r
-                               }\r
-                       } else\r
-                       {\r
-                               if(value_in_list(tok->c_str(), font_weight_strings))\r
-                               {\r
-                                       add_parsed_property(_t("font-weight"),          *tok, important);\r
-                               } else\r
-                               {\r
-                                       if(value_in_list(tok->c_str(), font_variant_strings))\r
-                                       {\r
-                                               add_parsed_property(_t("font-variant"), *tok, important);\r
-                                       } else if( iswdigit((*tok)[0]) )\r
-                                       {\r
-                                               string_vector szlh;\r
-                                               split_string(*tok, szlh, _t("/"));\r
-\r
-                                               if(szlh.size() == 1)\r
-                                               {\r
-                                                       add_parsed_property(_t("font-size"),    szlh[0], important);\r
-                                               } else  if(szlh.size() >= 2)\r
-                                               {\r
-                                                       add_parsed_property(_t("font-size"),    szlh[0], important);\r
-                                                       add_parsed_property(_t("line-height"),  szlh[1], important);\r
-                                               }\r
-                                       } else\r
-                                       {\r
-                                               is_family = true;\r
-                                               font_family += *tok;\r
-                                       }\r
-                               }\r
-                       }\r
-               } else\r
-               {\r
-                       font_family += *tok;\r
-               }\r
-       }\r
-       add_parsed_property(_t("font-family"), font_family, important);\r
-}\r
-\r
-void litehtml::style::add_parsed_property( const tstring& name, const tstring& val, bool important )\r
-{\r
-       bool is_valid = true;\r
-       string_map::iterator vals = m_valid_values.find(name);\r
-       if (vals != m_valid_values.end())\r
-       {\r
-               if (!value_in_list(val, vals->second))\r
-               {\r
-                       is_valid = false;\r
-               }\r
-       }\r
-\r
-       if (is_valid)\r
-       {\r
-               props_map::iterator prop = m_properties.find(name);\r
-               if (prop != m_properties.end())\r
-               {\r
-                       if (!prop->second.m_important || (important && prop->second.m_important))\r
-                       {\r
-                               prop->second.m_value = val;\r
-                               prop->second.m_important = important;\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       m_properties[name] = property_value(val.c_str(), important);\r
-               }\r
-       }\r
-}\r
-\r
-void litehtml::style::remove_property( const tstring& name, bool important )\r
-{\r
-       props_map::iterator prop = m_properties.find(name);\r
-       if(prop != m_properties.end())\r
-       {\r
-               if( !prop->second.m_important || (important && prop->second.m_important) )\r
-               {\r
-                       m_properties.erase(prop);\r
-               }\r
-       }\r
-}\r
+#include "html.h"
+#include "style.h"
+#include <functional>
+#include <algorithm>
+#ifndef WINCE
+#include <locale>
+#endif
+
+litehtml::string_map litehtml::style::m_valid_values =
+{
+       { _t("white-space"), white_space_strings }
+};
+
+litehtml::style::style()
+{
+}
+
+litehtml::style::style( const style& val )
+{
+       m_properties = val.m_properties;
+}
+
+litehtml::style::~style()
+{
+
+}
+
+void litehtml::style::parse( const tchar_t* txt, const tchar_t* baseurl )
+{
+       std::vector<tstring> properties;
+       split_string(txt, properties, _t(";"));
+
+       for(std::vector<tstring>::const_iterator i = properties.begin(); i != properties.end(); i++)
+       {
+               parse_property(*i, baseurl);
+       }
+}
+
+void litehtml::style::parse_property( const tstring& txt, const tchar_t* baseurl )
+{
+       tstring::size_type pos = txt.find_first_of(_t(":"));
+       if(pos != tstring::npos)
+       {
+               tstring name    = txt.substr(0, pos);
+               tstring val     = txt.substr(pos + 1);
+
+               trim(name);
+               trim(val);
+
+               lcase(name);
+
+               if(!name.empty() && !val.empty())
+               {
+                       string_vector vals;
+                       split_string(val, vals, _t("!"));
+                       if(vals.size() == 1)
+                       {
+                               add_property(name.c_str(), val.c_str(), baseurl, false);
+                       } else if(vals.size() > 1)
+                       {
+                               trim(vals[0]);
+                               lcase(vals[1]);
+                               if(vals[1] == _t("important"))
+                               {
+                                       add_property(name.c_str(), vals[0].c_str(), baseurl, true);
+                               } else
+                               {
+                                       add_property(name.c_str(), vals[0].c_str(), baseurl, false);
+                               }
+                       }
+               }
+       }
+}
+
+void litehtml::style::combine( const litehtml::style& src )
+{
+       for(props_map::const_iterator i = src.m_properties.begin(); i != src.m_properties.end(); i++)
+       {
+               add_parsed_property(i->first.c_str(), i->second.m_value.c_str(), i->second.m_important);
+       }
+}
+
+void litehtml::style::add_property( const tchar_t* name, const tchar_t* val, const tchar_t* baseurl, bool important )
+{
+       if(!name || !val)
+       {
+               return;
+       }
+
+       // Add baseurl for background image 
+       if(     !t_strcmp(name, _t("background-image")))
+       {
+               add_parsed_property(name, val, important);
+               if(baseurl)
+               {
+                       add_parsed_property(_t("background-image-baseurl"), baseurl, important);
+               }
+       } else
+
+       // Parse border spacing properties 
+       if(     !t_strcmp(name, _t("border-spacing")))
+       {
+               string_vector tokens;
+               split_string(val, tokens, _t(" "));
+               if(tokens.size() == 1)
+               {
+                       add_property(_t("-litehtml-border-spacing-x"), tokens[0].c_str(), baseurl, important);
+                       add_property(_t("-litehtml-border-spacing-y"), tokens[0].c_str(), baseurl, important);
+               } else if(tokens.size() == 2)
+               {
+                       add_property(_t("-litehtml-border-spacing-x"), tokens[0].c_str(), baseurl, important);
+                       add_property(_t("-litehtml-border-spacing-y"), tokens[1].c_str(), baseurl, important);
+               }
+       } else
+
+       // Parse borders shorthand properties 
+
+       if(     !t_strcmp(name, _t("border")))
+       {
+               string_vector tokens;
+               split_string(val, tokens, _t(" "), _t(""), _t("("));
+               int idx;
+               tstring str;
+               for(string_vector::const_iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+               {
+                       idx = value_index(tok->c_str(), border_style_strings, -1);
+                       if(idx >= 0)
+                       {
+                               add_property(_t("border-left-style"), tok->c_str(), baseurl, important);
+                               add_property(_t("border-right-style"), tok->c_str(), baseurl, important);
+                               add_property(_t("border-top-style"), tok->c_str(), baseurl, important);
+                               add_property(_t("border-bottom-style"), tok->c_str(), baseurl, important);
+                       } else
+                       {
+                               if (t_isdigit((*tok)[0]) || (*tok)[0] == _t('.') ||
+                                       value_in_list((*tok), _t("thin;medium;thick")))
+                               {
+                                       add_property(_t("border-left-width"), tok->c_str(), baseurl, important);
+                                       add_property(_t("border-right-width"), tok->c_str(), baseurl, important);
+                                       add_property(_t("border-top-width"), tok->c_str(), baseurl, important);
+                                       add_property(_t("border-bottom-width"), tok->c_str(), baseurl, important);
+                               } 
+                               else
+                               {
+                                       add_property(_t("border-left-color"), tok->c_str(), baseurl, important);
+                                       add_property(_t("border-right-color"), tok->c_str(), baseurl, important);
+                                       add_property(_t("border-top-color"), tok->c_str(), baseurl, important);
+                                       add_property(_t("border-bottom-color"), tok->c_str(), baseurl, important);
+                               }
+                       }
+               }
+       } else if(      !t_strcmp(name, _t("border-left"))      ||
+               !t_strcmp(name, _t("border-right"))     ||
+               !t_strcmp(name, _t("border-top"))       ||
+               !t_strcmp(name, _t("border-bottom")) )
+       {
+               string_vector tokens;
+               split_string(val, tokens, _t(" "), _t(""), _t("("));
+               int idx;
+               tstring str;
+               for(string_vector::const_iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+               {
+                       idx = value_index(tok->c_str(), border_style_strings, -1);
+                       if(idx >= 0)
+                       {
+                               str = name;
+                               str += _t("-style");
+                               add_property(str.c_str(), tok->c_str(), baseurl, important);
+                       } else
+                       {
+                               if(web_color::is_color(tok->c_str()))
+                               {
+                                       str = name;
+                                       str += _t("-color");
+                                       add_property(str.c_str(), tok->c_str(), baseurl, important);
+                               } else
+                               {
+                                       str = name;
+                                       str += _t("-width");
+                                       add_property(str.c_str(), tok->c_str(), baseurl, important);
+                               }
+                       }
+               }
+       } else 
+
+       // Parse border radius shorthand properties 
+       if(!t_strcmp(name, _t("border-bottom-left-radius")))
+       {
+               string_vector tokens;
+               split_string(val, tokens, _t(" "));
+               if(tokens.size() >= 2)
+               {
+                       add_property(_t("border-bottom-left-radius-x"), tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-left-radius-y"), tokens[1].c_str(), baseurl, important);
+               } else if(tokens.size() == 1)
+               {
+                       add_property(_t("border-bottom-left-radius-x"), tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-left-radius-y"), tokens[0].c_str(), baseurl, important);
+               }
+
+       } else if(!t_strcmp(name, _t("border-bottom-right-radius")))
+       {
+               string_vector tokens;
+               split_string(val, tokens, _t(" "));
+               if(tokens.size() >= 2)
+               {
+                       add_property(_t("border-bottom-right-radius-x"), tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-right-radius-y"), tokens[1].c_str(), baseurl, important);
+               } else if(tokens.size() == 1)
+               {
+                       add_property(_t("border-bottom-right-radius-x"), tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-right-radius-y"), tokens[0].c_str(), baseurl, important);
+               }
+
+       } else if(!t_strcmp(name, _t("border-top-right-radius")))
+       {
+               string_vector tokens;
+               split_string(val, tokens, _t(" "));
+               if(tokens.size() >= 2)
+               {
+                       add_property(_t("border-top-right-radius-x"), tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-top-right-radius-y"), tokens[1].c_str(), baseurl, important);
+               } else if(tokens.size() == 1)
+               {
+                       add_property(_t("border-top-right-radius-x"), tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-top-right-radius-y"), tokens[0].c_str(), baseurl, important);
+               }
+
+       } else if(!t_strcmp(name, _t("border-top-left-radius")))
+       {
+               string_vector tokens;
+               split_string(val, tokens, _t(" "));
+               if(tokens.size() >= 2)
+               {
+                       add_property(_t("border-top-left-radius-x"), tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-top-left-radius-y"), tokens[1].c_str(), baseurl, important);
+               } else if(tokens.size() == 1)
+               {
+                       add_property(_t("border-top-left-radius-x"), tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-top-left-radius-y"), tokens[0].c_str(), baseurl, important);
+               }
+
+       } else 
+
+       // Parse border-radius shorthand properties 
+       if(!t_strcmp(name, _t("border-radius")))
+       {
+               string_vector tokens;
+               split_string(val, tokens, _t("/"));
+               if(tokens.size() == 1)
+               {
+                       add_property(_t("border-radius-x"), tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-radius-y"), tokens[0].c_str(), baseurl, important);
+               } else if(tokens.size() >= 2)
+               {
+                       add_property(_t("border-radius-x"), tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-radius-y"), tokens[1].c_str(), baseurl, important);
+               }
+       } else if(!t_strcmp(name, _t("border-radius-x")))
+       {
+               string_vector tokens;
+               split_string(val, tokens, _t(" "));
+               if(tokens.size() == 1)
+               {
+                       add_property(_t("border-top-left-radius-x"),            tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-top-right-radius-x"),           tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-right-radius-x"),        tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-left-radius-x"), tokens[0].c_str(), baseurl, important);
+               } else if(tokens.size() == 2)
+               {
+                       add_property(_t("border-top-left-radius-x"),            tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-top-right-radius-x"),           tokens[1].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-right-radius-x"),        tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-left-radius-x"), tokens[1].c_str(), baseurl, important);
+               } else if(tokens.size() == 3)
+               {
+                       add_property(_t("border-top-left-radius-x"),            tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-top-right-radius-x"),           tokens[1].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-right-radius-x"),        tokens[2].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-left-radius-x"), tokens[1].c_str(), baseurl, important);
+               } else if(tokens.size() == 4)
+               {
+                       add_property(_t("border-top-left-radius-x"),            tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-top-right-radius-x"),           tokens[1].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-right-radius-x"),        tokens[2].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-left-radius-x"), tokens[3].c_str(), baseurl, important);
+               }
+       } else if(!t_strcmp(name, _t("border-radius-y")))
+       {
+               string_vector tokens;
+               split_string(val, tokens, _t(" "));
+               if(tokens.size() == 1)
+               {
+                       add_property(_t("border-top-left-radius-y"),            tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-top-right-radius-y"),           tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-right-radius-y"),        tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-left-radius-y"), tokens[0].c_str(), baseurl, important);
+               } else if(tokens.size() == 2)
+               {
+                       add_property(_t("border-top-left-radius-y"),            tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-top-right-radius-y"),           tokens[1].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-right-radius-y"),        tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-left-radius-y"), tokens[1].c_str(), baseurl, important);
+               } else if(tokens.size() == 3)
+               {
+                       add_property(_t("border-top-left-radius-y"),            tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-top-right-radius-y"),           tokens[1].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-right-radius-y"),        tokens[2].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-left-radius-y"), tokens[1].c_str(), baseurl, important);
+               } else if(tokens.size() == 4)
+               {
+                       add_property(_t("border-top-left-radius-y"),            tokens[0].c_str(), baseurl, important);
+                       add_property(_t("border-top-right-radius-y"),           tokens[1].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-right-radius-y"),        tokens[2].c_str(), baseurl, important);
+                       add_property(_t("border-bottom-left-radius-y"), tokens[3].c_str(), baseurl, important);
+               }
+       }
+       
+
+       // Parse list-style shorthand properties 
+       if(!t_strcmp(name, _t("list-style")))
+       {
+               add_parsed_property(_t("list-style-type"),                      _t("disc"),             important);
+               add_parsed_property(_t("list-style-position"),          _t("outside"),  important);
+               add_parsed_property(_t("list-style-image"),                     _t(""),                 important);
+               add_parsed_property(_t("list-style-image-baseurl"),     _t(""),                 important);
+
+               string_vector tokens;
+               split_string(val, tokens, _t(" "), _t(""), _t("("));
+               for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+               {
+                       int idx = value_index(tok->c_str(), list_style_type_strings, -1);
+                       if(idx >= 0)
+                       {
+                               add_parsed_property(_t("list-style-type"), *tok, important);
+                       } else
+                       {
+                               idx = value_index(tok->c_str(), list_style_position_strings, -1);
+                               if(idx >= 0)
+                               {
+                                       add_parsed_property(_t("list-style-position"), *tok, important);
+                               } else if(!t_strncmp(val, _t("url"), 3))
+                               {
+                                       add_parsed_property(_t("list-style-image"), *tok, important);
+                                       if(baseurl)
+                                       {
+                                               add_parsed_property(_t("list-style-image-baseurl"), baseurl, important);
+                                       }
+                               }
+                       }
+               }
+       } else 
+
+       // Add baseurl for background image 
+       if(     !t_strcmp(name, _t("list-style-image")))
+       {
+               add_parsed_property(name, val, important);
+               if(baseurl)
+               {
+                       add_parsed_property(_t("list-style-image-baseurl"), baseurl, important);
+               }
+       } else
+               
+       // Parse background shorthand properties 
+       if(!t_strcmp(name, _t("background")))
+       {
+               parse_short_background(val, baseurl, important);
+
+       } else 
+               
+       // Parse margin and padding shorthand properties 
+       if(!t_strcmp(name, _t("margin")) || !t_strcmp(name, _t("padding")))
+       {
+               string_vector tokens;
+               split_string(val, tokens, _t(" "));
+               if(tokens.size() >= 4)
+               {
+                       add_parsed_property(tstring(name) + _t("-top"),         tokens[0], important);
+                       add_parsed_property(tstring(name) + _t("-right"),               tokens[1], important);
+                       add_parsed_property(tstring(name) + _t("-bottom"),      tokens[2], important);
+                       add_parsed_property(tstring(name) + _t("-left"),                tokens[3], important);
+               } else if(tokens.size() == 3)
+               {
+                       add_parsed_property(tstring(name) + _t("-top"),         tokens[0], important);
+                       add_parsed_property(tstring(name) + _t("-right"),               tokens[1], important);
+                       add_parsed_property(tstring(name) + _t("-left"),                tokens[1], important);
+                       add_parsed_property(tstring(name) + _t("-bottom"),      tokens[2], important);
+               } else if(tokens.size() == 2)
+               {
+                       add_parsed_property(tstring(name) + _t("-top"),         tokens[0], important);
+                       add_parsed_property(tstring(name) + _t("-bottom"),      tokens[0], important);
+                       add_parsed_property(tstring(name) + _t("-right"),               tokens[1], important);
+                       add_parsed_property(tstring(name) + _t("-left"),                tokens[1], important);
+               } else if(tokens.size() == 1)
+               {
+                       add_parsed_property(tstring(name) + _t("-top"),         tokens[0], important);
+                       add_parsed_property(tstring(name) + _t("-bottom"),      tokens[0], important);
+                       add_parsed_property(tstring(name) + _t("-right"),               tokens[0], important);
+                       add_parsed_property(tstring(name) + _t("-left"),                tokens[0], important);
+               }
+       } else 
+               
+               
+       // Parse border-* shorthand properties 
+       if(     !t_strcmp(name, _t("border-left")) || 
+               !t_strcmp(name, _t("border-right")) ||
+               !t_strcmp(name, _t("border-top"))  || 
+               !t_strcmp(name, _t("border-bottom")))
+       {
+               parse_short_border(name, val, important);
+       } else 
+               
+       // Parse border-width/style/color shorthand properties 
+       if(     !t_strcmp(name, _t("border-width")) ||
+               !t_strcmp(name, _t("border-style"))  ||
+               !t_strcmp(name, _t("border-color")) )
+       {
+               string_vector nametokens;
+               split_string(name, nametokens, _t("-"));
+
+               string_vector tokens;
+               split_string(val, tokens, _t(" "));
+               if(tokens.size() >= 4)
+               {
+                       add_parsed_property(nametokens[0] + _t("-top-")         + nametokens[1],        tokens[0], important);
+                       add_parsed_property(nametokens[0] + _t("-right-")       + nametokens[1],        tokens[1], important);
+                       add_parsed_property(nametokens[0] + _t("-bottom-")      + nametokens[1],        tokens[2], important);
+                       add_parsed_property(nametokens[0] + _t("-left-")        + nametokens[1],        tokens[3], important);
+               } else if(tokens.size() == 3)
+               {
+                       add_parsed_property(nametokens[0] + _t("-top-")         + nametokens[1],        tokens[0], important);
+                       add_parsed_property(nametokens[0] + _t("-right-")       + nametokens[1],        tokens[1], important);
+                       add_parsed_property(nametokens[0] + _t("-left-")        + nametokens[1],        tokens[1], important);
+                       add_parsed_property(nametokens[0] + _t("-bottom-")      + nametokens[1],        tokens[2], important);
+               } else if(tokens.size() == 2)
+               {
+                       add_parsed_property(nametokens[0] + _t("-top-")         + nametokens[1],        tokens[0], important);
+                       add_parsed_property(nametokens[0] + _t("-bottom-")      + nametokens[1],        tokens[0], important);
+                       add_parsed_property(nametokens[0] + _t("-right-")       + nametokens[1],        tokens[1], important);
+                       add_parsed_property(nametokens[0] + _t("-left-")        + nametokens[1],        tokens[1], important);
+               } else if(tokens.size() == 1)
+               {
+                       add_parsed_property(nametokens[0] + _t("-top-")         + nametokens[1],        tokens[0], important);
+                       add_parsed_property(nametokens[0] + _t("-bottom-")      + nametokens[1],        tokens[0], important);
+                       add_parsed_property(nametokens[0] + _t("-right-")       + nametokens[1],        tokens[0], important);
+                       add_parsed_property(nametokens[0] + _t("-left-")        + nametokens[1],        tokens[0], important);
+               }
+       } else 
+               
+       // Parse font shorthand properties 
+       if(!t_strcmp(name, _t("font")))
+       {
+               parse_short_font(val, important);
+       } else 
+       {
+               add_parsed_property(name, val, important);
+       }
+}
+
+void litehtml::style::parse_short_border( const tstring& prefix, const tstring& val, bool important )
+{
+       string_vector tokens;
+       split_string(val, tokens, _t(" "), _t(""), _t("("));
+       if(tokens.size() >= 3)
+       {
+               add_parsed_property(prefix + _t("-width"),      tokens[0], important);
+               add_parsed_property(prefix + _t("-style"),      tokens[1], important);
+               add_parsed_property(prefix + _t("-color"),      tokens[2], important);
+       } else if(tokens.size() == 2)
+       {
+               if(iswdigit(tokens[0][0]) || value_index(val.c_str(), border_width_strings) >= 0)
+               {
+                       add_parsed_property(prefix + _t("-width"),      tokens[0], important);
+                       add_parsed_property(prefix + _t("-style"),      tokens[1], important);
+               } else
+               {
+                       add_parsed_property(prefix + _t("-style"),      tokens[0], important);
+                       add_parsed_property(prefix + _t("-color"),      tokens[1], important);
+               }
+       }
+}
+
+void litehtml::style::parse_short_background( const tstring& val, const tchar_t* baseurl, bool important )
+{
+       add_parsed_property(_t("background-color"),                     _t("transparent"),      important);
+       add_parsed_property(_t("background-image"),                     _t(""),                         important);
+       add_parsed_property(_t("background-image-baseurl"), _t(""),                             important);
+       add_parsed_property(_t("background-repeat"),            _t("repeat"),           important);
+       add_parsed_property(_t("background-origin"),            _t("padding-box"),      important);
+       add_parsed_property(_t("background-clip"),                      _t("border-box"),       important);
+       add_parsed_property(_t("background-attachment"),        _t("scroll"),           important);
+
+       if(val == _t("none"))
+       {
+               return;
+       }
+
+       string_vector tokens;
+       split_string(val, tokens, _t(" "), _t(""), _t("("));
+       bool origin_found = false;
+       for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+       {
+               if(tok->substr(0, 3) == _t("url"))
+               {
+                       add_parsed_property(_t("background-image"), *tok, important);
+                       if(baseurl)
+                       {
+                               add_parsed_property(_t("background-image-baseurl"), baseurl, important);
+                       }
+
+               } else if( value_in_list(tok->c_str(), background_repeat_strings) )
+               {
+                       add_parsed_property(_t("background-repeat"), *tok, important);
+               } else if( value_in_list(tok->c_str(), background_attachment_strings) )
+               {
+                       add_parsed_property(_t("background-attachment"), *tok, important);
+               } else if( value_in_list(tok->c_str(), background_box_strings) )
+               {
+                       if(!origin_found)
+                       {
+                               add_parsed_property(_t("background-origin"), *tok, important);
+                               origin_found = true;
+                       } else
+                       {
+                               add_parsed_property(_t("background-clip"),*tok, important);
+                       }
+               } else if(      value_in_list(tok->c_str(), _t("left;right;top;bottom;center")) ||
+                                       iswdigit((*tok)[0]) ||
+                                       (*tok)[0] == _t('-')    ||
+                                       (*tok)[0] == _t('.')    ||
+                                       (*tok)[0] == _t('+'))
+               {
+                       if(m_properties.find(_t("background-position")) != m_properties.end())
+                       {
+                               m_properties[_t("background-position")].m_value = m_properties[_t("background-position")].m_value + _t(" ") + *tok;
+                       } else
+                       {
+                               add_parsed_property(_t("background-position"), *tok, important);
+                       }
+               } else if (web_color::is_color(tok->c_str()))
+               {
+                       add_parsed_property(_t("background-color"), *tok, important);
+               }
+       }
+}
+
+void litehtml::style::parse_short_font( const tstring& val, bool important )
+{
+       add_parsed_property(_t("font-style"),   _t("normal"),   important);
+       add_parsed_property(_t("font-variant"), _t("normal"),   important);
+       add_parsed_property(_t("font-weight"),  _t("normal"),   important);
+       add_parsed_property(_t("font-size"),            _t("medium"),   important);
+       add_parsed_property(_t("line-height"),  _t("normal"),   important);
+
+       string_vector tokens;
+       split_string(val, tokens, _t(" "), _t(""), _t("\""));
+
+       int idx = 0;
+       bool was_normal = false;
+       bool is_family = false;
+       tstring font_family;
+       for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+       {
+               idx = value_index(tok->c_str(), font_style_strings);
+               if(!is_family)
+               {
+                       if(idx >= 0)
+                       {
+                               if(idx == 0 && !was_normal)
+                               {
+                                       add_parsed_property(_t("font-weight"),          *tok, important);
+                                       add_parsed_property(_t("font-variant"),         *tok, important);
+                                       add_parsed_property(_t("font-style"),           *tok, important);
+                               } else
+                               {
+                                       add_parsed_property(_t("font-style"),           *tok, important);
+                               }
+                       } else
+                       {
+                               if(value_in_list(tok->c_str(), font_weight_strings))
+                               {
+                                       add_parsed_property(_t("font-weight"),          *tok, important);
+                               } else
+                               {
+                                       if(value_in_list(tok->c_str(), font_variant_strings))
+                                       {
+                                               add_parsed_property(_t("font-variant"), *tok, important);
+                                       } else if( iswdigit((*tok)[0]) )
+                                       {
+                                               string_vector szlh;
+                                               split_string(*tok, szlh, _t("/"));
+
+                                               if(szlh.size() == 1)
+                                               {
+                                                       add_parsed_property(_t("font-size"),    szlh[0], important);
+                                               } else  if(szlh.size() >= 2)
+                                               {
+                                                       add_parsed_property(_t("font-size"),    szlh[0], important);
+                                                       add_parsed_property(_t("line-height"),  szlh[1], important);
+                                               }
+                                       } else
+                                       {
+                                               is_family = true;
+                                               font_family += *tok;
+                                       }
+                               }
+                       }
+               } else
+               {
+                       font_family += *tok;
+               }
+       }
+       add_parsed_property(_t("font-family"), font_family, important);
+}
+
+void litehtml::style::add_parsed_property( const tstring& name, const tstring& val, bool important )
+{
+       bool is_valid = true;
+       string_map::iterator vals = m_valid_values.find(name);
+       if (vals != m_valid_values.end())
+       {
+               if (!value_in_list(val, vals->second))
+               {
+                       is_valid = false;
+               }
+       }
+
+       if (is_valid)
+       {
+               props_map::iterator prop = m_properties.find(name);
+               if (prop != m_properties.end())
+               {
+                       if (!prop->second.m_important || (important && prop->second.m_important))
+                       {
+                               prop->second.m_value = val;
+                               prop->second.m_important = important;
+                       }
+               }
+               else
+               {
+                       m_properties[name] = property_value(val.c_str(), important);
+               }
+       }
+}
+
+void litehtml::style::remove_property( const tstring& name, bool important )
+{
+       props_map::iterator prop = m_properties.find(name);
+       if(prop != m_properties.end())
+       {
+               if( !prop->second.m_important || (important && prop->second.m_important) )
+               {
+                       m_properties.erase(prop);
+               }
+       }
+}
index bf05772018b6c3fd25f055410d1cc7a7e57b65b3..d84ee20e07db48d7948054f6573d416fbd68bad4 100644 (file)
@@ -1,91 +1,95 @@
-#pragma once\r
-#include "attributes.h"\r
-#include <string>\r
-\r
-namespace litehtml\r
-{\r
-       class property_value\r
-       {\r
-       public:\r
-               tstring m_value;\r
-               bool                    m_important;\r
-\r
-               property_value()\r
-               {\r
-                       m_important = false;\r
-               }\r
-               property_value(const tchar_t* val, bool imp)\r
-               {\r
-                       m_important = imp;\r
-                       m_value         = val;\r
-               }\r
-               property_value(const property_value& val)\r
-               {\r
-                       m_value         = val.m_value;\r
-                       m_important     = val.m_important;\r
-               }\r
-\r
-               property_value& operator=(const property_value& val)\r
-               {\r
-                       m_value         = val.m_value;\r
-                       m_important     = val.m_important;\r
-                       return *this;\r
-               }\r
-       };\r
-\r
-       typedef std::map<tstring, property_value>       props_map;\r
-\r
-       class style\r
-       {\r
-       public:\r
-               typedef std::shared_ptr<style>          ptr;\r
-               typedef std::vector<style::ptr>         vector;\r
-       private:\r
-               props_map                       m_properties;\r
-               static string_map       m_valid_values;\r
-       public:\r
-               style();\r
-               style(const style& val);\r
-               virtual ~style();\r
-\r
-               void operator=(const style& val)\r
-               {\r
-                       m_properties = val.m_properties;\r
-               }\r
-\r
-               void add(const tchar_t* txt, const tchar_t* baseurl)\r
-               {\r
-                       parse(txt, baseurl);\r
-               }\r
-\r
-               void add_property(const tchar_t* name, const tchar_t* val, const tchar_t* baseurl, bool important);\r
-\r
-               const tchar_t* get_property(const tchar_t* name) const\r
-               {\r
-                       if(name)\r
-                       {\r
-                               props_map::const_iterator f = m_properties.find(name);\r
-                               if(f != m_properties.end())\r
-                               {\r
-                                       return f->second.m_value.c_str();\r
-                               }\r
-                       }\r
-                       return 0;\r
-               }\r
-\r
-               void combine(const litehtml::style& src);\r
-               void clear()\r
-               {\r
-                       m_properties.clear();\r
-               }\r
-\r
-       private:\r
-               void parse_property(const tstring& txt, const tchar_t* baseurl);\r
-               void parse(const tchar_t* txt, const tchar_t* baseurl);\r
-               void parse_short_border(const tstring& prefix, const tstring& val, bool important);\r
-               void parse_short_background(const tstring& val, const tchar_t* baseurl, bool important);\r
-               void parse_short_font(const tstring& val, bool important);\r
-               void add_parsed_property(const tstring& name, const tstring& val, bool important);\r
-               void remove_property(const tstring& name, bool important);\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_STYLE_H
+#define LH_STYLE_H
+
+#include "attributes.h"
+#include <string>
+
+namespace litehtml
+{
+       class property_value
+       {
+       public:
+               tstring m_value;
+               bool                    m_important;
+
+               property_value()
+               {
+                       m_important = false;
+               }
+               property_value(const tchar_t* val, bool imp)
+               {
+                       m_important = imp;
+                       m_value         = val;
+               }
+               property_value(const property_value& val)
+               {
+                       m_value         = val.m_value;
+                       m_important     = val.m_important;
+               }
+
+               property_value& operator=(const property_value& val)
+               {
+                       m_value         = val.m_value;
+                       m_important     = val.m_important;
+                       return *this;
+               }
+       };
+
+       typedef std::map<tstring, property_value>       props_map;
+
+       class style
+       {
+       public:
+               typedef std::shared_ptr<style>          ptr;
+               typedef std::vector<style::ptr>         vector;
+       private:
+               props_map                       m_properties;
+               static string_map       m_valid_values;
+       public:
+               style();
+               style(const style& val);
+               virtual ~style();
+
+               void operator=(const style& val)
+               {
+                       m_properties = val.m_properties;
+               }
+
+               void add(const tchar_t* txt, const tchar_t* baseurl)
+               {
+                       parse(txt, baseurl);
+               }
+
+               void add_property(const tchar_t* name, const tchar_t* val, const tchar_t* baseurl, bool important);
+
+               const tchar_t* get_property(const tchar_t* name) const
+               {
+                       if(name)
+                       {
+                               props_map::const_iterator f = m_properties.find(name);
+                               if(f != m_properties.end())
+                               {
+                                       return f->second.m_value.c_str();
+                               }
+                       }
+                       return 0;
+               }
+
+               void combine(const litehtml::style& src);
+               void clear()
+               {
+                       m_properties.clear();
+               }
+
+       private:
+               void parse_property(const tstring& txt, const tchar_t* baseurl);
+               void parse(const tchar_t* txt, const tchar_t* baseurl);
+               void parse_short_border(const tstring& prefix, const tstring& val, bool important);
+               void parse_short_background(const tstring& val, const tchar_t* baseurl, bool important);
+               void parse_short_font(const tstring& val, bool important);
+               void add_parsed_property(const tstring& name, const tstring& val, bool important);
+               void remove_property(const tstring& name, bool important);
+       };
+}
+
+#endif  // LH_STYLE_H
index 7f0a2be1ace09524453b4aa5d40044e27cca37a4..08ace6205ee06100dc5344b348caf6ca2cbeaa9f 100644 (file)
-#include "html.h"\r
-#include "stylesheet.h"\r
-#include <algorithm>\r
-#include "document.h"\r
-\r
-\r
-void litehtml::css::parse_stylesheet(const tchar_t* str, const tchar_t* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media)\r
-{\r
-       tstring text = str;\r
-\r
-       // remove comments\r
-       tstring::size_type c_start = text.find(_t("/*"));\r
-       while(c_start != tstring::npos)\r
-       {\r
-               tstring::size_type c_end = text.find(_t("*/"), c_start + 2);\r
-               text.erase(c_start, c_end - c_start + 2);\r
-               c_start = text.find(_t("/*"));\r
-       }\r
-\r
-       tstring::size_type pos = text.find_first_not_of(_t(" \n\r\t"));\r
-       while(pos != tstring::npos)\r
-       {\r
-               while(pos != tstring::npos && text[pos] == _t('@'))\r
-               {\r
-                       tstring::size_type sPos = pos;\r
-                       pos = text.find_first_of(_t("{"), pos);\r
-                       if(pos != tstring::npos && text[pos] == _t('{'))\r
-                       {\r
-                               pos = find_close_bracket(text, pos, _t('{'), _t('}'));\r
-                       }\r
-                       if(pos != tstring::npos)\r
-                       {\r
-                               parse_atrule(text.substr(sPos, pos - sPos + 1), baseurl, doc, media);\r
-                       } else\r
-                       {\r
-                               parse_atrule(text.substr(sPos), baseurl, doc, media);\r
-                       }\r
-\r
-                       if(pos != tstring::npos)\r
-                       {\r
-                               pos = text.find_first_not_of(_t(" \n\r\t"), pos + 1);\r
-                       }\r
-               }\r
-\r
-               if(pos == tstring::npos)\r
-               {\r
-                       break;\r
-               }\r
-\r
-               tstring::size_type style_start = text.find(_t("{"), pos);\r
-               tstring::size_type style_end    = text.find(_t("}"), pos);\r
-               if(style_start != tstring::npos && style_end != tstring::npos)\r
-               {\r
-                       style::ptr st = std::make_shared<style>();\r
-                       st->add(text.substr(style_start + 1, style_end - style_start - 1).c_str(), baseurl);\r
-\r
-                       parse_selectors(text.substr(pos, style_start - pos), st, media);\r
-\r
-                       if(media && doc)\r
-                       {\r
-                               doc->add_media_list(media);\r
-                       }\r
-\r
-                       pos = style_end + 1;\r
-               } else\r
-               {\r
-                       pos = tstring::npos;\r
-               }\r
-\r
-               if(pos != tstring::npos)\r
-               {\r
-                       pos = text.find_first_not_of(_t(" \n\r\t"), pos);\r
-               }\r
-       }\r
-}\r
-\r
-void litehtml::css::parse_css_url( const tstring& str, tstring& url )\r
-{\r
-       url = _t("");\r
-       size_t pos1 = str.find(_t('('));\r
-       size_t pos2 = str.find(_t(')'));\r
-       if(pos1 != tstring::npos && pos2 != tstring::npos)\r
-       {\r
-               url = str.substr(pos1 + 1, pos2 - pos1 - 1);\r
-               if(url.length())\r
-               {\r
-                       if(url[0] == _t('\'') || url[0] == _t('"'))\r
-                       {\r
-                               url.erase(0, 1);\r
-                       }\r
-               }\r
-               if(url.length())\r
-               {\r
-                       if(url[url.length() - 1] == _t('\'') || url[url.length() - 1] == _t('"'))\r
-                       {\r
-                               url.erase(url.length() - 1, 1);\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-bool litehtml::css::parse_selectors( const tstring& txt, const litehtml::style::ptr& styles, const media_query_list::ptr& media )\r
-{\r
-       tstring selector = txt;\r
-       trim(selector);\r
-       string_vector tokens;\r
-       split_string(selector, tokens, _t(","));\r
-\r
-       bool added_something = false;\r
-\r
-       for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)\r
-       {\r
-               css_selector::ptr selector = std::make_shared<css_selector>(media);\r
-               selector->m_style = styles;\r
-               trim(*tok);\r
-               if(selector->parse(*tok))\r
-               {\r
-                       selector->calc_specificity();\r
-                       add_selector(selector);\r
-                       added_something = true;\r
-               }\r
-       }\r
-\r
-       return added_something;\r
-}\r
-\r
-void litehtml::css::sort_selectors()\r
-{\r
-       std::sort(m_selectors.begin(), m_selectors.end(),\r
-                [](const css_selector::ptr& v1, const css_selector::ptr& v2)\r
-                {\r
-                        return (*v1) < (*v2);\r
-                }\r
-       );\r
-}\r
-\r
-void litehtml::css::parse_atrule(const tstring& text, const tchar_t* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media)\r
-{\r
-       if(text.substr(0, 7) == _t("@import"))\r
-       {\r
-               int sPos = 7;\r
-               tstring iStr;\r
-               iStr = text.substr(sPos);\r
-               if(iStr[iStr.length() - 1] == _t(';'))\r
-               {\r
-                       iStr.erase(iStr.length() - 1);\r
-               }\r
-               trim(iStr);\r
-               string_vector tokens;\r
-               split_string(iStr, tokens, _t(" "), _t(""), _t("(\""));\r
-               if(!tokens.empty())\r
-               {\r
-                       tstring url;\r
-                       parse_css_url(tokens.front(), url);\r
-                       if(url.empty())\r
-                       {\r
-                               url = tokens.front();\r
-                       }\r
-                       tokens.erase(tokens.begin());\r
-                       if(doc)\r
-                       {\r
-                               document_container* doc_cont = doc->container();\r
-                               if(doc_cont)\r
-                               {\r
-                                       tstring css_text;\r
-                                       tstring css_baseurl;\r
-                                       if(baseurl)\r
-                                       {\r
-                                               css_baseurl = baseurl;\r
-                                       }\r
-                                       doc_cont->import_css(css_text, url, css_baseurl);\r
-                                       if(!css_text.empty())\r
-                                       {\r
-                                               media_query_list::ptr new_media = media;\r
-                                               if(!tokens.empty())\r
-                                               {\r
-                                                       tstring media_str;\r
-                                                       for(string_vector::iterator iter = tokens.begin(); iter != tokens.end(); iter++)\r
-                                                       {\r
-                                                               if(iter != tokens.begin())\r
-                                                               {\r
-                                                                       media_str += _t(" ");\r
-                                                               }\r
-                                                               media_str += (*iter);\r
-                                                       }\r
-                                                       new_media = media_query_list::create_from_string(media_str, doc);\r
-                                                       if(!new_media)\r
-                                                       {\r
-                                                               new_media = media;\r
-                                                       }\r
-                                               }\r
-                                               parse_stylesheet(css_text.c_str(), css_baseurl.c_str(), doc, new_media);\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       } else if(text.substr(0, 6) == _t("@media"))\r
-       {\r
-               tstring::size_type b1 = text.find_first_of(_t('{'));\r
-               tstring::size_type b2 = text.find_last_of(_t('}'));\r
-               if(b1 != tstring::npos)\r
-               {\r
-                       tstring media_type = text.substr(6, b1 - 6);\r
-                       trim(media_type);\r
-                       media_query_list::ptr new_media = media_query_list::create_from_string(media_type, doc);\r
-\r
-                       tstring media_style;\r
-                       if(b2 != tstring::npos)\r
-                       {\r
-                               media_style = text.substr(b1 + 1, b2 - b1 - 1);\r
-                       } else\r
-                       {\r
-                               media_style = text.substr(b1 + 1);\r
-                       }\r
-\r
-                       parse_stylesheet(media_style.c_str(), baseurl, doc, new_media);\r
-               }\r
-       }\r
-}\r
+#include "html.h"
+#include "stylesheet.h"
+#include <algorithm>
+#include "document.h"
+
+
+void litehtml::css::parse_stylesheet(const tchar_t* str, const tchar_t* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media)
+{
+       tstring text = str;
+
+       // remove comments
+       tstring::size_type c_start = text.find(_t("/*"));
+       while(c_start != tstring::npos)
+       {
+               tstring::size_type c_end = text.find(_t("*/"), c_start + 2);
+               text.erase(c_start, c_end - c_start + 2);
+               c_start = text.find(_t("/*"));
+       }
+
+       tstring::size_type pos = text.find_first_not_of(_t(" \n\r\t"));
+       while(pos != tstring::npos)
+       {
+               while(pos != tstring::npos && text[pos] == _t('@'))
+               {
+                       tstring::size_type sPos = pos;
+                       pos = text.find_first_of(_t("{;"), pos);
+                       if(pos != tstring::npos && text[pos] == _t('{'))
+                       {
+                               pos = find_close_bracket(text, pos, _t('{'), _t('}'));
+                       }
+                       if(pos != tstring::npos)
+                       {
+                               parse_atrule(text.substr(sPos, pos - sPos + 1), baseurl, doc, media);
+                       } else
+                       {
+                               parse_atrule(text.substr(sPos), baseurl, doc, media);
+                       }
+
+                       if(pos != tstring::npos)
+                       {
+                               pos = text.find_first_not_of(_t(" \n\r\t"), pos + 1);
+                       }
+               }
+
+               if(pos == tstring::npos)
+               {
+                       break;
+               }
+
+               tstring::size_type style_start = text.find(_t("{"), pos);
+               tstring::size_type style_end    = text.find(_t("}"), pos);
+               if(style_start != tstring::npos && style_end != tstring::npos)
+               {
+                       style::ptr st = std::make_shared<style>();
+                       st->add(text.substr(style_start + 1, style_end - style_start - 1).c_str(), baseurl);
+
+                       parse_selectors(text.substr(pos, style_start - pos), st, media);
+
+                       if(media && doc)
+                       {
+                               doc->add_media_list(media);
+                       }
+
+                       pos = style_end + 1;
+               } else
+               {
+                       pos = tstring::npos;
+               }
+
+               if(pos != tstring::npos)
+               {
+                       pos = text.find_first_not_of(_t(" \n\r\t"), pos);
+               }
+       }
+}
+
+void litehtml::css::parse_css_url( const tstring& str, tstring& url )
+{
+       url = _t("");
+       size_t pos1 = str.find(_t('('));
+       size_t pos2 = str.find(_t(')'));
+       if(pos1 != tstring::npos && pos2 != tstring::npos)
+       {
+               url = str.substr(pos1 + 1, pos2 - pos1 - 1);
+               if(url.length())
+               {
+                       if(url[0] == _t('\'') || url[0] == _t('"'))
+                       {
+                               url.erase(0, 1);
+                       }
+               }
+               if(url.length())
+               {
+                       if(url[url.length() - 1] == _t('\'') || url[url.length() - 1] == _t('"'))
+                       {
+                               url.erase(url.length() - 1, 1);
+                       }
+               }
+       }
+}
+
+bool litehtml::css::parse_selectors( const tstring& txt, const litehtml::style::ptr& styles, const media_query_list::ptr& media )
+{
+       tstring selector = txt;
+       trim(selector);
+       string_vector tokens;
+       split_string(selector, tokens, _t(","));
+
+       bool added_something = false;
+
+       for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+       {
+               css_selector::ptr selector = std::make_shared<css_selector>(media);
+               selector->m_style = styles;
+               trim(*tok);
+               if(selector->parse(*tok))
+               {
+                       selector->calc_specificity();
+                       add_selector(selector);
+                       added_something = true;
+               }
+       }
+
+       return added_something;
+}
+
+void litehtml::css::sort_selectors()
+{
+       std::sort(m_selectors.begin(), m_selectors.end(),
+                [](const css_selector::ptr& v1, const css_selector::ptr& v2)
+                {
+                        return (*v1) < (*v2);
+                }
+       );
+}
+
+void litehtml::css::parse_atrule(const tstring& text, const tchar_t* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media)
+{
+       if(text.substr(0, 7) == _t("@import"))
+       {
+               int sPos = 7;
+               tstring iStr;
+               iStr = text.substr(sPos);
+               if(iStr[iStr.length() - 1] == _t(';'))
+               {
+                       iStr.erase(iStr.length() - 1);
+               }
+               trim(iStr);
+               string_vector tokens;
+               split_string(iStr, tokens, _t(" "), _t(""), _t("(\""));
+               if(!tokens.empty())
+               {
+                       tstring url;
+                       parse_css_url(tokens.front(), url);
+                       if(url.empty())
+                       {
+                               url = tokens.front();
+                       }
+                       tokens.erase(tokens.begin());
+                       if(doc)
+                       {
+                               document_container* doc_cont = doc->container();
+                               if(doc_cont)
+                               {
+                                       tstring css_text;
+                                       tstring css_baseurl;
+                                       if(baseurl)
+                                       {
+                                               css_baseurl = baseurl;
+                                       }
+                                       doc_cont->import_css(css_text, url, css_baseurl);
+                                       if(!css_text.empty())
+                                       {
+                                               media_query_list::ptr new_media = media;
+                                               if(!tokens.empty())
+                                               {
+                                                       tstring media_str;
+                                                       for(string_vector::iterator iter = tokens.begin(); iter != tokens.end(); iter++)
+                                                       {
+                                                               if(iter != tokens.begin())
+                                                               {
+                                                                       media_str += _t(" ");
+                                                               }
+                                                               media_str += (*iter);
+                                                       }
+                                                       new_media = media_query_list::create_from_string(media_str, doc);
+                                                       if(!new_media)
+                                                       {
+                                                               new_media = media;
+                                                       }
+                                               }
+                                               parse_stylesheet(css_text.c_str(), css_baseurl.c_str(), doc, new_media);
+                                       }
+                               }
+                       }
+               }
+       } else if(text.substr(0, 6) == _t("@media"))
+       {
+               tstring::size_type b1 = text.find_first_of(_t('{'));
+               tstring::size_type b2 = text.find_last_of(_t('}'));
+               if(b1 != tstring::npos)
+               {
+                       tstring media_type = text.substr(6, b1 - 6);
+                       trim(media_type);
+                       media_query_list::ptr new_media = media_query_list::create_from_string(media_type, doc);
+
+                       tstring media_style;
+                       if(b2 != tstring::npos)
+                       {
+                               media_style = text.substr(b1 + 1, b2 - b1 - 1);
+                       } else
+                       {
+                               media_style = text.substr(b1 + 1);
+                       }
+
+                       parse_stylesheet(media_style.c_str(), baseurl, doc, new_media);
+               }
+       }
+}
index 04536c3b9275f8ff95c14ccaa4c3234b2e4a0daf..84c5f1fbf8cb4a9b6aeb8423de3116fad545674f 100644 (file)
@@ -1,50 +1,54 @@
-#pragma once\r
-#include "style.h"\r
-#include "css_selector.h"\r
-\r
-namespace litehtml\r
-{\r
-       class document_container;\r
-\r
-       class css\r
-       {\r
-               css_selector::vector    m_selectors;\r
-       public:\r
-               css()\r
-               {\r
-\r
-               }\r
-               \r
-               ~css()\r
-               {\r
-\r
-               }\r
-\r
-               const css_selector::vector& selectors() const\r
-               {\r
-                       return m_selectors;\r
-               }\r
-\r
-               void clear()\r
-               {\r
-                       m_selectors.clear();\r
-               }\r
-\r
-               void    parse_stylesheet(const tchar_t* str, const tchar_t* baseurl, const std::shared_ptr <document>& doc, const media_query_list::ptr& media);\r
-               void    sort_selectors();\r
-               static void     parse_css_url(const tstring& str, tstring& url);\r
-\r
-       private:\r
-               void    parse_atrule(const tstring& text, const tchar_t* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media);\r
-               void    add_selector(css_selector::ptr selector);\r
-               bool    parse_selectors(const tstring& txt, const litehtml::style::ptr& styles, const media_query_list::ptr& media);\r
-\r
-       };\r
-\r
-       inline void litehtml::css::add_selector( css_selector::ptr selector )\r
-       {\r
-               selector->m_order = (int) m_selectors.size();\r
-               m_selectors.push_back(selector);\r
-       }\r
-\r
-}\r
+#ifndef LH_STYLESHEET_H
+#define LH_STYLESHEET_H
+
+#include "style.h"
+#include "css_selector.h"
+
+namespace litehtml
+{
+       class document_container;
+
+       class css
+       {
+               css_selector::vector    m_selectors;
+       public:
+               css()
+               {
+
+               }
+               
+               ~css()
+               {
+
+               }
+
+               const css_selector::vector& selectors() const
+               {
+                       return m_selectors;
+               }
+
+               void clear()
+               {
+                       m_selectors.clear();
+               }
+
+               void    parse_stylesheet(const tchar_t* str, const tchar_t* baseurl, const std::shared_ptr <document>& doc, const media_query_list::ptr& media);
+               void    sort_selectors();
+               static void     parse_css_url(const tstring& str, tstring& url);
+
+       private:
+               void    parse_atrule(const tstring& text, const tchar_t* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media);
+               void    add_selector(css_selector::ptr selector);
+               bool    parse_selectors(const tstring& txt, const litehtml::style::ptr& styles, const media_query_list::ptr& media);
+
+       };
+
+       inline void litehtml::css::add_selector( css_selector::ptr selector )
+       {
+               selector->m_order = (int) m_selectors.size();
+               m_selectors.push_back(selector);
+       }
+
+}
+
+#endif  // LH_STYLESHEET_H
index 23d1e9abee3888405be9804713d6d841048caeda..c53509c76227a43945a27fecb0c8aa5dd140115b 100644 (file)
-#include "html.h"\r
-#include "table.h"\r
-#include "html_tag.h"\r
-\r
-void litehtml::table_grid::add_cell(element::ptr& el)\r
-{\r
-       table_cell cell;\r
-       cell.el = el;\r
-       cell.colspan    = t_atoi(el->get_attr(_t("colspan"), _t("1")));\r
-       cell.rowspan    = t_atoi(el->get_attr(_t("rowspan"), _t("1")));\r
-       cell.borders    = el->get_borders();\r
-\r
-       while( is_rowspanned( (int) m_cells.size() - 1, (int) m_cells.back().size() ) )\r
-       {\r
-               m_cells.back().push_back(table_cell());\r
-       }\r
-\r
-       m_cells.back().push_back(cell);\r
-       for(int i = 1; i < cell.colspan; i++)\r
-       {\r
-               table_cell empty_cell;\r
-               m_cells.back().push_back(empty_cell);\r
-       }\r
-}\r
-\r
-\r
-void litehtml::table_grid::begin_row(element::ptr& row)\r
-{\r
-       std::vector<table_cell> r;\r
-       m_cells.push_back(r);\r
-       \r
-       m_rows.push_back(table_row(0, row));\r
-\r
-}\r
-\r
-\r
-bool litehtml::table_grid::is_rowspanned( int r, int c )\r
-{\r
-       for(int row = r - 1; row >= 0; row--)\r
-       {\r
-               if(c < (int) m_cells[row].size())\r
-               {\r
-                       if(m_cells[row][c].rowspan > 1)\r
-                       {\r
-                               if(m_cells[row][c].rowspan >= r - row + 1)\r
-                               {\r
-                                       return true;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       return false;\r
-}\r
-\r
-void litehtml::table_grid::finish()\r
-{\r
-       m_rows_count    = (int) m_cells.size();\r
-       m_cols_count    = 0;\r
-       for(int i = 0; i < (int) m_cells.size(); i++)\r
-       {\r
-               m_cols_count = std::max(m_cols_count, (int) m_cells[i].size());\r
-       }\r
-       for(int i = 0; i < (int) m_cells.size(); i++)\r
-       {\r
-               for(int j = (int) m_cells[i].size(); j < m_cols_count; j++)\r
-               {\r
-                       table_cell empty_cell;\r
-                       m_cells[i].push_back(empty_cell);\r
-               }\r
-       }\r
-\r
-       m_columns.clear();\r
-       for(int i = 0; i < m_cols_count; i++)\r
-       {\r
-               m_columns.push_back(table_column(0, 0));\r
-       }\r
-\r
-       for(int col = 0; col < m_cols_count; col++)\r
-       {\r
-               for(int row = 0; row < m_rows_count; row++)\r
-               {\r
-                       if(cell(col, row)->el)\r
-                       {\r
-                               // find minimum left border width\r
-                               if(m_columns[col].border_left)\r
-                               {\r
-                                       m_columns[col].border_left = std::min(m_columns[col].border_left, cell(col, row)->borders.left);\r
-                               } else\r
-                               {\r
-                                       m_columns[col].border_left = cell(col, row)->borders.left;\r
-                               }\r
-                               // find minimum right border width\r
-                               if(m_columns[col].border_right)\r
-                               {\r
-                                       m_columns[col].border_right = std::min(m_columns[col].border_right, cell(col, row)->borders.right);\r
-                               } else\r
-                               {\r
-                                       m_columns[col].border_right = cell(col, row)->borders.right;\r
-                               }\r
-                               // find minimum top border width\r
-                               if(m_rows[row].border_top)\r
-                               {\r
-                                       m_rows[row].border_top = std::min(m_rows[row].border_top, cell(col, row)->borders.top);\r
-                               } else\r
-                               {\r
-                                       m_rows[row].border_top = cell(col, row)->borders.top;\r
-                               }\r
-                               // find minimum bottom border width\r
-                               if(m_rows[row].border_bottom)\r
-                               {\r
-                                       m_rows[row].border_bottom = std::min(m_rows[row].border_bottom, cell(col, row)->borders.bottom);\r
-                               } else\r
-                               {\r
-                                       m_rows[row].border_bottom = cell(col, row)->borders.bottom;\r
-                               }\r
-                       }\r
-\r
-                       if(cell(col, row)->el && cell(col, row)->colspan <= 1)\r
-                       {\r
-                               if (!cell(col, row)->el->get_css_width().is_predefined() && m_columns[col].css_width.is_predefined())\r
-                               {\r
-                                       m_columns[col].css_width = cell(col, row)->el->get_css_width();\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       for(int col = 0; col < m_cols_count; col++)\r
-       {\r
-               for(int row = 0; row < m_rows_count; row++)\r
-               {\r
-                       if(cell(col, row)->el)\r
-                       {\r
-                               cell(col, row)->el->set_css_width(m_columns[col].css_width);\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-litehtml::table_cell* litehtml::table_grid::cell( int t_col, int t_row )\r
-{\r
-       if(t_col >= 0 && t_col < m_cols_count && t_row >= 0 && t_row < m_rows_count)\r
-       {\r
-               return &m_cells[t_row][t_col];\r
-       }\r
-       return 0;\r
-}\r
-\r
-void litehtml::table_grid::distribute_max_width( int width, int start, int end )\r
-{\r
-       table_column_accessor_max_width selector;\r
-       distribute_width(width, start, end, &selector);\r
-}\r
-\r
-void litehtml::table_grid::distribute_min_width( int width, int start, int end )\r
-{\r
-       table_column_accessor_min_width selector;\r
-       distribute_width(width, start, end, &selector);\r
-}\r
-\r
-void litehtml::table_grid::distribute_width( int width, int start, int end, table_column_accessor* acc )\r
-{\r
-       if(!(start >= 0 && start < m_cols_count && end >= 0 && end < m_cols_count))\r
-       {\r
-               return;\r
-       }\r
-\r
-       int cols_width = 0;\r
-       for(int col = start; col <= end; col++)\r
-       {\r
-               cols_width              += m_columns[col].max_width;\r
-       }\r
-\r
-       int add = width / (end - start + 1);\r
-       int added_width = 0;\r
-       for(int col = start; col <= end; col++)\r
-       {\r
-               if(cols_width)\r
-               {\r
-                       add = round_f( (float) width * ((float) m_columns[col].max_width / (float) cols_width) );\r
-               }\r
-               added_width += add;\r
-               acc->get(m_columns[col]) += add;\r
-       }\r
-       if(added_width < width)\r
-       {\r
-               acc->get(m_columns[start]) += width - added_width;\r
-       }\r
-}\r
-\r
-void litehtml::table_grid::distribute_width( int width, int start, int end )\r
-{\r
-       if(!(start >= 0 && start < m_cols_count && end >= 0 && end < m_cols_count))\r
-       {\r
-               return;\r
-       }\r
-\r
-       std::vector<table_column*> distribute_columns;\r
-\r
-       for(int step = 0; step < 3; step++)\r
-       {\r
-               distribute_columns.clear();\r
-\r
-               switch(step)\r
-               {\r
-               case 0:\r
-                       {\r
-                               // distribute between the columns with width == auto\r
-                               for(int col = start; col <= end; col++)\r
-                               {\r
-                                       if(m_columns[col].css_width.is_predefined())\r
-                                       {\r
-                                               distribute_columns.push_back(&m_columns[col]);\r
-                                       }\r
-                               }\r
-                       }\r
-                       break;\r
-               case 1:\r
-                       {\r
-                               // distribute between the columns with percents\r
-                               for(int col = start; col <= end; col++)\r
-                               {\r
-                                       if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)\r
-                                       {\r
-                                               distribute_columns.push_back(&m_columns[col]);\r
-                                       }\r
-                               }\r
-                       }\r
-                       break;\r
-               case 2:\r
-                       {\r
-                               //well distribute between all columns\r
-                               for(int col = start; col <= end; col++)\r
-                               {\r
-                                       distribute_columns.push_back(&m_columns[col]);\r
-                               }\r
-                       }\r
-                       break;\r
-               }\r
-\r
-               int added_width = 0;\r
-\r
-               if(!distribute_columns.empty() || step == 2)\r
-               {\r
-                       int cols_width = 0;\r
-                       for(std::vector<table_column*>::iterator col = distribute_columns.begin(); col != distribute_columns.end(); col++)\r
-                       {\r
-                               cols_width += (*col)->max_width - (*col)->min_width;\r
-                       }\r
-\r
-                       if(cols_width)\r
-                       {\r
-                               int add = width / (int) distribute_columns.size();\r
-                               for(std::vector<table_column*>::iterator col = distribute_columns.begin(); col != distribute_columns.end(); col++)\r
-                               {\r
-                                       add = round_f( (float) width * ((float) ((*col)->max_width - (*col)->min_width) / (float) cols_width) );\r
-                                       if((*col)->width + add >= (*col)->min_width)\r
-                                       {\r
-                                               (*col)->width   += add;\r
-                                               added_width             += add;\r
-                                       } else\r
-                                       {\r
-                                               added_width     += ((*col)->width - (*col)->min_width) * (add / abs(add));\r
-                                               (*col)->width = (*col)->min_width;\r
-                                       }\r
-                               }\r
-                               if(added_width < width && step)\r
-                               {\r
-                                       distribute_columns.front()->width += width - added_width;\r
-                                       added_width = width;\r
-                               }\r
-                       } else\r
-                       {\r
-                               distribute_columns.back()->width += width;\r
-                               added_width = width;\r
-                       }\r
-               }\r
-\r
-               if(added_width == width)\r
-               {\r
-                       break;\r
-               } else\r
-               {\r
-                       width -= added_width;\r
-               }\r
-       }\r
-}\r
-\r
-int litehtml::table_grid::calc_table_width(int block_width, bool is_auto, int& min_table_width, int& max_table_width)\r
-{\r
-       //int table_width = 0;\r
-\r
-       min_table_width = 0; // MIN\r
-       max_table_width = 0; // MAX\r
-\r
-       int cur_width = 0;\r
-       int max_w = 0;\r
-       int min_w = 0;\r
-\r
-       for(int col = 0; col < m_cols_count; col++)\r
-       {\r
-               min_table_width += m_columns[col].min_width;\r
-               max_table_width += m_columns[col].max_width;\r
-\r
-               if(!m_columns[col].css_width.is_predefined())\r
-               {\r
-                       m_columns[col].width = m_columns[col].css_width.calc_percent(block_width);\r
-                       m_columns[col].width = std::max(m_columns[col].width, m_columns[col].min_width);\r
-               } else\r
-               {\r
-                       m_columns[col].width = m_columns[col].min_width;\r
-                       max_w += m_columns[col].max_width;\r
-                       min_w += m_columns[col].min_width;\r
-               }\r
-\r
-               cur_width += m_columns[col].width;\r
-       }\r
-\r
-       if(cur_width == block_width)\r
-       {\r
-               return cur_width;\r
-       }\r
-\r
-       if(cur_width < block_width)\r
-       {\r
-               if(cur_width - min_w + max_w <= block_width)\r
-               {\r
-                       cur_width = 0;\r
-                       for(int col = 0; col < m_cols_count; col++)\r
-                       {\r
-                               if(m_columns[col].css_width.is_predefined())\r
-                               {\r
-                                       m_columns[col].width = m_columns[col].max_width;\r
-                               }\r
-                               cur_width += m_columns[col].width;\r
-                       }\r
-                       if(cur_width == block_width || is_auto)\r
-                       {\r
-                               return cur_width;\r
-                       }\r
-               }\r
-               distribute_width(block_width - cur_width, 0, m_cols_count - 1);\r
-               cur_width = 0;\r
-               for(int col = 0; col < m_cols_count; col++)\r
-               {\r
-                       cur_width += m_columns[col].width;\r
-               }\r
-       } else\r
-       {\r
-               int fixed_width = 0;\r
-               float percent = 0;\r
-               for(int col = 0; col < m_cols_count; col++)\r
-               {\r
-                       if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)\r
-                       {\r
-                               percent += m_columns[col].css_width.val();\r
-                       } else\r
-                       {\r
-                               fixed_width += m_columns[col].width;\r
-                       }\r
-               }\r
-               float scale = (float) (100.0 / percent);\r
-               cur_width = 0;\r
-               for(int col = 0; col < m_cols_count; col++)\r
-               {\r
-                       if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)\r
-                       {\r
-                               css_length w;\r
-                               w.set_value(m_columns[col].css_width.val() * scale, css_units_percentage);\r
-                               m_columns[col].width = w.calc_percent(block_width - fixed_width);\r
-                               if(m_columns[col].width < m_columns[col].min_width)\r
-                               {\r
-                                       m_columns[col].width = m_columns[col].min_width;\r
-                               }\r
-                       }\r
-                       cur_width += m_columns[col].width;\r
-               }\r
-       }\r
-       return cur_width;\r
-}\r
-\r
-void litehtml::table_grid::clear()\r
-{\r
-       m_rows_count    = 0;\r
-       m_cols_count    = 0;\r
-       m_cells.clear();\r
-       m_columns.clear();\r
-       m_rows.clear();\r
-}\r
-\r
-void litehtml::table_grid::calc_horizontal_positions( margins& table_borders, border_collapse bc, int bdr_space_x)\r
-{\r
-       if(bc == border_collapse_separate)\r
-       {\r
-               int left = bdr_space_x;\r
-               for(int i = 0; i < m_cols_count; i++)\r
-               {\r
-                       m_columns[i].left       = left;\r
-                       m_columns[i].right      = m_columns[i].left + m_columns[i].width;\r
-                       left = m_columns[i].right + bdr_space_x;\r
-               }\r
-       } else\r
-       {\r
-               int left = 0;\r
-               if(m_cols_count)\r
-               {\r
-                       left -= std::min(table_borders.left, m_columns[0].border_left);\r
-               }\r
-               for(int i = 0; i < m_cols_count; i++)\r
-               {\r
-                       if(i > 0)\r
-                       {\r
-                               left -= std::min(m_columns[i - 1].border_right, m_columns[i].border_left);\r
-                       }\r
-\r
-                       m_columns[i].left       = left;\r
-                       m_columns[i].right      = m_columns[i].left + m_columns[i].width;\r
-                       left = m_columns[i].right;\r
-               }\r
-       }\r
-}\r
-\r
-void litehtml::table_grid::calc_vertical_positions( margins& table_borders, border_collapse bc, int bdr_space_y )\r
-{\r
-       if(bc == border_collapse_separate)\r
-       {\r
-               int top = bdr_space_y;\r
-               for(int i = 0; i < m_rows_count; i++)\r
-               {\r
-                       m_rows[i].top           = top;\r
-                       m_rows[i].bottom        = m_rows[i].top + m_rows[i].height;\r
-                       top = m_rows[i].bottom + bdr_space_y;\r
-               }\r
-       } else\r
-       {\r
-               int top = 0;\r
-               if(m_rows_count)\r
-               {\r
-                       top -= std::min(table_borders.top, m_rows[0].border_top);\r
-               }\r
-               for(int i = 0; i < m_rows_count; i++)\r
-               {\r
-                       if(i > 0)\r
-                       {\r
-                               top -= std::min(m_rows[i - 1].border_bottom, m_rows[i].border_top);\r
-                       }\r
-\r
-                       m_rows[i].top           = top;\r
-                       m_rows[i].bottom        = m_rows[i].top + m_rows[i].height;\r
-                       top = m_rows[i].bottom;\r
-               }\r
-       }\r
-}\r
-\r
-void litehtml::table_grid::calc_rows_height(int blockHeight, int borderSpacingY)\r
-{\r
-       int min_table_height = 0;\r
-\r
-       // compute vertical size inferred by cells\r
-       for (auto& row : m_rows)\r
-       {\r
-               if (!row.css_height.is_predefined())\r
-               {\r
-                       if (row.css_height.units() != css_units_percentage)\r
-                       {\r
-                               if (row.height < (int)row.css_height.val())\r
-                               {\r
-                                       row.height = (int)row.css_height.val();\r
-                               }\r
-                       }\r
-               }\r
-               row.min_height = row.height;\r
-               min_table_height += row.height;\r
-       }\r
-\r
-       //min_table_height += borderSpacingY * ((int) m_rows.size() + 1);\r
-\r
-       if (blockHeight > min_table_height)\r
-       {\r
-               int extra_height = blockHeight - min_table_height;\r
-               int auto_count = 0; // number of rows with height=auto\r
-               for (auto& row : m_rows)\r
-               {\r
-                       if (!row.css_height.is_predefined() && row.css_height.units() == css_units_percentage)\r
-                       {\r
-                               row.height = row.css_height.calc_percent(blockHeight);\r
-                               if (row.height < row.min_height)\r
-                               {\r
-                                       row.height = row.min_height;\r
-                               }\r
-\r
-                               extra_height -= row.height - row.min_height;\r
-\r
-                               if (extra_height <= 0) break;\r
-                       }\r
-                       else if (row.css_height.is_predefined())\r
-                       {\r
-                               auto_count++;\r
-                       }\r
-               }\r
-               if (extra_height > 0)\r
-               {\r
-                       if (auto_count)\r
-                       {\r
-                               // distribute height to the rows with height=auto\r
-                               int extra_row_height = (int)(extra_height / auto_count);\r
-                               for (auto& row : m_rows)\r
-                               {\r
-                                       if (row.css_height.is_predefined())\r
-                                       {\r
-                                               row.height += extra_row_height;\r
-                                       }\r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               // We don't have rows with height=auto, so distribute height to all rows\r
-                               if (!m_rows.empty())\r
-                               {\r
-                                       int extra_row_height = (int)(extra_height / m_rows.size());\r
-                                       for (auto& row : m_rows)\r
-                                       {\r
-                                               row.height += extra_row_height;\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               else if (extra_height < 0)\r
-               {\r
-                       extra_height = -extra_height;\r
-                       for (auto row = m_rows.rbegin(); row < m_rows.rend() && extra_height > 0; row++)\r
-                       {\r
-                               if (row->height > row->min_height)\r
-                               {\r
-                                       if (row->height - extra_height >= row->min_height)\r
-                                       {\r
-                                               row->height -= extra_height;\r
-                                               extra_height = 0;\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               extra_height -= row->height - row->min_height;\r
-                                               row->height = row->min_height;\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////////\r
-\r
-int& litehtml::table_column_accessor_max_width::get( table_column& col )\r
-{\r
-       return col.max_width;\r
-}\r
-\r
-int& litehtml::table_column_accessor_min_width::get( table_column& col )\r
-{\r
-       return col.min_width;\r
-}\r
-\r
-int& litehtml::table_column_accessor_width::get( table_column& col )\r
-{\r
-       return col.width;\r
-}\r
+#include "html.h"
+#include "table.h"
+#include "html_tag.h"
+
+void litehtml::table_grid::add_cell(element::ptr& el)
+{
+       table_cell cell;
+       cell.el = el;
+       cell.colspan    = t_atoi(el->get_attr(_t("colspan"), _t("1")));
+       cell.rowspan    = t_atoi(el->get_attr(_t("rowspan"), _t("1")));
+       cell.borders    = el->get_borders();
+
+       while( is_rowspanned( (int) m_cells.size() - 1, (int) m_cells.back().size() ) )
+       {
+               m_cells.back().push_back(table_cell());
+       }
+
+       m_cells.back().push_back(cell);
+       for(int i = 1; i < cell.colspan; i++)
+       {
+               table_cell empty_cell;
+               m_cells.back().push_back(empty_cell);
+       }
+}
+
+
+void litehtml::table_grid::begin_row(element::ptr& row)
+{
+       std::vector<table_cell> r;
+       m_cells.push_back(r);
+       
+       m_rows.push_back(table_row(0, row));
+
+}
+
+
+bool litehtml::table_grid::is_rowspanned( int r, int c )
+{
+       for(int row = r - 1; row >= 0; row--)
+       {
+               if(c < (int) m_cells[row].size())
+               {
+                       if(m_cells[row][c].rowspan > 1)
+                       {
+                               if(m_cells[row][c].rowspan >= r - row + 1)
+                               {
+                                       return true;
+                               }
+                       }
+               }
+       }
+       return false;
+}
+
+void litehtml::table_grid::finish()
+{
+       m_rows_count    = (int) m_cells.size();
+       m_cols_count    = 0;
+       for(int i = 0; i < (int) m_cells.size(); i++)
+       {
+               m_cols_count = std::max(m_cols_count, (int) m_cells[i].size());
+       }
+       for(int i = 0; i < (int) m_cells.size(); i++)
+       {
+               for(int j = (int) m_cells[i].size(); j < m_cols_count; j++)
+               {
+                       table_cell empty_cell;
+                       m_cells[i].push_back(empty_cell);
+               }
+       }
+
+       m_columns.clear();
+       for(int i = 0; i < m_cols_count; i++)
+       {
+               m_columns.push_back(table_column(0, 0));
+       }
+
+       for(int col = 0; col < m_cols_count; col++)
+       {
+               for(int row = 0; row < m_rows_count; row++)
+               {
+                       if(cell(col, row)->el)
+                       {
+                               // find minimum left border width
+                               if(m_columns[col].border_left)
+                               {
+                                       m_columns[col].border_left = std::min(m_columns[col].border_left, cell(col, row)->borders.left);
+                               } else
+                               {
+                                       m_columns[col].border_left = cell(col, row)->borders.left;
+                               }
+                               // find minimum right border width
+                               if(m_columns[col].border_right)
+                               {
+                                       m_columns[col].border_right = std::min(m_columns[col].border_right, cell(col, row)->borders.right);
+                               } else
+                               {
+                                       m_columns[col].border_right = cell(col, row)->borders.right;
+                               }
+                               // find minimum top border width
+                               if(m_rows[row].border_top)
+                               {
+                                       m_rows[row].border_top = std::min(m_rows[row].border_top, cell(col, row)->borders.top);
+                               } else
+                               {
+                                       m_rows[row].border_top = cell(col, row)->borders.top;
+                               }
+                               // find minimum bottom border width
+                               if(m_rows[row].border_bottom)
+                               {
+                                       m_rows[row].border_bottom = std::min(m_rows[row].border_bottom, cell(col, row)->borders.bottom);
+                               } else
+                               {
+                                       m_rows[row].border_bottom = cell(col, row)->borders.bottom;
+                               }
+                       }
+
+                       if(cell(col, row)->el && cell(col, row)->colspan <= 1)
+                       {
+                               if (!cell(col, row)->el->get_css_width().is_predefined() && m_columns[col].css_width.is_predefined())
+                               {
+                                       m_columns[col].css_width = cell(col, row)->el->get_css_width();
+                               }
+                       }
+               }
+       }
+
+       for(int col = 0; col < m_cols_count; col++)
+       {
+               for(int row = 0; row < m_rows_count; row++)
+               {
+                       if(cell(col, row)->el)
+                       {
+                               cell(col, row)->el->set_css_width(m_columns[col].css_width);
+                       }
+               }
+       }
+}
+
+litehtml::table_cell* litehtml::table_grid::cell( int t_col, int t_row )
+{
+       if(t_col >= 0 && t_col < m_cols_count && t_row >= 0 && t_row < m_rows_count)
+       {
+               return &m_cells[t_row][t_col];
+       }
+       return 0;
+}
+
+void litehtml::table_grid::distribute_max_width( int width, int start, int end )
+{
+       table_column_accessor_max_width selector;
+       distribute_width(width, start, end, &selector);
+}
+
+void litehtml::table_grid::distribute_min_width( int width, int start, int end )
+{
+       table_column_accessor_min_width selector;
+       distribute_width(width, start, end, &selector);
+}
+
+void litehtml::table_grid::distribute_width( int width, int start, int end, table_column_accessor* acc )
+{
+       if(!(start >= 0 && start < m_cols_count && end >= 0 && end < m_cols_count))
+       {
+               return;
+       }
+
+       int cols_width = 0;
+       for(int col = start; col <= end; col++)
+       {
+               cols_width              += m_columns[col].max_width;
+       }
+
+       int add = width / (end - start + 1);
+       int added_width = 0;
+       for(int col = start; col <= end; col++)
+       {
+               if(cols_width)
+               {
+                       add = round_f( (float) width * ((float) m_columns[col].max_width / (float) cols_width) );
+               }
+               added_width += add;
+               acc->get(m_columns[col]) += add;
+       }
+       if(added_width < width)
+       {
+               acc->get(m_columns[start]) += width - added_width;
+       }
+}
+
+void litehtml::table_grid::distribute_width( int width, int start, int end )
+{
+       if(!(start >= 0 && start < m_cols_count && end >= 0 && end < m_cols_count))
+       {
+               return;
+       }
+
+       std::vector<table_column*> distribute_columns;
+
+       for(int step = 0; step < 3; step++)
+       {
+               distribute_columns.clear();
+
+               switch(step)
+               {
+               case 0:
+                       {
+                               // distribute between the columns with width == auto
+                               for(int col = start; col <= end; col++)
+                               {
+                                       if(m_columns[col].css_width.is_predefined())
+                                       {
+                                               distribute_columns.push_back(&m_columns[col]);
+                                       }
+                               }
+                       }
+                       break;
+               case 1:
+                       {
+                               // distribute between the columns with percents
+                               for(int col = start; col <= end; col++)
+                               {
+                                       if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
+                                       {
+                                               distribute_columns.push_back(&m_columns[col]);
+                                       }
+                               }
+                       }
+                       break;
+               case 2:
+                       {
+                               //well distribute between all columns
+                               for(int col = start; col <= end; col++)
+                               {
+                                       distribute_columns.push_back(&m_columns[col]);
+                               }
+                       }
+                       break;
+               }
+
+               int added_width = 0;
+
+               if(!distribute_columns.empty() || step == 2)
+               {
+                       int cols_width = 0;
+                       for(std::vector<table_column*>::iterator col = distribute_columns.begin(); col != distribute_columns.end(); col++)
+                       {
+                               cols_width += (*col)->max_width - (*col)->min_width;
+                       }
+
+                       if(cols_width)
+                       {
+                               int add = width / (int) distribute_columns.size();
+                               for(std::vector<table_column*>::iterator col = distribute_columns.begin(); col != distribute_columns.end(); col++)
+                               {
+                                       add = round_f( (float) width * ((float) ((*col)->max_width - (*col)->min_width) / (float) cols_width) );
+                                       if((*col)->width + add >= (*col)->min_width)
+                                       {
+                                               (*col)->width   += add;
+                                               added_width             += add;
+                                       } else
+                                       {
+                                               added_width     += ((*col)->width - (*col)->min_width) * (add / abs(add));
+                                               (*col)->width = (*col)->min_width;
+                                       }
+                               }
+                               if(added_width < width && step)
+                               {
+                                       distribute_columns.front()->width += width - added_width;
+                                       added_width = width;
+                               }
+                       } else
+                       {
+                               distribute_columns.back()->width += width;
+                               added_width = width;
+                       }
+               }
+
+               if(added_width == width)
+               {
+                       break;
+               } else
+               {
+                       width -= added_width;
+               }
+       }
+}
+
+int litehtml::table_grid::calc_table_width(int block_width, bool is_auto, int& min_table_width, int& max_table_width)
+{
+       //int table_width = 0;
+
+       min_table_width = 0; // MIN
+       max_table_width = 0; // MAX
+
+       int cur_width = 0;
+       int max_w = 0;
+       int min_w = 0;
+
+       for(int col = 0; col < m_cols_count; col++)
+       {
+               min_table_width += m_columns[col].min_width;
+               max_table_width += m_columns[col].max_width;
+
+               if(!m_columns[col].css_width.is_predefined())
+               {
+                       m_columns[col].width = m_columns[col].css_width.calc_percent(block_width);
+                       m_columns[col].width = std::max(m_columns[col].width, m_columns[col].min_width);
+               } else
+               {
+                       m_columns[col].width = m_columns[col].min_width;
+                       max_w += m_columns[col].max_width;
+                       min_w += m_columns[col].min_width;
+               }
+
+               cur_width += m_columns[col].width;
+       }
+
+       if(cur_width == block_width)
+       {
+               return cur_width;
+       }
+
+       if(cur_width < block_width)
+       {
+               if(cur_width - min_w + max_w <= block_width)
+               {
+                       cur_width = 0;
+                       for(int col = 0; col < m_cols_count; col++)
+                       {
+                               if(m_columns[col].css_width.is_predefined())
+                               {
+                                       m_columns[col].width = m_columns[col].max_width;
+                               }
+                               cur_width += m_columns[col].width;
+                       }
+                       if(cur_width == block_width || is_auto)
+                       {
+                               return cur_width;
+                       }
+               }
+               distribute_width(block_width - cur_width, 0, m_cols_count - 1);
+               cur_width = 0;
+               for(int col = 0; col < m_cols_count; col++)
+               {
+                       cur_width += m_columns[col].width;
+               }
+       } else
+       {
+               int fixed_width = 0;
+               float percent = 0;
+               for(int col = 0; col < m_cols_count; col++)
+               {
+                       if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
+                       {
+                               percent += m_columns[col].css_width.val();
+                       } else
+                       {
+                               fixed_width += m_columns[col].width;
+                       }
+               }
+               float scale = (float) (100.0 / percent);
+               cur_width = 0;
+               for(int col = 0; col < m_cols_count; col++)
+               {
+                       if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
+                       {
+                               css_length w;
+                               w.set_value(m_columns[col].css_width.val() * scale, css_units_percentage);
+                               m_columns[col].width = w.calc_percent(block_width - fixed_width);
+                               if(m_columns[col].width < m_columns[col].min_width)
+                               {
+                                       m_columns[col].width = m_columns[col].min_width;
+                               }
+                       }
+                       cur_width += m_columns[col].width;
+               }
+       }
+       return cur_width;
+}
+
+void litehtml::table_grid::clear()
+{
+       m_rows_count    = 0;
+       m_cols_count    = 0;
+       m_cells.clear();
+       m_columns.clear();
+       m_rows.clear();
+}
+
+void litehtml::table_grid::calc_horizontal_positions( margins& table_borders, border_collapse bc, int bdr_space_x)
+{
+       if(bc == border_collapse_separate)
+       {
+               int left = bdr_space_x;
+               for(int i = 0; i < m_cols_count; i++)
+               {
+                       m_columns[i].left       = left;
+                       m_columns[i].right      = m_columns[i].left + m_columns[i].width;
+                       left = m_columns[i].right + bdr_space_x;
+               }
+       } else
+       {
+               int left = 0;
+               if(m_cols_count)
+               {
+                       left -= std::min(table_borders.left, m_columns[0].border_left);
+               }
+               for(int i = 0; i < m_cols_count; i++)
+               {
+                       if(i > 0)
+                       {
+                               left -= std::min(m_columns[i - 1].border_right, m_columns[i].border_left);
+                       }
+
+                       m_columns[i].left       = left;
+                       m_columns[i].right      = m_columns[i].left + m_columns[i].width;
+                       left = m_columns[i].right;
+               }
+       }
+}
+
+void litehtml::table_grid::calc_vertical_positions( margins& table_borders, border_collapse bc, int bdr_space_y )
+{
+       if(bc == border_collapse_separate)
+       {
+               int top = bdr_space_y;
+               for(int i = 0; i < m_rows_count; i++)
+               {
+                       m_rows[i].top           = top;
+                       m_rows[i].bottom        = m_rows[i].top + m_rows[i].height;
+                       top = m_rows[i].bottom + bdr_space_y;
+               }
+       } else
+       {
+               int top = 0;
+               if(m_rows_count)
+               {
+                       top -= std::min(table_borders.top, m_rows[0].border_top);
+               }
+               for(int i = 0; i < m_rows_count; i++)
+               {
+                       if(i > 0)
+                       {
+                               top -= std::min(m_rows[i - 1].border_bottom, m_rows[i].border_top);
+                       }
+
+                       m_rows[i].top           = top;
+                       m_rows[i].bottom        = m_rows[i].top + m_rows[i].height;
+                       top = m_rows[i].bottom;
+               }
+       }
+}
+
+void litehtml::table_grid::calc_rows_height(int blockHeight, int borderSpacingY)
+{
+       int min_table_height = 0;
+
+       // compute vertical size inferred by cells
+       for (auto& row : m_rows)
+       {
+               if (!row.css_height.is_predefined())
+               {
+                       if (row.css_height.units() != css_units_percentage)
+                       {
+                               if (row.height < (int)row.css_height.val())
+                               {
+                                       row.height = (int)row.css_height.val();
+                               }
+                       }
+               }
+               row.min_height = row.height;
+               min_table_height += row.height;
+       }
+
+       //min_table_height += borderSpacingY * ((int) m_rows.size() + 1);
+
+       if (blockHeight > min_table_height)
+       {
+               int extra_height = blockHeight - min_table_height;
+               int auto_count = 0; // number of rows with height=auto
+               for (auto& row : m_rows)
+               {
+                       if (!row.css_height.is_predefined() && row.css_height.units() == css_units_percentage)
+                       {
+                               row.height = row.css_height.calc_percent(blockHeight);
+                               if (row.height < row.min_height)
+                               {
+                                       row.height = row.min_height;
+                               }
+
+                               extra_height -= row.height - row.min_height;
+
+                               if (extra_height <= 0) break;
+                       }
+                       else if (row.css_height.is_predefined())
+                       {
+                               auto_count++;
+                       }
+               }
+               if (extra_height > 0)
+               {
+                       if (auto_count)
+                       {
+                               // distribute height to the rows with height=auto
+                               int extra_row_height = (int)(extra_height / auto_count);
+                               for (auto& row : m_rows)
+                               {
+                                       if (row.css_height.is_predefined())
+                                       {
+                                               row.height += extra_row_height;
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               // We don't have rows with height=auto, so distribute height to all rows
+                               if (!m_rows.empty())
+                               {
+                                       int extra_row_height = (int)(extra_height / m_rows.size());
+                                       for (auto& row : m_rows)
+                                       {
+                                               row.height += extra_row_height;
+                                       }
+                               }
+                       }
+               }
+               else if (extra_height < 0)
+               {
+                       extra_height = -extra_height;
+                       for (auto row = m_rows.rbegin(); row < m_rows.rend() && extra_height > 0; row++)
+                       {
+                               if (row->height > row->min_height)
+                               {
+                                       if (row->height - extra_height >= row->min_height)
+                                       {
+                                               row->height -= extra_height;
+                                               extra_height = 0;
+                                       }
+                                       else
+                                       {
+                                               extra_height -= row->height - row->min_height;
+                                               row->height = row->min_height;
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+int& litehtml::table_column_accessor_max_width::get( table_column& col )
+{
+       return col.max_width;
+}
+
+int& litehtml::table_column_accessor_min_width::get( table_column& col )
+{
+       return col.min_width;
+}
+
+int& litehtml::table_column_accessor_width::get( table_column& col )
+{
+       return col.width;
+}
index 6f23b97503285c1f5b358d0c0de5ec295d67ed77..ca95febf51462296858839b09ba074c39dc1e9c2 100644 (file)
-#pragma once\r
-\r
-namespace litehtml\r
-{\r
-       struct table_row\r
-       {\r
-               typedef std::vector<table_row>  vector;\r
-\r
-               int                             height;\r
-               int                             border_top;\r
-               int                             border_bottom;\r
-               element::ptr    el_row;\r
-               int                             top;\r
-               int                             bottom;\r
-               css_length              css_height;\r
-               int                             min_height;\r
-\r
-               table_row()\r
-               {\r
-                       min_height              = 0;\r
-                       top                             = 0;\r
-                       bottom                  = 0;\r
-                       border_bottom   = 0;\r
-                       border_top              = 0;\r
-                       height                  = 0;\r
-                       el_row                  = nullptr;\r
-                       css_height.predef(0);\r
-               }\r
-\r
-               table_row(int h, element::ptr& row)\r
-               {\r
-                       min_height              = 0;\r
-                       height                  = h;\r
-                       el_row                  = row;\r
-                       border_bottom   = 0;\r
-                       border_top              = 0;\r
-                       top                             = 0;\r
-                       bottom                  = 0;\r
-                       if (row)\r
-                       {\r
-                               css_height = row->get_css_height();\r
-                       }\r
-               }\r
-\r
-               table_row(const table_row& val)\r
-               {\r
-                       min_height = val.min_height;\r
-                       top = val.top;\r
-                       bottom = val.bottom;\r
-                       border_bottom = val.border_bottom;\r
-                       border_top = val.border_top;\r
-                       height = val.height;\r
-                       css_height = val.css_height;\r
-                       el_row = val.el_row;\r
-               }\r
-\r
-               table_row(table_row&& val)\r
-               {\r
-                       min_height = val.min_height;\r
-                       top = val.top;\r
-                       bottom = val.bottom;\r
-                       border_bottom = val.border_bottom;\r
-                       border_top = val.border_top;\r
-                       height = val.height;\r
-                       css_height = val.css_height;\r
-                       el_row = std::move(val.el_row);\r
-               }\r
-       };\r
-\r
-       struct table_column\r
-       {\r
-               typedef std::vector<table_column>       vector;\r
-               \r
-               int                     min_width;\r
-               int                     max_width;\r
-               int                     width;\r
-               css_length      css_width;\r
-               int                     border_left;\r
-               int                     border_right;\r
-               int                     left;\r
-               int                     right;\r
-\r
-               table_column()\r
-               {\r
-                       left                    = 0;\r
-                       right                   = 0;\r
-                       border_left             = 0;\r
-                       border_right    = 0;\r
-                       min_width               = 0;\r
-                       max_width               = 0;\r
-                       width                   = 0;\r
-                       css_width.predef(0);\r
-               }\r
-\r
-               table_column(int min_w, int max_w)\r
-               {\r
-                       left                    = 0;\r
-                       right                   = 0;\r
-                       border_left             = 0;\r
-                       border_right    = 0;\r
-                       max_width               = max_w;\r
-                       min_width               = min_w;\r
-                       width                   = 0;\r
-                       css_width.predef(0);\r
-               }\r
-\r
-               table_column(const table_column& val)\r
-               {\r
-                       left                    = val.left;\r
-                       right                   = val.right;\r
-                       border_left             = val.border_left;\r
-                       border_right    = val.border_right;\r
-                       max_width               = val.max_width;\r
-                       min_width               = val.min_width;\r
-                       width                   = val.width;\r
-                       css_width               = val.css_width;\r
-               }\r
-       };\r
-\r
-       class table_column_accessor\r
-       {\r
-       public:\r
-               virtual int& get(table_column& col) = 0;\r
-       };\r
-\r
-       class table_column_accessor_max_width : public table_column_accessor\r
-       {\r
-       public:\r
-               virtual int& get(table_column& col);\r
-       };\r
-\r
-       class table_column_accessor_min_width : public table_column_accessor\r
-       {\r
-       public:\r
-               virtual int& get(table_column& col);\r
-       };\r
-\r
-       class table_column_accessor_width : public table_column_accessor\r
-       {\r
-       public:\r
-               virtual int& get(table_column& col);\r
-       };\r
-\r
-       struct table_cell\r
-       {\r
-               element::ptr    el;\r
-               int                             colspan;\r
-               int                             rowspan;\r
-               int                             min_width;\r
-               int                             min_height;\r
-               int                             max_width;\r
-               int                             max_height;\r
-               int                             width;\r
-               int                             height;\r
-               margins                 borders;\r
-\r
-               table_cell()\r
-               {\r
-                       min_width               = 0;\r
-                       min_height              = 0;\r
-                       max_width               = 0;\r
-                       max_height              = 0;\r
-                       width                   = 0;\r
-                       height                  = 0;\r
-                       colspan                 = 1;\r
-                       rowspan                 = 1;\r
-                       el                              = nullptr;\r
-               }\r
-\r
-               table_cell(const table_cell& val)\r
-               {\r
-                       el                              = val.el;\r
-                       colspan                 = val.colspan;\r
-                       rowspan                 = val.rowspan;\r
-                       width                   = val.width;\r
-                       height                  = val.height;\r
-                       min_width               = val.min_width;\r
-                       min_height              = val.min_height;\r
-                       max_width               = val.max_width;\r
-                       max_height              = val.max_height;\r
-                       borders                 = val.borders;\r
-               }\r
-\r
-               table_cell(const table_cell&& val)\r
-               {\r
-                       el = std::move(val.el);\r
-                       colspan = val.colspan;\r
-                       rowspan = val.rowspan;\r
-                       width = val.width;\r
-                       height = val.height;\r
-                       min_width = val.min_width;\r
-                       min_height = val.min_height;\r
-                       max_width = val.max_width;\r
-                       max_height = val.max_height;\r
-                       borders = val.borders;\r
-               }\r
-       };\r
-\r
-       class table_grid\r
-       {\r
-       public:\r
-               typedef std::vector< std::vector<table_cell> >  rows;\r
-       private:\r
-               int                                             m_rows_count;\r
-               int                                             m_cols_count;\r
-               rows                                    m_cells;\r
-               table_column::vector    m_columns;\r
-               table_row::vector               m_rows;\r
-       public:\r
-\r
-               table_grid()\r
-               {\r
-                       m_rows_count    = 0;\r
-                       m_cols_count    = 0;\r
-               }\r
-\r
-               void                    clear();\r
-               void                    begin_row(element::ptr& row);\r
-               void                    add_cell(element::ptr& el);\r
-               bool                    is_rowspanned(int r, int c);\r
-               void                    finish();\r
-               table_cell*             cell(int t_col, int t_row);\r
-               table_column&   column(int c)   { return m_columns[c];  }\r
-               table_row&              row(int r)              { return m_rows[r];             }\r
-\r
-               int                             rows_count()    { return m_rows_count;  }\r
-               int                             cols_count()    { return m_cols_count;  }\r
-\r
-               void                    distribute_max_width(int width, int start, int end);\r
-               void                    distribute_min_width(int width, int start, int end);\r
-               void                    distribute_width(int width, int start, int end);\r
-               void                    distribute_width(int width, int start, int end, table_column_accessor* acc);\r
-               int                             calc_table_width(int block_width, bool is_auto, int& min_table_width, int& max_table_width);\r
-               void                    calc_horizontal_positions(margins& table_borders, border_collapse bc, int bdr_space_x);\r
-               void                    calc_vertical_positions(margins& table_borders, border_collapse bc, int bdr_space_y);\r
-               void                    calc_rows_height(int blockHeight, int borderSpacingY);\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_TABLE_H
+#define LH_TABLE_H
+
+namespace litehtml
+{
+       struct table_row
+       {
+               typedef std::vector<table_row>  vector;
+
+               int                             height;
+               int                             border_top;
+               int                             border_bottom;
+               element::ptr    el_row;
+               int                             top;
+               int                             bottom;
+               css_length              css_height;
+               int                             min_height;
+
+               table_row()
+               {
+                       min_height              = 0;
+                       top                             = 0;
+                       bottom                  = 0;
+                       border_bottom   = 0;
+                       border_top              = 0;
+                       height                  = 0;
+                       el_row                  = nullptr;
+                       css_height.predef(0);
+               }
+
+               table_row(int h, element::ptr& row)
+               {
+                       min_height              = 0;
+                       height                  = h;
+                       el_row                  = row;
+                       border_bottom   = 0;
+                       border_top              = 0;
+                       top                             = 0;
+                       bottom                  = 0;
+                       if (row)
+                       {
+                               css_height = row->get_css_height();
+                       }
+               }
+
+               table_row(const table_row& val)
+               {
+                       min_height = val.min_height;
+                       top = val.top;
+                       bottom = val.bottom;
+                       border_bottom = val.border_bottom;
+                       border_top = val.border_top;
+                       height = val.height;
+                       css_height = val.css_height;
+                       el_row = val.el_row;
+               }
+
+               table_row(table_row&& val)
+               {
+                       min_height = val.min_height;
+                       top = val.top;
+                       bottom = val.bottom;
+                       border_bottom = val.border_bottom;
+                       border_top = val.border_top;
+                       height = val.height;
+                       css_height = val.css_height;
+                       el_row = std::move(val.el_row);
+               }
+       };
+
+       struct table_column
+       {
+               typedef std::vector<table_column>       vector;
+               
+               int                     min_width;
+               int                     max_width;
+               int                     width;
+               css_length      css_width;
+               int                     border_left;
+               int                     border_right;
+               int                     left;
+               int                     right;
+
+               table_column()
+               {
+                       left                    = 0;
+                       right                   = 0;
+                       border_left             = 0;
+                       border_right    = 0;
+                       min_width               = 0;
+                       max_width               = 0;
+                       width                   = 0;
+                       css_width.predef(0);
+               }
+
+               table_column(int min_w, int max_w)
+               {
+                       left                    = 0;
+                       right                   = 0;
+                       border_left             = 0;
+                       border_right    = 0;
+                       max_width               = max_w;
+                       min_width               = min_w;
+                       width                   = 0;
+                       css_width.predef(0);
+               }
+
+               table_column(const table_column& val)
+               {
+                       left                    = val.left;
+                       right                   = val.right;
+                       border_left             = val.border_left;
+                       border_right    = val.border_right;
+                       max_width               = val.max_width;
+                       min_width               = val.min_width;
+                       width                   = val.width;
+                       css_width               = val.css_width;
+               }
+       };
+
+       class table_column_accessor
+       {
+       public:
+               virtual int& get(table_column& col) = 0;
+       };
+
+       class table_column_accessor_max_width : public table_column_accessor
+       {
+       public:
+               virtual int& get(table_column& col);
+       };
+
+       class table_column_accessor_min_width : public table_column_accessor
+       {
+       public:
+               virtual int& get(table_column& col);
+       };
+
+       class table_column_accessor_width : public table_column_accessor
+       {
+       public:
+               virtual int& get(table_column& col);
+       };
+
+       struct table_cell
+       {
+               element::ptr    el;
+               int                             colspan;
+               int                             rowspan;
+               int                             min_width;
+               int                             min_height;
+               int                             max_width;
+               int                             max_height;
+               int                             width;
+               int                             height;
+               margins                 borders;
+
+               table_cell()
+               {
+                       min_width               = 0;
+                       min_height              = 0;
+                       max_width               = 0;
+                       max_height              = 0;
+                       width                   = 0;
+                       height                  = 0;
+                       colspan                 = 1;
+                       rowspan                 = 1;
+                       el                              = nullptr;
+               }
+
+               table_cell(const table_cell& val)
+               {
+                       el                              = val.el;
+                       colspan                 = val.colspan;
+                       rowspan                 = val.rowspan;
+                       width                   = val.width;
+                       height                  = val.height;
+                       min_width               = val.min_width;
+                       min_height              = val.min_height;
+                       max_width               = val.max_width;
+                       max_height              = val.max_height;
+                       borders                 = val.borders;
+               }
+
+               table_cell(const table_cell&& val)
+               {
+                       el = std::move(val.el);
+                       colspan = val.colspan;
+                       rowspan = val.rowspan;
+                       width = val.width;
+                       height = val.height;
+                       min_width = val.min_width;
+                       min_height = val.min_height;
+                       max_width = val.max_width;
+                       max_height = val.max_height;
+                       borders = val.borders;
+               }
+       };
+
+       class table_grid
+       {
+       public:
+               typedef std::vector< std::vector<table_cell> >  rows;
+       private:
+               int                                             m_rows_count;
+               int                                             m_cols_count;
+               rows                                    m_cells;
+               table_column::vector    m_columns;
+               table_row::vector               m_rows;
+       public:
+
+               table_grid()
+               {
+                       m_rows_count    = 0;
+                       m_cols_count    = 0;
+               }
+
+               void                    clear();
+               void                    begin_row(element::ptr& row);
+               void                    add_cell(element::ptr& el);
+               bool                    is_rowspanned(int r, int c);
+               void                    finish();
+               table_cell*             cell(int t_col, int t_row);
+               table_column&   column(int c)   { return m_columns[c];  }
+               table_row&              row(int r)              { return m_rows[r];             }
+
+               int                             rows_count()    { return m_rows_count;  }
+               int                             cols_count()    { return m_cols_count;  }
+
+               void                    distribute_max_width(int width, int start, int end);
+               void                    distribute_min_width(int width, int start, int end);
+               void                    distribute_width(int width, int start, int end);
+               void                    distribute_width(int width, int start, int end, table_column_accessor* acc);
+               int                             calc_table_width(int block_width, bool is_auto, int& min_table_width, int& max_table_width);
+               void                    calc_horizontal_positions(margins& table_borders, border_collapse bc, int bdr_space_x);
+               void                    calc_vertical_positions(margins& table_borders, border_collapse bc, int bdr_space_y);
+               void                    calc_rows_height(int blockHeight, int borderSpacingY);
+       };
+}
+
+#endif  // LH_TABLE_H
index bb292a4623f781d1d9dc348e75e520365c3d06d6..7d3b6dc39576f447b173ddafc097c26184d141d1 100644 (file)
-#pragma once\r
-\r
-#include <stdlib.h>\r
-#include <memory>\r
-#include <map>\r
-#include <vector>\r
-\r
-namespace litehtml\r
-{\r
-       class document;\r
-       class element;\r
-\r
-       typedef std::map<litehtml::tstring, litehtml::tstring>                  string_map;\r
-       typedef std::vector< std::shared_ptr<litehtml::element> >               elements_vector;\r
-       typedef std::vector<int>                                                                                int_vector;\r
-       typedef std::vector<litehtml::tstring>                                                  string_vector;\r
-\r
-       const unsigned int font_decoration_none                 = 0x00;\r
-       const unsigned int font_decoration_underline    = 0x01;\r
-       const unsigned int font_decoration_linethrough  = 0x02;\r
-       const unsigned int font_decoration_overline             = 0x04;\r
-\r
-       typedef unsigned char   byte;\r
-       typedef unsigned int    ucode_t;\r
-\r
-       struct margins\r
-       {\r
-               int     left;\r
-               int     right;\r
-               int top;\r
-               int bottom;\r
-\r
-               margins()\r
-               {\r
-                       left = right = top = bottom = 0;\r
-               }\r
-\r
-               int width()             const   { return left + right; } \r
-               int height()    const   { return top + bottom; } \r
-       };\r
-\r
-       struct size\r
-       {\r
-               int             width;\r
-               int             height;\r
-\r
-               size()\r
-               {\r
-                       width   = 0;\r
-                       height  = 0;\r
-               }\r
-       };\r
-\r
-       struct position\r
-       {\r
-               typedef std::vector<position>   vector;\r
-\r
-               int     x;\r
-               int     y;\r
-               int     width;\r
-               int     height;\r
-\r
-               position()\r
-               {\r
-                       x = y = width = height = 0;\r
-               }\r
-\r
-               position(int x, int y, int width, int height)\r
-               {\r
-                       this->x                 = x;\r
-                       this->y                 = y;\r
-                       this->width             = width;\r
-                       this->height    = height;\r
-               }\r
-\r
-               int right()             const           { return x + width;             }\r
-               int bottom()    const           { return y + height;    }\r
-               int left()              const           { return x;                             }\r
-               int top()               const           { return y;                             }\r
-\r
-               void operator+=(const margins& mg)\r
-               {\r
-                       x               -= mg.left;\r
-                       y               -= mg.top;\r
-                       width   += mg.left + mg.right;\r
-                       height  += mg.top + mg.bottom;\r
-               }\r
-               void operator-=(const margins& mg)\r
-               {\r
-                       x               += mg.left;\r
-                       y               += mg.top;\r
-                       width   -= mg.left + mg.right;\r
-                       height  -= mg.top + mg.bottom;\r
-               }\r
-\r
-               void clear()\r
-               {\r
-                       x = y = width = height = 0;\r
-               }\r
-\r
-               void operator=(const size& sz)\r
-               {\r
-                       width   = sz.width;\r
-                       height  = sz.height;\r
-               }\r
-\r
-               void move_to(int x, int y)\r
-               {\r
-                       this->x = x;\r
-                       this->y = y;\r
-               }\r
-\r
-               bool does_intersect(const position* val) const\r
-               {\r
-                       if(!val) return true;\r
-\r
-                       return (\r
-                               left()                  <= val->right()         && \r
-                               right()                 >= val->left()          && \r
-                               bottom()                >= val->top()           && \r
-                               top()                   <= val->bottom()        )\r
-                               || (\r
-                               val->left()             <= right()                      && \r
-                               val->right()    >= left()                       && \r
-                               val->bottom()   >= top()                        && \r
-                               val->top()              <= bottom()                     );\r
-               }\r
-\r
-               bool empty() const\r
-               {\r
-                       if(!width && !height)\r
-                       {\r
-                               return true;\r
-                       }\r
-                       return false;\r
-               }\r
-\r
-               bool is_point_inside(int x, int y) const\r
-               {\r
-                       if(x >= left() && x <= right() && y >= top() && y <= bottom())\r
-                       {\r
-                               return true;\r
-                       }\r
-                       return false;\r
-               }\r
-       };\r
-\r
-       struct font_metrics\r
-       {\r
-               int             height;\r
-               int             ascent;\r
-               int             descent;\r
-               int             x_height;\r
-               bool    draw_spaces;\r
-\r
-               font_metrics()\r
-               {\r
-                       height                  = 0;\r
-                       ascent                  = 0;\r
-                       descent                 = 0;\r
-                       x_height                = 0;\r
-                       draw_spaces             = true;\r
-               }\r
-               int base_line() { return descent; }\r
-       };\r
-\r
-       struct font_item\r
-       {\r
-               uint_ptr                font;\r
-               font_metrics    metrics;\r
-       };\r
-\r
-       typedef std::map<tstring, font_item>    fonts_map;\r
-\r
-       enum draw_flag\r
-       {\r
-               draw_root,\r
-               draw_block,\r
-               draw_floats,\r
-               draw_inlines,\r
-               draw_positioned,\r
-       };\r
-\r
-#define  style_display_strings         _t("none;block;inline;inline-block;inline-table;list-item;table;table-caption;table-cell;table-column;table-column-group;table-footer-group;table-header-group;table-row;table-row-group")\r
-\r
-       enum style_display\r
-       {\r
-               display_none,\r
-               display_block,\r
-               display_inline,\r
-               display_inline_block,\r
-               display_inline_table,\r
-               display_list_item,\r
-               display_table,\r
-               display_table_caption,\r
-               display_table_cell,\r
-               display_table_column,\r
-               display_table_column_group,\r
-               display_table_footer_group,\r
-               display_table_header_group,\r
-               display_table_row,\r
-               display_table_row_group,\r
-               display_inline_text,\r
-       };\r
-\r
-       enum style_border\r
-       {\r
-               borderNope,\r
-               borderNone,\r
-               borderHidden,\r
-               borderDotted,\r
-               borderDashed,\r
-               borderSolid,\r
-               borderDouble\r
-       };\r
-\r
-#define  font_size_strings             _t("xx-small;x-small;small;medium;large;x-large;xx-large;smaller;larger")\r
-\r
-       enum font_size\r
-       {\r
-               fontSize_xx_small,\r
-               fontSize_x_small,\r
-               fontSize_small,\r
-               fontSize_medium,\r
-               fontSize_large,\r
-               fontSize_x_large,\r
-               fontSize_xx_large,\r
-               fontSize_smaller,\r
-               fontSize_larger,\r
-       };\r
-\r
-#define  font_style_strings            _t("normal;italic")\r
-\r
-       enum font_style\r
-       {\r
-               fontStyleNormal,\r
-               fontStyleItalic\r
-       };\r
-\r
-#define  font_variant_strings          _t("normal;small-caps")\r
-\r
-       enum font_variant\r
-       {\r
-               font_variant_normal,\r
-               font_variant_italic\r
-       };\r
-\r
-#define  font_weight_strings   _t("normal;bold;bolder;lighter100;200;300;400;500;600;700")\r
-\r
-       enum font_weight\r
-       {\r
-               fontWeightNormal,\r
-               fontWeightBold,\r
-               fontWeightBolder,\r
-               fontWeightLighter,\r
-               fontWeight100,\r
-               fontWeight200,\r
-               fontWeight300,\r
-               fontWeight400,\r
-               fontWeight500,\r
-               fontWeight600,\r
-               fontWeight700\r
-       };\r
-\r
-#define  list_style_type_strings       _t("none;circle;disc;square;armenian;cjk-ideographic;decimal;decimal-leading-zero;georgian;hebrew;hiragana;hiragana-iroha;katakana;katakana-iroha;lower-alpha;lower-greek;lower-latin;lower-roman;upper-alpha;upper-latin;upper-roman")\r
-\r
-       enum list_style_type\r
-       {\r
-               list_style_type_none,\r
-               list_style_type_circle,\r
-               list_style_type_disc,\r
-               list_style_type_square,\r
-               list_style_type_armenian,\r
-               list_style_type_cjk_ideographic,\r
-               list_style_type_decimal,\r
-               list_style_type_decimal_leading_zero,\r
-               list_style_type_georgian,\r
-               list_style_type_hebrew,\r
-               list_style_type_hiragana,\r
-               list_style_type_hiragana_iroha,\r
-               list_style_type_katakana,\r
-               list_style_type_katakana_iroha,\r
-               list_style_type_lower_alpha,\r
-               list_style_type_lower_greek,\r
-               list_style_type_lower_latin,\r
-               list_style_type_lower_roman,\r
-               list_style_type_upper_alpha,\r
-               list_style_type_upper_latin,\r
-               list_style_type_upper_roman,\r
-       };\r
-\r
-#define  list_style_position_strings   _t("inside;outside")\r
-\r
-       enum list_style_position\r
-       {\r
-               list_style_position_inside,\r
-               list_style_position_outside\r
-       };\r
-\r
-#define  vertical_align_strings        _t("baseline;sub;super;top;text-top;middle;bottom;text-bottom")\r
-\r
-       enum vertical_align\r
-       {\r
-               va_baseline,\r
-               va_sub,\r
-               va_super,\r
-               va_top,\r
-               va_text_top,\r
-               va_middle,\r
-               va_bottom,\r
-               va_text_bottom\r
-       };\r
-\r
-#define  border_width_strings  _t("thin;medium;thick")\r
-\r
-       enum border_width\r
-       {\r
-               border_width_thin,\r
-               border_width_medium,\r
-               border_width_thick\r
-       };\r
-\r
-#define  border_style_strings  _t("none;hidden;dotted;dashed;solid;double;groove;ridge;inset;outset")\r
-\r
-       enum border_style\r
-       {\r
-               border_style_none,\r
-               border_style_hidden,\r
-               border_style_dotted,\r
-               border_style_dashed,\r
-               border_style_solid,\r
-               border_style_double,\r
-               border_style_groove,\r
-               border_style_ridge,\r
-               border_style_inset,\r
-               border_style_outset\r
-       };\r
-\r
-#define  element_float_strings _t("none;left;right")\r
-\r
-       enum element_float\r
-       {\r
-               float_none,\r
-               float_left,\r
-               float_right\r
-       };\r
-\r
-#define  element_clear_strings _t("none;left;right;both")\r
-\r
-       enum element_clear\r
-       {\r
-               clear_none,\r
-               clear_left,\r
-               clear_right,\r
-               clear_both\r
-       };\r
-\r
-#define  css_units_strings     _t("none;%;in;cm;mm;em;ex;pt;pc;px;dpi;dpcm;vw;vh;vmin;vmax")\r
-\r
-       enum css_units\r
-       {\r
-               css_units_none,\r
-               css_units_percentage,\r
-               css_units_in,\r
-               css_units_cm,\r
-               css_units_mm,\r
-               css_units_em,\r
-               css_units_ex,\r
-               css_units_pt,\r
-               css_units_pc,\r
-               css_units_px,\r
-               css_units_dpi,\r
-               css_units_dpcm,\r
-               css_units_vw,\r
-               css_units_vh,\r
-               css_units_vmin,\r
-               css_units_vmax,\r
-       };\r
-\r
-#define  background_attachment_strings _t("scroll;fixed")\r
-\r
-       enum background_attachment\r
-       {\r
-               background_attachment_scroll,\r
-               background_attachment_fixed\r
-       };\r
-\r
-#define  background_repeat_strings     _t("repeat;repeat-x;repeat-y;no-repeat")\r
-\r
-       enum background_repeat\r
-       {\r
-               background_repeat_repeat,\r
-               background_repeat_repeat_x,\r
-               background_repeat_repeat_y,\r
-               background_repeat_no_repeat\r
-       };\r
-\r
-#define  background_box_strings        _t("border-box;padding-box;content-box")\r
-\r
-       enum background_box\r
-       {\r
-               background_box_border,\r
-               background_box_padding,\r
-               background_box_content\r
-       };\r
-\r
-#define element_position_strings       _t("static;relative;absolute;fixed")\r
-\r
-       enum element_position\r
-       {\r
-               element_position_static,\r
-               element_position_relative,\r
-               element_position_absolute,\r
-               element_position_fixed,\r
-       };\r
-\r
-#define text_align_strings             _t("left;right;center;justify")\r
-\r
-       enum text_align\r
-       {\r
-               text_align_left,\r
-               text_align_right,\r
-               text_align_center,\r
-               text_align_justify\r
-       };\r
-\r
-#define text_transform_strings         _t("none;capitalize;uppercase;lowercase")\r
-\r
-       enum text_transform\r
-       {\r
-               text_transform_none,\r
-               text_transform_capitalize,\r
-               text_transform_uppercase,\r
-               text_transform_lowercase\r
-       };\r
-\r
-#define white_space_strings            _t("normal;nowrap;pre;pre-line;pre-wrap")\r
-\r
-       enum white_space\r
-       {\r
-               white_space_normal,\r
-               white_space_nowrap,\r
-               white_space_pre,\r
-               white_space_pre_line,\r
-               white_space_pre_wrap\r
-       };\r
-\r
-#define overflow_strings               _t("visible;hidden;scroll;auto;no-display;no-content")\r
-\r
-       enum overflow\r
-       {\r
-               overflow_visible,\r
-               overflow_hidden,\r
-               overflow_scroll,\r
-               overflow_auto,\r
-               overflow_no_display,\r
-               overflow_no_content\r
-       };\r
-\r
-#define background_size_strings                _t("auto;cover;contain")\r
-\r
-       enum background_size\r
-       {\r
-               background_size_auto,\r
-               background_size_cover,\r
-               background_size_contain,\r
-       };\r
-\r
-#define visibility_strings                     _t("visible;hidden;collapse")\r
-\r
-       enum visibility\r
-       {\r
-               visibility_visible,\r
-               visibility_hidden,\r
-               visibility_collapse,\r
-       };\r
-\r
-#define border_collapse_strings                _t("collapse;separate")\r
-\r
-       enum border_collapse\r
-       {\r
-               border_collapse_collapse,\r
-               border_collapse_separate,\r
-       };\r
-\r
-\r
-#define pseudo_class_strings           _t("only-child;only-of-type;first-child;first-of-type;last-child;last-of-type;nth-child;nth-of-type;nth-last-child;nth-last-of-type;not;lang")\r
-\r
-       enum pseudo_class\r
-       {\r
-               pseudo_class_only_child,\r
-               pseudo_class_only_of_type,\r
-               pseudo_class_first_child,\r
-               pseudo_class_first_of_type,\r
-               pseudo_class_last_child,\r
-               pseudo_class_last_of_type,\r
-               pseudo_class_nth_child,\r
-               pseudo_class_nth_of_type,\r
-               pseudo_class_nth_last_child,\r
-               pseudo_class_nth_last_of_type,\r
-               pseudo_class_not,\r
-               pseudo_class_lang,\r
-       };\r
-\r
-#define content_property_string                _t("none;normal;open-quote;close-quote;no-open-quote;no-close-quote")\r
-\r
-       enum content_property\r
-       {\r
-               content_property_none,\r
-               content_property_normal,\r
-               content_property_open_quote,\r
-               content_property_close_quote,\r
-               content_property_no_open_quote,\r
-               content_property_no_close_quote,\r
-       };\r
-\r
-\r
-       struct floated_box\r
-       {\r
-               typedef std::vector<floated_box>        vector;\r
-\r
-               position                pos;\r
-               element_float   float_side;\r
-               element_clear   clear_floats;\r
-               std::shared_ptr<element>        el;\r
-\r
-               floated_box() = default;\r
-               floated_box(const floated_box& val)\r
-               {\r
-                       pos = val.pos;\r
-                       float_side = val.float_side;\r
-                       clear_floats = val.clear_floats;\r
-                       el = val.el;\r
-               }\r
-               floated_box& operator=(const floated_box& val)\r
-               {\r
-                       pos = val.pos;\r
-                       float_side = val.float_side;\r
-                       clear_floats = val.clear_floats;\r
-                       el = val.el;\r
-                       return *this;\r
-               }\r
-               floated_box(floated_box&& val)\r
-               {\r
-                       pos = val.pos;\r
-                       float_side = val.float_side;\r
-                       clear_floats = val.clear_floats;\r
-                       el = std::move(val.el);\r
-               }\r
-               void operator=(floated_box&& val)\r
-               {\r
-                       pos = val.pos;\r
-                       float_side = val.float_side;\r
-                       clear_floats = val.clear_floats;\r
-                       el = std::move(val.el);\r
-               }\r
-       };\r
-\r
-       struct int_int_cache\r
-       {\r
-               int             hash;\r
-               int             val;\r
-               bool    is_valid;\r
-               bool    is_default;\r
-\r
-               int_int_cache()\r
-               {\r
-                       hash            = 0;\r
-                       val                     = 0;\r
-                       is_valid        = false;\r
-                       is_default      = false;\r
-               }\r
-               void invalidate()\r
-               {\r
-                       is_valid        = false;\r
-                       is_default      = false;\r
-               }\r
-               void set_value(int vHash, int vVal)\r
-               {\r
-                       hash            = vHash;\r
-                       val                     = vVal;\r
-                       is_valid        = true;\r
-               }\r
-       };\r
-\r
-       enum select_result\r
-       {\r
-               select_no_match                         = 0x00,\r
-               select_match                            = 0x01,\r
-               select_match_pseudo_class       = 0x02,\r
-               select_match_with_before        = 0x10,\r
-               select_match_with_after         = 0x20,\r
-       };\r
-\r
-       template<class T>\r
-       class def_value\r
-       {\r
-               T               m_val;\r
-               bool    m_is_default;\r
-       public:\r
-               def_value(T def_val)\r
-               {\r
-                       m_is_default    = true;\r
-                       m_val                   = def_val;\r
-               }\r
-               void reset(T def_val)\r
-               {\r
-                       m_is_default    = true;\r
-                       m_val                   = def_val;\r
-               }\r
-               bool is_default()\r
-               {\r
-                       return m_is_default;\r
-               }\r
-               T operator=(T new_val)\r
-               {\r
-                       m_val                   = new_val;\r
-                       m_is_default    = false;\r
-                       return m_val;\r
-               }\r
-               operator T()\r
-               {\r
-                       return m_val;\r
-               }\r
-       };\r
-\r
-\r
-#define media_orientation_strings              _t("portrait;landscape")\r
-\r
-       enum media_orientation\r
-       {\r
-               media_orientation_portrait,\r
-               media_orientation_landscape,\r
-       };\r
-\r
-#define media_feature_strings          _t("none;width;min-width;max-width;height;min-height;max-height;device-width;min-device-width;max-device-width;device-height;min-device-height;max-device-height;orientation;aspect-ratio;min-aspect-ratio;max-aspect-ratio;device-aspect-ratio;min-device-aspect-ratio;max-device-aspect-ratio;color;min-color;max-color;color-index;min-color-index;max-color-index;monochrome;min-monochrome;max-monochrome;resolution;min-resolution;max-resolution")\r
-\r
-       enum media_feature\r
-       {\r
-               media_feature_none,\r
-\r
-               media_feature_width,\r
-               media_feature_min_width,\r
-               media_feature_max_width,\r
-\r
-               media_feature_height,\r
-               media_feature_min_height,\r
-               media_feature_max_height,\r
-\r
-               media_feature_device_width,\r
-               media_feature_min_device_width,\r
-               media_feature_max_device_width,\r
-\r
-               media_feature_device_height,\r
-               media_feature_min_device_height,\r
-               media_feature_max_device_height,\r
-\r
-               media_feature_orientation,\r
-\r
-               media_feature_aspect_ratio,\r
-               media_feature_min_aspect_ratio,\r
-               media_feature_max_aspect_ratio,\r
-\r
-               media_feature_device_aspect_ratio,\r
-               media_feature_min_device_aspect_ratio,\r
-               media_feature_max_device_aspect_ratio,\r
-\r
-               media_feature_color,\r
-               media_feature_min_color,\r
-               media_feature_max_color,\r
-\r
-               media_feature_color_index,\r
-               media_feature_min_color_index,\r
-               media_feature_max_color_index,\r
-\r
-               media_feature_monochrome,\r
-               media_feature_min_monochrome,\r
-               media_feature_max_monochrome,\r
-\r
-               media_feature_resolution,\r
-               media_feature_min_resolution,\r
-               media_feature_max_resolution,\r
-       };\r
-\r
-#define box_sizing_strings             _t("content-box;border-box")\r
-\r
-       enum box_sizing\r
-       {\r
-               box_sizing_content_box,\r
-               box_sizing_border_box,\r
-       };\r
-\r
-\r
-#define media_type_strings             _t("none;all;screen;print;braille;embossed;handheld;projection;speech;tty;tv")\r
-\r
-       enum media_type\r
-       {\r
-               media_type_none,\r
-               media_type_all,\r
-               media_type_screen,\r
-               media_type_print,\r
-               media_type_braille,\r
-               media_type_embossed,\r
-               media_type_handheld,\r
-               media_type_projection,\r
-               media_type_speech,\r
-               media_type_tty,\r
-               media_type_tv,\r
-       };\r
-\r
-       struct media_features\r
-       {\r
-               media_type      type;\r
-               int                     width;                  // (pixels) For continuous media, this is the width of the viewport including the size of a rendered scroll bar (if any). For paged media, this is the width of the page box.\r
-               int                     height;                 // (pixels) The height of the targeted display area of the output device. For continuous media, this is the height of the viewport including the size of a rendered scroll bar (if any). For paged media, this is the height of the page box.\r
-               int                     device_width;   // (pixels) The width of the rendering surface of the output device. For continuous media, this is the width of the screen. For paged media, this is the width of the page sheet size.\r
-               int                     device_height;  // (pixels) The height of the rendering surface of the output device. For continuous media, this is the height of the screen. For paged media, this is the height of the page sheet size.\r
-               int                     color;                  // The number of bits per color component of the output device. If the device is not a color device, the value is zero.\r
-               int                     color_index;    // The number of entries in the color lookup table of the output device. If the device does not use a color lookup table, the value is zero.\r
-               int                     monochrome;             // The number of bits per pixel in a monochrome frame buffer. If the device is not a monochrome device, the output device value will be 0.\r
-               int                     resolution;             // The resolution of the output device (in DPI)\r
-       };\r
-\r
-       enum render_type\r
-       {\r
-               render_all,\r
-               render_no_fixed,\r
-               render_fixed_only,\r
-       };\r
-\r
-       // List of the Void Elements (can't have any contents)\r
-       const litehtml::tchar_t* const void_elements = _t("area;base;br;col;command;embed;hr;img;input;keygen;link;meta;param;source;track;wbr");\r
-}\r
+#ifndef LH_TYPES_H
+#define LH_TYPES_H
+
+#include <stdlib.h>
+#include <memory>
+#include <map>
+#include <vector>
+
+namespace litehtml
+{
+       class document;
+       class element;
+
+       typedef std::map<litehtml::tstring, litehtml::tstring>                  string_map;
+       typedef std::vector< std::shared_ptr<litehtml::element> >               elements_vector;
+       typedef std::vector<int>                                                                                int_vector;
+       typedef std::vector<litehtml::tstring>                                                  string_vector;
+
+       const unsigned int font_decoration_none                 = 0x00;
+       const unsigned int font_decoration_underline    = 0x01;
+       const unsigned int font_decoration_linethrough  = 0x02;
+       const unsigned int font_decoration_overline             = 0x04;
+
+       typedef unsigned char   byte;
+       typedef unsigned int    ucode_t;
+
+       struct margins
+       {
+               int     left;
+               int     right;
+               int top;
+               int bottom;
+
+               margins()
+               {
+                       left = right = top = bottom = 0;
+               }
+
+               int width()             const   { return left + right; } 
+               int height()    const   { return top + bottom; } 
+       };
+
+       struct size
+       {
+               int             width;
+               int             height;
+
+               size()
+               {
+                       width   = 0;
+                       height  = 0;
+               }
+       };
+
+       struct position
+       {
+               typedef std::vector<position>   vector;
+
+               int     x;
+               int     y;
+               int     width;
+               int     height;
+
+               position()
+               {
+                       x = y = width = height = 0;
+               }
+
+               position(int x, int y, int width, int height)
+               {
+                       this->x                 = x;
+                       this->y                 = y;
+                       this->width             = width;
+                       this->height    = height;
+               }
+
+               int right()             const           { return x + width;             }
+               int bottom()    const           { return y + height;    }
+               int left()              const           { return x;                             }
+               int top()               const           { return y;                             }
+
+               void operator+=(const margins& mg)
+               {
+                       x               -= mg.left;
+                       y               -= mg.top;
+                       width   += mg.left + mg.right;
+                       height  += mg.top + mg.bottom;
+               }
+               void operator-=(const margins& mg)
+               {
+                       x               += mg.left;
+                       y               += mg.top;
+                       width   -= mg.left + mg.right;
+                       height  -= mg.top + mg.bottom;
+               }
+
+               void clear()
+               {
+                       x = y = width = height = 0;
+               }
+
+               void operator=(const size& sz)
+               {
+                       width   = sz.width;
+                       height  = sz.height;
+               }
+
+               void move_to(int x, int y)
+               {
+                       this->x = x;
+                       this->y = y;
+               }
+
+               bool does_intersect(const position* val) const
+               {
+                       if(!val) return true;
+
+                       return (
+                               left()                  <= val->right()         && 
+                               right()                 >= val->left()          && 
+                               bottom()                >= val->top()           && 
+                               top()                   <= val->bottom()        )
+                               || (
+                               val->left()             <= right()                      && 
+                               val->right()    >= left()                       && 
+                               val->bottom()   >= top()                        && 
+                               val->top()              <= bottom()                     );
+               }
+
+               bool empty() const
+               {
+                       if(!width && !height)
+                       {
+                               return true;
+                       }
+                       return false;
+               }
+
+               bool is_point_inside(int x, int y) const
+               {
+                       if(x >= left() && x <= right() && y >= top() && y <= bottom())
+                       {
+                               return true;
+                       }
+                       return false;
+               }
+       };
+
+       struct font_metrics
+       {
+               int             height;
+               int             ascent;
+               int             descent;
+               int             x_height;
+               bool    draw_spaces;
+
+               font_metrics()
+               {
+                       height                  = 0;
+                       ascent                  = 0;
+                       descent                 = 0;
+                       x_height                = 0;
+                       draw_spaces             = true;
+               }
+               int base_line() { return descent; }
+       };
+
+       struct font_item
+       {
+               uint_ptr                font;
+               font_metrics    metrics;
+       };
+
+       typedef std::map<tstring, font_item>    fonts_map;
+
+       enum draw_flag
+       {
+               draw_root,
+               draw_block,
+               draw_floats,
+               draw_inlines,
+               draw_positioned,
+       };
+
+#define  style_display_strings         _t("none;block;inline;inline-block;inline-table;list-item;table;table-caption;table-cell;table-column;table-column-group;table-footer-group;table-header-group;table-row;table-row-group")
+
+       enum style_display
+       {
+               display_none,
+               display_block,
+               display_inline,
+               display_inline_block,
+               display_inline_table,
+               display_list_item,
+               display_table,
+               display_table_caption,
+               display_table_cell,
+               display_table_column,
+               display_table_column_group,
+               display_table_footer_group,
+               display_table_header_group,
+               display_table_row,
+               display_table_row_group,
+               display_inline_text,
+       };
+
+       enum style_border
+       {
+               borderNope,
+               borderNone,
+               borderHidden,
+               borderDotted,
+               borderDashed,
+               borderSolid,
+               borderDouble
+       };
+
+#define  font_size_strings             _t("xx-small;x-small;small;medium;large;x-large;xx-large;smaller;larger")
+
+       enum font_size
+       {
+               fontSize_xx_small,
+               fontSize_x_small,
+               fontSize_small,
+               fontSize_medium,
+               fontSize_large,
+               fontSize_x_large,
+               fontSize_xx_large,
+               fontSize_smaller,
+               fontSize_larger,
+       };
+
+#define  font_style_strings            _t("normal;italic")
+
+       enum font_style
+       {
+               fontStyleNormal,
+               fontStyleItalic
+       };
+
+#define  font_variant_strings          _t("normal;small-caps")
+
+       enum font_variant
+       {
+               font_variant_normal,
+               font_variant_italic
+       };
+
+#define  font_weight_strings   _t("normal;bold;bolder;lighter100;200;300;400;500;600;700")
+
+       enum font_weight
+       {
+               fontWeightNormal,
+               fontWeightBold,
+               fontWeightBolder,
+               fontWeightLighter,
+               fontWeight100,
+               fontWeight200,
+               fontWeight300,
+               fontWeight400,
+               fontWeight500,
+               fontWeight600,
+               fontWeight700
+       };
+
+#define  list_style_type_strings       _t("none;circle;disc;square;armenian;cjk-ideographic;decimal;decimal-leading-zero;georgian;hebrew;hiragana;hiragana-iroha;katakana;katakana-iroha;lower-alpha;lower-greek;lower-latin;lower-roman;upper-alpha;upper-latin;upper-roman")
+
+       enum list_style_type
+       {
+               list_style_type_none,
+               list_style_type_circle,
+               list_style_type_disc,
+               list_style_type_square,
+               list_style_type_armenian,
+               list_style_type_cjk_ideographic,
+               list_style_type_decimal,
+               list_style_type_decimal_leading_zero,
+               list_style_type_georgian,
+               list_style_type_hebrew,
+               list_style_type_hiragana,
+               list_style_type_hiragana_iroha,
+               list_style_type_katakana,
+               list_style_type_katakana_iroha,
+               list_style_type_lower_alpha,
+               list_style_type_lower_greek,
+               list_style_type_lower_latin,
+               list_style_type_lower_roman,
+               list_style_type_upper_alpha,
+               list_style_type_upper_latin,
+               list_style_type_upper_roman,
+       };
+
+#define  list_style_position_strings   _t("inside;outside")
+
+       enum list_style_position
+       {
+               list_style_position_inside,
+               list_style_position_outside
+       };
+
+#define  vertical_align_strings        _t("baseline;sub;super;top;text-top;middle;bottom;text-bottom")
+
+       enum vertical_align
+       {
+               va_baseline,
+               va_sub,
+               va_super,
+               va_top,
+               va_text_top,
+               va_middle,
+               va_bottom,
+               va_text_bottom
+       };
+
+#define  border_width_strings  _t("thin;medium;thick")
+
+       enum border_width
+       {
+               border_width_thin,
+               border_width_medium,
+               border_width_thick
+       };
+
+#define  border_style_strings  _t("none;hidden;dotted;dashed;solid;double;groove;ridge;inset;outset")
+
+       enum border_style
+       {
+               border_style_none,
+               border_style_hidden,
+               border_style_dotted,
+               border_style_dashed,
+               border_style_solid,
+               border_style_double,
+               border_style_groove,
+               border_style_ridge,
+               border_style_inset,
+               border_style_outset
+       };
+
+#define  element_float_strings _t("none;left;right")
+
+       enum element_float
+       {
+               float_none,
+               float_left,
+               float_right
+       };
+
+#define  element_clear_strings _t("none;left;right;both")
+
+       enum element_clear
+       {
+               clear_none,
+               clear_left,
+               clear_right,
+               clear_both
+       };
+
+#define  css_units_strings     _t("none;%;in;cm;mm;em;ex;pt;pc;px;dpi;dpcm;vw;vh;vmin;vmax")
+
+       enum css_units
+       {
+               css_units_none,
+               css_units_percentage,
+               css_units_in,
+               css_units_cm,
+               css_units_mm,
+               css_units_em,
+               css_units_ex,
+               css_units_pt,
+               css_units_pc,
+               css_units_px,
+               css_units_dpi,
+               css_units_dpcm,
+               css_units_vw,
+               css_units_vh,
+               css_units_vmin,
+               css_units_vmax,
+       };
+
+#define  background_attachment_strings _t("scroll;fixed")
+
+       enum background_attachment
+       {
+               background_attachment_scroll,
+               background_attachment_fixed
+       };
+
+#define  background_repeat_strings     _t("repeat;repeat-x;repeat-y;no-repeat")
+
+       enum background_repeat
+       {
+               background_repeat_repeat,
+               background_repeat_repeat_x,
+               background_repeat_repeat_y,
+               background_repeat_no_repeat
+       };
+
+#define  background_box_strings        _t("border-box;padding-box;content-box")
+
+       enum background_box
+       {
+               background_box_border,
+               background_box_padding,
+               background_box_content
+       };
+
+#define element_position_strings       _t("static;relative;absolute;fixed")
+
+       enum element_position
+       {
+               element_position_static,
+               element_position_relative,
+               element_position_absolute,
+               element_position_fixed,
+       };
+
+#define text_align_strings             _t("left;right;center;justify")
+
+       enum text_align
+       {
+               text_align_left,
+               text_align_right,
+               text_align_center,
+               text_align_justify
+       };
+
+#define text_transform_strings         _t("none;capitalize;uppercase;lowercase")
+
+       enum text_transform
+       {
+               text_transform_none,
+               text_transform_capitalize,
+               text_transform_uppercase,
+               text_transform_lowercase
+       };
+
+#define white_space_strings            _t("normal;nowrap;pre;pre-line;pre-wrap")
+
+       enum white_space
+       {
+               white_space_normal,
+               white_space_nowrap,
+               white_space_pre,
+               white_space_pre_line,
+               white_space_pre_wrap
+       };
+
+#define overflow_strings               _t("visible;hidden;scroll;auto;no-display;no-content")
+
+       enum overflow
+       {
+               overflow_visible,
+               overflow_hidden,
+               overflow_scroll,
+               overflow_auto,
+               overflow_no_display,
+               overflow_no_content
+       };
+
+#define background_size_strings                _t("auto;cover;contain")
+
+       enum background_size
+       {
+               background_size_auto,
+               background_size_cover,
+               background_size_contain,
+       };
+
+#define visibility_strings                     _t("visible;hidden;collapse")
+
+       enum visibility
+       {
+               visibility_visible,
+               visibility_hidden,
+               visibility_collapse,
+       };
+
+#define border_collapse_strings                _t("collapse;separate")
+
+       enum border_collapse
+       {
+               border_collapse_collapse,
+               border_collapse_separate,
+       };
+
+
+#define pseudo_class_strings           _t("only-child;only-of-type;first-child;first-of-type;last-child;last-of-type;nth-child;nth-of-type;nth-last-child;nth-last-of-type;not;lang")
+
+       enum pseudo_class
+       {
+               pseudo_class_only_child,
+               pseudo_class_only_of_type,
+               pseudo_class_first_child,
+               pseudo_class_first_of_type,
+               pseudo_class_last_child,
+               pseudo_class_last_of_type,
+               pseudo_class_nth_child,
+               pseudo_class_nth_of_type,
+               pseudo_class_nth_last_child,
+               pseudo_class_nth_last_of_type,
+               pseudo_class_not,
+               pseudo_class_lang,
+       };
+
+#define content_property_string                _t("none;normal;open-quote;close-quote;no-open-quote;no-close-quote")
+
+       enum content_property
+       {
+               content_property_none,
+               content_property_normal,
+               content_property_open_quote,
+               content_property_close_quote,
+               content_property_no_open_quote,
+               content_property_no_close_quote,
+       };
+
+
+       struct floated_box
+       {
+               typedef std::vector<floated_box>        vector;
+
+               position                pos;
+               element_float   float_side;
+               element_clear   clear_floats;
+               std::shared_ptr<element>        el;
+
+               floated_box() = default;
+               floated_box(const floated_box& val)
+               {
+                       pos = val.pos;
+                       float_side = val.float_side;
+                       clear_floats = val.clear_floats;
+                       el = val.el;
+               }
+               floated_box& operator=(const floated_box& val)
+               {
+                       pos = val.pos;
+                       float_side = val.float_side;
+                       clear_floats = val.clear_floats;
+                       el = val.el;
+                       return *this;
+               }
+               floated_box(floated_box&& val)
+               {
+                       pos = val.pos;
+                       float_side = val.float_side;
+                       clear_floats = val.clear_floats;
+                       el = std::move(val.el);
+               }
+               void operator=(floated_box&& val)
+               {
+                       pos = val.pos;
+                       float_side = val.float_side;
+                       clear_floats = val.clear_floats;
+                       el = std::move(val.el);
+               }
+       };
+
+       struct int_int_cache
+       {
+               int             hash;
+               int             val;
+               bool    is_valid;
+               bool    is_default;
+
+               int_int_cache()
+               {
+                       hash            = 0;
+                       val                     = 0;
+                       is_valid        = false;
+                       is_default      = false;
+               }
+               void invalidate()
+               {
+                       is_valid        = false;
+                       is_default      = false;
+               }
+               void set_value(int vHash, int vVal)
+               {
+                       hash            = vHash;
+                       val                     = vVal;
+                       is_valid        = true;
+               }
+       };
+
+       enum select_result
+       {
+               select_no_match                         = 0x00,
+               select_match                            = 0x01,
+               select_match_pseudo_class       = 0x02,
+               select_match_with_before        = 0x10,
+               select_match_with_after         = 0x20,
+       };
+
+       template<class T>
+       class def_value
+       {
+               T               m_val;
+               bool    m_is_default;
+       public:
+               def_value(T def_val)
+               {
+                       m_is_default    = true;
+                       m_val                   = def_val;
+               }
+               void reset(T def_val)
+               {
+                       m_is_default    = true;
+                       m_val                   = def_val;
+               }
+               bool is_default()
+               {
+                       return m_is_default;
+               }
+               T operator=(T new_val)
+               {
+                       m_val                   = new_val;
+                       m_is_default    = false;
+                       return m_val;
+               }
+               operator T()
+               {
+                       return m_val;
+               }
+       };
+
+
+#define media_orientation_strings              _t("portrait;landscape")
+
+       enum media_orientation
+       {
+               media_orientation_portrait,
+               media_orientation_landscape,
+       };
+
+#define media_feature_strings          _t("none;width;min-width;max-width;height;min-height;max-height;device-width;min-device-width;max-device-width;device-height;min-device-height;max-device-height;orientation;aspect-ratio;min-aspect-ratio;max-aspect-ratio;device-aspect-ratio;min-device-aspect-ratio;max-device-aspect-ratio;color;min-color;max-color;color-index;min-color-index;max-color-index;monochrome;min-monochrome;max-monochrome;resolution;min-resolution;max-resolution")
+
+       enum media_feature
+       {
+               media_feature_none,
+
+               media_feature_width,
+               media_feature_min_width,
+               media_feature_max_width,
+
+               media_feature_height,
+               media_feature_min_height,
+               media_feature_max_height,
+
+               media_feature_device_width,
+               media_feature_min_device_width,
+               media_feature_max_device_width,
+
+               media_feature_device_height,
+               media_feature_min_device_height,
+               media_feature_max_device_height,
+
+               media_feature_orientation,
+
+               media_feature_aspect_ratio,
+               media_feature_min_aspect_ratio,
+               media_feature_max_aspect_ratio,
+
+               media_feature_device_aspect_ratio,
+               media_feature_min_device_aspect_ratio,
+               media_feature_max_device_aspect_ratio,
+
+               media_feature_color,
+               media_feature_min_color,
+               media_feature_max_color,
+
+               media_feature_color_index,
+               media_feature_min_color_index,
+               media_feature_max_color_index,
+
+               media_feature_monochrome,
+               media_feature_min_monochrome,
+               media_feature_max_monochrome,
+
+               media_feature_resolution,
+               media_feature_min_resolution,
+               media_feature_max_resolution,
+       };
+
+#define box_sizing_strings             _t("content-box;border-box")
+
+       enum box_sizing
+       {
+               box_sizing_content_box,
+               box_sizing_border_box,
+       };
+
+
+#define media_type_strings             _t("none;all;screen;print;braille;embossed;handheld;projection;speech;tty;tv")
+
+       enum media_type
+       {
+               media_type_none,
+               media_type_all,
+               media_type_screen,
+               media_type_print,
+               media_type_braille,
+               media_type_embossed,
+               media_type_handheld,
+               media_type_projection,
+               media_type_speech,
+               media_type_tty,
+               media_type_tv,
+       };
+
+       struct media_features
+       {
+               media_type      type;
+               int                     width;                  // (pixels) For continuous media, this is the width of the viewport including the size of a rendered scroll bar (if any). For paged media, this is the width of the page box.
+               int                     height;                 // (pixels) The height of the targeted display area of the output device. For continuous media, this is the height of the viewport including the size of a rendered scroll bar (if any). For paged media, this is the height of the page box.
+               int                     device_width;   // (pixels) The width of the rendering surface of the output device. For continuous media, this is the width of the screen. For paged media, this is the width of the page sheet size.
+               int                     device_height;  // (pixels) The height of the rendering surface of the output device. For continuous media, this is the height of the screen. For paged media, this is the height of the page sheet size.
+               int                     color;                  // The number of bits per color component of the output device. If the device is not a color device, the value is zero.
+               int                     color_index;    // The number of entries in the color lookup table of the output device. If the device does not use a color lookup table, the value is zero.
+               int                     monochrome;             // The number of bits per pixel in a monochrome frame buffer. If the device is not a monochrome device, the output device value will be 0.
+               int                     resolution;             // The resolution of the output device (in DPI)
+       };
+
+       enum render_type
+       {
+               render_all,
+               render_no_fixed,
+               render_fixed_only,
+       };
+
+       // List of the Void Elements (can't have any contents)
+       const litehtml::tchar_t* const void_elements = _t("area;base;br;col;command;embed;hr;img;input;keygen;link;meta;param;source;track;wbr");
+}
+
+#endif  // LH_TYPES_H
index fcb18c8b5f3667d736c042e413b3119b63d58286..cdd58e12664bfacfcd87e1e2f0cb877ef39539f0 100644 (file)
@@ -1,97 +1,97 @@
-#include "html.h"\r
-#include "utf8_strings.h"\r
-\r
-\r
-litehtml::utf8_to_wchar::utf8_to_wchar(const char* val)\r
-{\r
-       m_utf8 = (const byte*) val;\r
-       while (true)\r
-       {\r
-               ucode_t wch = get_char();\r
-               if (!wch) break;\r
-               m_str += wch;\r
-       }\r
-}\r
-\r
-litehtml::ucode_t litehtml::utf8_to_wchar::get_char()\r
-{\r
-       ucode_t b1 = getb();\r
-\r
-       if (!b1)\r
-       {\r
-               return 0;\r
-       }\r
-\r
-       // Determine whether we are dealing\r
-       // with a one-, two-, three-, or four-\r
-       // byte sequence.\r
-       if ((b1 & 0x80) == 0)\r
-       {\r
-               // 1-byte sequence: 000000000xxxxxxx = 0xxxxxxx\r
-               return b1;\r
-       }\r
-       else if ((b1 & 0xe0) == 0xc0)\r
-       {\r
-               // 2-byte sequence: 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx\r
-               ucode_t r = (b1 & 0x1f) << 6;\r
-               r |= get_next_utf8(getb());\r
-               return r;\r
-       }\r
-       else if ((b1 & 0xf0) == 0xe0)\r
-       {\r
-               // 3-byte sequence: zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx\r
-               ucode_t r = (b1 & 0x0f) << 12;\r
-               r |= get_next_utf8(getb()) << 6;\r
-               r |= get_next_utf8(getb());\r
-               return r;\r
-       }\r
-       else if ((b1 & 0xf8) == 0xf0)\r
-       {\r
-               // 4-byte sequence: 11101110wwwwzzzzyy + 110111yyyyxxxxxx\r
-               //     = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx\r
-               // (uuuuu = wwww + 1)\r
-               int b2 = get_next_utf8(getb());\r
-               int b3 = get_next_utf8(getb());\r
-               int b4 = get_next_utf8(getb());\r
-               return ((b1 & 7) << 18) | ((b2 & 0x3f) << 12) |\r
-                       ((b3 & 0x3f) << 6) | (b4 & 0x3f);\r
-       }\r
-\r
-       //bad start for UTF-8 multi-byte sequence\r
-       return '?';\r
-}\r
-\r
-litehtml::wchar_to_utf8::wchar_to_utf8(const wchar_t* val)\r
-{\r
-       unsigned int code;\r
-       for (int i = 0; val[i]; i++)\r
-       {\r
-               code = val[i];\r
-               if (code <= 0x7F)\r
-               {\r
-                       m_str += (char)code;\r
-               }\r
-               else if (code <= 0x7FF)\r
-               {\r
-                       m_str += (code >> 6) + 192;\r
-                       m_str += (code & 63) + 128;\r
-               }\r
-               else if (0xd800 <= code && code <= 0xdfff)\r
-               {\r
-                       //invalid block of utf8\r
-               }\r
-               else if (code <= 0xFFFF)\r
-               {\r
-                       m_str += (code >> 12) + 224;\r
-                       m_str += ((code >> 6) & 63) + 128;\r
-                       m_str += (code & 63) + 128;\r
-               }\r
-               else if (code <= 0x10FFFF)\r
-               {\r
-                       m_str += (code >> 18) + 240;\r
-                       m_str += ((code >> 12) & 63) + 128;\r
-                       m_str += ((code >> 6) & 63) + 128;\r
-                       m_str += (code & 63) + 128;\r
-               }\r
-       }\r
-}\r
+#include "html.h"
+#include "utf8_strings.h"
+
+
+litehtml::utf8_to_wchar::utf8_to_wchar(const char* val)
+{
+       m_utf8 = (const byte*) val;
+       while (true)
+       {
+               ucode_t wch = get_char();
+               if (!wch) break;
+               m_str += wch;
+       }
+}
+
+litehtml::ucode_t litehtml::utf8_to_wchar::get_char()
+{
+       ucode_t b1 = getb();
+
+       if (!b1)
+       {
+               return 0;
+       }
+
+       // Determine whether we are dealing
+       // with a one-, two-, three-, or four-
+       // byte sequence.
+       if ((b1 & 0x80) == 0)
+       {
+               // 1-byte sequence: 000000000xxxxxxx = 0xxxxxxx
+               return b1;
+       }
+       else if ((b1 & 0xe0) == 0xc0)
+       {
+               // 2-byte sequence: 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
+               ucode_t r = (b1 & 0x1f) << 6;
+               r |= get_next_utf8(getb());
+               return r;
+       }
+       else if ((b1 & 0xf0) == 0xe0)
+       {
+               // 3-byte sequence: zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
+               ucode_t r = (b1 & 0x0f) << 12;
+               r |= get_next_utf8(getb()) << 6;
+               r |= get_next_utf8(getb());
+               return r;
+       }
+       else if ((b1 & 0xf8) == 0xf0)
+       {
+               // 4-byte sequence: 11101110wwwwzzzzyy + 110111yyyyxxxxxx
+               //     = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
+               // (uuuuu = wwww + 1)
+               int b2 = get_next_utf8(getb());
+               int b3 = get_next_utf8(getb());
+               int b4 = get_next_utf8(getb());
+               return ((b1 & 7) << 18) | ((b2 & 0x3f) << 12) |
+                       ((b3 & 0x3f) << 6) | (b4 & 0x3f);
+       }
+
+       //bad start for UTF-8 multi-byte sequence
+       return '?';
+}
+
+litehtml::wchar_to_utf8::wchar_to_utf8(const wchar_t* val)
+{
+       unsigned int code;
+       for (int i = 0; val[i]; i++)
+       {
+               code = val[i];
+               if (code <= 0x7F)
+               {
+                       m_str += (char)code;
+               }
+               else if (code <= 0x7FF)
+               {
+                       m_str += (code >> 6) + 192;
+                       m_str += (code & 63) + 128;
+               }
+               else if (0xd800 <= code && code <= 0xdfff)
+               {
+                       //invalid block of utf8
+               }
+               else if (code <= 0xFFFF)
+               {
+                       m_str += (code >> 12) + 224;
+                       m_str += ((code >> 6) & 63) + 128;
+                       m_str += (code & 63) + 128;
+               }
+               else if (code <= 0x10FFFF)
+               {
+                       m_str += (code >> 18) + 240;
+                       m_str += ((code >> 12) & 63) + 128;
+                       m_str += ((code >> 6) & 63) + 128;
+                       m_str += (code & 63) + 128;
+               }
+       }
+}
index c932ed5074f1a4891136aef66a2797c703711c63..0120262766e6d1f96fa6684872b8c38b34f3eb60 100644 (file)
@@ -1,48 +1,51 @@
-#pragma once\r
-\r
-namespace litehtml\r
-{\r
-       class utf8_to_wchar\r
-       {\r
-               const byte* m_utf8;\r
-               std::wstring m_str;\r
-       public:\r
-               utf8_to_wchar(const char* val);\r
-               operator const wchar_t*() const\r
-               {\r
-                       return m_str.c_str();\r
-               }\r
-       private:\r
-               ucode_t getb()\r
-               {\r
-                       if (!(*m_utf8)) return 0;\r
-                       return *m_utf8++;\r
-               }\r
-               ucode_t get_next_utf8(ucode_t val)\r
-               {\r
-                       return (val & 0x3f);\r
-               }\r
-               ucode_t get_char();\r
-       };\r
-\r
-       class wchar_to_utf8\r
-       {\r
-               std::string m_str;\r
-       public:\r
-               wchar_to_utf8(const wchar_t* val);\r
-               operator const char*() const\r
-               {\r
-                       return m_str.c_str();\r
-               }\r
-       };\r
-\r
-#ifdef LITEHTML_UTF8\r
-#define litehtml_from_utf8(str)                str\r
-#define litehtml_to_utf8(str)          str\r
-#define litehtml_from_wchar(str)       wchar_to_utf8(str)\r
-#else\r
-#define litehtml_from_utf8(str)                utf8_to_wchar(str)\r
-#define litehtml_from_wchar(str)       str\r
-#define litehtml_to_utf8(str)          wchar_to_utf8(str)\r
-#endif\r
-}
\ No newline at end of file
+#ifndef LH_UTF8_STRINGS_H
+#define LH_UTF8_STRINGS_H
+
+namespace litehtml
+{
+       class utf8_to_wchar
+       {
+               const byte* m_utf8;
+               std::wstring m_str;
+       public:
+               utf8_to_wchar(const char* val);
+               operator const wchar_t*() const
+               {
+                       return m_str.c_str();
+               }
+       private:
+               ucode_t getb()
+               {
+                       if (!(*m_utf8)) return 0;
+                       return *m_utf8++;
+               }
+               ucode_t get_next_utf8(ucode_t val)
+               {
+                       return (val & 0x3f);
+               }
+               ucode_t get_char();
+       };
+
+       class wchar_to_utf8
+       {
+               std::string m_str;
+       public:
+               wchar_to_utf8(const wchar_t* val);
+               operator const char*() const
+               {
+                       return m_str.c_str();
+               }
+       };
+
+#ifdef LITEHTML_UTF8
+#define litehtml_from_utf8(str)                str
+#define litehtml_to_utf8(str)          str
+#define litehtml_from_wchar(str)       wchar_to_utf8(str)
+#else
+#define litehtml_from_utf8(str)                utf8_to_wchar(str)
+#define litehtml_from_wchar(str)       str
+#define litehtml_to_utf8(str)          wchar_to_utf8(str)
+#endif
+}
+
+#endif  // LH_UTF8_STRINGS_H
index 814765dc3c57651adbeac49cca6a9e0bedc7d382..39ce2d7f075450f91b416b1522902342b2b3a0a1 100644 (file)
@@ -1,28 +1,28 @@
-#include "html.h"\r
-#include "web_color.h"\r
-#include <string.h>\r
-\r
-litehtml::def_color litehtml::g_def_colors[] = \r
-{\r
-       {_t("transparent"),_t("rgba(0, 0, 0, 0)")},\r
-       {_t("AliceBlue"),_t("#F0F8FF")},\r
-       {_t("AntiqueWhite"),_t("#FAEBD7")},\r
-       {_t("Aqua"),_t("#00FFFF")},\r
-       {_t("Aquamarine"),_t("#7FFFD4")},\r
-       {_t("Azure"),_t("#F0FFFF")},\r
-       {_t("Beige"),_t("#F5F5DC")},\r
-       {_t("Bisque"),_t("#FFE4C4")},\r
-       {_t("Black"),_t("#000000")},\r
-       {_t("BlanchedAlmond"),_t("#FFEBCD")},\r
-       {_t("Blue"),_t("#0000FF")},\r
-       {_t("BlueViolet"),_t("#8A2BE2")},\r
-       {_t("Brown"),_t("#A52A2A")},\r
-       {_t("BurlyWood"),_t("#DEB887")},\r
-       {_t("CadetBlue"),_t("#5F9EA0")},\r
-       {_t("Chartreuse"),_t("#7FFF00")},\r
-       {_t("Chocolate"),_t("#D2691E")},\r
-       {_t("Coral"),_t("#FF7F50")},\r
-       {_t("CornflowerBlue"),_t("#6495ED")},\r
+#include "html.h"
+#include "web_color.h"
+#include <string.h>
+
+litehtml::def_color litehtml::g_def_colors[] = 
+{
+       {_t("transparent"),_t("rgba(0, 0, 0, 0)")},
+       {_t("AliceBlue"),_t("#F0F8FF")},
+       {_t("AntiqueWhite"),_t("#FAEBD7")},
+       {_t("Aqua"),_t("#00FFFF")},
+       {_t("Aquamarine"),_t("#7FFFD4")},
+       {_t("Azure"),_t("#F0FFFF")},
+       {_t("Beige"),_t("#F5F5DC")},
+       {_t("Bisque"),_t("#FFE4C4")},
+       {_t("Black"),_t("#000000")},
+       {_t("BlanchedAlmond"),_t("#FFEBCD")},
+       {_t("Blue"),_t("#0000FF")},
+       {_t("BlueViolet"),_t("#8A2BE2")},
+       {_t("Brown"),_t("#A52A2A")},
+       {_t("BurlyWood"),_t("#DEB887")},
+       {_t("CadetBlue"),_t("#5F9EA0")},
+       {_t("Chartreuse"),_t("#7FFF00")},
+       {_t("Chocolate"),_t("#D2691E")},
+       {_t("Coral"),_t("#FF7F50")},
+       {_t("CornflowerBlue"),_t("#6495ED")},
        {_t("Cornsilk"),_t("#FFF8DC")},
        {_t("Crimson"),_t("#DC143C")},
        {_t("Cyan"),_t("#00FFFF")},
@@ -149,103 +149,108 @@ litehtml::def_color litehtml::g_def_colors[] =
        {_t("White"),_t("#FFFFFF")},
        {_t("WhiteSmoke"),_t("#F5F5F5")},
        {_t("Yellow"),_t("#FFFF00")},
-       {_t("YellowGreen"),_t("#9ACD32")},\r
-       {0,0}\r
-};\r
-\r
-\r
-litehtml::web_color litehtml::web_color::from_string( const tchar_t* str )\r
-{\r
-       if(!str)\r
-       {\r
-               return web_color(0, 0, 0);\r
-       }\r
-       if(str[0] == _t('#'))\r
-       {\r
-               tstring red             = _t("");\r
-               tstring green           = _t("");\r
-               tstring blue            = _t("");\r
-               if(t_strlen(str + 1) == 3)\r
-               {\r
-                       red             += str[1];\r
-                       red             += str[1];\r
-                       green   += str[2];\r
-                       green   += str[2];\r
-                       blue    += str[3];\r
-                       blue    += str[3];\r
-               } else if(t_strlen(str + 1) == 6)\r
-               {\r
-                       red             += str[1];\r
-                       red             += str[2];\r
-                       green   += str[3];\r
-                       green   += str[4];\r
-                       blue    += str[5];\r
-                       blue    += str[6];\r
-               }\r
-               tchar_t* sss = 0;\r
-               web_color clr;\r
-               clr.red         = (byte) t_strtol(red.c_str(),  &sss, 16);\r
-               clr.green       = (byte) t_strtol(green.c_str(),        &sss, 16);\r
-               clr.blue        = (byte) t_strtol(blue.c_str(), &sss, 16);\r
-               return clr;\r
-       } else if(!t_strncmp(str, _t("rgb"), 3))\r
-       {\r
-               tstring s = str;\r
-\r
-               tstring::size_type pos = s.find_first_of(_t("("));\r
-               if(pos != tstring::npos)\r
-               {\r
-                       s.erase(s.begin(), s.begin() + pos + 1);\r
-               }\r
-               pos = s.find_last_of(_t(")"));\r
-               if(pos != tstring::npos)\r
-               {\r
-                       s.erase(s.begin() + pos, s.end());\r
-               }\r
-\r
-               std::vector<tstring> tokens;\r
-               split_string(s, tokens, _t(", \t"));\r
-\r
-               web_color clr;\r
-\r
-               if(tokens.size() >= 1)  clr.red         = (byte) t_atoi(tokens[0].c_str());\r
-               if(tokens.size() >= 2)  clr.green       = (byte) t_atoi(tokens[1].c_str());\r
-               if(tokens.size() >= 3)  clr.blue        = (byte) t_atoi(tokens[2].c_str());\r
-               if(tokens.size() >= 4)  clr.alpha       = (byte) (t_strtod(tokens[3].c_str(), 0) * 255.0);\r
-\r
-               return clr;\r
-       } else\r
-       {\r
-               const tchar_t* rgb = resolve_name(str);\r
-               if(rgb)\r
-               {\r
-                       return from_string(rgb);\r
-               }\r
-       }\r
-       return web_color(0, 0, 0);\r
-}\r
-\r
-const litehtml::tchar_t* litehtml::web_color::resolve_name( const tchar_t* name )\r
-{\r
-       for(int i=0; g_def_colors[i].name; i++)\r
-       {\r
-               if(!t_strcasecmp(name, g_def_colors[i].name))\r
-               {\r
-                       return g_def_colors[i].rgb;\r
-               }\r
-       }\r
-       return 0;\r
-}\r
-\r
-bool litehtml::web_color::is_color( const tchar_t* str )\r
-{\r
-       if(!t_strncasecmp(str, _t("rgb"), 3) || str[0] == _t('#'))\r
-       {\r
-               return true;\r
-       }\r
-       if(resolve_name(str))\r
-       {\r
-               return true;\r
-       }\r
-       return false;\r
-}\r
+       {_t("YellowGreen"),_t("#9ACD32")},
+       {0,0}
+};
+
+
+litehtml::web_color litehtml::web_color::from_string(const tchar_t* str, litehtml::document_container* callback)
+{
+       if(!str || !str[0])
+       {
+               return web_color(0, 0, 0);
+       }
+       if(str[0] == _t('#'))
+       {
+               tstring red             = _t("");
+               tstring green           = _t("");
+               tstring blue            = _t("");
+               if(t_strlen(str + 1) == 3)
+               {
+                       red             += str[1];
+                       red             += str[1];
+                       green   += str[2];
+                       green   += str[2];
+                       blue    += str[3];
+                       blue    += str[3];
+               } else if(t_strlen(str + 1) == 6)
+               {
+                       red             += str[1];
+                       red             += str[2];
+                       green   += str[3];
+                       green   += str[4];
+                       blue    += str[5];
+                       blue    += str[6];
+               }
+               tchar_t* sss = 0;
+               web_color clr;
+               clr.red         = (byte) t_strtol(red.c_str(),  &sss, 16);
+               clr.green       = (byte) t_strtol(green.c_str(),        &sss, 16);
+               clr.blue        = (byte) t_strtol(blue.c_str(), &sss, 16);
+               return clr;
+       } else if(!t_strncmp(str, _t("rgb"), 3))
+       {
+               tstring s = str;
+
+               tstring::size_type pos = s.find_first_of(_t("("));
+               if(pos != tstring::npos)
+               {
+                       s.erase(s.begin(), s.begin() + pos + 1);
+               }
+               pos = s.find_last_of(_t(")"));
+               if(pos != tstring::npos)
+               {
+                       s.erase(s.begin() + pos, s.end());
+               }
+
+               std::vector<tstring> tokens;
+               split_string(s, tokens, _t(", \t"));
+
+               web_color clr;
+
+               if(tokens.size() >= 1)  clr.red         = (byte) t_atoi(tokens[0].c_str());
+               if(tokens.size() >= 2)  clr.green       = (byte) t_atoi(tokens[1].c_str());
+               if(tokens.size() >= 3)  clr.blue        = (byte) t_atoi(tokens[2].c_str());
+               if(tokens.size() >= 4)  clr.alpha       = (byte) (t_strtod(tokens[3].c_str(), 0) * 255.0);
+
+               return clr;
+       } else
+       {
+               tstring rgb = resolve_name(str, callback);
+               if(!rgb.empty())
+               {
+                       return from_string(rgb.c_str(), callback);
+               }
+       }
+       return web_color(0, 0, 0);
+}
+
+litehtml::tstring litehtml::web_color::resolve_name(const tchar_t* name, litehtml::document_container* callback)
+{
+       for(int i=0; g_def_colors[i].name; i++)
+       {
+               if(!t_strcasecmp(name, g_def_colors[i].name))
+               {
+            return std::move(litehtml::tstring(g_def_colors[i].rgb));
+               }
+       }
+    if (callback)
+    {
+        litehtml::tstring clr = callback->resolve_color(name);
+        return std::move(clr);
+    }
+    return std::move(litehtml::tstring());
+}
+
+bool litehtml::web_color::is_color(const tchar_t* str)
+{
+       if(!t_strncasecmp(str, _t("rgb"), 3) || str[0] == _t('#'))
+       {
+               return true;
+       }
+    if (!t_isdigit(str[0]) && str[0] != _t('.'))
+       {
+               return true;
+       }
+       return false;
+}
index 8d4829fd4020238bf2ab691ec1dc6494280db7c1..fa3b370b87aeca1c224f7ba0d1aea121688e0590 100644 (file)
@@ -1,56 +1,61 @@
-#pragma once\r
-\r
-namespace litehtml\r
-{\r
-       struct def_color\r
-       {\r
-               const tchar_t*  name;\r
-               const tchar_t*  rgb;\r
-       };\r
-\r
-       extern def_color g_def_colors[];\r
-\r
-       struct web_color\r
-       {\r
-               byte    blue;\r
-               byte    green;\r
-               byte    red;\r
-               byte    alpha;\r
-\r
-               web_color(byte r, byte g, byte b, byte a = 255)\r
-               {\r
-                       blue    = b;\r
-                       green   = g;\r
-                       red             = r;\r
-                       alpha   = a;\r
-               }\r
-\r
-               web_color()\r
-               {\r
-                       blue    = 0;\r
-                       green   = 0;\r
-                       red             = 0;\r
-                       alpha   = 0xFF;\r
-               }\r
-\r
-               web_color(const web_color& val)\r
-               {\r
-                       blue    = val.blue;\r
-                       green   = val.green;\r
-                       red             = val.red;\r
-                       alpha   = val.alpha;\r
-               }\r
-\r
-               web_color& operator=(const web_color& val)\r
-               {\r
-                       blue    = val.blue;\r
-                       green   = val.green;\r
-                       red             = val.red;\r
-                       alpha   = val.alpha;\r
-                       return *this;\r
-               }\r
-               static web_color                from_string(const tchar_t* str);\r
-               static const tchar_t*   resolve_name(const tchar_t* name);\r
-               static bool                             is_color(const tchar_t* str);\r
-       };\r
-}
\ No newline at end of file
+#ifndef LH_WEB_COLOR_H
+#define LH_WEB_COLOR_H
+
+namespace litehtml
+{
+       struct def_color
+       {
+               const tchar_t*  name;
+               const tchar_t*  rgb;
+       };
+
+       extern def_color g_def_colors[];
+
+    class document_container;
+
+       struct web_color
+       {
+               byte    blue;
+               byte    green;
+               byte    red;
+               byte    alpha;
+
+               web_color(byte r, byte g, byte b, byte a = 255)
+               {
+                       blue    = b;
+                       green   = g;
+                       red             = r;
+                       alpha   = a;
+               }
+
+               web_color()
+               {
+                       blue    = 0;
+                       green   = 0;
+                       red             = 0;
+                       alpha   = 0xFF;
+               }
+
+               web_color(const web_color& val)
+               {
+                       blue    = val.blue;
+                       green   = val.green;
+                       red             = val.red;
+                       alpha   = val.alpha;
+               }
+
+               web_color& operator=(const web_color& val)
+               {
+                       blue    = val.blue;
+                       green   = val.green;
+                       red             = val.red;
+                       alpha   = val.alpha;
+                       return *this;
+               }
+        static web_color            from_string(const tchar_t* str, litehtml::document_container* callback);
+               static litehtml::tstring    resolve_name(const tchar_t* name, litehtml::document_container* callback);
+        static bool                 is_color(const tchar_t* str);
+       };
+}
+
+#endif  // LH_WEB_COLOR_H