Initial commit of litehtml_viewer
authorMichael Rasmussen <mir@datanom.net>
Tue, 6 Nov 2018 18:50:31 +0000 (19:50 +0100)
committerAndrej Kacian <ticho@claws-mail.org>
Tue, 12 Feb 2019 18:38:09 +0000 (19:38 +0100)
See TODO for missing functionality.

Signed-off-by: Michael Rasmussen <mir@datanom.net>
99 files changed:
configure.ac
src/plugins/Makefile.am
src/plugins/litehtml_viewer/Makefile.am [new file with mode: 0644]
src/plugins/litehtml_viewer/TODO [new file with mode: 0644]
src/plugins/litehtml_viewer/claws.def [new file with mode: 0644]
src/plugins/litehtml_viewer/container_linux.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/container_linux.h [new file with mode: 0644]
src/plugins/litehtml_viewer/css.inc [new file with mode: 0644]
src/plugins/litehtml_viewer/lh_viewer.c [new file with mode: 0644]
src/plugins/litehtml_viewer/lh_viewer.h [new file with mode: 0644]
src/plugins/litehtml_viewer/lh_widget.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/lh_widget.h [new file with mode: 0644]
src/plugins/litehtml_viewer/lh_widget_wrapped.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/LICENSE [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/Makefile.am [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/README.md [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/attributes.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/background.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/background.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/borders.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/box.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/box.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/context.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/context.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/css_length.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/css_length.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/css_margins.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/css_offsets.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/css_position.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/css_selector.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/css_selector.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/document.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/document.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_anchor.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_anchor.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_base.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_base.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_before_after.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_before_after.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_body.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_body.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_break.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_break.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_cdata.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_cdata.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_comment.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_comment.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_div.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_div.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_font.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_font.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_image.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_image.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_link.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_link.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_para.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_para.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_script.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_script.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_space.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_space.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_style.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_style.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_table.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_table.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_td.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_td.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_text.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_text.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_title.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_title.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_tr.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/el_tr.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/element.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/element.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/html.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/html.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/html_tag.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/html_tag.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/iterators.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/iterators.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/litehtml.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/media_query.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/media_query.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/os_types.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/style.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/style.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/stylesheet.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/stylesheet.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/table.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/table.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/types.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/utf8_strings.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/utf8_strings.h [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/web_color.cpp [new file with mode: 0644]
src/plugins/litehtml_viewer/litehtml/web_color.h [new file with mode: 0644]
src/plugins/litehtml_viewer/plugin.c [new file with mode: 0644]
src/plugins/litehtml_viewer/plugin.def [new file with mode: 0644]
src/plugins/litehtml_viewer/version.rc [new file with mode: 0644]

index f504316..6b4b946 100644 (file)
@@ -109,6 +109,7 @@ LT_AC_PROG_RC
 AC_LIBTOOL_RC
 AC_PROG_LIBTOOL
 AC_PROG_AWK
+AC_PROG_CXX
 
 AC_SYS_LARGEFILE
 
@@ -1039,6 +1040,10 @@ AC_ARG_ENABLE(libravatar-plugin,
                [  --disable-libravatar-plugin     Do not build libravatar  plugin],
                [enable_libravatar_plugin=$enableval], [enable_libravatar_plugin=auto])
 
+AC_ARG_ENABLE(litehtml_viewer-plugin,
+               [  --disable-litehtml_viewer-plugin       Do not build litehtml_viewer plugin],
+               [enable_litehtml_viewer_plugin=$enableval], [enable_litehtml_viewer_plugin=auto])
+
 AC_ARG_ENABLE(mailmbox-plugin,
                [  --disable-mailmbox-plugin       Do not build mailmbox plugin],
                [enable_mailmbox_plugin=$enableval], [enable_mailmbox_plugin=auto])
@@ -1119,6 +1124,7 @@ dnl either yes or no, and do the AC_SUBST calls.
 dnl Archive:           libarchive
 dnl Fancy:             Webkit, curl, optionally libsoup-gnome
 dnl Gdata:             libgdata
+dnl Litehtml           cairo, fontconfig, gumbo
 dnl Libravatar:                libcurl
 dnl Notification:      optionally libnotify  unity/messaging-menu
 dnl                               libcanberra_gtk hotkey
@@ -1192,6 +1198,21 @@ PKG_CHECK_MODULES(GDATA, libgdata >= 0.17.2, HAVE_GDATA=yes, HAVE_GDATA=no)
 AC_SUBST(GDATA_CFLAGS)
 AC_SUBST(GDATA_LIBS)
 
+dnl cairo **********************************************************************
+PKG_CHECK_MODULES(CAIRO, cairo, HAVE_CAIRO=yes, HAVE_CAIRO=no)
+AC_SUBST(CAIRO_CFLAGS)
+AC_SUBST(CAIRO_LIBS)
+
+dnl fontconfig *****************************************************************
+PKG_CHECK_MODULES(FONTCONFIG, fontconfig, HAVE_FONTCONFIG=yes, HAVE_FONTCONFIG=no)
+AC_SUBST(FONTCONFIG_CFLAGS)
+AC_SUBST(FONTCONFIG_LIBS)
+
+dnl gumbo **********************************************************************
+PKG_CHECK_MODULES(LIBGUMBO, gumbo >= 0.10, HAVE_LIBGUMBO=yes, HAVE_LIBGUMBO=no)
+AC_SUBST(LIBGUMBO_CFLAGS)
+AC_SUBST(LIBGUMBO_LIBS)
+
 dnl libical ********************************************************************
 PKG_CHECK_MODULES(LIBICAL, libical >= 2.0, HAVE_LIBICAL=yes, HAVE_LIBICAL=no)
 AC_SUBST(LIBICAL_CFLAGS)
@@ -1602,6 +1623,37 @@ else
        AC_MSG_RESULT(no)
 fi
 
+AC_MSG_CHECKING([whether to build litehtml_viewer plugin])
+if test x"$enable_litehtml_viewer_plugin" != xno; then
+        dependencies_missing=""
+
+        if test x"$HAVE_CAIRO" = xno; then
+                dependencies_missing="cairo $dependencies_missing"
+        fi
+        if test x"$HAVE_FONTCONFIG" = xno; then
+                dependencies_missing="fontconfig $dependencies_missing"
+        fi
+       if test x"$HAVE_LIBGUMBO" = xno; then
+               dependencies_missing="libgumbo $dependencies_missing"
+       fi
+
+        if test x"$dependencies_missing" = x; then
+                PLUGINS="$PLUGINS litehtml_viewer"
+                AC_MSG_RESULT(yes)
+        elif test x"$enable_litehtml_viewer_plugin" = xauto; then
+                AC_MSG_RESULT(no)
+                AC_MSG_WARN("Plugin litehtml_viewer will not be built; missing $dependencies_missing")
+                enable_litehtml_viewer_plugin=no
+                MISSING_DEPS_PLUGINS="$MISSING_DEPS_PLUGINS litehtml_viewer"
+        else
+                AC_MSG_RESULT(no)
+                AC_MSG_ERROR("Plugin litehtml_viewer cannot be built; missing $dependencies_missing")
+        fi
+else
+        DISABLED_PLUGINS="$DISABLED_PLUGINS litehtml_viewer"
+        AC_MSG_RESULT(no)
+fi
+
 AC_MSG_CHECKING([whether to build mailmbox plugin])
 if test x"$enable_mailmbox_plugin" != xno; then
        PLUGINS="$PLUGINS mailmbox"
@@ -2015,6 +2067,7 @@ AM_CONDITIONAL(BUILD_FANCY_PLUGIN,                test x"$enable_fancy_plugin" != xno)
 AM_CONDITIONAL(BUILD_FETCHINFO_PLUGIN,         test x"$enable_fetchinfo_plugin" != xno)
 AM_CONDITIONAL(BUILD_GDATA_PLUGIN,             test x"$enable_gdata_plugin" != xno)
 AM_CONDITIONAL(BUILD_LIBRAVATAR_PLUGIN,                test x"$enable_libravatar_plugin" != xno)
+AM_CONDITIONAL(BUILD_LITEHTML_PLUGIN,          test x"$enable_litehtml_viewer_plugin" != xno)
 AM_CONDITIONAL(BUILD_MAILMBOX_PLUGIN,          test x"$enable_mailmbox_plugin" != xno)
 AM_CONDITIONAL(BUILD_MANAGESIEVE_PLUGIN,               test x"$enable_managesieve_plugin" != xno)
 AM_CONDITIONAL(BUILD_NEWMAIL_PLUGIN,           test x"$enable_newmail_plugin" != xno)
@@ -2064,6 +2117,8 @@ src/plugins/dillo/Makefile
 src/plugins/fancy/Makefile
 src/plugins/fetchinfo/Makefile
 src/plugins/gdata/Makefile
+src/plugins/litehtml_viewer/Makefile
+src/plugins/litehtml_viewer/litehtml/Makefile
 src/plugins/libravatar/Makefile
 src/plugins/mailmbox/Makefile
 src/plugins/managesieve/Makefile
index 1f88956..4af74dd 100644 (file)
@@ -19,6 +19,7 @@ SUBDIRS = \
        fancy \
        fetchinfo \
        gdata \
+       litehtml_viewer \
        libravatar \
        mailmbox \
        managesieve \
diff --git a/src/plugins/litehtml_viewer/Makefile.am b/src/plugins/litehtml_viewer/Makefile.am
new file mode 100644 (file)
index 0000000..5e4e732
--- /dev/null
@@ -0,0 +1,66 @@
+# Copyright 1999-2018 the Claws Mail team.
+# This file is part of Claws Mail package, and distributed under the
+# terms of the General Public License version 3 (or later).
+# See COPYING file for license details.
+
+SUBDIRS = litehtml
+EXTRA_DIST = claws.def plugin.def version.rc css.inc
+
+IFLAGS = \
+        -I$(top_srcdir)/src \
+        -I$(top_srcdir)/src/common \
+        -I$(top_builddir)/src \
+        -I$(top_srcdir)/src/gtk \
+       -I$(top_srcdir)/src/plugins/litehtml_viewer/litehtml
+
+plugin_res =
+plugin_res_ldflag =
+export_symbols =
+plugin_deps =
+plugin_ldadd =
+
+no_undefined =
+
+cygwin_export_lib =
+
+plugindir = $(pkglibdir)/plugins
+
+#if BUILD_LITEHTML_VIEWER_PLUGIN
+plugin_LTLIBRARIES = litehtml_viewer.la
+#endif
+
+litehtml_viewer_la_DEPENDENCIES = $(plugin_deps)
+
+litehtml_viewer_la_LIBADD = $(plugin_ldadd) $(cygwin_export_lib) \
+       $(top_builddir)/src/plugins/litehtml_viewer/litehtml/liblitehtml.la \
+        $(GTK_LIBS)
+
+litehtml_viewer_la_CXXFLAGS = -std=c++11
+litehtml_viewer_la_CFLAGS = -std=c99
+
+litehtml_viewer_la_SOURCES = \
+       container_linux.cpp \
+       plugin.c \
+       lh_viewer.c \
+       lh_widget.cpp \
+       container_linux.h \
+       lh_viewer.h \
+       lh_widget.h \
+       lh_widget_wrapped.h
+
+litehtml_viewer_la_LDFLAGS = \
+       $(plugin_res_ldflag) $(no_undefined) $(export_symbols) \
+       -avoid-version -module \
+       $(GTK_LIBS) \
+       $(FONTCONFIG_LIBS) \
+       $(CAIRO_LIBS)
+
+litehtml_viewer_la_CPPFLAGS = \
+       $(IFLAGS) \
+       $(GLIB_CFLAGS) \
+       $(GTK_CFLAGS) \
+       $(FONTCONFIG_CFLAGS) \
+       $(CAIRO_CFLAGS) 
+
+.PHONY: test
+
diff --git a/src/plugins/litehtml_viewer/TODO b/src/plugins/litehtml_viewer/TODO
new file mode 100644 (file)
index 0000000..912078f
--- /dev/null
@@ -0,0 +1,4 @@
+- Add support for displaying images
+- Add support for printing
+- Add support for links (open in default browser)
+
diff --git a/src/plugins/litehtml_viewer/claws.def b/src/plugins/litehtml_viewer/claws.def
new file mode 100644 (file)
index 0000000..9a6ff50
--- /dev/null
@@ -0,0 +1,98 @@
+LIBRARY CLAWS-MAIL.EXE
+EXPORTS
+addressbook_folder_selection
+alertpanel
+alertpanel_error
+check_plugin_version
+claws_do_idle
+claws_fopen
+claws_fdopen
+claws_fclose
+claws_safe_fclose
+combobox_get_active_data
+combobox_select_by_data
+combobox_text_new
+complete_address
+compose_new
+conv_codeset_strdup
+conv_get_locale_charset_str
+conv_get_locale_charset_str_no_utf8
+debug_print_real
+debug_srcname
+end_address_completion
+extract_address
+file_exist
+file_read_to_str_no_recode
+filesel_select_file_open
+filesel_select_file_save
+folder_find_item_from_identifier
+folder_get_default_trash
+folder_item_get_identifier
+folder_item_get_path
+folder_item_remove_msg
+foldersel_folder_sel
+folder_subscribe
+get_complete_address
+get_locale_dir
+get_rc_dir
+gtkut_get_browse_directory_btn
+gtkut_get_browse_file_btn
+gtkut_get_options_frame
+gtkutils_scroll_one_line
+gtkutils_scroll_page
+gtkut_sc_combobox_create
+hooks_register_hook
+hooks_unregister_hook
+is_dir_exist
+line_has_quote_char
+log_error
+make_dir
+matcherlist_free
+matcherlist_match
+matcherlist_new
+matcherprop_new
+mimeview_register_viewer_factory
+mimeview_unregister_viewer_factory
+noticeview_hide
+open_txt_editor
+open_uri
+plugin_get_loaded_by_name
+pref_get_escaped_pref
+pref_get_pref_from_entry
+pref_get_unescaped_pref
+prefs_button_toggled
+prefs_button_toggled follow
+prefs_common
+prefs_common_get_ext_editor_cmd
+prefs_common_get_prefs
+prefs_common_get_uri_cmd
+pref_set_entry_from_pref
+prefs_file_close
+prefs_file_close_revert
+prefs_gtk_register_page
+prefs_gtk_unregister_page
+prefs_read_config
+prefs_set_block_label
+prefs_set_default
+prefs_write_open
+prefs_write_param
+printing_get_page_setup
+printing_get_settings
+printing_store_settings
+procmime_get_part
+procmime_get_tmp_file_name
+procmime_mimeinfo_get_parameter
+procmime_mimeinfo_next
+procmsg_get_message_file
+procmsg_msginfo_set_flags
+procmsg_msginfo_unset_flags
+procmsg_register_spam_learner
+procmsg_spam_set_folder
+procmsg_unregister_spam_learner
+settings
+start_address_completion
+statusbar_pop_all
+statusbar_print_all
+statusbar_progress_all
+str_write_to_file
+subst_char
diff --git a/src/plugins/litehtml_viewer/container_linux.cpp b/src/plugins/litehtml_viewer/container_linux.cpp
new file mode 100644 (file)
index 0000000..2341da5
--- /dev/null
@@ -0,0 +1,910 @@
+/*
+ * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client
+ * Copyright(C) 1999-2015 the Claws Mail Team
+ * == Fancy Plugin ==
+ * This file Copyright (C) 2009-2015 Salvatore De Paolis
+ * <iwkse@claws-mail.org> and the Claws Mail Team
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write tothe Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#include "claws-features.h"
+#endif
+
+#include "container_linux.h"
+
+#include <cairo-ft.h>
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+
+#ifndef M_PI
+#       define M_PI    3.14159265358979323846
+#endif
+
+container_linux::container_linux(void)
+{
+       m_temp_surface  = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 2, 2);
+       m_temp_cr               = cairo_create(m_temp_surface);
+}
+
+container_linux::~container_linux(void)
+{
+       clear_images();
+       cairo_surface_destroy(m_temp_surface);
+       cairo_destroy(m_temp_cr);
+}
+
+litehtml::uint_ptr container_linux::create_font( const litehtml::tchar_t* faceName, int size, int weight, litehtml::font_style italic, unsigned int decoration, litehtml::font_metrics* fm )
+{
+       litehtml::string_vector fonts;
+       litehtml::split_string(faceName, fonts, ",");
+       litehtml::trim(fonts[0]);
+
+       cairo_font_face_t* fnt = 0;
+
+       FcPattern *pattern = FcPatternCreate();
+       bool found = false;
+       for(litehtml::string_vector::iterator i = fonts.begin(); i != fonts.end(); i++)
+       {
+               if(FcPatternAddString(pattern, FC_FAMILY, (unsigned char *) i->c_str()))
+               {
+                       found = true;
+                       break;
+               }
+       }
+       if(found)
+       {
+               if(italic == litehtml::fontStyleItalic )
+               {
+                       FcPatternAddInteger (pattern, FC_SLANT, FC_SLANT_ITALIC);
+               } else
+               {
+                       FcPatternAddInteger (pattern, FC_SLANT, FC_SLANT_ROMAN);
+               }
+
+               int fc_weight = FC_WEIGHT_NORMAL;
+               if(weight >= 0 && weight < 150)                 fc_weight = FC_WEIGHT_THIN;
+               else if(weight >= 150 && weight < 250)  fc_weight = FC_WEIGHT_EXTRALIGHT;
+               else if(weight >= 250 && weight < 350)  fc_weight = FC_WEIGHT_LIGHT;
+               else if(weight >= 350 && weight < 450)  fc_weight = FC_WEIGHT_NORMAL;
+               else if(weight >= 450 && weight < 550)  fc_weight = FC_WEIGHT_MEDIUM;
+               else if(weight >= 550 && weight < 650)  fc_weight = FC_WEIGHT_SEMIBOLD;
+               else if(weight >= 650 && weight < 750)  fc_weight = FC_WEIGHT_BOLD;
+               else if(weight >= 750 && weight < 850)  fc_weight = FC_WEIGHT_EXTRABOLD;
+               else if(weight >= 950)                                  fc_weight = FC_WEIGHT_BLACK;
+
+               FcPatternAddInteger (pattern, FC_WEIGHT, fc_weight);
+
+               fnt = cairo_ft_font_face_create_for_pattern(pattern);
+       }
+
+       FcPatternDestroy(pattern);
+
+       cairo_font* ret = 0;
+
+       if(fm && fnt)
+       {
+               cairo_save(m_temp_cr);
+
+               cairo_set_font_face(m_temp_cr, fnt);
+               cairo_set_font_size(m_temp_cr, size);
+               cairo_font_extents_t ext;
+               cairo_font_extents(m_temp_cr, &ext);
+
+               cairo_text_extents_t tex;
+               cairo_text_extents(m_temp_cr, "x", &tex);
+
+               fm->ascent              = (int) ext.ascent;
+               fm->descent             = (int) ext.descent;
+               fm->height              = (int) (ext.ascent + ext.descent);
+               fm->x_height    = (int) tex.height;
+
+               cairo_restore(m_temp_cr);
+
+               ret = new cairo_font;
+               ret->font               = fnt;
+               ret->size               = size;
+               ret->strikeout  = (decoration & litehtml::font_decoration_linethrough) ? true : false;
+               ret->underline  = (decoration & litehtml::font_decoration_underline) ? true : false;
+
+       }
+
+       return (litehtml::uint_ptr) ret;
+}
+
+void container_linux::delete_font( litehtml::uint_ptr hFont )
+{
+       cairo_font* fnt = (cairo_font*) hFont;
+       if(fnt)
+       {
+               cairo_font_face_destroy(fnt->font);
+               delete fnt;
+       }
+}
+
+int container_linux::text_width( const litehtml::tchar_t* text, litehtml::uint_ptr hFont )
+{
+       cairo_font* fnt = (cairo_font*) hFont;
+
+       cairo_save(m_temp_cr);
+
+       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);
+
+       cairo_restore(m_temp_cr);
+
+       return (int) ext.x_advance;
+}
+
+void container_linux::draw_text( litehtml::uint_ptr hdc, const litehtml::tchar_t* text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos )
+{
+       cairo_font* fnt = (cairo_font*) hFont;
+       cairo_t* cr             = (cairo_t*) hdc;
+       cairo_save(cr);
+
+       apply_clip(cr);
+
+       cairo_set_font_face(cr, fnt->font);
+       cairo_set_font_size(cr, fnt->size);
+       cairo_font_extents_t ext;
+       cairo_font_extents(cr, &ext);
+
+       int x = pos.left();
+       int y = pos.bottom()    - ext.descent;
+
+       set_color(cr, color);
+
+       cairo_move_to(cr, x, y);
+       cairo_show_text(cr, text);
+
+       int tw = 0;
+
+       if(fnt->underline || fnt->strikeout)
+       {
+               tw = text_width(text, hFont);
+       }
+
+       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)
+       {
+               cairo_text_extents_t tex;
+               cairo_text_extents(cr, "x", &tex);
+
+               int ln_y = y - tex.height / 2.0;
+
+               cairo_set_line_width(cr, 1);
+               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);
+}
+
+int container_linux::pt_to_px( int pt )
+{
+       GdkScreen* screen = gdk_screen_get_default();
+       double dpi = gdk_screen_get_resolution(screen);
+
+       return (int) ((double) pt * dpi / 72.0);
+}
+
+int container_linux::get_default_font_size() const
+{
+       return 16;
+}
+
+void container_linux::draw_list_marker( litehtml::uint_ptr hdc, const litehtml::list_marker& marker )
+{
+       if(!marker.image.empty())
+       {
+               /*litehtml::tstring url;
+               make_url(marker.image.c_str(), marker.baseurl, url);
+
+               lock_images_cache();
+               images_map::iterator img_i = m_images.find(url.c_str());
+               if(img_i != m_images.end())
+               {
+                       if(img_i->second)
+                       {
+                               draw_txdib((cairo_t*) hdc, img_i->second, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height);
+                       }
+               }
+               unlock_images_cache();*/
+       } else
+       {
+               switch(marker.marker_type)
+               {
+               case litehtml::list_style_type_circle:
+                       {
+                               draw_ellipse((cairo_t*) hdc, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height, marker.color, 0.5);
+                       }
+                       break;
+               case litehtml::list_style_type_disc:
+                       {
+                               fill_ellipse((cairo_t*) hdc, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height, marker.color);
+                       }
+                       break;
+               case litehtml::list_style_type_square:
+                       if(hdc)
+                       {
+                               cairo_t* cr = (cairo_t*) hdc;
+                               cairo_save(cr);
+
+                               cairo_new_path(cr);
+                               cairo_rectangle(cr, marker.pos.x, marker.pos.y, marker.pos.width, marker.pos.height);
+
+                               set_color(cr, marker.color);
+                               cairo_fill(cr);
+                               cairo_restore(cr);
+                       }
+                       break;
+               default:
+                       /*do nothing*/
+                       break;
+               }
+       }
+}
+
+void container_linux::load_image( const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, bool redraw_on_ready )
+{
+       litehtml::tstring url;
+       make_url(src, baseurl, url);
+       if(m_images.find(url.c_str()) == m_images.end())
+       {
+               try
+               {
+                       GdkPixbuf *img = get_image(url.c_str(), true);
+                       if(img)
+                       {
+                               m_images[url.c_str()] = img;
+                       }
+               } catch(...)
+               {
+                       int iii=0;
+                       iii++;
+               }
+       }
+}
+
+void container_linux::get_image_size( const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, litehtml::size& sz )
+{
+       litehtml::tstring url;
+       make_url(src, baseurl, url);
+
+       images_map::iterator img = m_images.find(url.c_str());
+       if(img != m_images.end())
+       {
+               sz.width        = gdk_pixbuf_get_width(img->second);
+               sz.height       = gdk_pixbuf_get_height(img->second);
+       } else
+       {
+               sz.width        = 0;
+               sz.height       = 0;
+       }
+}
+
+void container_linux::draw_background( litehtml::uint_ptr hdc, const litehtml::background_paint& bg )
+{
+       cairo_t* cr = (cairo_t*) hdc;
+       cairo_save(cr);
+       apply_clip(cr);
+
+       rounded_rectangle(cr, bg.border_box, bg.border_radius);
+       cairo_clip(cr);
+
+       cairo_rectangle(cr, bg.clip_box.x, bg.clip_box.y, bg.clip_box.width, bg.clip_box.height);
+       cairo_clip(cr);
+
+       if(bg.color.alpha)
+       {
+               set_color(cr, bg.color);
+               cairo_paint(cr);
+       }
+
+       litehtml::tstring url;
+       make_url(bg.image.c_str(), bg.baseurl.c_str(), url);
+
+       //lock_images_cache();
+       images_map::iterator img_i = m_images.find(url.c_str());
+       if(img_i != m_images.end() && img_i->second)
+       {
+               GdkPixbuf *bgbmp = img_i->second;
+
+               GdkPixbuf *new_img;
+               if(bg.image_size.width != gdk_pixbuf_get_width(bgbmp) || bg.image_size.height != gdk_pixbuf_get_height(bgbmp))
+               {
+                       new_img = gdk_pixbuf_scale_simple(bgbmp, bg.image_size.width, bg.image_size.height, GDK_INTERP_BILINEAR);
+                       bgbmp = new_img;
+               }
+
+               cairo_surface_t* img = surface_from_pixbuf(bgbmp);
+               cairo_pattern_t *pattern = cairo_pattern_create_for_surface(img);
+               cairo_matrix_t flib_m;
+               cairo_matrix_init_identity(&flib_m);
+               cairo_matrix_translate(&flib_m, -bg.position_x, -bg.position_y);
+               cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+               cairo_pattern_set_matrix (pattern, &flib_m);
+
+               switch(bg.repeat)
+               {
+               case litehtml::background_repeat_no_repeat:
+                       draw_pixbuf(cr, bgbmp, bg.position_x, bg.position_y, gdk_pixbuf_get_width(bgbmp), gdk_pixbuf_get_height(bgbmp));
+                       break;
+
+               case litehtml::background_repeat_repeat_x:
+                       cairo_set_source(cr, pattern);
+                       cairo_rectangle(cr, bg.clip_box.left(), bg.position_y, bg.clip_box.width, gdk_pixbuf_get_height(bgbmp));
+                       cairo_fill(cr);
+                       break;
+
+               case litehtml::background_repeat_repeat_y:
+                       cairo_set_source(cr, pattern);
+                       cairo_rectangle(cr, bg.position_x, bg.clip_box.top(), gdk_pixbuf_get_width(bgbmp), bg.clip_box.height);
+                       cairo_fill(cr);
+                       break;
+
+               case litehtml::background_repeat_repeat:
+                       cairo_set_source(cr, pattern);
+                       cairo_rectangle(cr, bg.clip_box.left(), bg.clip_box.top(), bg.clip_box.width, bg.clip_box.height);
+                       cairo_fill(cr);
+                       break;
+               }
+
+               cairo_pattern_destroy(pattern);
+               cairo_surface_destroy(img);
+
+       }
+//     unlock_images_cache();
+       cairo_restore(cr);
+}
+
+void container_linux::make_url(const litehtml::tchar_t* url,   const litehtml::tchar_t* basepath, litehtml::tstring& out)
+{
+       out = url;
+}
+
+void container_linux::add_path_arc(cairo_t* cr, double x, double y, double rx, double ry, double a1, double a2, bool neg)
+{
+       if(rx > 0 && ry > 0)
+       {
+
+               cairo_save(cr);
+
+               cairo_translate(cr, x, y);
+               cairo_scale(cr, 1, ry / rx);
+               cairo_translate(cr, -x, -y);
+
+               if(neg)
+               {
+                       cairo_arc_negative(cr, x, y, rx, a1, a2);
+               } else
+               {
+                       cairo_arc(cr, x, y, rx, a1, a2);
+               }
+
+               cairo_restore(cr);
+       } else
+       {
+               cairo_move_to(cr, x, y);
+       }
+}
+
+void container_linux::draw_borders(litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root)
+{
+       cairo_t* cr = (cairo_t*) hdc;
+       cairo_save(cr);
+       apply_clip(cr);
+
+       cairo_new_path(cr);
+
+       int bdr_top             = 0;
+       int bdr_bottom  = 0;
+       int bdr_left    = 0;
+       int bdr_right   = 0;
+
+       if(borders.top.width != 0 && borders.top.style > litehtml::border_style_hidden)
+       {
+               bdr_top = (int) borders.top.width;
+       }
+       if(borders.bottom.width != 0 && borders.bottom.style > litehtml::border_style_hidden)
+       {
+               bdr_bottom = (int) borders.bottom.width;
+       }
+       if(borders.left.width != 0 && borders.left.style > litehtml::border_style_hidden)
+       {
+               bdr_left = (int) borders.left.width;
+       }
+       if(borders.right.width != 0 && borders.right.style > litehtml::border_style_hidden)
+       {
+               bdr_right = (int) borders.right.width;
+       }
+
+       // draw right border
+       if(bdr_right)
+       {
+               set_color(cr, borders.right.color);
+
+               double r_top    = borders.radius.top_right_x;
+               double r_bottom = borders.radius.bottom_right_x;
+
+               if(r_top)
+               {
+                       double end_angle        = 2 * M_PI;
+                       double start_angle      = end_angle - M_PI / 2.0  / ((double) bdr_top / (double) bdr_right + 1);
+
+                       add_path_arc(cr,
+                               draw_pos.right() - r_top,
+                               draw_pos.top() + r_top,
+                               r_top - bdr_right,
+                               r_top - bdr_right + (bdr_right - bdr_top),
+                               end_angle,
+                               start_angle, true);
+
+                       add_path_arc(cr,
+                               draw_pos.right() - r_top,
+                               draw_pos.top() + r_top,
+                               r_top,
+                               r_top,
+                               start_angle,
+                               end_angle, false);
+               } else
+               {
+                       cairo_move_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top);
+                       cairo_line_to(cr, draw_pos.right(), draw_pos.top());
+               }
+
+               if(r_bottom)
+               {
+                       cairo_line_to(cr, draw_pos.right(),     draw_pos.bottom() - r_bottom);
+
+                       double start_angle      = 0;
+                       double end_angle        = start_angle + M_PI / 2.0  / ((double) bdr_bottom / (double) bdr_right + 1);
+
+                       add_path_arc(cr,
+                               draw_pos.right() - r_bottom,
+                               draw_pos.bottom() - r_bottom,
+                               r_bottom,
+                               r_bottom,
+                               start_angle,
+                               end_angle, false);
+
+                       add_path_arc(cr,
+                               draw_pos.right() - r_bottom,
+                               draw_pos.bottom() - r_bottom,
+                               r_bottom - bdr_right,
+                               r_bottom - bdr_right + (bdr_right - bdr_bottom),
+                               end_angle,
+                               start_angle, true);
+               } else
+               {
+                       cairo_line_to(cr, draw_pos.right(),     draw_pos.bottom());
+                       cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.bottom() - bdr_bottom);
+               }
+
+               cairo_fill(cr);
+       }
+
+       // draw bottom border
+       if(bdr_bottom)
+       {
+               set_color(cr, borders.bottom.color);
+
+               double r_left   = borders.radius.bottom_left_x;
+               double r_right  = borders.radius.bottom_right_x;
+
+               if(r_left)
+               {
+                       double start_angle      = M_PI / 2.0;
+                       double end_angle        = start_angle + M_PI / 2.0  / ((double) bdr_left / (double) bdr_bottom + 1);
+
+                       add_path_arc(cr,
+                               draw_pos.left() + r_left,
+                               draw_pos.bottom() - r_left,
+                               r_left - bdr_bottom + (bdr_bottom - bdr_left),
+                               r_left - bdr_bottom,
+                               start_angle,
+                               end_angle, false);
+
+                       add_path_arc(cr,
+                               draw_pos.left() + r_left,
+                               draw_pos.bottom() - r_left,
+                               r_left,
+                               r_left,
+                               end_angle,
+                               start_angle, true);
+               } else
+               {
+                       cairo_move_to(cr, draw_pos.left(), draw_pos.bottom());
+                       cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.bottom() - bdr_bottom);
+               }
+
+               if(r_right)
+               {
+                       cairo_line_to(cr, draw_pos.right() - r_right,   draw_pos.bottom());
+
+                       double end_angle        = M_PI / 2.0;
+                       double start_angle      = end_angle - M_PI / 2.0  / ((double) bdr_right / (double) bdr_bottom + 1);
+
+                       add_path_arc(cr,
+                               draw_pos.right() - r_right,
+                               draw_pos.bottom() - r_right,
+                               r_right,
+                               r_right,
+                               end_angle,
+                               start_angle, true);
+
+                       add_path_arc(cr,
+                               draw_pos.right() - r_right,
+                               draw_pos.bottom() - r_right,
+                               r_right - bdr_bottom + (bdr_bottom - bdr_right),
+                               r_right - bdr_bottom,
+                               start_angle,
+                               end_angle, false);
+               } else
+               {
+                       cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.bottom() - bdr_bottom);
+                       cairo_line_to(cr, draw_pos.right(),     draw_pos.bottom());
+               }
+
+               cairo_fill(cr);
+       }
+
+       // draw top border
+       if(bdr_top)
+       {
+               set_color(cr, borders.top.color);
+
+               double r_left   = borders.radius.top_left_x;
+               double r_right  = borders.radius.top_right_x;
+
+               if(r_left)
+               {
+                       double end_angle        = M_PI * 3.0 / 2.0;
+                       double start_angle      = end_angle - M_PI / 2.0  / ((double) bdr_left / (double) bdr_top + 1);
+
+                       add_path_arc(cr,
+                               draw_pos.left() + r_left,
+                               draw_pos.top() + r_left,
+                               r_left,
+                               r_left,
+                               end_angle,
+                               start_angle, true);
+
+                       add_path_arc(cr,
+                               draw_pos.left() + r_left,
+                               draw_pos.top() + r_left,
+                               r_left - bdr_top + (bdr_top - bdr_left),
+                               r_left - bdr_top,
+                               start_angle,
+                               end_angle, false);
+               } else
+               {
+                       cairo_move_to(cr, draw_pos.left(), draw_pos.top());
+                       cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
+               }
+
+               if(r_right)
+               {
+                       cairo_line_to(cr, draw_pos.right() - r_right,   draw_pos.top() + bdr_top);
+
+                       double start_angle      = M_PI * 3.0 / 2.0;
+                       double end_angle        = start_angle + M_PI / 2.0  / ((double) bdr_right / (double) bdr_top + 1);
+
+                       add_path_arc(cr,
+                               draw_pos.right() - r_right,
+                               draw_pos.top() + r_right,
+                               r_right - bdr_top + (bdr_top - bdr_right),
+                               r_right - bdr_top,
+                               start_angle,
+                               end_angle, false);
+
+                       add_path_arc(cr,
+                               draw_pos.right() - r_right,
+                               draw_pos.top() + r_right,
+                               r_right,
+                               r_right,
+                               end_angle,
+                               start_angle, true);
+               } else
+               {
+                       cairo_line_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top);
+                       cairo_line_to(cr, draw_pos.right(),     draw_pos.top());
+               }
+
+               cairo_fill(cr);
+       }
+
+       // draw left border
+       if(bdr_left)
+       {
+               set_color(cr, borders.left.color);
+
+               double r_top    = borders.radius.top_left_x;
+               double r_bottom = borders.radius.bottom_left_x;
+
+               if(r_top)
+               {
+                       double start_angle      = M_PI;
+                       double end_angle        = start_angle + M_PI / 2.0  / ((double) bdr_top / (double) bdr_left + 1);
+
+                       add_path_arc(cr,
+                               draw_pos.left() + r_top,
+                               draw_pos.top() + r_top,
+                               r_top - bdr_left,
+                               r_top - bdr_left + (bdr_left - bdr_top),
+                               start_angle,
+                               end_angle, false);
+
+                       add_path_arc(cr,
+                               draw_pos.left() + r_top,
+                               draw_pos.top() + r_top,
+                               r_top,
+                               r_top,
+                               end_angle,
+                               start_angle, true);
+               } else
+               {
+                       cairo_move_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
+                       cairo_line_to(cr, draw_pos.left(), draw_pos.top());
+               }
+
+               if(r_bottom)
+               {
+                       cairo_line_to(cr, draw_pos.left(),      draw_pos.bottom() - r_bottom);
+
+                       double end_angle        = M_PI;
+                       double start_angle      = end_angle - M_PI / 2.0  / ((double) bdr_bottom / (double) bdr_left + 1);
+
+                       add_path_arc(cr,
+                               draw_pos.left() + r_bottom,
+                               draw_pos.bottom() - r_bottom,
+                               r_bottom,
+                               r_bottom,
+                               end_angle,
+                               start_angle, true);
+
+                       add_path_arc(cr,
+                               draw_pos.left() + r_bottom,
+                               draw_pos.bottom() - r_bottom,
+                               r_bottom - bdr_left,
+                               r_bottom - bdr_left + (bdr_left - bdr_bottom),
+                               start_angle,
+                               end_angle, false);
+               } else
+               {
+                       cairo_line_to(cr, draw_pos.left(),      draw_pos.bottom());
+                       cairo_line_to(cr, draw_pos.left() + bdr_left,   draw_pos.bottom() - bdr_bottom);
+               }
+
+               cairo_fill(cr);
+       }
+       cairo_restore(cr);
+}
+
+void container_linux::transform_text(litehtml::tstring& text, litehtml::text_transform tt)
+{
+
+}
+
+void container_linux::set_clip( const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius, bool valid_x, bool valid_y )
+{
+       litehtml::position clip_pos = pos;
+       litehtml::position client_pos;
+       get_client_rect(client_pos);
+       if(!valid_x)
+       {
+               clip_pos.x              = client_pos.x;
+               clip_pos.width  = client_pos.width;
+       }
+       if(!valid_y)
+       {
+               clip_pos.y              = client_pos.y;
+               clip_pos.height = client_pos.height;
+       }
+       m_clips.emplace_back(clip_pos, bdr_radius);
+}
+
+void container_linux::del_clip()
+{
+       if(!m_clips.empty())
+       {
+               m_clips.pop_back();
+       }
+}
+
+void container_linux::apply_clip( cairo_t* cr )
+{
+       for(const auto& clip_box : m_clips)
+       {
+               rounded_rectangle(cr, clip_box.box, clip_box.radius);
+               cairo_clip(cr);
+       }
+}
+
+void container_linux::draw_ellipse( cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color, int line_width )
+{
+       if(!cr) return;
+       cairo_save(cr);
+
+       apply_clip(cr);
+
+       cairo_new_path(cr);
+
+       cairo_translate (cr, x + width / 2.0, y + height / 2.0);
+       cairo_scale (cr, width / 2.0, height / 2.0);
+       cairo_arc (cr, 0, 0, 1, 0, 2 * M_PI);
+
+       set_color(cr, color);
+       cairo_set_line_width(cr, line_width);
+       cairo_stroke(cr);
+
+       cairo_restore(cr);
+}
+
+void container_linux::fill_ellipse( cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color )
+{
+       if(!cr) return;
+       cairo_save(cr);
+
+       apply_clip(cr);
+
+       cairo_new_path(cr);
+
+       cairo_translate (cr, x + width / 2.0, y + height / 2.0);
+       cairo_scale (cr, width / 2.0, height / 2.0);
+       cairo_arc (cr, 0, 0, 1, 0, 2 * M_PI);
+
+       set_color(cr, color);
+       cairo_fill(cr);
+
+       cairo_restore(cr);
+}
+
+void container_linux::clear_images()
+{
+/*     for(images_map::iterator i = m_images.begin(); i != m_images.end(); i++)
+       {
+               if(i->second)
+               {
+                       delete i->second;
+               }
+       }
+       m_images.clear();
+*/
+}
+
+const litehtml::tchar_t* container_linux::get_default_font_name() const
+{
+       return "Times New Roman";
+}
+
+std::shared_ptr<litehtml::element>     container_linux::create_element(const litehtml::tchar_t *tag_name,
+                                                                                                                                         const litehtml::string_map &attributes,
+                                                                                                                                         const std::shared_ptr<litehtml::document> &doc)
+{
+       return 0;
+}
+
+void container_linux::rounded_rectangle( cairo_t* cr, const litehtml::position &pos, const litehtml::border_radiuses &radius )
+{
+       cairo_new_path(cr);
+       if(radius.top_left_x)
+       {
+               cairo_arc(cr, pos.left() + radius.top_left_x, pos.top() + radius.top_left_x, radius.top_left_x, M_PI, M_PI * 3.0 / 2.0);
+       } else
+       {
+               cairo_move_to(cr, pos.left(), pos.top());
+       }
+
+       cairo_line_to(cr, pos.right() - radius.top_right_x, pos.top());
+
+       if(radius.top_right_x)
+       {
+               cairo_arc(cr, pos.right() - radius.top_right_x, pos.top() + radius.top_right_x, radius.top_right_x, M_PI * 3.0 / 2.0, 2.0 * M_PI);
+       }
+
+       cairo_line_to(cr, pos.right(), pos.bottom() - radius.bottom_right_x);
+
+       if(radius.bottom_right_x)
+       {
+               cairo_arc(cr, pos.right() - radius.bottom_right_x, pos.bottom() - radius.bottom_right_x, radius.bottom_right_x, 0, M_PI / 2.0);
+       }
+
+       cairo_line_to(cr, pos.left() - radius.bottom_left_x, pos.bottom());
+
+       if(radius.bottom_left_x)
+       {
+               cairo_arc(cr, pos.left() + radius.bottom_left_x, pos.bottom() - radius.bottom_left_x, radius.bottom_left_x, M_PI / 2.0, M_PI);
+       }
+}
+
+void container_linux::draw_pixbuf(cairo_t* cr, const GdkPixbuf *bmp, int x,    int y, int cx, int cy)
+{
+       cairo_save(cr);
+
+       {
+               cairo_matrix_t flib_m;
+               cairo_matrix_init(&flib_m, 1, 0, 0, -1, 0, 0);
+
+               if(cx != gdk_pixbuf_get_width(bmp) || cy != gdk_pixbuf_get_height(bmp))
+               {
+                       GdkPixbuf *new_img = gdk_pixbuf_scale_simple(bmp, cx, cy, GDK_INTERP_BILINEAR);
+                       gdk_cairo_set_source_pixbuf(cr, new_img, x, y);
+                       cairo_paint(cr);
+               } else
+               {
+                       gdk_cairo_set_source_pixbuf(cr, bmp, x, y);
+                       cairo_paint(cr);
+               }
+       }
+
+       cairo_restore(cr);
+}
+
+cairo_surface_t* container_linux::surface_from_pixbuf(const GdkPixbuf *bmp)
+{
+       cairo_surface_t* ret = NULL;
+
+       if(gdk_pixbuf_get_has_alpha(bmp))
+       {
+               ret = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, gdk_pixbuf_get_width(bmp), gdk_pixbuf_get_height(bmp));
+       } else
+       {
+               ret = cairo_image_surface_create(CAIRO_FORMAT_RGB24, gdk_pixbuf_get_width(bmp), gdk_pixbuf_get_height(bmp));
+       }
+
+//     Cairo::RefPtr<Cairo::Surface> surface(new Cairo::Surface(ret, false));
+//     Cairo::RefPtr<Cairo::Context> ctx = Cairo::Context::create(surface);
+//     Gdk::Cairo::set_source_pixbuf(ctx, bmp, 0.0, 0.0);
+       cairo_t *ctx = cairo_create(ret);
+       cairo_paint(ctx);
+
+       return ret;
+}
+
+void container_linux::get_media_features(litehtml::media_features& media) const
+{
+       litehtml::position client;
+    get_client_rect(client);
+       media.type                      = litehtml::media_type_screen;
+       media.width                     = client.width;
+       media.height            = client.height;
+       media.device_width      = gdk_screen_width();
+       media.device_height     = gdk_screen_height();
+       media.color                     = 8;
+       media.monochrome        = 0;
+       media.color_index       = 256;
+       media.resolution        = 96;
+}
+
+void container_linux::get_language(litehtml::tstring& language, litehtml::tstring& culture) const
+{
+       language = _t("en");
+       culture = _t("");
+}
+
+void container_linux::link(const std::shared_ptr<litehtml::document> &ptr, const litehtml::element::ptr& el)
+{
+
+}
diff --git a/src/plugins/litehtml_viewer/container_linux.h b/src/plugins/litehtml_viewer/container_linux.h
new file mode 100644 (file)
index 0000000..94eafab
--- /dev/null
@@ -0,0 +1,98 @@
+#pragma once
+
+#include <vector>
+#include <string>
+
+#include <cairo.h>
+#include <gtk/gtk.h>
+#include <fontconfig/fontconfig.h>
+
+#include "litehtml/litehtml.h"
+
+struct cairo_clip_box
+{
+       typedef std::vector<cairo_clip_box> vector;
+       litehtml::position      box;
+       litehtml::border_radiuses radius;
+
+       cairo_clip_box(const litehtml::position& vBox, litehtml::border_radiuses vRad)
+       {
+               box = vBox;
+               radius = vRad;
+       }
+
+       cairo_clip_box(const cairo_clip_box& val)
+       {
+               box = val.box;
+               radius = val.radius;
+       }
+       cairo_clip_box& operator=(const cairo_clip_box& val)
+       {
+               box = val.box;
+               radius = val.radius;
+               return *this;
+       }
+};
+
+struct cairo_font
+{
+       cairo_font_face_t*      font;
+       int                                     size;
+       bool                            underline;
+       bool                            strikeout;
+};
+
+class container_linux :        public litehtml::document_container
+{
+       typedef std::map<litehtml::tstring, GdkPixbuf* >        images_map;
+
+protected:
+       cairo_surface_t*                        m_temp_surface;
+       cairo_t*                                        m_temp_cr;
+       images_map                                      m_images;
+    cairo_clip_box::vector             m_clips;
+public:
+       container_linux(void);
+       virtual ~container_linux(void);
+
+       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) override;
+       virtual void                                            delete_font(litehtml::uint_ptr hFont) override;
+       virtual int                                             text_width(const litehtml::tchar_t* text, litehtml::uint_ptr hFont) override;
+       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) override;
+       virtual int                                             pt_to_px(int pt) override;
+       virtual int                                             get_default_font_size() const override;
+       virtual const litehtml::tchar_t*        get_default_font_name() const override;
+       virtual void                                            load_image(const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, bool redraw_on_ready) override;
+       virtual void                                            get_image_size(const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, litehtml::size& sz) override;
+       virtual void                                            draw_background(litehtml::uint_ptr hdc, const litehtml::background_paint& bg) override;
+       virtual void                                            draw_borders(litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root) override;
+       virtual void                                            draw_list_marker(litehtml::uint_ptr hdc, const litehtml::list_marker& marker) override;
+       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) override;
+       virtual void                                            get_media_features(litehtml::media_features& media) const override;
+       virtual void                                            get_language(litehtml::tstring& language, litehtml::tstring & culture) const override;
+       virtual void                                            link(const std::shared_ptr<litehtml::document> &ptr, const litehtml::element::ptr& el) override;
+
+
+       virtual void                                            transform_text(litehtml::tstring& text, litehtml::text_transform tt) override;
+       virtual void                                            set_clip(const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius, bool valid_x, bool valid_y) override;
+       virtual void                                            del_clip() override;
+
+       virtual void                                            make_url( const litehtml::tchar_t* url, const litehtml::tchar_t* basepath, litehtml::tstring& out );
+       virtual GdkPixbuf       *get_image(const litehtml::tchar_t* url, bool redraw_on_ready) = 0;
+
+       void                                                            clear_images();
+
+protected:
+       virtual void                                            draw_ellipse(cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color, int line_width);
+       virtual void                                            fill_ellipse(cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color);
+       virtual void                                            rounded_rectangle( cairo_t* cr, const litehtml::position &pos, const litehtml::border_radiuses &radius );
+
+private:
+       void                                                            apply_clip(cairo_t* cr);
+       void                                                            add_path_arc(cairo_t* cr, double x, double y, double rx, double ry, double a1, double a2, bool neg);
+       void                                                            set_color(cairo_t* cr, litehtml::web_color color)       { cairo_set_source_rgba(cr, color.red / 255.0, color.green / 255.0, color.blue / 255.0, color.alpha / 255.0); }
+       void                                                            draw_pixbuf(cairo_t* cr, const GdkPixbuf *bmp, int x, int y, int cx, int cy);
+       cairo_surface_t*                                        surface_from_pixbuf(const GdkPixbuf *bmp);
+};
diff --git a/src/plugins/litehtml_viewer/css.inc b/src/plugins/litehtml_viewer/css.inc
new file mode 100644 (file)
index 0000000..3dc2ad7
--- /dev/null
@@ -0,0 +1,326 @@
+"html { \
+    display: block; \
+    height:100%; \
+    width:100%; \
+       position: relative; \
+} \
+ \
+head { \
+    display: none \
+} \
+ \
+meta { \
+    display: none \
+} \
+ \
+title { \
+    display: none \
+} \
+ \
+link { \
+    display: none \
+} \
+ \
+style { \
+    display: none \
+} \
+ \
+script { \
+    display: none \
+} \
+ \
+body { \
+       display:block;  \
+       margin:8px;  \
+    height:100%; \
+    width:100%; \
+} \
+ \
+p { \
+       display:block;  \
+       margin-top:1em;  \
+       margin-bottom:1em; \
+} \
+ \
+b, strong { \
+       display:inline;  \
+       font-weight:bold; \
+} \
+ \
+i, em { \
+       display:inline;  \
+       font-style:italic; \
+} \
+ \
+center  \
+{ \
+       text-align:center; \
+       display:block; \
+} \
+ \
+a:link \
+{ \
+       text-decoration: underline; \
+       color: #00f; \
+       cursor: pointer; \
+} \
+ \
+h1, h2, h3, h4, h5, h6, div { \
+       display:block; \
+} \
+ \
+h1 { \
+       font-weight:bold;  \
+       margin-top:0.67em;  \
+       margin-bottom:0.67em;  \
+       font-size: 2em; \
+} \
+ \
+h2 { \
+       font-weight:bold;  \
+       margin-top:0.83em;  \
+       margin-bottom:0.83em;  \
+       font-size: 1.5em; \
+} \
+ \
+h3 { \
+       font-weight:bold;  \
+       margin-top:1em;  \
+       margin-bottom:1em;  \
+       font-size:1.17em; \
+} \
+ \
+h4 { \
+       font-weight:bold;  \
+       margin-top:1.33em;  \
+       margin-bottom:1.33em \
+} \
+ \
+h5 { \
+       font-weight:bold;  \
+       margin-top:1.67em;  \
+       margin-bottom:1.67em; \
+       font-size:.83em; \
+} \
+ \
+h6 { \
+       font-weight:bold;  \
+       margin-top:2.33em;  \
+       margin-bottom:2.33em; \
+       font-size:.67em; \
+}  \
+ \
+br { \
+       display:inline-block; \
+} \
+ \
+br[clear=\"all\"] \
+{ \
+       clear:both; \
+} \
+ \
+br[clear=\"left\"] \
+{ \
+       clear:left; \
+} \
+ \
+br[clear=\"right\"] \
+{ \
+       clear:right; \
+} \
+ \
+span { \
+       display:inline \
+} \
+ \
+img { \
+       display: inline-block; \
+} \
+ \
+img[align=\"right\"] \
+{ \
+       float: right; \
+} \
+ \
+img[align=\"left\"] \
+{ \
+       float: left; \
+} \
+ \
+hr { \
+    display: block; \
+    margin-top: 0.5em; \
+    margin-bottom: 0.5em; \
+    margin-left: auto; \
+    margin-right: auto; \
+    border-style: inset; \
+    border-width: 1px \
+} \
+ \
+ \
+/***************** TABLES ********************/ \
+ \
+table { \
+    display: table; \
+    border-collapse: separate; \
+    border-spacing: 2px; \
+    border-top-color:gray; \
+    border-left-color:gray; \
+    border-bottom-color:black; \
+    border-right-color:black; \
+} \
+ \
+tbody, tfoot, thead { \
+       display:table-row-group; \
+       vertical-align:middle; \
+} \
+ \
+tr { \
+    display: table-row; \
+    vertical-align: inherit; \
+    border-color: inherit; \
+} \
+ \
+td, th { \
+    display: table-cell; \
+    vertical-align: inherit; \
+    border-width:1px; \
+    padding:1px; \
+} \
+ \
+th { \
+       font-weight: bold; \
+} \
+ \
+table[border] { \
+    border-style:solid; \
+} \
+ \
+table[border|=0] { \
+    border-style:none; \
+} \
+ \
+table[border] td, table[border] th { \
+    border-style:solid; \
+    border-top-color:black; \
+    border-left-color:black; \
+    border-bottom-color:gray; \
+    border-right-color:gray; \
+} \
+ \
+table[border|=0] td, table[border|=0] th { \
+    border-style:none; \
+} \
+ \
+caption { \
+       display: table-caption; \
+} \
+ \
+td[nowrap], th[nowrap] { \
+       white-space:nowrap; \
+} \
+ \
+tt, code, kbd, samp { \
+    font-family: monospace \
+} \
+ \
+pre, xmp, plaintext, listing { \
+    display: block; \
+    font-family: monospace; \
+    white-space: pre; \
+    margin: 1em 0 \
+} \
+ \
+/***************** LISTS ********************/ \
+ \
+ul, menu, dir { \
+    display: block; \
+    list-style-type: disc; \
+    margin-top: 1em; \
+    margin-bottom: 1em; \
+    margin-left: 0; \
+    margin-right: 0; \
+    padding-left: 40px \
+} \
+ \
+ol { \
+    display: block; \
+    list-style-type: decimal; \
+    margin-top: 1em; \
+    margin-bottom: 1em; \
+    margin-left: 0; \
+    margin-right: 0; \
+    padding-left: 40px \
+} \
+ \
+li { \
+    display: list-item; \
+} \
+ \
+ul ul, ol ul { \
+    list-style-type: circle; \
+} \
+ \
+ol ol ul, ol ul ul, ul ol ul, ul ul ul { \
+    list-style-type: square; \
+} \
+ \
+dd { \
+    display: block; \
+    margin-left: 40px; \
+} \
+ \
+dl { \
+    display: block; \
+    margin-top: 1em; \
+    margin-bottom: 1em; \
+    margin-left: 0; \
+    margin-right: 0; \
+} \
+ \
+dt { \
+    display: block; \
+} \
+ \
+ol ul, ul ol, ul ul, ol ol { \
+    margin-top: 0; \
+    margin-bottom: 0 \
+} \
+ \
+blockquote { \
+       display: block; \
+       margin-top: 1em; \
+       margin-bottom: 1em; \
+       margin-left: 40px; \
+       margin-left: 40px; \
+} \
+ \
+/*********** FORM ELEMENTS ************/ \
+ \
+form { \
+       display: block; \
+       margin-top: 0em; \
+} \
+ \
+option { \
+       display: none; \
+} \
+ \
+input, textarea, keygen, select, button, isindex { \
+       margin: 0em; \
+       color: initial; \
+       line-height: normal; \
+       text-transform: none; \
+       text-indent: 0; \
+       text-shadow: none; \
+       display: inline-block; \
+} \
+input[type=\"hidden\"] { \
+       display: none; \
+} \
+ \
+ \
+article, aside, footer, header, hgroup, nav, section  \
+{ \
+       display: block; \
+}"
diff --git a/src/plugins/litehtml_viewer/lh_viewer.c b/src/plugins/litehtml_viewer/lh_viewer.c
new file mode 100644 (file)
index 0000000..73c1b69
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client
+ * Copyright(C) 1999-2015 the Claws Mail Team
+ * == Fancy Plugin ==
+ * This file Copyright (C) 2009-2015 Salvatore De Paolis
+ * <iwkse@claws-mail.org> and the Claws Mail Team
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write tothe Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#include "claws-features.h"
+#endif
+
+#include <codeconv.h>
+#include "lh_viewer.h"
+
+static gchar *content_types[] = { "text/html", NULL };
+
+MimeViewer *lh_viewer_create();
+
+MimeViewerFactory lh_viewer_factory = {
+       content_types,
+       0,
+       lh_viewer_create
+};
+
+static GtkWidget *lh_get_widget(MimeViewer *_viewer)
+{
+       debug_print("LH: get_widget\n");
+       LHViewer *viewer = (LHViewer *)_viewer;
+       return viewer->vbox;
+}
+
+static gchar *get_utf8_string(const gchar *string) {
+        gchar *utf8;
+        gsize length;
+        GError *error = NULL;
+
+       if (!g_utf8_validate(string, -1, NULL)) {
+               const gchar *cur_locale = conv_get_current_locale();
+               utf8 = g_convert(string, -1, "utf-8", cur_locale, NULL, &length, &error);
+               if (error) {
+                       debug_print("Failed convertion to current locale: %s", error->message);
+                       g_error_free(error);
+                       error = NULL;
+                       utf8 = g_convert(string, -1, "utf-8", "iso-8859-1", NULL, &length, &error);
+                       if (error) {
+                               debug_print("Charset detection failed");
+                               utf8 = g_strdup(string);
+                               g_error_free(error);
+                       }
+               }
+       } else {
+               utf8 = g_strdup(string);
+       }
+
+       return utf8;
+}
+
+static void lh_show_mimepart(MimeViewer *_viewer, const gchar *infole,
+               MimeInfo *partinfo)
+{
+       debug_print("LH: show_mimepart\n");
+       LHViewer *viewer = (LHViewer *)_viewer;
+
+       gchar *msgfile = procmime_get_tmp_file_name(partinfo);
+       debug_print("LH: msgfile '%s'\n", msgfile);
+
+       if (procmime_get_part(msgfile, partinfo) < 0) {
+               debug_print("LH: couldn't get MIME part file\n");
+               g_free(msgfile);
+               return;
+       }
+
+       gchar *contents, *utf8;
+       gsize length;
+       GError *error = NULL;
+       if (!g_file_get_contents(msgfile, &contents, &length, &error)) {
+               g_warning("LiteHTML viewer: couldn't read contents of file '%s': %s",
+                               msgfile, error->message);
+               g_error_free(error);
+               return;
+       } else {
+               utf8 = get_utf8_string(contents);
+               g_free(contents);
+       }
+
+       g_free(msgfile);
+
+       lh_widget_open_html(viewer->widget, utf8);
+       g_free(utf8);
+}
+
+static void lh_clear_viewer(MimeViewer *_viewer)
+{
+       debug_print("LH: clear_viewer\n");
+       LHViewer *viewer = (LHViewer *)_viewer;
+       lh_widget_clear(viewer->widget);
+}
+
+static void lh_destroy_viewer(MimeViewer *_viewer)
+{
+       debug_print("LH: destroy_viewer\n");
+
+       /* Just in case. */
+       lh_clear_viewer(_viewer);
+
+//     LHViewer *viewer = (LHViewer *)_viewer;
+//     lh_widget_destroy(viewer->widget);
+}
+
+/***************************************************************/
+MimeViewer *lh_viewer_create()
+{
+       debug_print("LH: viewer_create\n");
+
+       LHViewer *viewer = g_new0(LHViewer, 1);
+       viewer->mimeviewer.factory = &lh_viewer_factory;
+       viewer->widget = lh_widget_new();
+
+       viewer->mimeviewer.get_widget = lh_get_widget;
+       viewer->mimeviewer.show_mimepart = lh_show_mimepart;
+
+       viewer->mimeviewer.clear_viewer = lh_clear_viewer;
+       viewer->mimeviewer.destroy_viewer = lh_destroy_viewer;
+
+       viewer->vbox = gtk_vbox_new(FALSE, 0);
+
+       GtkWidget *w = lh_widget_get_widget(viewer->widget);
+       gtk_box_pack_start(GTK_BOX(viewer->vbox), w,
+                       TRUE, TRUE, 1);
+
+       gtk_widget_show_all(viewer->vbox);
+
+       return (MimeViewer *)viewer;
+}
+
diff --git a/src/plugins/litehtml_viewer/lh_viewer.h b/src/plugins/litehtml_viewer/lh_viewer.h
new file mode 100644 (file)
index 0000000..d733642
--- /dev/null
@@ -0,0 +1,12 @@
+#include <mimeview.h>
+
+#include "lh_widget_wrapped.h"
+
+MimeViewer *lh_viewer_create();
+
+typedef struct _LHViewer LHViewer;
+struct _LHViewer {
+       MimeViewer mimeviewer;
+       lh_widget_wrapped *widget;
+       GtkWidget *vbox;
+};
diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
new file mode 100644 (file)
index 0000000..a700b63
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client
+ * Copyright(C) 1999-2015 the Claws Mail Team
+ * == Fancy Plugin ==
+ * This file Copyright (C) 2009-2015 Salvatore De Paolis
+ * <iwkse@claws-mail.org> and the Claws Mail Team
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write tothe Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#include "claws-features.h"
+#endif
+
+#include "lh_widget.h"
+#include "lh_widget_wrapped.h"
+
+char master_css[] = {
+#include "css.inc"
+};
+
+static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
+               gpointer user_data);
+static void size_allocate_cb(GtkWidget *widget, GdkRectangle *allocation,
+               gpointer user_data);
+
+lh_widget::lh_widget()
+{
+       /* scrolled window */
+       m_scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(m_scrolled_window),
+                       GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+       g_signal_connect(m_scrolled_window, "size-allocate",
+                       G_CALLBACK(size_allocate_cb), this);
+
+       /* viewport */
+       GtkScrolledWindow *scw = GTK_SCROLLED_WINDOW(m_scrolled_window);
+       m_viewport = gtk_viewport_new(
+                       gtk_scrolled_window_get_hadjustment(scw),
+                       gtk_scrolled_window_get_vadjustment(scw));
+       gtk_container_add(GTK_CONTAINER(m_scrolled_window), m_viewport);
+
+       /* drawing area */
+       m_drawing_area = gtk_drawing_area_new();
+       gtk_container_add(GTK_CONTAINER(m_viewport), m_drawing_area);
+       g_signal_connect(m_drawing_area, "expose-event",
+                       G_CALLBACK(expose_event_cb), this);
+
+       gtk_widget_show_all(m_scrolled_window);
+
+       m_html = NULL;
+       m_rendered_width = 0;
+       m_context.load_master_stylesheet(master_css);
+}
+
+lh_widget::~lh_widget()
+{
+       g_object_unref(m_drawing_area);
+       m_drawing_area = NULL;
+       g_object_unref(m_scrolled_window);
+       m_scrolled_window = NULL;
+       m_html = NULL;
+}
+
+GtkWidget *lh_widget::get_widget() const
+{
+       return m_scrolled_window;
+}
+
+void lh_widget::set_caption(const litehtml::tchar_t* caption)
+{
+       g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget set_caption");
+       return;
+}
+
+void lh_widget::set_base_url(const litehtml::tchar_t* base_url)
+{
+       g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget set_base_url");
+       return;
+}
+
+void lh_widget::on_anchor_click(const litehtml::tchar_t* url, const litehtml::element::ptr& el)
+{
+       g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget on_anchor_click");
+       return;
+}
+
+void lh_widget::set_cursor(const litehtml::tchar_t* cursor)
+{
+       g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget set_cursor");
+       if (cursor == NULL)
+               return;
+}
+
+void lh_widget::import_css(litehtml::tstring& text, const litehtml::tstring& url, litehtml::tstring& baseurl)
+{
+       g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget import_css");
+       baseurl = master_css;
+}
+
+void lh_widget::get_client_rect(litehtml::position& client) const
+{
+       if (m_drawing_area == NULL)
+               return;
+
+       client.width = m_rendered_width;
+       client.height = m_height;
+       client.x = 0;
+       client.y = 0;
+
+//     g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget::get_client_rect: %dx%d",
+//                     client.width, client.height);
+}
+
+GdkPixbuf *lh_widget::get_image(const litehtml::tchar_t* url, bool redraw_on_ready)
+{
+       return NULL;
+}
+
+void lh_widget::open_html(const gchar *contents)
+{
+       m_html = litehtml::document::createFromString(contents, this, &m_context);
+       m_rendered_width = 0;
+       if (m_html != NULL) {
+               g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget::open_html created document");
+               redraw();
+       }
+}
+
+void lh_widget::draw(cairo_t *cr)
+{
+       double x1, x2, y1, y2;
+       double width, height;
+
+       if (m_html == NULL)
+               return;
+
+       cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
+
+       width = x2 - x1;
+       height = y2 - y1;
+
+       litehtml::position pos;
+       pos.width = (int)width;
+       pos.height = (int)height;
+       pos.x = (int)x1;
+       pos.y = (int)y1;
+
+       m_html->draw((litehtml::uint_ptr)cr, 0, 0, &pos);
+}
+
+void lh_widget::redraw()
+{
+       GtkAllocation rect;
+       gint width, height;
+       GdkWindow *gdkwin;
+       cairo_t *cr;
+
+       if (m_html == NULL) {
+               g_log(NULL, G_LOG_LEVEL_WARNING, "lh_widget::redraw: No document!");
+               return;
+       }
+
+       /* Get width of the viewport. */
+       gdkwin = gtk_viewport_get_view_window(GTK_VIEWPORT(m_viewport));
+       gdk_drawable_get_size(gdkwin, &width, NULL);
+
+       /* If the available width has changed, rerender the HTML content. */
+       if (m_rendered_width != width) {
+               g_log(NULL, G_LOG_LEVEL_MESSAGE,
+                               "lh_widget::redraw: width changed: %d != %d",
+                               m_rendered_width, width);
+
+               /* Update our internally stored width, mainly so that
+                * lh_widget::get_client_rect() gives correct width during the
+                * render. */
+               m_rendered_width = width;
+
+               /* Re-render HTML for this width. */
+               m_html->media_changed();
+               m_html->render(m_rendered_width);
+               g_log(NULL, G_LOG_LEVEL_MESSAGE, "render is %dx%d",
+                               m_html->width(), m_html->height());
+
+               /* Change drawing area's size to match what was rendered. */
+               gtk_widget_set_size_request(m_drawing_area,
+                               m_html->width(), m_html->height());
+       }
+
+       paint_white();
+
+       /* Paint the rendered HTML. */
+       gdkwin = gtk_widget_get_window(m_drawing_area);
+       if (gdkwin == NULL) {
+               g_log(NULL, G_LOG_LEVEL_WARNING, "lh_widget::redraw: No GdkWindow to draw on!");
+               return;
+       }
+       cr = gdk_cairo_create(GDK_DRAWABLE(gdkwin));
+       draw(cr);
+
+       cairo_destroy(cr);
+}
+
+void lh_widget::paint_white()
+{
+       GdkWindow *gdkwin = gtk_widget_get_window(m_drawing_area);
+       if (gdkwin == NULL) {
+               g_log(NULL, G_LOG_LEVEL_WARNING, "lh_widget::clear: No GdkWindow to draw on!");
+               return;
+       }
+       cairo_t *cr = gdk_cairo_create(GDK_DRAWABLE(gdkwin));
+
+       /* Paint white background. */
+       gint width, height;
+       gdk_drawable_get_size(gdkwin, &width, &height);
+       cairo_rectangle(cr, 0, 0, width, height);
+       cairo_set_source_rgb(cr, 255, 255, 255);
+       cairo_fill(cr);
+
+       cairo_destroy(cr);
+}
+void lh_widget::clear()
+{
+       paint_white();
+       m_rendered_width = 0;
+}
+
+static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
+               gpointer user_data)
+{
+       lh_widget *w = (lh_widget *)user_data;
+       w->redraw();
+       return FALSE;
+}
+
+static void size_allocate_cb(GtkWidget *widget, GdkRectangle *allocation,
+               gpointer user_data)
+{
+       lh_widget *w = (lh_widget *)user_data;
+
+       g_log(NULL, G_LOG_LEVEL_MESSAGE, "size_allocate_cb: %dx%d",
+                       allocation->width, allocation->height);
+
+       w->setHeight(allocation->height);
+       w->redraw();
+}
+
+///////////////////////////////////////////////////////////
+extern "C" {
+
+lh_widget_wrapped *lh_widget_new()
+{
+       return new lh_widget;
+}
+
+GtkWidget *lh_widget_get_widget(lh_widget_wrapped *w)
+{
+       return w->get_widget();
+}
+
+void lh_widget_open_html(lh_widget_wrapped *w, const gchar *path)
+{
+       w->open_html(path);
+}
+
+void lh_widget_clear(lh_widget_wrapped *w)
+{
+       w->clear();
+}
+
+void lh_widget_destroy(lh_widget_wrapped *w)
+{
+       delete w;
+}
+
+} /* extern "C" */
diff --git a/src/plugins/litehtml_viewer/lh_widget.h b/src/plugins/litehtml_viewer/lh_widget.h
new file mode 100644 (file)
index 0000000..4cdf8ce
--- /dev/null
@@ -0,0 +1,39 @@
+#include <gtk/gtk.h>
+#include <glib.h>
+
+#include "container_linux.h"
+
+class lh_widget : public container_linux
+{
+       public:
+               lh_widget();
+               ~lh_widget();
+
+               GtkWidget *get_widget() const;
+
+               void set_caption(const litehtml::tchar_t* caption);
+               void set_base_url(const litehtml::tchar_t* base_url);
+               void on_anchor_click(const litehtml::tchar_t* url, const litehtml::element::ptr& el);
+               void set_cursor(const litehtml::tchar_t* cursor);
+               void import_css(litehtml::tstring& text, const litehtml::tstring& url, litehtml::tstring& baseurl);
+               void get_client_rect(litehtml::position& client) const;
+               GdkPixbuf *get_image(const litehtml::tchar_t* url, bool redraw_on_ready);
+
+               gint height() const { return m_height; };
+               void setHeight(gint height) { m_height = height; };
+               void draw(cairo_t *cr);
+               void redraw();
+               void open_html(const gchar *contents);
+               void clear();
+
+       private:
+               void paint_white();
+
+               litehtml::document::ptr m_html;
+               gint m_rendered_width;
+               GtkWidget *m_drawing_area;
+               GtkWidget *m_scrolled_window;
+               GtkWidget *m_viewport;
+               litehtml::context m_context;
+               gint m_height;
+};
diff --git a/src/plugins/litehtml_viewer/lh_widget_wrapped.h b/src/plugins/litehtml_viewer/lh_widget_wrapped.h
new file mode 100644 (file)
index 0000000..521c7f4
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __LH_WIDGET_WRAPPED_H
+#define __LH_WIDGET_WRAPPED_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct lh_widget lh_widget_wrapped;
+
+lh_widget_wrapped *lh_widget_new();
+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);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __LH_WIDGET_WRAPPED_H */
diff --git a/src/plugins/litehtml_viewer/litehtml/LICENSE b/src/plugins/litehtml_viewer/litehtml/LICENSE
new file mode 100644 (file)
index 0000000..601e1c7
--- /dev/null
@@ -0,0 +1,24 @@
+Copyright (c) 2013, Yuri Kobets (tordex)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the <organization> nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/plugins/litehtml_viewer/litehtml/Makefile.am b/src/plugins/litehtml_viewer/litehtml/Makefile.am
new file mode 100644 (file)
index 0000000..b412926
--- /dev/null
@@ -0,0 +1,65 @@
+# Copyright 1999-2018 the Claws Mail team.
+# This file is part of Claws Mail package, and distributed under the
+# terms of the General Public License version 3 (or later).
+# See COPYING file for license details.
+
+#if BUILD_LITEHTML_VIEWER_PLUGIN
+noinst_LTLIBRARIES = liblitehtml.la
+#endif
+
+liblitehtml_la_CXXFLAGS = -std=c++11
+
+liblitehtml_la_SOURCES = \
+       attributes.h \
+       background.cpp background.h \
+       borders.h \
+       box.cpp box.h \
+       context.cpp context.h \
+       css_length.cpp css_length.h \
+       css_margins.h css_offsets.h css_position.h \
+       css_selector.cpp css_selector.h \
+       document.cpp document.h \
+       el_anchor.cpp el_anchor.h \
+       el_base.cpp el_base.h \
+       el_before_after.cpp el_before_after.h \
+       el_body.cpp el_body.h \
+       el_break.cpp el_break.h \
+       el_cdata.cpp el_cdata.h \
+       el_comment.cpp el_comment.h \
+       el_div.cpp el_div.h \
+       element.cpp element.h \
+       el_font.cpp el_font.h \
+       el_image.cpp el_image.h \
+       el_link.cpp el_link.h \
+       el_para.cpp el_para.h \
+       el_script.cpp el_script.h \
+       el_space.cpp el_space.h \
+       el_style.cpp el_style.h \
+       el_table.cpp el_table.h \
+       el_td.cpp el_td.h \
+       el_text.cpp el_text.h \
+       el_title.cpp el_title.h \
+       el_tr.cpp el_tr.h \
+       html.cpp html.h \
+       html_tag.cpp html_tag.h \
+       iterators.cpp iterators.h \
+       litehtml.h \
+       media_query.cpp media_query.h \
+       os_types.h \
+       style.cpp style.h \
+       stylesheet.cpp stylesheet.h \
+       table.cpp table.h \
+       types.h \
+       utf8_strings.cpp utf8_strings.h \
+       web_color.cpp web_color.h
+
+liblitehtml_la_LDFLAGS = \
+        -avoid-version -module \
+        $(LIBGUMBO_LIBS)
+
+liblitehtml_la_CPPFLAGS = \
+        $(LIBGUMBO_CFLAGS)
+
+EXTRA_DIST = \
+       LICENSE \
+       README.md
diff --git a/src/plugins/litehtml_viewer/litehtml/README.md b/src/plugins/litehtml_viewer/litehtml/README.md
new file mode 100644 (file)
index 0000000..86be96e
--- /dev/null
@@ -0,0 +1,42 @@
+#What is litehtml?\r
+\r
+**litehtml** is the lightweight HTML rendering engine with CSS2/CSS3 support. Note, **litehtml** itself does not draw any text, pictures or other graphics and **litehtml** does not depend of any image/draw/font library. You are free to use any library to draw images, fonts and any other graphics. **litehtml** just parses HTML/CSS and places the HTML elements into right position (renders HTML). To draw the html elemens you have to implement the simple callback interface [document_container](https://github.com/litehtml/litehtml/wiki/document_container). This interface is really simple, check it! Note, the [document_container](https://github.com/litehtml/litehtml/wiki/document_container) implementation is required to render HTML correctly. \r
+\r
+#Where litehtml can be used\r
+\r
+**litehtml** can be used when you need to show the html-formated texts or even to create a mini-browser, but the using full-featured html engine is not possible. Usually you don't need something like WebKit to show some html tooltips or html-formated text, **litehtml** is much better for these.\r
+\r
+##HTML Parser\r
+\r
+**litehtml** uses the [gumbo-parser](https://github.com/google/gumbo-parser) to parse HTML. Gumbo is an implementation of the HTML5 parsing algorithm implemented as a pure C99 library with no outside dependencies. It's designed to serve as a building block for other tools and libraries such as linters, validators, templating languages, and refactoring and analysis tools.\r
+\r
+##Compatibility\r
+\r
+**litehtml** is compatible with any platform suported C++ and STL. For Windows the MS Visual Studio 2013 is recommended. **litehtml** supports both utf-8 and unicode strings on Windows and utf-8 strings on Linux.\r
+\r
+##Support for HTML and CSS standards\r
+\r
+Unfortunately **litehtml** is not fully compatible with HTML/CSS standards. There are lots of work to do to make **litehtml** as well as modern browsers. But **litehtml** supports most HTML tags and CSS properties. You can find the list of supported CSS properties in  [this table](https://docs.google.com/spreadsheet/ccc?key=0AvHXl5n24PuhdHdELUdhaUl4OGlncXhDcDJuM1JpMnc&usp=sharing). In the most cases the html/css features supported by **litehtml** are enough. Right now **litehtml** supports the pages with very complex html/css designs. As example the pages created with [bootstrap framework](http://getbootstrap.com/) are usually well formated by **litehtml**.\r
+\r
+##Testing litehtml\r
+\r
+You can [download the simple browser](http://www.litehtml.com/download.html) (**litebrowser**) to test the **litehtml** rendering engine. \r
+\r
+The litebrowser source codes are available on GitHub:\r
+  * [For Windows](https://github.com/tordex/litebrowser)\r
+  * [For Linux](https://github.com/tordex/litebrowser-linux)\r
+\r
+##License\r
+\r
+**litehtml** is distributed under [New BSD License](http://opensource.org/licenses/BSD-3-Clause).\r
+The **gumbo-parser** is disributed under [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)\r
+\r
+##Support litehtml project\r
+\r
+If you think litehtml is amazing please consider a small donation:\r
+\r
+[ ![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif) ](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UHBQG6EAFCRBA)\r
+\r
+Bitcoin: **1CS1174GVSLbP33TBp8RFwqPS6KmQK6kLY**\r
+\r
+![BitCoin](https://www.tordex.com/assets/images/litehtml-bitcoin.png)\r
diff --git a/src/plugins/litehtml_viewer/litehtml/attributes.h b/src/plugins/litehtml_viewer/litehtml/attributes.h
new file mode 100644 (file)
index 0000000..ca1c9a7
--- /dev/null
@@ -0,0 +1,32 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/background.cpp b/src/plugins/litehtml_viewer/litehtml/background.cpp
new file mode 100644 (file)
index 0000000..87ce59e
--- /dev/null
@@ -0,0 +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
diff --git a/src/plugins/litehtml_viewer/litehtml/background.h b/src/plugins/litehtml_viewer/litehtml/background.h
new file mode 100644 (file)
index 0000000..e3fc2f6
--- /dev/null
@@ -0,0 +1,54 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/borders.h b/src/plugins/litehtml_viewer/litehtml/borders.h
new file mode 100644 (file)
index 0000000..a46a9f8
--- /dev/null
@@ -0,0 +1,296 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/box.cpp b/src/plugins/litehtml_viewer/litehtml/box.cpp
new file mode 100644 (file)
index 0000000..023d15c
--- /dev/null
@@ -0,0 +1,434 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/box.h b/src/plugins/litehtml_viewer/litehtml/box.h
new file mode 100644 (file)
index 0000000..d15a528
--- /dev/null
@@ -0,0 +1,117 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/context.cpp b/src/plugins/litehtml_viewer/litehtml/context.cpp
new file mode 100644 (file)
index 0000000..5f26269
--- /dev/null
@@ -0,0 +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
diff --git a/src/plugins/litehtml_viewer/litehtml/context.h b/src/plugins/litehtml_viewer/litehtml/context.h
new file mode 100644 (file)
index 0000000..ce62991
--- /dev/null
@@ -0,0 +1,16 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/css_length.cpp b/src/plugins/litehtml_viewer/litehtml/css_length.cpp
new file mode 100644 (file)
index 0000000..06d5580
--- /dev/null
@@ -0,0 +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
diff --git a/src/plugins/litehtml_viewer/litehtml/css_length.h b/src/plugins/litehtml_viewer/litehtml/css_length.h
new file mode 100644 (file)
index 0000000..078f9dd
--- /dev/null
@@ -0,0 +1,131 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/css_margins.h b/src/plugins/litehtml_viewer/litehtml/css_margins.h
new file mode 100644 (file)
index 0000000..fbe1d40
--- /dev/null
@@ -0,0 +1,35 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/css_offsets.h b/src/plugins/litehtml_viewer/litehtml/css_offsets.h
new file mode 100644 (file)
index 0000000..e4ca723
--- /dev/null
@@ -0,0 +1,35 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/css_position.h b/src/plugins/litehtml_viewer/litehtml/css_position.h
new file mode 100644 (file)
index 0000000..05f046d
--- /dev/null
@@ -0,0 +1,35 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/css_selector.cpp b/src/plugins/litehtml_viewer/litehtml/css_selector.cpp
new file mode 100644 (file)
index 0000000..a8e5f41
--- /dev/null
@@ -0,0 +1,266 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/css_selector.h b/src/plugins/litehtml_viewer/litehtml/css_selector.h
new file mode 100644 (file)
index 0000000..ae8f9c9
--- /dev/null
@@ -0,0 +1,274 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/document.cpp b/src/plugins/litehtml_viewer/litehtml/document.cpp
new file mode 100644 (file)
index 0000000..e9775aa
--- /dev/null
@@ -0,0 +1,930 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/document.h b/src/plugins/litehtml_viewer/litehtml/document.h
new file mode 100644 (file)
index 0000000..33287f4
--- /dev/null
@@ -0,0 +1,124 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_anchor.cpp b/src/plugins/litehtml_viewer/litehtml/el_anchor.cpp
new file mode 100644 (file)
index 0000000..b48b3f9
--- /dev/null
@@ -0,0 +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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_anchor.h b/src/plugins/litehtml_viewer/litehtml/el_anchor.h
new file mode 100644 (file)
index 0000000..4e351ff
--- /dev/null
@@ -0,0 +1,15 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_base.cpp b/src/plugins/litehtml_viewer/litehtml/el_base.cpp
new file mode 100644 (file)
index 0000000..928bc2e
--- /dev/null
@@ -0,0 +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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_base.h b/src/plugins/litehtml_viewer/litehtml/el_base.h
new file mode 100644 (file)
index 0000000..c4c388f
--- /dev/null
@@ -0,0 +1,14 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_before_after.cpp b/src/plugins/litehtml_viewer/litehtml/el_before_after.cpp
new file mode 100644 (file)
index 0000000..5c9ca34
--- /dev/null
@@ -0,0 +1,200 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_before_after.h b/src/plugins/litehtml_viewer/litehtml/el_before_after.h
new file mode 100644 (file)
index 0000000..5d0e9cb
--- /dev/null
@@ -0,0 +1,37 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_body.cpp b/src/plugins/litehtml_viewer/litehtml/el_body.cpp
new file mode 100644 (file)
index 0000000..7ada94b
--- /dev/null
@@ -0,0 +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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_body.h b/src/plugins/litehtml_viewer/litehtml/el_body.h
new file mode 100644 (file)
index 0000000..2248bbc
--- /dev/null
@@ -0,0 +1,14 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_break.cpp b/src/plugins/litehtml_viewer/litehtml/el_break.cpp
new file mode 100644 (file)
index 0000000..a798912
--- /dev/null
@@ -0,0 +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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_break.h b/src/plugins/litehtml_viewer/litehtml/el_break.h
new file mode 100644 (file)
index 0000000..dac1789
--- /dev/null
@@ -0,0 +1,14 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_cdata.cpp b/src/plugins/litehtml_viewer/litehtml/el_cdata.cpp
new file mode 100644 (file)
index 0000000..6e785d1
--- /dev/null
@@ -0,0 +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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_cdata.h b/src/plugins/litehtml_viewer/litehtml/el_cdata.h
new file mode 100644 (file)
index 0000000..e138f9d
--- /dev/null
@@ -0,0 +1,16 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_comment.cpp b/src/plugins/litehtml_viewer/litehtml/el_comment.cpp
new file mode 100644 (file)
index 0000000..3b46e2a
--- /dev/null
@@ -0,0 +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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_comment.h b/src/plugins/litehtml_viewer/litehtml/el_comment.h
new file mode 100644 (file)
index 0000000..5b8459d
--- /dev/null
@@ -0,0 +1,16 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_div.cpp b/src/plugins/litehtml_viewer/litehtml/el_div.cpp
new file mode 100644 (file)
index 0000000..ec63963
--- /dev/null
@@ -0,0 +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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_div.h b/src/plugins/litehtml_viewer/litehtml/el_div.h
new file mode 100644 (file)
index 0000000..54eed84
--- /dev/null
@@ -0,0 +1,14 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_font.cpp b/src/plugins/litehtml_viewer/litehtml/el_font.cpp
new file mode 100644 (file)
index 0000000..cef9aae
--- /dev/null
@@ -0,0 +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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_font.h b/src/plugins/litehtml_viewer/litehtml/el_font.h
new file mode 100644 (file)
index 0000000..9d5e4a1
--- /dev/null
@@ -0,0 +1,14 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_image.cpp b/src/plugins/litehtml_viewer/litehtml/el_image.cpp
new file mode 100644 (file)
index 0000000..4d5486b
--- /dev/null
@@ -0,0 +1,255 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_image.h b/src/plugins/litehtml_viewer/litehtml/el_image.h
new file mode 100644 (file)
index 0000000..670aa66
--- /dev/null
@@ -0,0 +1,23 @@
+#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
diff --git a/src/plugins/litehtml_viewer/litehtml/el_link.cpp b/src/plugins/litehtml_viewer/litehtml/el_link.cpp
new file mode 100644 (file)
index 0000000..709c399
--- /dev/null
@@ -0,0 +1,44 @@
+#include "html.h"\r
+#include "el_link.h"\r
+#include "document.h"\r
+\r
+\r<