[Commits] [SCM] claws branch, gtk3, updated. 3.16.0-740-g3c7b518

ticho at claws-mail.org ticho at claws-mail.org
Sat May 4 17:33:12 CEST 2019


The branch, gtk3 has been updated
       via  3c7b518b7b9e265a96a8bd437a8f3bddb6623dbc (commit)
       via  6e3ba6de4bffb9fb39db7e1b32dd8081cc31a15e (commit)
       via  3d290a4f13ebd849b25890bf62bea7e38a8ce618 (commit)
       via  4cb31b49abd02e934a8da0842cafc076fa0f4849 (commit)
       via  b007c1233c5f08639e9552077a5e26823f7b5ae6 (commit)
       via  7c6693d7085636df23c44d1b40895f0e43c1f166 (commit)
       via  85fae2899e6a93b13da4871d9b090001318901ad (commit)
       via  0ceccd127ac294f21719d3689a39d44e0490c48a (commit)
       via  5e478fb0483b044659cc11682790464244bd03d0 (commit)
       via  6cfa503d18ee2ae15c6f86a4ece4ea201576ecee (commit)
       via  e352c009cee756bd1b49aaca42717e64be9d695f (commit)
       via  0e508b34104481edd43a586c02e2d95799834d21 (commit)
       via  6f207b229121049cd3136b94432103196e9da15d (commit)
       via  25389c8db3e217aa1383f8c32d19de984fce261e (commit)
       via  f2915834e36233eec60a94e8dfe178e7dbaa7b18 (commit)
       via  79659144fcf27bb7cd71a5ac3e1a7790bb28be06 (commit)
       via  22a159866b8a9dfdf4aae6d8a10c5ef9e8efc7fc (commit)
       via  42231eff67ccb62b3cd278adeb85489f20e2b4c2 (commit)
       via  fa7135fa3b791697eefdaaccbfeb42cc413a10e4 (commit)
       via  8071229a71fabe20b16b5f0dfdb2cfe725b5e3c6 (commit)
       via  cd43a4956b861ad55e6fba21a264b795e8ee6584 (commit)
       via  3d209145f3b91fec635b5d956d56a79ab8059f90 (commit)
       via  f0dc8213f7d907be763c70bd8189f998ca914117 (commit)
       via  82106bb0655a5274f84674646948f6ea942994ec (commit)
       via  9d95039f9cb819d2a258627329cc61b952fb00d2 (commit)
       via  ab65f5037401bc78f5144034d8797bdef94bdb06 (commit)
       via  79bf393df1d293cf7ad78609744e5eed522a1680 (commit)
       via  f9d496bff63d513a265086a07601b186284907a5 (commit)
       via  4271751d2116073b731b163800844e6094f107df (commit)
       via  0fafa987e7f5f4f44fd67ae3c2f38a3a87226663 (commit)
       via  96d1595dcdbb49a87780adab389c829506461940 (commit)
       via  6e437d475fdf79fad55ff6c45b074b62cc2db8d5 (commit)
       via  a300f65525e509204fd133292badb6836b32dc11 (commit)
       via  44fff45e2c28ef5fb224abd0b344edb18e2a4f98 (commit)
       via  dc6e20c6ebc652f243676cb4bd4222babb0603ac (commit)
       via  bd0e8d8455d44450a709065824f268f32124f19a (commit)
       via  a75a6516bd962b780c7c56b07ac16ac53a2c577a (commit)
       via  03d8afe96798aca22400f693ceb7a42f0be3a9a2 (commit)
       via  b31dc41035cc54ea98cbcdeec51c6ecfd020849a (commit)
       via  8c1f502b438b009b8ef0ee2612a76923e994910d (commit)
       via  25a07eba8f796c029fa839037c2d9920799ed8e7 (commit)
       via  c24d165f1d242d0bda1800d042c19ae2d8218c85 (commit)
       via  822b482afa172bf7621a8c9b49706d8f697fc4d6 (commit)
       via  5446663475a6fe5881ae15f39cf503ace1cd984b (commit)
       via  d6e19f9d606e89e2d6eeca737623ef4b42da2947 (commit)
       via  882efa14e4b171edd5550ec98f23a14e251983c4 (commit)
       via  2ce3418fef6b233faf18abd7d67add1c1baf41d0 (commit)
       via  e905518e7224100e3bb0970c7615069c525ce56b (commit)
       via  f1227adc26b0eda9b4852578212398f5320ebe4d (commit)
       via  8f42ff225dfbafbf80c05754855a5c0d888528e5 (commit)
       via  636f075a395c3c010ff077410b429265b061d8bb (commit)
       via  5f100b9612fc42434d8793bc78a8241ec5fb7669 (commit)
       via  1e2ed07afeefa2bb748f273a8d3ad0519d78c54e (commit)
       via  6fdbe65294b86829889e2e583deaf63d664cf247 (commit)
       via  f9ce00fb2e4d4d8ba3c1fd1060fb360f8f19cdc7 (commit)
       via  2d53f85576e2db0783a121d7ceb83b5842226504 (commit)
       via  251d6bcffede3cac0453c377e84c9245cb0982b6 (commit)
       via  97c3cabcf0e75a5b279e876cb353e9d92f775849 (commit)
       via  93e2128494e10fce46955429e8d6eeeef61ea468 (commit)
       via  4ae8864929ee38e8fd8c4648850adbb8acf8a737 (commit)
       via  d38ab508ad6133ddaa9524318bd9fef6fd2a1846 (commit)
       via  e035ca4f0844b022399f82d323e3839c2f577e9a (commit)
       via  14b89d30c8ad53fb734a84a9696a71d46479b021 (commit)
       via  4f3a94b969648c6cd7703053ddcbd05fcb3d6c9a (commit)
       via  81379996cd48fdb4115189ed394d470697089dd4 (commit)
       via  ce6fa72069affbe12945f396fba10deec6bd064a (commit)
       via  59ca7ef79b2d22e033b8971f706b4618b71bdbd7 (commit)
       via  ff5ef90b73a3ca7b806455b218efde1fdbc69c58 (commit)
       via  95d249d866ea6dd069537df07ee5c3f76fcd5b20 (commit)
       via  b10324dea0905d1f014d51bf064628a41280fda1 (commit)
       via  3b4a311d506acffb87e0c057825dee7c91b7ed0c (commit)
       via  b629b57eb9d511fe15e1b418e7ed674e0764a65a (commit)
       via  cab9f7c7a3ec9134197188dbeacb1b2b9e6c19ec (commit)
       via  b17dda3046b44e615747ad59fbcc7b5c75053fd1 (commit)
       via  a73b1eec22aeb59262113ba7044081349da446db (commit)
       via  0ae08c27c278560b157259b62b09fb8244e96e53 (commit)
       via  fe13430b1687828b6b8c22672ea626dbd4812302 (commit)
       via  a534a94ff6a02d7e7a2e1a6f8e8463e40ae19dd9 (commit)
       via  4a51eec45e2a45ff531874cd8972f2786cba8e23 (commit)
       via  bfc55f7a4e6fe27aa9fa3086dc5930bad52943bb (commit)
       via  6a99577ab05c39eec8674af6c7786b5e1fd4b6a2 (commit)
       via  70eebdd11a9e2fa542425768cbffa1b5c57888f9 (commit)
       via  9b490d06142246b6dda2bf36484ff4e5a6bfec00 (commit)
       via  b524c3fadd2e9213f39582233cc258b7159e79db (commit)
       via  509ed390092c95640ccf71460be8594931b54edb (commit)
       via  ddfa3c24f186ce768680dd4b97433752a27a1210 (commit)
       via  59fdc07ddeff92ab869956e142de8716c973330e (commit)
       via  fd2dcd76f62fcb3baa34a427b712937d0fccb1a7 (commit)
       via  92074af6a19075e9865bfb573013b8ca48da73a2 (commit)
       via  c992286253f10e928362583d2fd2676e6c48f405 (commit)
       via  65af7e84abf09b87e60efb7714e1326b8bc01fe7 (commit)
       via  2aa6fdce4045d93cce4082ece711c8cc047b8fde (commit)
       via  d8761d2da6c6dcadff995348383afea0c127b19e (commit)
       via  fb775752ebf03a505c17f0674d73b220dc41a97c (commit)
       via  b38dbc64cb0dc06386314646f6def1a8b1495723 (commit)
       via  52b0e21c190fa02e9b5dde7cd95f8c9ee339288c (commit)
       via  78547fd63e16a76d656e668c17b7ae8975c46e12 (commit)
       via  08697167f45960f875d22f82e77bd5b633b8e5a0 (commit)
       via  1ce55620fdfa1b9d5b9e92e9a7a0d8f87ecc5fa3 (commit)
       via  4699946d4002084d50451d631f66b1df5bfbe41b (commit)
       via  52e13bbc7a9a703335c74fcd71202ef16fa18561 (commit)
       via  ffe5a18e30b56f526f29e42812b2e805797eadae (commit)
       via  9da4fcef8f3410c5df9b18659a47b6fa4d7f9d8b (commit)
       via  0695cdcb6cd24d13e462f158ac0368197b9c7b0f (commit)
       via  59bd8db042b4514e696c3fc39906130563f0691a (commit)
       via  7506d0eee5d92f5c58dcd284febd426c96f073be (commit)
       via  51cff5109d0943007f75a34fd26034b2b987ce11 (commit)
       via  85fab199401113cc31da29958727c709c0d09081 (commit)
       via  99fbe41c47ff6bc119986d476e21aa24515c0cd4 (commit)
       via  6c9f5e1b6350e8b510d39b91d9efa30902f14604 (commit)
       via  7855a65deb5fdc6a2db1fa1cb667dfe4b99f4f55 (commit)
       via  c0e2f35a7520634ddf723dc6954d5bf257652cbb (commit)
       via  04ecd4fcf4ae2e94fb023fb6f7ee60564d80fd18 (commit)
       via  6a2fdebfbf1c048f19fd082613157f3fd4741a0e (commit)
       via  29694b10b75c2e39c074c61e86fad7a79d211cfd (commit)
      from  9a699ab9debabae9ba223c66418464713a8570d8 (commit)

Summary of changes:
 configure.ac                                       |   80 +-
 po/de.po                                           |    2 +-
 src/action.c                                       |    9 +-
 src/addrbook.c                                     |    5 +-
 src/addressbook.c                                  |   90 +-
 src/addrharvest.c                                  |    4 +-
 src/addrindex.c                                    |    6 +-
 src/addritem.c                                     |    2 -
 src/common/mgutils.c                               |   98 -
 src/common/mgutils.h                               |    6 -
 src/common/session.c                               |    2 +-
 src/common/socket.c                                |   12 +-
 src/common/socket.h                                |    2 +-
 src/common/utils.h                                 |    1 +
 src/compose.c                                      |    4 +-
 src/editgroup.c                                    |    3 +-
 src/editjpilot.c                                   |    2 +-
 src/editldap.c                                     |    2 +-
 src/editldap_basedn.c                              |    2 +-
 src/etpan/imap-thread.c                            |   20 +-
 src/etpan/nntp-thread.c                            |   18 +-
 src/export.c                                       |    1 +
 src/image_viewer.c                                 |   53 +-
 src/imap.c                                         |   98 +-
 src/jpilot.c                                       |    4 +-
 src/ldapctrl.c                                     |    5 +-
 src/ldapquery.c                                    |   12 +-
 src/ldif.c                                         |   10 +-
 src/main.c                                         |   29 +-
 src/messageview.c                                  |   48 +-
 src/mimeview.c                                     |    6 +-
 src/mutt.c                                         |    8 +-
 src/pine.c                                         |   10 +-
 src/plugins/Makefile.am                            |    1 +
 src/plugins/fancy/fancy_viewer.c                   |   10 +-
 src/plugins/litehtml_viewer/Makefile.am            |   75 +
 src/plugins/litehtml_viewer/TODO                   |    5 +
 src/plugins/{fancy => litehtml_viewer}/claws.def   |    0
 src/plugins/litehtml_viewer/container_linux.cpp    |  706 +++
 src/plugins/litehtml_viewer/container_linux.h      |  114 +
 .../litehtml_viewer/container_linux_images.cpp     |  262 ++
 src/plugins/litehtml_viewer/css.inc                |  332 ++
 src/plugins/litehtml_viewer/http.cpp               |  111 +
 .../fancy_prefs.h => litehtml_viewer/http.h}       |   58 +-
 src/plugins/litehtml_viewer/lh_prefs.c             |  219 +
 .../fancy_prefs.h => litehtml_viewer/lh_prefs.h}   |   49 +-
 src/plugins/litehtml_viewer/lh_viewer.c            |  162 +
 .../{smime/smime.h => litehtml_viewer/lh_viewer.h} |   26 +-
 src/plugins/litehtml_viewer/lh_widget.cpp          |  644 +++
 src/plugins/litehtml_viewer/lh_widget.h            |   92 +
 src/plugins/litehtml_viewer/lh_widget_text.cpp     |  142 +
 .../lh_widget_wrapped.h}                           |   52 +-
 src/plugins/litehtml_viewer/litehtml/LICENSE       |   24 +
 src/plugins/litehtml_viewer/litehtml/Makefile.am   |   65 +
 src/plugins/litehtml_viewer/litehtml/README.md     |   42 +
 src/plugins/litehtml_viewer/litehtml/attributes.h  |   35 +
 .../litehtml_viewer/litehtml/background.cpp        |   79 +
 src/plugins/litehtml_viewer/litehtml/background.h  |   58 +
 src/plugins/litehtml_viewer/litehtml/borders.h     |  300 ++
 src/plugins/litehtml_viewer/litehtml/box.cpp       |  434 ++
 src/plugins/litehtml_viewer/litehtml/box.h         |  120 +
 src/plugins/litehtml_viewer/litehtml/context.cpp   |   12 +
 src/plugins/litehtml_viewer/litehtml/context.h     |   20 +
 .../litehtml_viewer/litehtml/css_length.cpp        |   54 +
 src/plugins/litehtml_viewer/litehtml/css_length.h  |  135 +
 src/plugins/litehtml_viewer/litehtml/css_margins.h |   39 +
 src/plugins/litehtml_viewer/litehtml/css_offsets.h |   39 +
 .../litehtml_viewer/litehtml/css_position.h        |   39 +
 .../litehtml_viewer/litehtml/css_selector.cpp      |  266 ++
 .../litehtml_viewer/litehtml/css_selector.h        |  278 ++
 src/plugins/litehtml_viewer/litehtml/document.cpp  |  930 ++++
 src/plugins/litehtml_viewer/litehtml/document.h    |  133 +
 src/plugins/litehtml_viewer/litehtml/el_anchor.cpp |   31 +
 src/plugins/litehtml_viewer/litehtml/el_anchor.h   |   19 +
 src/plugins/litehtml_viewer/litehtml/el_base.cpp   |   18 +
 src/plugins/litehtml_viewer/litehtml/el_base.h     |   18 +
 .../litehtml_viewer/litehtml/el_before_after.cpp   |  200 +
 .../litehtml_viewer/litehtml/el_before_after.h     |   41 +
 src/plugins/litehtml_viewer/litehtml/el_body.cpp   |   17 +
 src/plugins/litehtml_viewer/litehtml/el_body.h     |   18 +
 src/plugins/litehtml_viewer/litehtml/el_break.cpp  |   18 +
 src/plugins/litehtml_viewer/litehtml/el_break.h    |   18 +
 src/plugins/litehtml_viewer/litehtml/el_cdata.cpp  |   25 +
 src/plugins/litehtml_viewer/litehtml/el_cdata.h    |   20 +
 .../litehtml_viewer/litehtml/el_comment.cpp        |   25 +
 src/plugins/litehtml_viewer/litehtml/el_comment.h  |   20 +
 src/plugins/litehtml_viewer/litehtml/el_div.cpp    |   23 +
 src/plugins/litehtml_viewer/litehtml/el_div.h      |   18 +
 src/plugins/litehtml_viewer/litehtml/el_font.cpp   |   60 +
 src/plugins/litehtml_viewer/litehtml/el_font.h     |   18 +
 src/plugins/litehtml_viewer/litehtml/el_image.cpp  |  255 ++
 src/plugins/litehtml_viewer/litehtml/el_image.h    |   26 +
 src/plugins/litehtml_viewer/litehtml/el_link.cpp   |   44 +
 src/plugins/litehtml_viewer/litehtml/el_link.h     |   19 +
 src/plugins/litehtml_viewer/litehtml/el_para.cpp   |   23 +
 src/plugins/litehtml_viewer/litehtml/el_para.h     |   19 +
 src/plugins/litehtml_viewer/litehtml/el_script.cpp |   30 +
 src/plugins/litehtml_viewer/litehtml/el_script.h   |   21 +
 src/plugins/litehtml_viewer/litehtml/el_space.cpp  |   39 +
 src/plugins/litehtml_viewer/litehtml/el_space.h    |   20 +
 src/plugins/litehtml_viewer/litehtml/el_style.cpp  |   36 +
 src/plugins/litehtml_viewer/litehtml/el_style.h    |   21 +
 src/plugins/litehtml_viewer/litehtml/el_table.cpp  |  108 +
 src/plugins/litehtml_viewer/litehtml/el_table.h    |   27 +
 src/plugins/litehtml_viewer/litehtml/el_td.cpp     |   49 +
 src/plugins/litehtml_viewer/litehtml/el_td.h       |   18 +
 src/plugins/litehtml_viewer/litehtml/el_text.cpp   |  188 +
 src/plugins/litehtml_viewer/litehtml/el_text.h     |   38 +
 src/plugins/litehtml_viewer/litehtml/el_title.cpp  |   20 +
 src/plugins/litehtml_viewer/litehtml/el_title.h    |   19 +
 src/plugins/litehtml_viewer/litehtml/el_tr.cpp     |   51 +
 src/plugins/litehtml_viewer/litehtml/el_tr.h       |   19 +
 src/plugins/litehtml_viewer/litehtml/element.cpp   |  409 ++
 src/plugins/litehtml_viewer/litehtml/element.h     |  403 ++
 src/plugins/litehtml_viewer/litehtml/html.cpp      |  169 +
 src/plugins/litehtml_viewer/litehtml/html.h        |   96 +
 src/plugins/litehtml_viewer/litehtml/html_tag.cpp  | 4663 ++++++++++++++++++++
 src/plugins/litehtml_viewer/litehtml/html_tag.h    |  248 ++
 src/plugins/litehtml_viewer/litehtml/iterators.cpp |   94 +
 src/plugins/litehtml_viewer/litehtml/iterators.h   |   90 +
 src/plugins/litehtml_viewer/litehtml/litehtml.h    |   12 +
 .../litehtml_viewer/litehtml/media_query.cpp       |  432 ++
 src/plugins/litehtml_viewer/litehtml/media_query.h |   77 +
 src/plugins/litehtml_viewer/litehtml/os_types.h    |   86 +
 src/plugins/litehtml_viewer/litehtml/style.cpp     |  656 +++
 src/plugins/litehtml_viewer/litehtml/style.h       |   95 +
 .../litehtml_viewer/litehtml/stylesheet.cpp        |  219 +
 src/plugins/litehtml_viewer/litehtml/stylesheet.h  |   54 +
 src/plugins/litehtml_viewer/litehtml/table.cpp     |  566 +++
 src/plugins/litehtml_viewer/litehtml/table.h       |  241 +
 src/plugins/litehtml_viewer/litehtml/types.h       |  736 +++
 .../litehtml_viewer/litehtml/utf8_strings.cpp      |   97 +
 .../litehtml_viewer/litehtml/utf8_strings.h        |   51 +
 src/plugins/litehtml_viewer/litehtml/web_color.cpp |  256 ++
 src/plugins/litehtml_viewer/litehtml/web_color.h   |   61 +
 src/plugins/litehtml_viewer/plugin.c               |   81 +
 .../{address_keeper => litehtml_viewer}/plugin.def |    0
 src/plugins/{fancy => litehtml_viewer}/version.rc  |    0
 src/plugins/notification/notification_lcdproc.c    |    4 +-
 src/plugins/pgpcore/Makefile.am                    |    8 +-
 src/plugins/pgpcore/pgp_utils.c                    |  146 +-
 src/plugins/pgpcore/pgp_utils.h                    |    4 +-
 src/plugins/pgpcore/plugin.def                     |    2 -
 src/plugins/pgpcore/sgpgme.c                       |    4 +
 src/{ => plugins/pgpcore}/tests/Makefile.am        |    7 +-
 src/plugins/pgpcore/tests/pgp_utils_test.c         |   85 +
 src/plugins/pgpinline/claws.def                    |    1 +
 src/plugins/pgpinline/mypgpcore.def                |    2 -
 src/plugins/pgpinline/pgpinline.c                  |   12 +-
 src/plugins/pgpmime/claws.def                      |    1 +
 src/plugins/pgpmime/mypgpcore.def                  |    1 -
 src/plugins/pgpmime/pgpmime.c                      |    5 +-
 src/plugins/rssyl/libfeed/feeditem.c               |    4 +-
 src/plugins/rssyl/libfeed/feeditemenclosure.c      |    9 +
 src/plugins/rssyl/libfeed/feeditemenclosure.h      |    2 +
 src/plugins/rssyl/parse822.c                       |   28 +-
 src/plugins/rssyl/rssyl.c                          |    3 +-
 src/plugins/rssyl/rssyl_add_item.c                 |   26 +-
 src/plugins/rssyl/rssyl_deleted.c                  |    3 +-
 src/plugins/rssyl/rssyl_update_feed.c              |    2 +-
 src/plugins/smime/mypgpcore.def                    |    1 -
 src/plugins/smime/smime.c                          |    4 +-
 src/plugins/vcalendar/vcalendar.c                  |   18 +-
 src/procmime.c                                     |   80 +-
 src/procmime.h                                     |    8 +
 src/stock_pixmap.c                                 |    4 +-
 src/summaryview.c                                  |   21 +-
 src/textview.c                                     |  248 +-
 src/vcard.c                                        |   10 +-
 169 files changed, 18330 insertions(+), 828 deletions(-)
 create mode 100644 src/plugins/litehtml_viewer/Makefile.am
 create mode 100644 src/plugins/litehtml_viewer/TODO
 copy src/plugins/{fancy => litehtml_viewer}/claws.def (100%)
 create mode 100644 src/plugins/litehtml_viewer/container_linux.cpp
 create mode 100644 src/plugins/litehtml_viewer/container_linux.h
 create mode 100644 src/plugins/litehtml_viewer/container_linux_images.cpp
 create mode 100644 src/plugins/litehtml_viewer/css.inc
 create mode 100644 src/plugins/litehtml_viewer/http.cpp
 copy src/plugins/{fancy/fancy_prefs.h => litehtml_viewer/http.h} (52%)
 create mode 100644 src/plugins/litehtml_viewer/lh_prefs.c
 copy src/plugins/{fancy/fancy_prefs.h => litehtml_viewer/lh_prefs.h} (55%)
 create mode 100644 src/plugins/litehtml_viewer/lh_viewer.c
 copy src/plugins/{smime/smime.h => litehtml_viewer/lh_viewer.h} (57%)
 create mode 100644 src/plugins/litehtml_viewer/lh_widget.cpp
 create mode 100644 src/plugins/litehtml_viewer/lh_widget.h
 create mode 100644 src/plugins/litehtml_viewer/lh_widget_text.cpp
 copy src/plugins/{fancy/fancy_prefs.h => litehtml_viewer/lh_widget_wrapped.h} (51%)
 create mode 100644 src/plugins/litehtml_viewer/litehtml/LICENSE
 create mode 100644 src/plugins/litehtml_viewer/litehtml/Makefile.am
 create mode 100644 src/plugins/litehtml_viewer/litehtml/README.md
 create mode 100644 src/plugins/litehtml_viewer/litehtml/attributes.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/background.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/background.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/borders.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/box.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/box.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/context.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/context.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/css_length.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/css_length.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/css_margins.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/css_offsets.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/css_position.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/css_selector.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/css_selector.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/document.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/document.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_anchor.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_anchor.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_base.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_base.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_before_after.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_before_after.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_body.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_body.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_break.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_break.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_cdata.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_cdata.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_comment.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_comment.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_div.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_div.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_font.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_font.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_image.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_image.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_link.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_link.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_para.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_para.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_script.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_script.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_space.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_space.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_style.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_style.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_table.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_table.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_td.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_td.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_text.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_text.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_title.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_title.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_tr.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/el_tr.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/element.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/element.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/html.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/html.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/html_tag.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/html_tag.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/iterators.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/iterators.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/litehtml.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/media_query.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/media_query.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/os_types.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/style.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/style.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/stylesheet.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/stylesheet.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/table.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/table.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/types.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/utf8_strings.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/utf8_strings.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/web_color.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/web_color.h
 create mode 100644 src/plugins/litehtml_viewer/plugin.c
 copy src/plugins/{address_keeper => litehtml_viewer}/plugin.def (100%)
 copy src/plugins/{fancy => litehtml_viewer}/version.rc (100%)
 copy src/{ => plugins/pgpcore}/tests/Makefile.am (57%)
 create mode 100644 src/plugins/pgpcore/tests/pgp_utils_test.c


- Log -----------------------------------------------------------------
commit 3c7b518b7b9e265a96a8bd437a8f3bddb6623dbc
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sat May 4 17:32:16 2019 +0200

    Use "draw" signal to render the contents in litehtml plugin, instead of obsolete "expose-event" signal

diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index 71518ed..355e75f 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -45,7 +45,7 @@ char master_css[] = {
 #include "css.inc"
 };
 
-static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
+static gboolean draw_cb(GtkWidget *widget, cairo_t *cr,
 		gpointer user_data);
 static gboolean button_press_event(GtkWidget *widget, GdkEventButton *event,
 		gpointer user_data);
@@ -75,8 +75,8 @@ lh_widget::lh_widget()
 	/* 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);
+	g_signal_connect(m_drawing_area, "draw",
+			G_CALLBACK(draw_cb), this);
 	g_signal_connect(m_drawing_area, "motion_notify_event",
 			G_CALLBACK(motion_notify_event), this);
 	g_signal_connect(m_drawing_area, "button_press_event",
@@ -255,13 +255,13 @@ void lh_widget::redraw(gboolean force_render)
 				m_html->width(), m_html->height());
 	}
 
-	/* Paint the rendered HTML. */
 	gdkwin = gtk_widget_get_window(m_drawing_area);
 	if (gdkwin == NULL) {
 		g_warning("lh_widget::redraw: No GdkWindow to draw on!");
 		return;
 	}
 	cr = gdk_cairo_create(gdkwin);
+
 	draw(cr);
 
 	cairo_destroy(cr);
@@ -480,7 +480,7 @@ GdkPixbuf *lh_widget::get_local_image(const litehtml::tstring url) const
 }
 
 ////////////////////////////////////////////////
-static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
+static gboolean draw_cb(GtkWidget *widget, cairo_t *cr,
 		gpointer user_data)
 {
 	lh_widget *w = (lh_widget *)user_data;

commit 6e3ba6de4bffb9fb39db7e1b32dd8081cc31a15e
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sat May 4 17:17:39 2019 +0200

    Fix GTK3-related compile errors for litehtml plugin

diff --git a/src/plugins/litehtml_viewer/lh_prefs.c b/src/plugins/litehtml_viewer/lh_prefs.c
index c43abbd..8768ff4 100644
--- a/src/plugins/litehtml_viewer/lh_prefs.c
+++ b/src/plugins/litehtml_viewer/lh_prefs.c
@@ -104,7 +104,7 @@ static void create_lh_prefs_page(PrefsPage *page, GtkWindow *window,
 	GtkWidget *enable_remote_content;
 	GtkWidget *image_cache_size;
 	GtkWidget *default_font;
-	GtkObject *adj;
+	GtkAdjustment *adj;
 
 	vbox = gtk_vbox_new(FALSE, 3);
 	gtk_container_set_border_width(GTK_CONTAINER(vbox), VBOX_BORDER);
diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index 7f87b0d..71518ed 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -261,7 +261,7 @@ void lh_widget::redraw(gboolean force_render)
 		g_warning("lh_widget::redraw: No GdkWindow to draw on!");
 		return;
 	}
-	cr = gdk_cairo_create(GDK_DRAWABLE(gdkwin));
+	cr = gdk_cairo_create(gdkwin);
 	draw(cr);
 
 	cairo_destroy(cr);
@@ -274,12 +274,15 @@ void lh_widget::paint_white()
 		g_warning("lh_widget::clear: No GdkWindow to draw on!");
 		return;
 	}
-	cairo_t *cr = gdk_cairo_create(GDK_DRAWABLE(gdkwin));
+	cairo_t *cr = gdk_cairo_create(gdkwin);
 
 	/* Paint white background. */
 	gint width, height;
-	gdk_drawable_get_size(gdkwin, &width, &height);
-	cairo_rectangle(cr, 0, 0, width, height);
+	width = gdk_window_get_width(gdkwin);
+	height = gdk_window_get_height(gdkwin);
+	cairo_rectangle(cr, 0, 0,
+			gdk_window_get_width(gdkwin),
+			gdk_window_get_height(gdkwin));
 	cairo_set_source_rgb(cr, 255, 255, 255);
 	cairo_fill(cr);
 
diff --git a/src/stock_pixmap.c b/src/stock_pixmap.c
index 67cd3c3..c8e702d 100644
--- a/src/stock_pixmap.c
+++ b/src/stock_pixmap.c
@@ -1029,13 +1029,15 @@ GtkWidget *stock_pixmap_widget_with_overlay(StockPixmap icon,
 
 	if (pos != OVERLAY_NONE) {
 		stock_wid = stock_pixmap_widget(overlay);
+		g_object_ref_sink(stock_wid);
+
 		stock_pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(stock_wid));
 		g_object_ref(stock_pixbuf);
 		data->overlay_pixbuf = stock_pixbuf;
 		data->overlay_height = height;
 		data->overlay_width  = width;
 
-		gtk_widget_destroy(stock_wid);
+		g_object_unref(stock_wid);
 	}
 
 	data->position = pos;

commit 3d290a4f13ebd849b25890bf62bea7e38a8ce618
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Thu Apr 25 23:16:53 2019 +0200

    Fix two memory leaks in litehtml plugin

diff --git a/src/plugins/litehtml_viewer/lh_viewer.c b/src/plugins/litehtml_viewer/lh_viewer.c
index cf22959..a567d2c 100644
--- a/src/plugins/litehtml_viewer/lh_viewer.c
+++ b/src/plugins/litehtml_viewer/lh_viewer.c
@@ -107,13 +107,10 @@ static void lh_clear_viewer(MimeViewer *_viewer)
 
 static void lh_destroy_viewer(MimeViewer *_viewer)
 {
-	debug_print("LH: destroy_viewer\n");
-
-	/* Just in case. */
-	lh_clear_viewer(_viewer);
+	LHViewer *viewer = (LHViewer *)_viewer;
 
-//	LHViewer *viewer = (LHViewer *)_viewer;
-//	lh_widget_destroy(viewer->widget);
+	debug_print("LH: destroy_viewer\n");
+	g_free(viewer);
 }
 
 static void lh_print_viewer (MimeViewer *_viewer)
diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index b02fa61..7f87b0d 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -121,6 +121,7 @@ lh_widget::~lh_widget()
 	g_object_unref(m_scrolled_window);
 	m_scrolled_window = NULL;
 	m_html = NULL;
+	g_free(m_font_name);
 }
 
 GtkWidget *lh_widget::get_widget() const

commit 4cb31b49abd02e934a8da0842cafc076fa0f4849
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Thu Apr 25 22:40:31 2019 +0200

    Fix a memory leak in litehtml plugin's container_linux::load_image()

diff --git a/src/plugins/litehtml_viewer/container_linux_images.cpp b/src/plugins/litehtml_viewer/container_linux_images.cpp
index 5c6f7f6..5ef7c0c 100644
--- a/src/plugins/litehtml_viewer/container_linux_images.cpp
+++ b/src/plugins/litehtml_viewer/container_linux_images.cpp
@@ -109,7 +109,7 @@ void container_linux::load_image( const litehtml::tchar_t* src, const litehtml::
 	unlock_images_cache();
 
 	if (!found) {
-		struct FetchCtx *ctx = g_new(struct FetchCtx, 1);
+		struct FetchCtx *ctx;
 
 		/* Attached images can be loaded into cache right here. */
 		if (!strncmp(src, "cid:", 4)) {
@@ -128,6 +128,7 @@ void container_linux::load_image( const litehtml::tchar_t* src, const litehtml::
 
 		debug_print("allowing download of image from '%s'\n", src);
 
+		ctx = g_new(struct FetchCtx, 1);
 		ctx->url = g_strdup(url.c_str());
 		ctx->container = this;
 

commit b007c1233c5f08639e9552077a5e26823f7b5ae6
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Wed Apr 10 21:00:01 2019 +0200

    Fix incorrect logic in lh_widget::set_cursor().

diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index 4e6d785..b02fa61 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -295,35 +295,31 @@ void lh_widget::clear()
 
 void lh_widget::set_cursor(const litehtml::tchar_t* cursor)
 {
-	litehtml::element::ptr over_el;
+	litehtml::element::ptr over_el = m_html->over_element();
 	gint x, y;
-	GdkWindow *w = gdk_display_get_window_at_pointer(gdk_display_get_default(),
-			&x, &y);
 
-	if (w != gtk_widget_get_window(m_drawing_area))
-		return;
-
-	over_el = m_html->root()->get_element_by_point(x, y, x, y);
-
-	if (!over_el) {
-		m_over_element = NULL;
-		return;
+	if (m_showing_url &&
+			(over_el == NULL || over_el != m_over_element)) {
+		lh_widget_statusbar_pop();
+		m_showing_url = FALSE;
 	}
 
-	if (cursor && over_el) {
-		if (over_el != m_over_element) {
-			m_over_element = over_el;
-			update_cursor(cursor);
-		}
+	if (over_el != m_over_element) {
+		m_over_element = over_el;
+		update_cursor(cursor);
 	}
 }
 
 void lh_widget::update_cursor(const litehtml::tchar_t* cursor)
 {
-	const litehtml::tchar_t *href;
 	GdkCursorType cursType = GDK_ARROW;
+	const litehtml::tchar_t *href = get_href_at(m_over_element);
 
-	if (cursor == _t("pointer")) {
+	/* If there is a href, and litehtml is okay with showing a pointer
+	 * cursor ("pointer" or "auto"), set it, otherwise keep the
+	 * default arrow cursor */
+	if ((!strcmp(cursor, "pointer") || !strcmp(cursor, "auto")) &&
+			href != NULL) {
 		cursType = GDK_HAND2;
 	}
 
@@ -333,14 +329,8 @@ void lh_widget::update_cursor(const litehtml::tchar_t* cursor)
 		gdk_window_set_cursor(gtk_widget_get_window(m_drawing_area), gdk_cursor_new(cursType));
 	}
 
-	/* If it's an anchor, show its "href" attribute in statusbar,
-	 * otherwise clear statusbar. */
-	if (m_showing_url) {
-		lh_widget_statusbar_pop();
-		m_showing_url = FALSE;
-	}
-
-	if ((href = get_href_at(m_over_element)) != NULL) {
+	/* If there is a href, show it in statusbar */
+	if (href != NULL) {
 		lh_widget_statusbar_push(fullurl(href).c_str());
 		m_showing_url = TRUE;
 	}

commit 7c6693d7085636df23c44d1b40895f0e43c1f166
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Wed Apr 10 21:12:57 2019 +0200

    Add a getter for litehtml::document's m_over_element member
    
    This allows us to avoid some expensive GDK calls in
    lh_widget::set_cursor().

diff --git a/src/plugins/litehtml_viewer/litehtml/document.h b/src/plugins/litehtml_viewer/litehtml/document.h
index db30793..4484c92 100644
--- a/src/plugins/litehtml_viewer/litehtml/document.h
+++ b/src/plugins/litehtml_viewer/litehtml/document.h
@@ -90,6 +90,7 @@ namespace litehtml
 		bool							on_mouse_leave(position::vector& redraw_boxes);
 		litehtml::element::ptr			create_element(const tchar_t* tag_name, const string_map& attributes);
 		element::ptr					root();
+		const element::ptr					over_element() const;
 		void							get_fixed_boxes(position::vector& fixed_boxes);
 		void							add_fixed_box(const position& pos);
 		void							add_media_list(media_query_list::ptr list);
@@ -115,6 +116,10 @@ namespace litehtml
 	{
 		return m_root;
 	}
+	inline const element::ptr document::over_element() const
+	{
+		return m_over_element;
+	}
 	inline void document::add_tabular(const element::ptr& el)
 	{
 		m_tabular_elements.push_back(el);

commit 85fae2899e6a93b13da4871d9b090001318901ad
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Wed Apr 10 19:37:38 2019 +0200

    Make cursor and statusbar URL display smarter in litehtml plugin

diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index 64fdbdd..4e6d785 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -106,6 +106,8 @@ lh_widget::lh_widget()
 
 	m_partinfo = NULL;
 
+	m_showing_url = FALSE;
+
 	gtk_widget_set_events(m_drawing_area,
 			        GDK_BUTTON_RELEASE_MASK
 			      | GDK_BUTTON_PRESS_MASK
@@ -293,23 +295,35 @@ void lh_widget::clear()
 
 void lh_widget::set_cursor(const litehtml::tchar_t* cursor)
 {
-	if (cursor) {
-		if (m_cursor != cursor) {
-			m_cursor = cursor;
-			update_cursor();
+	litehtml::element::ptr over_el;
+	gint x, y;
+	GdkWindow *w = gdk_display_get_window_at_pointer(gdk_display_get_default(),
+			&x, &y);
+
+	if (w != gtk_widget_get_window(m_drawing_area))
+		return;
+
+	over_el = m_html->root()->get_element_by_point(x, y, x, y);
+
+	if (!over_el) {
+		m_over_element = NULL;
+		return;
+	}
+
+	if (cursor && over_el) {
+		if (over_el != m_over_element) {
+			m_over_element = over_el;
+			update_cursor(cursor);
 		}
 	}
 }
 
-void lh_widget::update_cursor()
+void lh_widget::update_cursor(const litehtml::tchar_t* cursor)
 {
-	gint x, y;
 	const litehtml::tchar_t *href;
-	GdkWindow *w = gdk_display_get_window_at_pointer(gdk_display_get_default(),
-			&x, &y);
 	GdkCursorType cursType = GDK_ARROW;
 
-	if (m_cursor == _t("pointer")) {
+	if (cursor == _t("pointer")) {
 		cursType = GDK_HAND2;
 	}
 
@@ -319,47 +333,58 @@ void lh_widget::update_cursor()
 		gdk_window_set_cursor(gtk_widget_get_window(m_drawing_area), gdk_cursor_new(cursType));
 	}
 
-	if (w != gtk_widget_get_window(m_drawing_area))
-		return;
-
 	/* If it's an anchor, show its "href" attribute in statusbar,
 	 * otherwise clear statusbar. */
-	if ((href = get_href_at(x, y)) != NULL) {
-		lh_widget_statusbar_push(fullurl(href).c_str());
-	} else {
+	if (m_showing_url) {
 		lh_widget_statusbar_pop();
+		m_showing_url = FALSE;
+	}
+
+	if ((href = get_href_at(m_over_element)) != NULL) {
+		lh_widget_statusbar_push(fullurl(href).c_str());
+		m_showing_url = TRUE;
 	}
 }
 
-const litehtml::tchar_t *lh_widget::get_href_at(const gint x, const gint y) const
+const litehtml::tchar_t *lh_widget::get_href_at(litehtml::element::ptr element) const
 {
-	litehtml::element::ptr over_el, el;
+	litehtml::element::ptr el;
 
-	if (m_html == NULL)
-		return NULL;
-
-	over_el = m_html->root()->get_element_by_point(x, y, x, y);
-	if (over_el == NULL)
+	if (element == NULL)
 		return NULL;
 
 	/* If it's not an anchor, check if it has a parent anchor
 	 * (e.g. it's an image within an anchor) and grab a pointer
 	 * to that. */
-	if (strcmp(over_el->get_tagName(), "a") && over_el->parent()) {
-		el = over_el->parent();
+	if (strcmp(element->get_tagName(), "a") && element->parent()) {
+		el = element->parent();
 		while (el && el != m_html->root() && strcmp(el->get_tagName(), "a")) {
 			el = el->parent();
 		}
 
-		if (el && el != m_html->root())
-			over_el = el;
-		else
+		if (!el || el == m_html->root())
 			return NULL;
+	} else {
+		el = element;
 	}
 
 	/* At this point, over_el is pointing at an anchor tag, so let's
 	 * grab its href attribute. */
-	return over_el->get_attr(_t("href"));
+	return el->get_attr(_t("href"));
+}
+
+const litehtml::tchar_t *lh_widget::get_href_at(const gint x, const gint y) const
+{
+	litehtml::element::ptr over_el, el;
+
+	if (m_html == NULL)
+		return NULL;
+
+	over_el = m_html->root()->get_element_by_point(x, y, x, y);
+	if (over_el == NULL)
+		return NULL;
+
+	return get_href_at(over_el);
 }
 
 void lh_widget::print()
diff --git a/src/plugins/litehtml_viewer/lh_widget.h b/src/plugins/litehtml_viewer/lh_widget.h
index e6b784a..9b95ef8 100644
--- a/src/plugins/litehtml_viewer/lh_widget.h
+++ b/src/plugins/litehtml_viewer/lh_widget.h
@@ -57,10 +57,11 @@ class lh_widget : public container_linux
 		void redraw(gboolean force_render);
 		void open_html(const gchar *contents);
 		void clear();
-		void update_cursor();
+		void update_cursor(const litehtml::tchar_t* cursor);
 		void update_font();
 		void print();
 
+		const litehtml::tchar_t *get_href_at(litehtml::element::ptr element) const;
 		const litehtml::tchar_t *get_href_at(const gint x, const gint y) const;
 		void popup_context_menu(const litehtml::tchar_t *url, GdkEventButton *event);
 		const litehtml::tstring fullurl(const litehtml::tchar_t *url) const;
@@ -82,7 +83,8 @@ class lh_widget : public container_linux
 		GtkWidget *m_context_menu;
 		litehtml::context m_context;
 		gint m_height;
-		litehtml::tstring m_cursor;
+		litehtml::element::ptr m_over_element;
+		gboolean m_showing_url;
 		MimeInfo *m_partinfo;
 
 		litehtml::tchar_t *m_font_name;

commit 0ceccd127ac294f21719d3689a39d44e0490c48a
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sat Mar 9 22:53:10 2019 +0100

    Always remove local images from Litehtml image cache
    
    Since their "url" in cache only includes MIME
    file name, they are not guaranteed to be unique
    across different messages.

diff --git a/src/plugins/litehtml_viewer/container_linux_images.cpp b/src/plugins/litehtml_viewer/container_linux_images.cpp
index 2c9d91d..5c6f7f6 100644
--- a/src/plugins/litehtml_viewer/container_linux_images.cpp
+++ b/src/plugins/litehtml_viewer/container_linux_images.cpp
@@ -214,7 +214,19 @@ gint container_linux::clear_images(gint desired_size)
 
 	lock_images_cache();
 
-	/* First, tally up size of all the stored GdkPixbufs and
+	/* First, remove all local images - the ones with "cid:"
+	 * URL. We will remove their list elements later. */
+	for (auto i = m_images.rbegin(); i != m_images.rend(); ++i) {
+		image *img = &(*i);
+
+		if (!strncmp(img->first.c_str(), "cid:", 4)) {
+			g_object_unref(img->second);
+			img->second = NULL;
+			num++;
+		}
+	}
+
+	/* Now tally up size of all the stored GdkPixbufs and
 	 * deallocate those which make the total size be above
 	 * the desired_size limit. We will remove their list
 	 * elements later. */

commit 5e478fb0483b044659cc11682790464244bd03d0
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sat Mar 9 22:32:32 2019 +0100

    Added support for local image attachments to the Litehtml plugin

diff --git a/src/plugins/litehtml_viewer/container_linux.cpp b/src/plugins/litehtml_viewer/container_linux.cpp
index 923ce76..ac0f40e 100644
--- a/src/plugins/litehtml_viewer/container_linux.cpp
+++ b/src/plugins/litehtml_viewer/container_linux.cpp
@@ -127,15 +127,14 @@ void container_linux::draw_background( litehtml::uint_ptr hdc, const litehtml::b
 	litehtml::tstring url;
 	make_url(bg.image.c_str(), bg.baseurl.c_str(), url);
 
-	lock_images_cache();
-	bool found = false;
 	const image *img_i = NULL;
 
+	lock_images_cache();
+
 	for (auto ii = m_images.cbegin(); ii != m_images.cend(); ++ii) {
 		const image *i = &(*ii);
 		if (i->first == url) {
 			img_i = i;
-			found = true;
 			break;
 		}
 	}
diff --git a/src/plugins/litehtml_viewer/container_linux.h b/src/plugins/litehtml_viewer/container_linux.h
index 627bda6..f35ffea 100644
--- a/src/plugins/litehtml_viewer/container_linux.h
+++ b/src/plugins/litehtml_viewer/container_linux.h
@@ -96,6 +96,7 @@ public:
 
 	void								add_image_to_cache(const gchar *url, GdkPixbuf *image);
 	virtual void				redraw(gboolean force_render) = 0;
+	virtual GdkPixbuf *get_local_image(const litehtml::tstring url) const = 0;
 
 protected:
 	virtual void						draw_ellipse(cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color, int line_width);
diff --git a/src/plugins/litehtml_viewer/container_linux_images.cpp b/src/plugins/litehtml_viewer/container_linux_images.cpp
index eeefd40..2c9d91d 100644
--- a/src/plugins/litehtml_viewer/container_linux_images.cpp
+++ b/src/plugins/litehtml_viewer/container_linux_images.cpp
@@ -32,13 +32,6 @@ static GdkPixbuf *lh_get_image(const litehtml::tchar_t* url)
 	GdkPixbuf *pixbuf = NULL;
 	http* http_loader = NULL;
 
-	if (!lh_prefs_get()->enable_remote_content) {
-		debug_print("blocking download of image from '%s'\n", url);
-		return NULL;
-	}
-
-	debug_print("allowing download of image from '%s'\n", url);
-
 	http_loader = new http();
 	GInputStream *image = http_loader->load_url(url, &error);
 
@@ -115,8 +108,26 @@ void container_linux::load_image( const litehtml::tchar_t* src, const litehtml::
 
 	unlock_images_cache();
 
-	if(!found) {
+	if (!found) {
 		struct FetchCtx *ctx = g_new(struct FetchCtx, 1);
+
+		/* Attached images can be loaded into cache right here. */
+		if (!strncmp(src, "cid:", 4)) {
+			GdkPixbuf *pixbuf = get_local_image(src);
+
+			if (pixbuf != NULL)
+				add_image_to_cache(src, pixbuf);
+
+			return;
+		}
+
+		if (!lh_prefs_get()->enable_remote_content) {
+			debug_print("blocking download of image from '%s'\n", src);
+			return;
+		}
+
+		debug_print("allowing download of image from '%s'\n", src);
+
 		ctx->url = g_strdup(url.c_str());
 		ctx->container = this;
 
diff --git a/src/plugins/litehtml_viewer/lh_viewer.c b/src/plugins/litehtml_viewer/lh_viewer.c
index e3e1fdb..cf22959 100644
--- a/src/plugins/litehtml_viewer/lh_viewer.c
+++ b/src/plugins/litehtml_viewer/lh_viewer.c
@@ -93,6 +93,7 @@ static void lh_show_mimepart(MimeViewer *_viewer, const gchar *infile,
 		return;
 	}
 
+	lh_widget_set_partinfo(viewer->widget, partinfo);
 	lh_widget_open_html(viewer->widget, utf8);
 	g_free(utf8);
 }
diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index 759b46e..64fdbdd 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -104,6 +104,8 @@ lh_widget::lh_widget()
 	m_font_name = NULL;
 	m_font_size = 0;
 
+	m_partinfo = NULL;
+
 	gtk_widget_set_events(m_drawing_area,
 			        GDK_BUTTON_RELEASE_MASK
 			      | GDK_BUTTON_PRESS_MASK
@@ -406,6 +408,58 @@ const litehtml::tstring lh_widget::fullurl(const litehtml::tchar_t *url) const
 	return _t(url);
 }
 
+void lh_widget::set_partinfo(MimeInfo *partinfo)
+{
+	m_partinfo = partinfo;
+}
+
+GdkPixbuf *lh_widget::get_local_image(const litehtml::tstring url) const
+{
+	GdkPixbuf *pixbuf;
+	const gchar *name;
+	MimeInfo *p = m_partinfo;
+
+	if (strncmp(url.c_str(), "cid:", 4) != 0) {
+		debug_print("lh_widget::get_local_image: '%s' is not a local URI, ignoring\n", url.c_str());
+		return NULL;
+	}
+
+	name = url.c_str() + 4;
+	debug_print("getting message part '%s'\n", name);
+
+	while ((p = procmime_mimeinfo_next(p)) != NULL) {
+		size_t len = strlen(name);
+
+		/* p->id is in format "<partname>" */
+		if (!strncasecmp(name, p->id + 1, len) &&
+				strlen(p->id) >= len + 2 &&
+				*(p->id + len + 1) == '>') {
+			GInputStream *stream;
+			GError *error = NULL;
+
+			stream = procmime_get_part_as_inputstream(p, &error);
+			if (error != NULL) {
+				g_warning("Couldn't get image MIME part: %s\n", error->message);
+				g_error_free(error);
+				return NULL;
+			}
+
+			pixbuf = gdk_pixbuf_new_from_stream(stream, NULL, &error);
+			g_object_unref(stream);
+			if (error != NULL) {
+				g_warning("Couldn't load image: %s\n", error->message);
+				g_error_free(error);
+				return NULL;
+			}
+
+			return pixbuf;
+		}
+	}
+
+	/* MIME part with requested name was not found */
+	return NULL;
+}
+
 ////////////////////////////////////////////////
 static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
 		gpointer user_data)
@@ -563,4 +617,9 @@ void lh_widget_print(lh_widget_wrapped *w) {
 	w->print();
 }
 
+void lh_widget_set_partinfo(lh_widget_wrapped *w, MimeInfo *partinfo)
+{
+	w->set_partinfo(partinfo);
+}
+
 } /* extern "C" */
diff --git a/src/plugins/litehtml_viewer/lh_widget.h b/src/plugins/litehtml_viewer/lh_widget.h
index 204d612..e6b784a 100644
--- a/src/plugins/litehtml_viewer/lh_widget.h
+++ b/src/plugins/litehtml_viewer/lh_widget.h
@@ -19,6 +19,8 @@
 #include <glib.h>
 #include <gio/gio.h>
 
+#include "procmime.h"
+
 #include "container_linux.h"
 
 struct pango_font
@@ -63,6 +65,9 @@ class lh_widget : public container_linux
 		void popup_context_menu(const litehtml::tchar_t *url, GdkEventButton *event);
 		const litehtml::tstring fullurl(const litehtml::tchar_t *url) const;
 
+		void set_partinfo(MimeInfo *partinfo);
+		GdkPixbuf *get_local_image(const litehtml::tstring url) const;
+
 		litehtml::document::ptr m_html;
 		litehtml::tstring m_clicked_url;
 		litehtml::tstring m_base_url;
@@ -78,6 +83,7 @@ class lh_widget : public container_linux
 		litehtml::context m_context;
 		gint m_height;
 		litehtml::tstring m_cursor;
+		MimeInfo *m_partinfo;
 
 		litehtml::tchar_t *m_font_name;
 		int m_font_size;
diff --git a/src/plugins/litehtml_viewer/lh_widget_wrapped.h b/src/plugins/litehtml_viewer/lh_widget_wrapped.h
index 8d3e2eb..2f15812 100644
--- a/src/plugins/litehtml_viewer/lh_widget_wrapped.h
+++ b/src/plugins/litehtml_viewer/lh_widget_wrapped.h
@@ -32,6 +32,7 @@ void lh_widget_destroy(lh_widget_wrapped *w);
 void lh_widget_statusbar_push(const gchar* msg);
 void lh_widget_statusbar_pop();
 void lh_widget_print(lh_widget_wrapped *w);
+void lh_widget_set_partinfo(lh_widget_wrapped *w, MimeInfo *partinfo);
 
 #ifdef __cplusplus
 } /* extern "C" */

commit 6cfa503d18ee2ae15c6f86a4ece4ea201576ecee
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Mar 5 23:00:52 2019 +0100

    Update callers of procmime_get_part_as_string()

diff --git a/src/plugins/litehtml_viewer/lh_viewer.c b/src/plugins/litehtml_viewer/lh_viewer.c
index 011bbe8..e3e1fdb 100644
--- a/src/plugins/litehtml_viewer/lh_viewer.c
+++ b/src/plugins/litehtml_viewer/lh_viewer.c
@@ -86,7 +86,7 @@ static void lh_show_mimepart(MimeViewer *_viewer, const gchar *infile,
 {
 	debug_print("LH: show_mimepart\n");
 	LHViewer *viewer = (LHViewer *)_viewer;
-	gchar *utf8 = procmime_get_part_as_string(partinfo);
+	gchar *utf8 = procmime_get_part_as_string(partinfo, TRUE);
 
 	if (utf8 == NULL) {
 		g_warning("LH: couldn't get MIME part file\n");
diff --git a/src/plugins/pgpinline/pgpinline.c b/src/plugins/pgpinline/pgpinline.c
index f0801c4..f69c791 100644
--- a/src/plugins/pgpinline/pgpinline.c
+++ b/src/plugins/pgpinline/pgpinline.c
@@ -115,7 +115,7 @@ static gboolean pgpinline_is_signed(MimeInfo *mimeinfo)
 			return data->is_signed;
 	}
 	
-	textdata = procmime_get_part_as_string(mimeinfo);
+	textdata = procmime_get_part_as_string(mimeinfo, TRUE);
 	if (!textdata)
 		return FALSE;
 	
@@ -164,7 +164,7 @@ static gint pgpinline_check_signature(MimeInfo *mimeinfo)
 	cm_return_val_if_fail(mimeinfo->privacy != NULL, 0);
 	data = (PrivacyDataPGP *) mimeinfo->privacy;
 
-	textdata = procmime_get_part_as_string(mimeinfo);
+	textdata = procmime_get_part_as_string(mimeinfo, TRUE);
 
 	if (!textdata) {
 		g_free(textdata);
@@ -265,7 +265,7 @@ static gboolean pgpinline_is_encrypted(MimeInfo *mimeinfo)
 		mimeinfo->subtype = g_strdup("plain");
 	}
 
-	textdata = procmime_get_part_as_string(mimeinfo);
+	textdata = procmime_get_part_as_string(mimeinfo, TRUE);
 	if (!textdata)
 		return FALSE;
 
@@ -317,7 +317,7 @@ static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo)
 		return NULL;
 	}
 
-	textdata = procmime_get_part_as_string(mimeinfo);
+	textdata = procmime_get_part_as_string(mimeinfo, TRUE);
 	if (!textdata) {
 		gpgme_release(ctx);
 		privacy_set_error(_("Couldn't get text data."));
diff --git a/src/plugins/pgpmime/pgpmime.c b/src/plugins/pgpmime/pgpmime.c
index bd64439..539c2f8 100644
--- a/src/plugins/pgpmime/pgpmime.c
+++ b/src/plugins/pgpmime/pgpmime.c
@@ -293,7 +293,7 @@ static gboolean pgpmime_is_encrypted(MimeInfo *mimeinfo)
 	if (g_ascii_strcasecmp(tmpinfo->subtype, "octet-stream"))
 		return FALSE;
 	
-	textdata = procmime_get_part_as_string(tmpinfo);
+	textdata = procmime_get_part_as_string(tmpinfo, TRUE);
 	if (!textdata)
 		return FALSE;
 	
diff --git a/src/plugins/vcalendar/vcalendar.c b/src/plugins/vcalendar/vcalendar.c
index 75acc11..1f2cae6 100644
--- a/src/plugins/vcalendar/vcalendar.c
+++ b/src/plugins/vcalendar/vcalendar.c
@@ -648,7 +648,7 @@ gchar *vcalviewer_get_uid_from_mimeinfo(MimeInfo *mimeinfo)
 	gchar *res = NULL;
 	VCalEvent *event = NULL;
 
-	compstr = procmime_get_part_as_string(mimeinfo);
+	compstr = procmime_get_part_as_string(mimeinfo, TRUE);
 	
 	event = vcal_get_event_from_ical(compstr, NULL);
 	if (event)

commit e352c009cee756bd1b49aaca42717e64be9d695f
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Mar 5 08:48:11 2019 +0100

    Require GLib >= 2.36 for Litehtml plugin

diff --git a/configure.ac b/configure.ac
index 6d4ff8c..3064610 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1135,7 +1135,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		a C++ compiler, cairo, fontconfig, gumbo, curl
+dnl Litehtml		a C++ compiler, >=glib-2.36, cairo, fontconfig, gumbo, curl
 dnl Libravatar:		libcurl
 dnl Notification:	optionally libnotify  unity/messaging-menu
 dnl 				   libcanberra_gtk hotkey
@@ -1641,6 +1641,8 @@ if test x"$enable_litehtml_viewer_plugin" != xno; then
         if test x"$HAVE_CXX" = xno; then
                 dependencies_missing="C++ compiler $dependencies_missing"
         fi
+        PKG_CHECK_EXISTS([glib-2.0 >= 2.36], [],
+                [dependencies_missing="glib-2.0 >= 2.36 $dependencies_missing"])
         if test x"$HAVE_CAIRO" = xno; then
                 dependencies_missing="cairo $dependencies_missing"
         fi

commit 0e508b34104481edd43a586c02e2d95799834d21
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Mar 5 08:40:32 2019 +0100

    Make Litehtml image loading non-blocking using threads

diff --git a/src/plugins/litehtml_viewer/Makefile.am b/src/plugins/litehtml_viewer/Makefile.am
index 81ce766..a1dcd91 100644
--- a/src/plugins/litehtml_viewer/Makefile.am
+++ b/src/plugins/litehtml_viewer/Makefile.am
@@ -40,6 +40,7 @@ litehtml_viewer_la_CFLAGS = -std=c99
 
 litehtml_viewer_la_SOURCES = \
 	container_linux.cpp \
+	container_linux_images.cpp \
 	plugin.c \
 	lh_prefs.c \
 	lh_viewer.c \
diff --git a/src/plugins/litehtml_viewer/container_linux.cpp b/src/plugins/litehtml_viewer/container_linux.cpp
index e64d413..923ce76 100644
--- a/src/plugins/litehtml_viewer/container_linux.cpp
+++ b/src/plugins/litehtml_viewer/container_linux.cpp
@@ -106,65 +106,6 @@ void container_linux::draw_list_marker( litehtml::uint_ptr hdc, const litehtml::
 	}
 }
 
-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);
-	bool found = false;
-
-	for (auto ii = m_images.cbegin(); ii != m_images.cend(); ++ii) {
-		const image *i = &(*ii);
-
-		if (!strcmp(i->first.c_str(), url.c_str())) {
-			found = true;
-			break;
-		}
-	}
-
-	if(!found)
-	{
-		try
-		{
-			GdkPixbuf *img = get_image(url.c_str(), true);
-			if(img)
-			{
-				m_images.push_back(std::make_pair(url, 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);
-	bool found = false;
-	const image *img = NULL;
-
-	for (auto ii = m_images.cbegin(); ii != m_images.cend(); ++ii) {
-		const image *i = &(*ii);
-		if (i->first == url) {
-			img = i;
-			found = true;
-			break;
-		}
-	}
-
-	if(img != NULL)
-	{
-		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;
@@ -654,64 +595,6 @@ void container_linux::fill_ellipse( cairo_t* cr, int x, int y, int width, int he
 	cairo_restore(cr);
 }
 
-void container_linux::clear_images()
-{
-	lock_images_cache();
-
-	for(auto i = m_images.begin(); i != m_images.end(); ++i) {
-		image *img = &(*i);
-
-		if (img->second) {
-			g_object_unref(img->second);
-		}
-	}
-
-	m_images.clear();
-
-	unlock_images_cache();
-}
-
-gint container_linux::clear_images(gint desired_size)
-{
-	gint size = 0;
-	gint num = 0;
-
-	lock_images_cache();
-
-	/* First, tally up size of all the stored GdkPixbufs and
-	 * deallocate those which make the total size be above
-	 * the desired_size limit. We will remove their list
-	 * elements later. */
-	for (auto i = m_images.rbegin(); i != m_images.rend(); ++i) {
-		image *img = &(*i);
-		gint cursize;
-
-		if (img->second == NULL)
-			continue;
-
-		cursize = gdk_pixbuf_get_byte_length(img->second);
-
-		if (size + cursize > desired_size) {
-			g_object_unref(img->second);
-			img->second = NULL;
-			num++;
-		} else {
-			size += cursize;
-		}
-	}
-
-	/* Remove elements whose GdkPixbuf pointers point to NULL. */
-	m_images.remove_if([&](image _img) -> bool {
-			if (_img.second == NULL)
-				return true;
-			return false;
-			});
-
-	unlock_images_cache();
-
-	return num;
-}
-
 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)
diff --git a/src/plugins/litehtml_viewer/container_linux.h b/src/plugins/litehtml_viewer/container_linux.h
index 0b5f006..627bda6 100644
--- a/src/plugins/litehtml_viewer/container_linux.h
+++ b/src/plugins/litehtml_viewer/container_linux.h
@@ -87,7 +87,6 @@ public:
 	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();
 
@@ -95,6 +94,9 @@ public:
 	 * starting from oldest stored. */
 	gint								clear_images(gint desired_size);
 
+	void								add_image_to_cache(const gchar *url, GdkPixbuf *image);
+	virtual void				redraw(gboolean force_render) = 0;
+
 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);
diff --git a/src/plugins/litehtml_viewer/container_linux_images.cpp b/src/plugins/litehtml_viewer/container_linux_images.cpp
new file mode 100644
index 0000000..eeefd40
--- /dev/null
+++ b/src/plugins/litehtml_viewer/container_linux_images.cpp
@@ -0,0 +1,238 @@
+/*
+ * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client
+ * Copyright(C) 2019 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 "common/utils.h"
+
+#include "container_linux.h"
+#include "http.h"
+#include "lh_prefs.h"
+
+static GdkPixbuf *lh_get_image(const litehtml::tchar_t* url)
+{
+	GError *error = NULL;
+	GdkPixbuf *pixbuf = NULL;
+	http* http_loader = NULL;
+
+	if (!lh_prefs_get()->enable_remote_content) {
+		debug_print("blocking download of image from '%s'\n", url);
+		return NULL;
+	}
+
+	debug_print("allowing download of image from '%s'\n", url);
+
+	http_loader = new http();
+	GInputStream *image = http_loader->load_url(url, &error);
+
+	if (error || !image) {
+		if (error) {
+			g_warning("lh_get_image: Could not create pixbuf %s",
+					error->message);
+			g_clear_error(&error);
+		}
+		goto theend;
+	}
+
+	pixbuf = gdk_pixbuf_new_from_stream(image, NULL, &error);
+	if (error) {
+		g_warning("lh_get_image: Could not create pixbuf %s",
+				error->message);
+		pixbuf = NULL;
+		g_clear_error(&error);
+	}
+
+theend:
+	if (http_loader) {
+		delete http_loader;
+	}
+
+	return pixbuf;
+}
+
+struct FetchCtx {
+	container_linux *container;
+	gchar *url;
+};
+
+static void get_image_threaded(GTask *task, gpointer source, gpointer task_data, GCancellable *cancellable)
+{
+	struct FetchCtx *ctx = (struct FetchCtx *)task_data;
+	GdkPixbuf *pixbuf = lh_get_image(ctx->url);
+
+	g_task_return_pointer(task, pixbuf, NULL);
+}
+
+static void get_image_callback(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+	GdkPixbuf *pixbuf;
+	struct FetchCtx *ctx = (struct FetchCtx *)user_data;
+
+	pixbuf = GDK_PIXBUF(g_task_propagate_pointer(G_TASK(res), NULL));
+
+	if (pixbuf != NULL) {
+		ctx->container->add_image_to_cache(ctx->url, pixbuf);
+		ctx->container->redraw(true);
+	}
+
+	g_free(ctx->url);
+	g_free(ctx);
+}
+
+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);
+	bool found = false;
+
+	lock_images_cache();
+
+	for (auto ii = m_images.cbegin(); ii != m_images.cend(); ++ii) {
+		const image *i = &(*ii);
+
+		if (!strcmp(i->first.c_str(), url.c_str())) {
+			found = true;
+			break;
+		}
+	}
+
+	unlock_images_cache();
+
+	if(!found) {
+		struct FetchCtx *ctx = g_new(struct FetchCtx, 1);
+		ctx->url = g_strdup(url.c_str());
+		ctx->container = this;
+
+		GTask *task = g_task_new(this, NULL, get_image_callback, ctx);
+		g_task_set_task_data(task, ctx, NULL);
+		g_task_run_in_thread(task, get_image_threaded);
+	} else {
+		debug_print("found image in cache: '%s'\n", url.c_str());
+	}
+}
+
+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);
+	bool found = false;
+	const image *img = NULL;
+
+	lock_images_cache();
+
+	for (auto ii = m_images.cbegin(); ii != m_images.cend(); ++ii) {
+		const image *i = &(*ii);
+		if (i->first == url) {
+			img = i;
+			found = true;
+			break;
+		}
+	}
+
+	if(img != NULL)
+	{
+		sz.width	= gdk_pixbuf_get_width(img->second);
+		sz.height	= gdk_pixbuf_get_height(img->second);
+	} else
+	{
+		sz.width	= 0;
+		sz.height	= 0;
+	}
+
+	unlock_images_cache();
+}
+
+void container_linux::add_image_to_cache(const gchar *url, GdkPixbuf *image)
+{
+	g_return_if_fail(url != NULL);
+	g_return_if_fail(image != NULL);
+
+	debug_print("adding image to cache: '%s'\n", url);
+	lock_images_cache();
+	m_images.push_back(std::make_pair(url, image));
+	unlock_images_cache();
+}
+void container_linux::lock_images_cache(void)
+{
+	g_rec_mutex_lock(&m_images_lock);
+}
+
+void container_linux::unlock_images_cache(void)
+{
+	g_rec_mutex_unlock(&m_images_lock);
+}
+
+void container_linux::clear_images()
+{
+	lock_images_cache();
+
+	for(auto i = m_images.begin(); i != m_images.end(); ++i) {
+		image *img = &(*i);
+
+		if (img->second) {
+			g_object_unref(img->second);
+		}
+	}
+
+	m_images.clear();
+
+	unlock_images_cache();
+}
+
+gint container_linux::clear_images(gint desired_size)
+{
+	gint size = 0;
+	gint num = 0;
+
+	lock_images_cache();
+
+	/* First, tally up size of all the stored GdkPixbufs and
+	 * deallocate those which make the total size be above
+	 * the desired_size limit. We will remove their list
+	 * elements later. */
+	for (auto i = m_images.rbegin(); i != m_images.rend(); ++i) {
+		image *img = &(*i);
+		gint cursize;
+
+		if (img->second == NULL)
+			continue;
+
+		cursize = gdk_pixbuf_get_byte_length(img->second);
+
+		if (size + cursize > desired_size) {
+			g_object_unref(img->second);
+			img->second = NULL;
+			num++;
+		} else {
+			size += cursize;
+		}
+	}
+
+	/* Remove elements whose GdkPixbuf pointers point to NULL. */
+	m_images.remove_if([&](image _img) -> bool {
+			if (_img.second == NULL)
+				return true;
+			return false;
+			});
+
+	unlock_images_cache();
+
+	return num;
+}
diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index eb3ec2e..759b46e 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -36,7 +36,6 @@
 #include "lh_prefs.h"
 #include "lh_widget.h"
 #include "lh_widget_wrapped.h"
-#include "http.h"
 
 extern "C" {
 const gchar *prefs_common_get_uri_cmd(void);
@@ -167,53 +166,6 @@ void lh_widget::get_client_rect(litehtml::position& client) const
 //			client.width, client.height);
 }
 
-GdkPixbuf *lh_widget::get_image(const litehtml::tchar_t* url, bool redraw_on_ready)
-{
-	GError *error = NULL;
-	GdkPixbuf *pixbuf = NULL;
-	http* http_loader = NULL;
-
-	if (!lh_prefs_get()->enable_remote_content) {
-		debug_print("blocking download of image from '%s'\n", url);
-		return NULL;
-	}
-
-	debug_print("Loading... %s\n", url);
-	gchar *msg = g_strdup_printf("Loading %s ...", url);
-        lh_widget_statusbar_push(msg);
-	g_free(msg);
-	
-	http_loader = new http();
-	GInputStream *image = http_loader->load_url(url, &error);
-    
-	if (error || !image) {
-	    if (error) {
-		g_warning("lh_widget::get_image: Could not create pixbuf %s", error->message);
-		g_clear_error(&error);
-	    }
-	    goto statusbar_pop;
-	}
-
-	pixbuf = gdk_pixbuf_new_from_stream(image, NULL, &error);
-	if (error) {
-	    g_warning("lh_widget::get_image: Could not create pixbuf %s", error->message);
-	    pixbuf = NULL;
-	    g_clear_error(&error);
-	}
-
-/*	if (redraw_on_ready) {
-		redraw();
-	}*/
-
-statusbar_pop:
-	lh_widget_statusbar_pop();
-	if (http_loader) {
-		delete http_loader;
-	}
-	
-	return pixbuf;
-}
-
 void lh_widget::open_html(const gchar *contents)
 {
 	gint num = clear_images(lh_prefs_get()->image_cache_size * 1024 * 1000);
@@ -234,7 +186,7 @@ void lh_widget::open_html(const gchar *contents)
 		adj = gtk_scrolled_window_get_vadjustment(
 				GTK_SCROLLED_WINDOW(m_scrolled_window));
 		gtk_adjustment_set_value(adj, 0.0);
-		redraw();
+		redraw(false);
 	}
 	lh_widget_statusbar_pop();
 }
@@ -261,7 +213,7 @@ void lh_widget::draw(cairo_t *cr)
 	m_html->draw((litehtml::uint_ptr)cr, 0, 0, &pos);
 }
 
-void lh_widget::redraw()
+void lh_widget::redraw(gboolean force_render)
 {
 	GtkAllocation rect;
 	gint width;
@@ -279,7 +231,7 @@ void lh_widget::redraw()
 	m_height = gdk_window_get_height(gdkwin);
 
 	/* If the available width has changed, rerender the HTML content. */
-	if (m_rendered_width != width) {
+	if (m_rendered_width != width || force_render) {
 		debug_print("lh_widget::redraw: width changed: %d != %d\n",
 				m_rendered_width, width);
 
@@ -459,7 +411,7 @@ static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
 		gpointer user_data)
 {
 	lh_widget *w = (lh_widget *)user_data;
-	w->redraw();
+	w->redraw(false);
 	return FALSE;
 }
 
diff --git a/src/plugins/litehtml_viewer/lh_widget.h b/src/plugins/litehtml_viewer/lh_widget.h
index 5ca1d38..204d612 100644
--- a/src/plugins/litehtml_viewer/lh_widget.h
+++ b/src/plugins/litehtml_viewer/lh_widget.h
@@ -44,7 +44,6 @@ class lh_widget : public container_linux
 		void import_css(litehtml::tstring& text, const litehtml::tstring& url, litehtml::tstring& baseurl);
 		void get_client_rect(litehtml::position& client) const;
 		inline const litehtml::tchar_t *get_default_font_name() const { return m_font_name; };
-		GdkPixbuf *get_image(const litehtml::tchar_t* url, bool redraw_on_ready);
 
 		inline int get_default_font_size() const { return m_font_size; };
 		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);
@@ -53,7 +52,7 @@ class lh_widget : public container_linux
 		void draw_text(litehtml::uint_ptr hdc, const litehtml::tchar_t* text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos);
 
 		void draw(cairo_t *cr);
-		void redraw();
+		void redraw(gboolean force_render);
 		void open_html(const gchar *contents);
 		void clear();
 		void update_cursor();

commit 6f207b229121049cd3136b94432103196e9da15d
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Mar 5 08:40:20 2019 +0100

    Add a mutex lock for Litehtml plugin image cache

diff --git a/src/plugins/litehtml_viewer/container_linux.cpp b/src/plugins/litehtml_viewer/container_linux.cpp
index 9a11757..e64d413 100644
--- a/src/plugins/litehtml_viewer/container_linux.cpp
+++ b/src/plugins/litehtml_viewer/container_linux.cpp
@@ -35,6 +35,7 @@ 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);
+	g_rec_mutex_init(&m_images_lock);
 }
 
 container_linux::~container_linux(void)
@@ -42,6 +43,7 @@ container_linux::~container_linux(void)
 	clear_images();
 	cairo_surface_destroy(m_temp_surface);
 	cairo_destroy(m_temp_cr);
+	g_rec_mutex_clear(&m_images_lock);
 }
 
 int container_linux::pt_to_px( int pt )
@@ -184,7 +186,7 @@ void container_linux::draw_background( litehtml::uint_ptr hdc, const litehtml::b
 	litehtml::tstring url;
 	make_url(bg.image.c_str(), bg.baseurl.c_str(), url);
 
-	//lock_images_cache();
+	lock_images_cache();
 	bool found = false;
 	const image *img_i = NULL;
 
@@ -245,7 +247,8 @@ void container_linux::draw_background( litehtml::uint_ptr hdc, const litehtml::b
 		cairo_surface_destroy(img);
 
 	}
-//	unlock_images_cache();
+
+	unlock_images_cache();
 	cairo_restore(cr);
 }
 
@@ -653,6 +656,8 @@ void container_linux::fill_ellipse( cairo_t* cr, int x, int y, int width, int he
 
 void container_linux::clear_images()
 {
+	lock_images_cache();
+
 	for(auto i = m_images.begin(); i != m_images.end(); ++i) {
 		image *img = &(*i);
 
@@ -662,6 +667,8 @@ void container_linux::clear_images()
 	}
 
 	m_images.clear();
+
+	unlock_images_cache();
 }
 
 gint container_linux::clear_images(gint desired_size)
@@ -669,6 +676,8 @@ gint container_linux::clear_images(gint desired_size)
 	gint size = 0;
 	gint num = 0;
 
+	lock_images_cache();
+
 	/* First, tally up size of all the stored GdkPixbufs and
 	 * deallocate those which make the total size be above
 	 * the desired_size limit. We will remove their list
@@ -698,6 +707,8 @@ gint container_linux::clear_images(gint desired_size)
 			return false;
 			});
 
+	unlock_images_cache();
+
 	return num;
 }
 
diff --git a/src/plugins/litehtml_viewer/container_linux.h b/src/plugins/litehtml_viewer/container_linux.h
index a68502d..0b5f006 100644
--- a/src/plugins/litehtml_viewer/container_linux.h
+++ b/src/plugins/litehtml_viewer/container_linux.h
@@ -61,7 +61,9 @@ protected:
 	cairo_surface_t*			m_temp_surface;
 	cairo_t*					m_temp_cr;
 	images_map					m_images;
-    cairo_clip_box::vector		m_clips;
+	GRecMutex					m_images_lock;
+	cairo_clip_box::vector				m_clips;
+
 public:
 	container_linux(void);
 	virtual ~container_linux(void);
@@ -104,4 +106,6 @@ private:
 	void								add_path_arc(cairo_t* cr, double x, double y, double rx, double ry, double a1, double a2, bool neg);
 	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);
+	void lock_images_cache(void);
+	void unlock_images_cache(void);
 };

commit 25389c8db3e217aa1383f8c32d19de984fce261e
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Mon Mar 4 21:37:23 2019 +0100

    Write missing prefs_done() in Litehtml plugin

diff --git a/src/plugins/litehtml_viewer/lh_prefs.c b/src/plugins/litehtml_viewer/lh_prefs.c
index 94acc4e..c43abbd 100644
--- a/src/plugins/litehtml_viewer/lh_prefs.c
+++ b/src/plugins/litehtml_viewer/lh_prefs.c
@@ -89,6 +89,7 @@ void lh_prefs_init(void)
 
 void lh_prefs_done(void)
 {
+	prefs_gtk_unregister_page((PrefsPage *) &lh_prefs_page);
 }
 
 static void create_lh_prefs_page(PrefsPage *page, GtkWindow *window,

commit f2915834e36233eec60a94e8dfe178e7dbaa7b18
Author: Michael Rasmussen <mir at datanom.net>
Date:   Sat Mar 2 13:25:13 2019 +0100

    Remove useless debug code. Add copyright
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/litehtml_viewer/container_linux.cpp b/src/plugins/litehtml_viewer/container_linux.cpp
index 15f8836..9a11757 100644
--- a/src/plugins/litehtml_viewer/container_linux.cpp
+++ b/src/plugins/litehtml_viewer/container_linux.cpp
@@ -1,9 +1,7 @@
 /*
  * 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 at claws-mail.org> and the Claws Mail Team
+ * Copyright(C) 2019 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
diff --git a/src/plugins/litehtml_viewer/container_linux.h b/src/plugins/litehtml_viewer/container_linux.h
index 8132bfb..a68502d 100644
--- a/src/plugins/litehtml_viewer/container_linux.h
+++ b/src/plugins/litehtml_viewer/container_linux.h
@@ -1,3 +1,20 @@
+/*
+ * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client
+ * Copyright(C) 2019 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.
+ */
+
 #pragma once
 
 #include <vector>
diff --git a/src/plugins/litehtml_viewer/http.cpp b/src/plugins/litehtml_viewer/http.cpp
index 21e53fc..dba8e6d 100644
--- a/src/plugins/litehtml_viewer/http.cpp
+++ b/src/plugins/litehtml_viewer/http.cpp
@@ -1,3 +1,20 @@
+/*
+ * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client
+ * Copyright(C) 2019 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"
 #endif
diff --git a/src/plugins/litehtml_viewer/http.h b/src/plugins/litehtml_viewer/http.h
index 0e36212..d533dc5 100644
--- a/src/plugins/litehtml_viewer/http.h
+++ b/src/plugins/litehtml_viewer/http.h
@@ -1,3 +1,20 @@
+/*
+ * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client
+ * Copyright(C) 2019 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.
+ */
+
 #include <glib.h>
 #include <glib/gstdio.h>
 #include <fcntl.h>
diff --git a/src/plugins/litehtml_viewer/lh_viewer.c b/src/plugins/litehtml_viewer/lh_viewer.c
index 93dd02c..011bbe8 100644
--- a/src/plugins/litehtml_viewer/lh_viewer.c
+++ b/src/plugins/litehtml_viewer/lh_viewer.c
@@ -1,9 +1,7 @@
 /*
  * 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 at claws-mail.org> and the Claws Mail Team
+ * Copyright(C) 2019 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
diff --git a/src/plugins/litehtml_viewer/lh_viewer.h b/src/plugins/litehtml_viewer/lh_viewer.h
index d733642..c22727c 100644
--- a/src/plugins/litehtml_viewer/lh_viewer.h
+++ b/src/plugins/litehtml_viewer/lh_viewer.h
@@ -1,3 +1,20 @@
+/*
+ * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client
+ * Copyright(C) 2019 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.
+ */
+
 #include <mimeview.h>
 
 #include "lh_widget_wrapped.h"
diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index e75ec4a..eb3ec2e 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -1,9 +1,7 @@
 /*
  * 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 at claws-mail.org> and the Claws Mail Team
+ * Copyright(C) 2019 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
@@ -474,7 +472,7 @@ static gboolean button_press_event(GtkWidget *widget, GdkEventButton *event,
 	if (w->m_html == NULL)
 		return false;
 
-	debug_print("lh_widget on_button_press_event\n");
+	//debug_print("lh_widget on_button_press_event\n");
 
 	if (event->type == GDK_2BUTTON_PRESS ||
 			event->type == GDK_3BUTTON_PRESS)
@@ -511,7 +509,6 @@ static gboolean motion_notify_event(GtkWidget *widget, GdkEventButton *event,
 
     if(w->m_html)
     {    
-	//if(m_cursor == _t("pointer"))
         if(w->m_html->on_mouse_over((int) event->x, (int) event->y, (int) event->x, (int) event->y, redraw_boxes))
         {
             for (auto& pos : redraw_boxes)
@@ -535,7 +532,7 @@ static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event,
 	if (w->m_html == NULL)
 		return false;
 
-	debug_print("lh_widget on_button_release_event\n");
+	//debug_print("lh_widget on_button_release_event\n");
 
 	if (event->type == GDK_2BUTTON_PRESS ||
 			event->type == GDK_3BUTTON_PRESS)
diff --git a/src/plugins/litehtml_viewer/lh_widget.h b/src/plugins/litehtml_viewer/lh_widget.h
index 55fc56d..5ca1d38 100644
--- a/src/plugins/litehtml_viewer/lh_widget.h
+++ b/src/plugins/litehtml_viewer/lh_widget.h
@@ -1,3 +1,20 @@
+/*
+ * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client
+ * Copyright(C) 2019 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.
+ */
+
 #include <gtk/gtk.h>
 #include <glib.h>
 #include <gio/gio.h>
diff --git a/src/plugins/litehtml_viewer/lh_widget_wrapped.h b/src/plugins/litehtml_viewer/lh_widget_wrapped.h
index 24dcb57..8d3e2eb 100644
--- a/src/plugins/litehtml_viewer/lh_widget_wrapped.h
+++ b/src/plugins/litehtml_viewer/lh_widget_wrapped.h
@@ -1,3 +1,20 @@
+/*
+ * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client
+ * Copyright(C) 2019 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.
+ */
+
 #ifndef __LH_WIDGET_WRAPPED_H
 #define __LH_WIDGET_WRAPPED_H
 
diff --git a/src/plugins/litehtml_viewer/plugin.c b/src/plugins/litehtml_viewer/plugin.c
index bfdc48e..32705d8 100644
--- a/src/plugins/litehtml_viewer/plugin.c
+++ b/src/plugins/litehtml_viewer/plugin.c
@@ -1,9 +1,7 @@
 /*
  * 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 at claws-mail.org> and the Claws Mail Team
+ * Copyright(C) 2019 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

commit 79659144fcf27bb7cd71a5ac3e1a7790bb28be06
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri Mar 1 14:52:22 2019 +0100

    Simplify Litehtml plugin's show_mimepart

diff --git a/src/plugins/litehtml_viewer/lh_viewer.c b/src/plugins/litehtml_viewer/lh_viewer.c
index fe5727f..93dd02c 100644
--- a/src/plugins/litehtml_viewer/lh_viewer.c
+++ b/src/plugins/litehtml_viewer/lh_viewer.c
@@ -83,36 +83,18 @@ static gchar *get_utf8_string(const gchar *string) {
 	return utf8;
 }
 
-static void lh_show_mimepart(MimeViewer *_viewer, const gchar *infole,
+static void lh_show_mimepart(MimeViewer *_viewer, const gchar *infile,
 		MimeInfo *partinfo)
 {
 	debug_print("LH: show_mimepart\n");
 	LHViewer *viewer = (LHViewer *)_viewer;
+	gchar *utf8 = procmime_get_part_as_string(partinfo);
 
-	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_clear_error(&error);
+	if (utf8 == NULL) {
+		g_warning("LH: couldn't get MIME part file\n");
 		return;
-	} else {
-		utf8 = get_utf8_string(contents);
-		g_free(contents);
 	}
 
-	g_free(msgfile);
-
 	lh_widget_open_html(viewer->widget, utf8);
 	g_free(utf8);
 }

commit 22a159866b8a9dfdf4aae6d8a10c5ef9e8efc7fc
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Mon Feb 25 23:19:24 2019 +0100

    Use Pango to render text in Litehtml plugin
    
    Since we're no longer using the "toy" cairo text API, we
    can now render all Unicode glyphs, and the code even ends
    up slightly simpler.
    
    The text-related Litehtml callbacks have been moved from
    container_linux to lh_widget class, and into a separate
    .cpp file.

diff --git a/src/plugins/litehtml_viewer/Makefile.am b/src/plugins/litehtml_viewer/Makefile.am
index d603a30..81ce766 100644
--- a/src/plugins/litehtml_viewer/Makefile.am
+++ b/src/plugins/litehtml_viewer/Makefile.am
@@ -44,6 +44,7 @@ litehtml_viewer_la_SOURCES = \
 	lh_prefs.c \
 	lh_viewer.c \
 	lh_widget.cpp \
+	lh_widget_text.cpp \
 	container_linux.h \
 	lh_prefs.h \
 	lh_viewer.h \
diff --git a/src/plugins/litehtml_viewer/container_linux.cpp b/src/plugins/litehtml_viewer/container_linux.cpp
index a2b1908..15f8836 100644
--- a/src/plugins/litehtml_viewer/container_linux.cpp
+++ b/src/plugins/litehtml_viewer/container_linux.cpp
@@ -46,169 +46,6 @@ container_linux::~container_linux(void)
 	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, ",");
-	if (! fonts.empty()) {
-	    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);
-
-	if (fnt) {
-	    cairo_set_font_size(m_temp_cr, fnt->size);
-	    cairo_set_font_face(m_temp_cr, fnt->font);
-	}
-	cairo_text_extents_t ext;
-	cairo_text_extents(m_temp_cr, text, &ext);
-
-	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);
-
-	if (fnt) {
-	    cairo_set_font_face(cr, fnt->font);
-	    cairo_set_font_size(cr, fnt->size);
-	}
-	cairo_font_extents_t ext;
-	cairo_font_extents(cr, &ext);
-
-	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) {
-	    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();
diff --git a/src/plugins/litehtml_viewer/container_linux.h b/src/plugins/litehtml_viewer/container_linux.h
index 43a917c..8132bfb 100644
--- a/src/plugins/litehtml_viewer/container_linux.h
+++ b/src/plugins/litehtml_viewer/container_linux.h
@@ -35,14 +35,6 @@ struct cairo_clip_box
 	}
 };
 
-struct cairo_font
-{
-	cairo_font_face_t*	font;
-	int					size;
-	bool				underline;
-	bool				strikeout;
-};
-
 class container_linux :	public litehtml::document_container
 {
 	typedef std::pair<litehtml::tstring, GdkPixbuf*> image;
@@ -57,10 +49,6 @@ 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 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;
@@ -92,11 +80,11 @@ 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 );
+	void								apply_clip(cairo_t* cr);
+	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); }
 
 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/lh_widget.h b/src/plugins/litehtml_viewer/lh_widget.h
index da2dc7f..55fc56d 100644
--- a/src/plugins/litehtml_viewer/lh_widget.h
+++ b/src/plugins/litehtml_viewer/lh_widget.h
@@ -4,6 +4,13 @@
 
 #include "container_linux.h"
 
+struct pango_font
+{
+	PangoFontDescription *font;
+	bool underline;
+	bool strikethrough;
+};
+
 class lh_widget : public container_linux
 {
 	public:
@@ -20,9 +27,14 @@ class lh_widget : public container_linux
 		void import_css(litehtml::tstring& text, const litehtml::tstring& url, litehtml::tstring& baseurl);
 		void get_client_rect(litehtml::position& client) const;
 		inline const litehtml::tchar_t *get_default_font_name() const { return m_font_name; };
-		inline int get_default_font_size() const { return m_font_size; };
 		GdkPixbuf *get_image(const litehtml::tchar_t* url, bool redraw_on_ready);
 
+		inline int get_default_font_size() const { return m_font_size; };
+		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);
+		void delete_font(litehtml::uint_ptr hFont);
+		int text_width(const litehtml::tchar_t* text, litehtml::uint_ptr hFont);
+		void draw_text(litehtml::uint_ptr hdc, const litehtml::tchar_t* text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos);
+
 		void draw(cairo_t *cr);
 		void redraw();
 		void open_html(const gchar *contents);
diff --git a/src/plugins/litehtml_viewer/lh_widget_text.cpp b/src/plugins/litehtml_viewer/lh_widget_text.cpp
new file mode 100644
index 0000000..ed29055
--- /dev/null
+++ b/src/plugins/litehtml_viewer/lh_widget_text.cpp
@@ -0,0 +1,142 @@
+/*
+ * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client
+ * Copyright(C) 2019 the Claws Mail Team
+ *
+ * litehtml callbacks related to text rendering
+ *
+ * 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.
+ */
+
+#include <glib.h>
+
+#include "litehtml/litehtml.h"
+
+#include "lh_widget.h"
+
+litehtml::uint_ptr lh_widget::create_font( const litehtml::tchar_t* faceName, int size, int weight, litehtml::font_style italic, unsigned int decoration, litehtml::font_metrics* fm )
+{
+	PangoFontDescription *desc =
+		pango_font_description_from_string(faceName);
+
+	pango_font_description_set_size(desc, size * PANGO_SCALE);
+	pango_font_description_set_weight(desc, (PangoWeight)weight);
+
+	if (italic == litehtml::fontStyleItalic)
+		pango_font_description_set_style(desc, PANGO_STYLE_ITALIC);
+	else
+		pango_font_description_set_style(desc, PANGO_STYLE_NORMAL);
+
+	if(fm != NULL) {
+		PangoContext *context = gtk_widget_get_pango_context(m_drawing_area);
+		PangoFontMetrics *metrics = pango_context_get_metrics(
+				context, desc,
+				pango_context_get_language(context));
+		PangoLayout *x_layout;
+		PangoRectangle rect;
+
+		x_layout = pango_layout_new(context);
+		pango_layout_set_font_description(x_layout, desc);
+		pango_layout_set_text(x_layout, "x", -1);
+		pango_layout_get_pixel_extents(x_layout, NULL, &rect);
+
+		fm->ascent		= pango_font_metrics_get_ascent(metrics) / PANGO_SCALE;
+		fm->descent		= pango_font_metrics_get_descent(metrics) / PANGO_SCALE;
+		fm->height		= fm->ascent + fm->descent;
+		fm->x_height	= rect.height;
+
+		g_object_unref(x_layout);
+		pango_font_metrics_unref(metrics);
+	}
+
+	pango_font *ret = new pango_font;
+	ret->font = desc;
+	ret->strikethrough = (decoration & litehtml::font_decoration_linethrough) ? true : false;
+	ret->underline = (decoration & litehtml::font_decoration_underline) ? true : false;
+
+	return (litehtml::uint_ptr) ret;
+}
+
+void lh_widget::delete_font( litehtml::uint_ptr hFont )
+{
+	pango_font *fnt = (pango_font *)hFont;
+
+	if (fnt != NULL) {
+		pango_font_description_free(fnt->font);
+		delete fnt;
+	}
+}
+
+int lh_widget::text_width( const litehtml::tchar_t* text, litehtml::uint_ptr hFont )
+{
+	pango_font *fnt = (pango_font *) hFont;
+	PangoContext *context = gtk_widget_get_pango_context(m_drawing_area);
+	PangoLayout *layout = pango_layout_new(context);
+	PangoRectangle rect;
+
+	if (fnt)
+		pango_layout_set_font_description(layout, fnt->font);
+
+	pango_layout_set_text(layout, text, -1);
+	pango_layout_get_pixel_extents(layout, NULL, &rect);
+
+	g_object_unref(layout);
+
+	return rect.width;
+}
+
+void lh_widget::draw_text( litehtml::uint_ptr hdc, const litehtml::tchar_t* text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos )
+{
+	pango_font *fnt = (pango_font *)hFont;
+	cairo_t *cr = (cairo_t *)hdc;
+	PangoLayout *layout = pango_cairo_create_layout(cr);
+	PangoContext *context = pango_layout_get_context(layout);
+
+	if (fnt != NULL) {
+		/* Set font */
+		pango_layout_set_font_description(layout, fnt->font);
+
+		/* Set additional font attributes */
+		if (fnt->underline || fnt->strikethrough) {
+			PangoAttrList *attr_list = pango_attr_list_new();
+			PangoUnderline ul;
+
+			if (fnt->underline )
+				ul = PANGO_UNDERLINE_SINGLE;
+			else
+				ul = PANGO_UNDERLINE_NONE;
+
+			pango_attr_list_insert(attr_list,
+					pango_attr_underline_new(ul));
+			pango_attr_list_insert(attr_list,
+					pango_attr_strikethrough_new(fnt->strikethrough));
+
+			pango_layout_set_attributes(layout, attr_list);
+			pango_attr_list_unref(attr_list);
+		}
+	}
+
+	/* Set actual text content */
+	pango_layout_set_text(layout, text, -1);
+
+	cairo_save(cr);
+
+	/* Draw the text where it's supposed to be */
+	apply_clip(cr);
+	set_color(cr, color);
+	cairo_move_to(cr, pos.left(), pos.top());
+	pango_cairo_show_layout(cr, layout);
+
+	/* Cleanup */
+	g_object_unref(layout);
+	cairo_restore(cr);
+}

commit 42231eff67ccb62b3cd278adeb85489f20e2b4c2
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Mon Feb 18 00:46:24 2019 +0100

    Use prepend document base url to #fragment links in Litehtml plugin

diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index 17ae04e..e75ec4a 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -135,15 +135,17 @@ void lh_widget::set_caption(const litehtml::tchar_t* caption)
 
 void lh_widget::set_base_url(const litehtml::tchar_t* base_url)
 {
-	debug_print("lh_widget set_base_url\n");
+	debug_print("lh_widget set_base_url '%s'\n",
+			(base_url ? base_url : "(null)"));
+	m_base_url = base_url;
 	return;
 }
 
 void lh_widget::on_anchor_click(const litehtml::tchar_t* url, const litehtml::element::ptr& el)
 {
 	debug_print("lh_widget on_anchor_click. url -> %s\n", url);
-	m_clicked_url = url;
-	
+
+	m_clicked_url = fullurl(url);
 	return;
 }
 
@@ -333,6 +335,8 @@ void lh_widget::clear()
 	m_html = nullptr;
 	paint_white();
 	m_rendered_width = 0;
+	m_base_url.clear();
+	m_clicked_url.clear();
 }
 
 void lh_widget::set_cursor(const litehtml::tchar_t* cursor)
@@ -369,7 +373,7 @@ void lh_widget::update_cursor()
 	/* If it's an anchor, show its "href" attribute in statusbar,
 	 * otherwise clear statusbar. */
 	if ((href = get_href_at(x, y)) != NULL) {
-		lh_widget_statusbar_push(href);
+		lh_widget_statusbar_push(fullurl(href).c_str());
 	} else {
 		lh_widget_statusbar_pop();
 	}
@@ -444,6 +448,14 @@ void lh_widget::update_font()
 	debug_print("Font set to '%s', size %d\n", m_font_name, m_font_size);
 }
 
+const litehtml::tstring lh_widget::fullurl(const litehtml::tchar_t *url) const
+{
+	if (*url == '#' && !m_base_url.empty())
+		return m_base_url + url;
+
+	return _t(url);
+}
+
 ////////////////////////////////////////////////
 static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
 		gpointer user_data)
diff --git a/src/plugins/litehtml_viewer/lh_widget.h b/src/plugins/litehtml_viewer/lh_widget.h
index a792197..da2dc7f 100644
--- a/src/plugins/litehtml_viewer/lh_widget.h
+++ b/src/plugins/litehtml_viewer/lh_widget.h
@@ -33,9 +33,11 @@ class lh_widget : public container_linux
 
 		const litehtml::tchar_t *get_href_at(const gint x, const gint y) const;
 		void popup_context_menu(const litehtml::tchar_t *url, GdkEventButton *event);
+		const litehtml::tstring fullurl(const litehtml::tchar_t *url) const;
 
 		litehtml::document::ptr m_html;
 		litehtml::tstring m_clicked_url;
+		litehtml::tstring m_base_url;
 
 	private:
 		void paint_white();

commit fa7135fa3b791697eefdaaccbfeb42cc413a10e4
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sun Feb 17 20:48:17 2019 +0100

    Add default_font preference to Litehtml plugin

diff --git a/src/plugins/litehtml_viewer/container_linux.cpp b/src/plugins/litehtml_viewer/container_linux.cpp
index 0993f8d..a2b1908 100644
--- a/src/plugins/litehtml_viewer/container_linux.cpp
+++ b/src/plugins/litehtml_viewer/container_linux.cpp
@@ -217,11 +217,6 @@ int container_linux::pt_to_px( int pt )
 	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())
@@ -871,11 +866,6 @@ gint container_linux::clear_images(gint desired_size)
 	return num;
 }
 
-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)
diff --git a/src/plugins/litehtml_viewer/container_linux.h b/src/plugins/litehtml_viewer/container_linux.h
index c6cda8e..43a917c 100644
--- a/src/plugins/litehtml_viewer/container_linux.h
+++ b/src/plugins/litehtml_viewer/container_linux.h
@@ -62,8 +62,6 @@ public:
 	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;
diff --git a/src/plugins/litehtml_viewer/lh_prefs.c b/src/plugins/litehtml_viewer/lh_prefs.c
index 7dcc7aa..94acc4e 100644
--- a/src/plugins/litehtml_viewer/lh_prefs.c
+++ b/src/plugins/litehtml_viewer/lh_prefs.c
@@ -44,6 +44,7 @@ struct _LHPrefsPage {
 	PrefsPage page;
 	GtkWidget *enable_remote_content;
 	GtkWidget *image_cache_size;
+	GtkWidget *default_font;
 };
 typedef struct _LHPrefsPage LHPrefsPage;
 
@@ -52,6 +53,8 @@ static PrefParam param[] = {
 		NULL, NULL, NULL },
 	{ "image_cache_size", "20", &lh_prefs.image_cache_size, P_INT,
 		NULL, NULL, NULL },
+	{ "default_font", "Sans 16", &lh_prefs.default_font, P_STRING,
+		NULL, NULL, NULL },
 	{ NULL, NULL, NULL, 0, NULL, NULL, NULL }
 };
 
@@ -99,6 +102,7 @@ static void create_lh_prefs_page(PrefsPage *page, GtkWindow *window,
 	GtkWidget *label;
 	GtkWidget *enable_remote_content;
 	GtkWidget *image_cache_size;
+	GtkWidget *default_font;
 	GtkObject *adj;
 
 	vbox = gtk_vbox_new(FALSE, 3);
@@ -136,10 +140,22 @@ static void create_lh_prefs_page(PrefsPage *page, GtkWindow *window,
 			lh_prefs.image_cache_size);
 	gtk_box_pack_start(GTK_BOX(hbox), image_cache_size, FALSE, FALSE, 0);
 
+	/* Font */
+	hbox = gtk_hbox_new(FALSE, 8);
+	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+	label = gtk_label_new(_("Default font"));
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+	default_font = gtk_font_button_new_with_font(lh_prefs.default_font);
+	g_object_set(G_OBJECT(default_font), "use-font", TRUE, NULL);
+	gtk_box_pack_start(GTK_BOX(hbox), default_font, FALSE, FALSE, 0);
+
 	gtk_widget_show_all(hbox);
 
 	prefs_page->enable_remote_content = enable_remote_content;
 	prefs_page->image_cache_size = image_cache_size;
+	prefs_page->default_font = default_font;
 	prefs_page->page.widget = vbox;
 }
 
@@ -153,9 +169,14 @@ static void save_lh_prefs_page(PrefsPage *page)
 
 	lh_prefs.enable_remote_content = gtk_toggle_button_get_active(
 			GTK_TOGGLE_BUTTON(prefs_page->enable_remote_content));
+
 	lh_prefs.image_cache_size = gtk_spin_button_get_value_as_int(
 			GTK_SPIN_BUTTON(prefs_page->image_cache_size));
 
+	g_free(lh_prefs.default_font);
+	lh_prefs.default_font = g_strdup(gtk_font_button_get_font_name(
+			GTK_FONT_BUTTON(prefs_page->default_font)));
+
 	save_prefs();
 }
 
diff --git a/src/plugins/litehtml_viewer/lh_prefs.h b/src/plugins/litehtml_viewer/lh_prefs.h
index d226fe6..cd73f81 100644
--- a/src/plugins/litehtml_viewer/lh_prefs.h
+++ b/src/plugins/litehtml_viewer/lh_prefs.h
@@ -30,6 +30,7 @@ struct _LHPrefs
 {
 	gboolean enable_remote_content;
 	gint image_cache_size;
+	gchar *default_font;
 };
 
 LHPrefs *lh_prefs_get(void);
diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index bf047cf..17ae04e 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -104,6 +104,9 @@ lh_widget::lh_widget()
 	m_rendered_width = 0;
 	m_context.load_master_stylesheet(master_css);
 
+	m_font_name = NULL;
+	m_font_size = 0;
+
 	gtk_widget_set_events(m_drawing_area,
 			        GDK_BUTTON_RELEASE_MASK
 			      | GDK_BUTTON_PRESS_MASK
@@ -218,6 +221,8 @@ void lh_widget::open_html(const gchar *contents)
 
 	debug_print("LH: cleared %d images from image cache\n", num);
 
+	update_font();
+
 	lh_widget_statusbar_push("Loading HTML part ...");
 	m_html = litehtml::document::createFromString(contents, this, &m_context);
 	m_rendered_width = 0;
@@ -421,6 +426,25 @@ void lh_widget::popup_context_menu(const litehtml::tchar_t *url,
 			event->button, event->time);
 }
 
+void lh_widget::update_font()
+{
+	PangoFontDescription *pd =
+		pango_font_description_from_string(lh_prefs_get()->default_font);
+	gboolean absolute = pango_font_description_get_size_is_absolute(pd);
+
+	g_free(m_font_name);
+	m_font_name = g_strdup(pango_font_description_get_family(pd));
+	m_font_size = pango_font_description_get_size(pd);
+
+	pango_font_description_free(pd);
+
+	if (!absolute)
+		m_font_size /= PANGO_SCALE;
+
+	debug_print("Font set to '%s', size %d\n", m_font_name, m_font_size);
+}
+
+////////////////////////////////////////////////
 static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
 		gpointer user_data)
 {
diff --git a/src/plugins/litehtml_viewer/lh_widget.h b/src/plugins/litehtml_viewer/lh_widget.h
index 5e2a872..a792197 100644
--- a/src/plugins/litehtml_viewer/lh_widget.h
+++ b/src/plugins/litehtml_viewer/lh_widget.h
@@ -12,12 +12,15 @@ class lh_widget : public container_linux
 
 		GtkWidget *get_widget() const;
 
+		/* Methods that litehtml calls */
 		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;
+		inline const litehtml::tchar_t *get_default_font_name() const { return m_font_name; };
+		inline int get_default_font_size() const { return m_font_size; };
 		GdkPixbuf *get_image(const litehtml::tchar_t* url, bool redraw_on_ready);
 
 		void draw(cairo_t *cr);
@@ -25,6 +28,7 @@ class lh_widget : public container_linux
 		void open_html(const gchar *contents);
 		void clear();
 		void update_cursor();
+		void update_font();
 		void print();
 
 		const litehtml::tchar_t *get_href_at(const gint x, const gint y) const;
@@ -44,4 +48,7 @@ class lh_widget : public container_linux
 		litehtml::context m_context;
 		gint m_height;
 		litehtml::tstring m_cursor;
+
+		litehtml::tchar_t *m_font_name;
+		int m_font_size;
 };

commit 8071229a71fabe20b16b5f0dfdb2cfe725b5e3c6
Author: Michael Rasmussen <mir at datanom.net>
Date:   Wed Feb 13 00:47:34 2019 +0100

    Fix build error
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/configure.ac b/configure.ac
index 4dfbac3..6d4ff8c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2085,9 +2085,9 @@ 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_LITEHTML_VIEWER_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_MANAGESIEVE_PLUGIN,	test x"$enable_managesieve_plugin" != xno)
 AM_CONDITIONAL(BUILD_NEWMAIL_PLUGIN,		test x"$enable_newmail_plugin" != xno)
 AM_CONDITIONAL(BUILD_NOTIFICATION_PLUGIN,	test x"$enable_notification_plugin" != xno)
 AM_CONDITIONAL(BUILD_HOTKEYS,			test x"$enable_notification_plugin" != xno -a x"$HAVE_HOTKEYS" = xyes)
diff --git a/src/plugins/litehtml_viewer/Makefile.am b/src/plugins/litehtml_viewer/Makefile.am
index ded5d58..d603a30 100644
--- a/src/plugins/litehtml_viewer/Makefile.am
+++ b/src/plugins/litehtml_viewer/Makefile.am
@@ -25,9 +25,9 @@ cygwin_export_lib =
 
 plugindir = $(pkglibdir)/plugins
 
-#if BUILD_LITEHTML_VIEWER_PLUGIN
+if BUILD_LITEHTML_VIEWER_PLUGIN
 plugin_LTLIBRARIES = litehtml_viewer.la
-#endif
+endif
 
 litehtml_viewer_la_DEPENDENCIES = $(plugin_deps)
 
diff --git a/src/plugins/litehtml_viewer/litehtml/Makefile.am b/src/plugins/litehtml_viewer/litehtml/Makefile.am
index b412926..025e315 100644
--- a/src/plugins/litehtml_viewer/litehtml/Makefile.am
+++ b/src/plugins/litehtml_viewer/litehtml/Makefile.am
@@ -3,9 +3,9 @@
 # terms of the General Public License version 3 (or later).
 # See COPYING file for license details.
 
-#if BUILD_LITEHTML_VIEWER_PLUGIN
+if BUILD_LITEHTML_VIEWER_PLUGIN
 noinst_LTLIBRARIES = liblitehtml.la
-#endif
+endif
 
 liblitehtml_la_CXXFLAGS = -std=c++11
 

commit cd43a4956b861ad55e6fba21a264b795e8ee6584
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Feb 12 00:54:07 2019 +0100

    Make Litehtml display sub- and superscript correctly

diff --git a/src/plugins/litehtml_viewer/css.inc b/src/plugins/litehtml_viewer/css.inc
index 3dc2ad7..1288982 100644
--- a/src/plugins/litehtml_viewer/css.inc
+++ b/src/plugins/litehtml_viewer/css.inc
@@ -323,4 +323,10 @@ input[type=\"hidden\"] { \
 article, aside, footer, header, hgroup, nav, section  \
 { \
 	display: block; \
-}"
+} \
+\
+small, sub, sup { font-size: 80%; } \
+sub, sup { position: relative; } \
+sub { top: +0.5em; } \
+sup { top: -0.5em; } \
+"

commit 3d209145f3b91fec635b5d956d56a79ab8059f90
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Feb 12 00:32:44 2019 +0100

    Use height of the viewport, not the scrolled window when telling Litehtml size of the area it has available for rendering

diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index df6ee99..bf047cf 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -50,8 +50,6 @@ char master_css[] = {
 
 static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
 		gpointer user_data);
-static void size_allocate_cb(GtkWidget *widget, GdkRectangle *allocation,
-		gpointer user_data);
 static gboolean button_press_event(GtkWidget *widget, GdkEventButton *event,
 		gpointer user_data);
 static gboolean motion_notify_event(GtkWidget *widget, GdkEventButton *event,
@@ -69,8 +67,6 @@ lh_widget::lh_widget()
 	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);
@@ -263,7 +259,7 @@ void lh_widget::draw(cairo_t *cr)
 void lh_widget::redraw()
 {
 	GtkAllocation rect;
-	gint width, height;
+	gint width;
 	GdkWindow *gdkwin;
 	cairo_t *cr;
 
@@ -274,7 +270,8 @@ void lh_widget::redraw()
 
 	/* Get width of the viewport. */
 	gdkwin = gtk_viewport_get_view_window(GTK_VIEWPORT(m_viewport));
-	gdk_drawable_get_size(gdkwin, &width, NULL);
+	width = gdk_window_get_width(gdkwin);
+	m_height = gdk_window_get_height(gdkwin);
 
 	/* If the available width has changed, rerender the HTML content. */
 	if (m_rendered_width != width) {
@@ -432,18 +429,6 @@ static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
 	return FALSE;
 }
 
-static void size_allocate_cb(GtkWidget *widget, GdkRectangle *allocation,
-		gpointer user_data)
-{
-	lh_widget *w = (lh_widget *)user_data;
-
-	debug_print("size_allocate_cb: %dx%d\n",
-			allocation->width, allocation->height);
-
-	w->setHeight(allocation->height);
-	w->redraw();
-}
-
 static gboolean button_press_event(GtkWidget *widget, GdkEventButton *event,
 		gpointer user_data)
 {
diff --git a/src/plugins/litehtml_viewer/lh_widget.h b/src/plugins/litehtml_viewer/lh_widget.h
index f4060d5..5e2a872 100644
--- a/src/plugins/litehtml_viewer/lh_widget.h
+++ b/src/plugins/litehtml_viewer/lh_widget.h
@@ -20,8 +20,6 @@ class lh_widget : public container_linux
 		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);

commit f0dc8213f7d907be763c70bd8189f998ca914117
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Mon Feb 11 23:10:45 2019 +0100

    Reset Litehtml scrolledwindow to top-left when displaying new content

diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index 61abf61..df6ee99 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -218,6 +218,7 @@ statusbar_pop:
 void lh_widget::open_html(const gchar *contents)
 {
 	gint num = clear_images(lh_prefs_get()->image_cache_size * 1024 * 1000);
+	GtkAdjustment *adj;
 
 	debug_print("LH: cleared %d images from image cache\n", num);
 
@@ -226,6 +227,12 @@ void lh_widget::open_html(const gchar *contents)
 	m_rendered_width = 0;
 	if (m_html != NULL) {
 		debug_print("lh_widget::open_html created document\n");
+		adj = gtk_scrolled_window_get_hadjustment(
+				GTK_SCROLLED_WINDOW(m_scrolled_window));
+		gtk_adjustment_set_value(adj, 0.0);
+		adj = gtk_scrolled_window_get_vadjustment(
+				GTK_SCROLLED_WINDOW(m_scrolled_window));
+		gtk_adjustment_set_value(adj, 0.0);
 		redraw();
 	}
 	lh_widget_statusbar_pop();

commit 82106bb0655a5274f84674646948f6ea942994ec
Author: Ricardo Mones <ricardo at mones.org>
Date:   Sun Feb 10 12:51:53 2019 +0100

    Fix typo in variable name

diff --git a/configure.ac b/configure.ac
index 4a38878..4dfbac3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1639,7 +1639,7 @@ if test x"$enable_litehtml_viewer_plugin" != xno; then
         dependencies_missing=""
 
         if test x"$HAVE_CXX" = xno; then
-                dependencies_missing="C++ compiler $dependencies missing"
+                dependencies_missing="C++ compiler $dependencies_missing"
         fi
         if test x"$HAVE_CAIRO" = xno; then
                 dependencies_missing="cairo $dependencies_missing"

commit 9d95039f9cb819d2a258627329cc61b952fb00d2
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri Feb 8 20:09:38 2019 +0100

    Show number of cleared Litehtml cache images on debug

diff --git a/src/plugins/litehtml_viewer/container_linux.cpp b/src/plugins/litehtml_viewer/container_linux.cpp
index e4d3c1d..0993f8d 100644
--- a/src/plugins/litehtml_viewer/container_linux.cpp
+++ b/src/plugins/litehtml_viewer/container_linux.cpp
@@ -834,9 +834,10 @@ void container_linux::clear_images()
 	m_images.clear();
 }
 
-void container_linux::clear_images(gint desired_size)
+gint container_linux::clear_images(gint desired_size)
 {
 	gint size = 0;
+	gint num = 0;
 
 	/* First, tally up size of all the stored GdkPixbufs and
 	 * deallocate those which make the total size be above
@@ -854,6 +855,7 @@ void container_linux::clear_images(gint desired_size)
 		if (size + cursize > desired_size) {
 			g_object_unref(img->second);
 			img->second = NULL;
+			num++;
 		} else {
 			size += cursize;
 		}
@@ -865,6 +867,8 @@ void container_linux::clear_images(gint desired_size)
 				return true;
 			return false;
 			});
+
+	return num;
 }
 
 const litehtml::tchar_t* container_linux::get_default_font_name() const
diff --git a/src/plugins/litehtml_viewer/container_linux.h b/src/plugins/litehtml_viewer/container_linux.h
index 8298437..c6cda8e 100644
--- a/src/plugins/litehtml_viewer/container_linux.h
+++ b/src/plugins/litehtml_viewer/container_linux.h
@@ -88,7 +88,7 @@ public:
 
 	/* Trim down images cache to less than desired_size [bytes],
 	 * starting from oldest stored. */
-	void								clear_images(gint desired_size);
+	gint								clear_images(gint desired_size);
 
 protected:
 	virtual void						draw_ellipse(cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color, int line_width);
diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index 3fcb359..61abf61 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -217,7 +217,10 @@ statusbar_pop:
 
 void lh_widget::open_html(const gchar *contents)
 {
-	clear_images(lh_prefs_get()->image_cache_size * 1024 * 1000);
+	gint num = clear_images(lh_prefs_get()->image_cache_size * 1024 * 1000);
+
+	debug_print("LH: cleared %d images from image cache\n", num);
+
 	lh_widget_statusbar_push("Loading HTML part ...");
 	m_html = litehtml::document::createFromString(contents, this, &m_context);
 	m_rendered_width = 0;

commit ab65f5037401bc78f5144034d8797bdef94bdb06
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri Feb 8 20:05:06 2019 +0100

    Add image_cache_size pref to Litehtml

diff --git a/src/plugins/litehtml_viewer/lh_prefs.c b/src/plugins/litehtml_viewer/lh_prefs.c
index fec2ff5..7dcc7aa 100644
--- a/src/plugins/litehtml_viewer/lh_prefs.c
+++ b/src/plugins/litehtml_viewer/lh_prefs.c
@@ -43,12 +43,15 @@ LHPrefs lh_prefs;
 struct _LHPrefsPage {
 	PrefsPage page;
 	GtkWidget *enable_remote_content;
+	GtkWidget *image_cache_size;
 };
 typedef struct _LHPrefsPage LHPrefsPage;
 
 static PrefParam param[] = {
 	{ "enable_remote_content", "FALSE", &lh_prefs.enable_remote_content, P_BOOL,
 		NULL, NULL, NULL },
+	{ "image_cache_size", "20", &lh_prefs.image_cache_size, P_INT,
+		NULL, NULL, NULL },
 	{ NULL, NULL, NULL, 0, NULL, NULL, NULL }
 };
 
@@ -91,9 +94,12 @@ static void create_lh_prefs_page(PrefsPage *page, GtkWindow *window,
 	LHPrefsPage *prefs_page = (LHPrefsPage *)page;
 	GtkWidget *vbox;
 	GtkWidget *vbox_remote;
+	GtkWidget *hbox;
 	GtkWidget *frame;
 	GtkWidget *label;
 	GtkWidget *enable_remote_content;
+	GtkWidget *image_cache_size;
+	GtkObject *adj;
 
 	vbox = gtk_vbox_new(FALSE, 3);
 	gtk_container_set_border_width(GTK_CONTAINER(vbox), VBOX_BORDER);
@@ -115,7 +121,25 @@ static void create_lh_prefs_page(PrefsPage *page, GtkWindow *window,
 	gtk_box_pack_start(GTK_BOX(vbox_remote), enable_remote_content, FALSE, FALSE, 0);
 	gtk_widget_show_all(vbox_remote);
 
+	/* Image cache size */
+	hbox = gtk_hbox_new(FALSE, 8);
+	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+	label = gtk_label_new(_("Size of image cache in megabytes"));
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+	adj = gtk_adjustment_new(0, 0, 99999, 1, 10, 0);
+	image_cache_size = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1, 0);
+	gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(image_cache_size), TRUE);
+	gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(image_cache_size), FALSE);
+	gtk_spin_button_set_value(GTK_SPIN_BUTTON(image_cache_size),
+			lh_prefs.image_cache_size);
+	gtk_box_pack_start(GTK_BOX(hbox), image_cache_size, FALSE, FALSE, 0);
+
+	gtk_widget_show_all(hbox);
+
 	prefs_page->enable_remote_content = enable_remote_content;
+	prefs_page->image_cache_size = image_cache_size;
 	prefs_page->page.widget = vbox;
 }
 
@@ -129,6 +153,8 @@ static void save_lh_prefs_page(PrefsPage *page)
 
 	lh_prefs.enable_remote_content = gtk_toggle_button_get_active(
 			GTK_TOGGLE_BUTTON(prefs_page->enable_remote_content));
+	lh_prefs.image_cache_size = gtk_spin_button_get_value_as_int(
+			GTK_SPIN_BUTTON(prefs_page->image_cache_size));
 
 	save_prefs();
 }
diff --git a/src/plugins/litehtml_viewer/lh_prefs.h b/src/plugins/litehtml_viewer/lh_prefs.h
index 25dcbd2..d226fe6 100644
--- a/src/plugins/litehtml_viewer/lh_prefs.h
+++ b/src/plugins/litehtml_viewer/lh_prefs.h
@@ -29,6 +29,7 @@ typedef struct _LHPrefs LHPrefs;
 struct _LHPrefs
 {
 	gboolean enable_remote_content;
+	gint image_cache_size;
 };
 
 LHPrefs *lh_prefs_get(void);
diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index 152053d..3fcb359 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -217,6 +217,7 @@ statusbar_pop:
 
 void lh_widget::open_html(const gchar *contents)
 {
+	clear_images(lh_prefs_get()->image_cache_size * 1024 * 1000);
 	lh_widget_statusbar_push("Loading HTML part ...");
 	m_html = litehtml::document::createFromString(contents, this, &m_context);
 	m_rendered_width = 0;

commit 79bf393df1d293cf7ad78609744e5eed522a1680
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri Feb 8 19:42:54 2019 +0100

    Implement size limit for Litehtml image cache

diff --git a/src/plugins/litehtml_viewer/container_linux.cpp b/src/plugins/litehtml_viewer/container_linux.cpp
index f24add4..e4d3c1d 100644
--- a/src/plugins/litehtml_viewer/container_linux.cpp
+++ b/src/plugins/litehtml_viewer/container_linux.cpp
@@ -823,15 +823,48 @@ void container_linux::fill_ellipse( cairo_t* cr, int x, int y, int width, int he
 
 void container_linux::clear_images()
 {
-/*	for(images_map::iterator i = m_images.begin(); i != m_images.end(); i++)
-	{
-		if(i->second)
-		{
-			delete i->second;
+	for(auto i = m_images.begin(); i != m_images.end(); ++i) {
+		image *img = &(*i);
+
+		if (img->second) {
+			g_object_unref(img->second);
 		}
 	}
+
 	m_images.clear();
-*/
+}
+
+void container_linux::clear_images(gint desired_size)
+{
+	gint size = 0;
+
+	/* First, tally up size of all the stored GdkPixbufs and
+	 * deallocate those which make the total size be above
+	 * the desired_size limit. We will remove their list
+	 * elements later. */
+	for (auto i = m_images.rbegin(); i != m_images.rend(); ++i) {
+		image *img = &(*i);
+		gint cursize;
+
+		if (img->second == NULL)
+			continue;
+
+		cursize = gdk_pixbuf_get_byte_length(img->second);
+
+		if (size + cursize > desired_size) {
+			g_object_unref(img->second);
+			img->second = NULL;
+		} else {
+			size += cursize;
+		}
+	}
+
+	/* Remove elements whose GdkPixbuf pointers point to NULL. */
+	m_images.remove_if([&](image _img) -> bool {
+			if (_img.second == NULL)
+				return true;
+			return false;
+			});
 }
 
 const litehtml::tchar_t* container_linux::get_default_font_name() const
diff --git a/src/plugins/litehtml_viewer/container_linux.h b/src/plugins/litehtml_viewer/container_linux.h
index 8c6eb6d..8298437 100644
--- a/src/plugins/litehtml_viewer/container_linux.h
+++ b/src/plugins/litehtml_viewer/container_linux.h
@@ -86,6 +86,10 @@ public:
 
 	void								clear_images();
 
+	/* Trim down images cache to less than desired_size [bytes],
+	 * starting from oldest stored. */
+	void								clear_images(gint desired_size);
+
 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);

commit f9d496bff63d513a265086a07601b186284907a5
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri Feb 8 18:33:00 2019 +0100

    Switch Litehtml's image cache from std::map to std::list
    
    This makes the cache ordered, so we are able to remove
    oldest entries if we want to trim memory usage.

diff --git a/src/plugins/litehtml_viewer/container_linux.cpp b/src/plugins/litehtml_viewer/container_linux.cpp
index 26845fb..f24add4 100644
--- a/src/plugins/litehtml_viewer/container_linux.cpp
+++ b/src/plugins/litehtml_viewer/container_linux.cpp
@@ -278,14 +278,25 @@ void container_linux::load_image( const litehtml::tchar_t* src, const litehtml::
 {
 	litehtml::tstring url;
 	make_url(src, baseurl, url);
-	if(m_images.find(url.c_str()) == m_images.end())
+	bool found = false;
+
+	for (auto ii = m_images.cbegin(); ii != m_images.cend(); ++ii) {
+		const image *i = &(*ii);
+
+		if (!strcmp(i->first.c_str(), url.c_str())) {
+			found = true;
+			break;
+		}
+	}
+
+	if(!found)
 	{
 		try
 		{
 			GdkPixbuf *img = get_image(url.c_str(), true);
 			if(img)
 			{
-				m_images[url.c_str()] = img;
+				m_images.push_back(std::make_pair(url, img));
 			}
 		} catch(...)
 		{
@@ -299,9 +310,19 @@ void container_linux::get_image_size( const litehtml::tchar_t* src, const liteht
 {
 	litehtml::tstring url;
 	make_url(src, baseurl, url);
+	bool found = false;
+	const image *img = NULL;
 
-	images_map::iterator img = m_images.find(url.c_str());
-	if(img != m_images.end())
+	for (auto ii = m_images.cbegin(); ii != m_images.cend(); ++ii) {
+		const image *i = &(*ii);
+		if (i->first == url) {
+			img = i;
+			found = true;
+			break;
+		}
+	}
+
+	if(img != NULL)
 	{
 		sz.width	= gdk_pixbuf_get_width(img->second);
 		sz.height	= gdk_pixbuf_get_height(img->second);
@@ -334,8 +355,19 @@ void container_linux::draw_background( litehtml::uint_ptr hdc, const litehtml::b
 	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)
+	bool found = false;
+	const image *img_i = NULL;
+
+	for (auto ii = m_images.cbegin(); ii != m_images.cend(); ++ii) {
+		const image *i = &(*ii);
+		if (i->first == url) {
+			img_i = i;
+			found = true;
+			break;
+		}
+	}
+
+	if(img_i != NULL && img_i->second)
 	{
 		GdkPixbuf *bgbmp = img_i->second;
 
diff --git a/src/plugins/litehtml_viewer/container_linux.h b/src/plugins/litehtml_viewer/container_linux.h
index 94eafab..8c6eb6d 100644
--- a/src/plugins/litehtml_viewer/container_linux.h
+++ b/src/plugins/litehtml_viewer/container_linux.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <vector>
+#include <list>
 #include <string>
 
 #include <cairo.h>
@@ -44,7 +45,8 @@ struct cairo_font
 
 class container_linux :	public litehtml::document_container
 {
-	typedef std::map<litehtml::tstring, GdkPixbuf* >	images_map;
+	typedef std::pair<litehtml::tstring, GdkPixbuf*> image;
+	typedef std::list<image> images_map;
 
 protected:
 	cairo_surface_t*			m_temp_surface;

commit 4271751d2116073b731b163800844e6094f107df
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sun Feb 3 14:50:30 2019 +0100

    Do not build the litehtml plugin if a C++ compiler is not available

diff --git a/configure.ac b/configure.ac
index a23d8c7..4a38878 100644
--- a/configure.ac
+++ b/configure.ac
@@ -109,7 +109,16 @@ LT_AC_PROG_RC
 AC_LIBTOOL_RC
 AC_PROG_LIBTOOL
 AC_PROG_AWK
+
+dnl AC_PROG_CXX will set CXX=g++ even if it finds no useable C++
+dnl compiler, so we have to check whether the program named by
+dnl CXX exists.
 AC_PROG_CXX
+AC_PATH_PROG(REAL_CXX, $CXX)
+HAVE_CXX=no
+if test -n "$REAL_CXX"; then
+	HAVE_CXX=yes
+fi
 
 AC_SYS_LARGEFILE
 
@@ -1126,7 +1135,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, curl
+dnl Litehtml		a C++ compiler, cairo, fontconfig, gumbo, curl
 dnl Libravatar:		libcurl
 dnl Notification:	optionally libnotify  unity/messaging-menu
 dnl 				   libcanberra_gtk hotkey
@@ -1629,6 +1638,9 @@ AC_MSG_CHECKING([whether to build litehtml_viewer plugin])
 if test x"$enable_litehtml_viewer_plugin" != xno; then
         dependencies_missing=""
 
+        if test x"$HAVE_CXX" = xno; then
+                dependencies_missing="C++ compiler $dependencies missing"
+        fi
         if test x"$HAVE_CAIRO" = xno; then
                 dependencies_missing="cairo $dependencies_missing"
         fi

commit 0fafa987e7f5f4f44fd67ae3c2f38a3a87226663
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri Feb 1 21:33:36 2019 +0100

    Make Litehtml's "Copy Link" menuitem actually do something

diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index a92735a..152053d 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -542,7 +542,12 @@ static void open_link_cb(GtkMenuItem *item, gpointer user_data)
 
 static void copy_link_cb(GtkMenuItem *item, gpointer user_data)
 {
-//	lh_widget_wrapped *w = (lh_widget_wrapped *)user_data;
+	lh_widget_wrapped *w = (lh_widget_wrapped *)user_data;
+
+	gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY),
+			w->m_clicked_url.c_str(), -1);
+	gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
+			w->m_clicked_url.c_str(), -1);
 }
 
 ///////////////////////////////////////////////////////////

commit 96d1595dcdbb49a87780adab389c829506461940
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri Feb 1 16:55:48 2019 +0100

    Implement link context menu in Litehtml

diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index 1cc93e9..a92735a 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -23,6 +23,7 @@
 #endif
 
 #include <glib.h>
+#include <glib/gi18n.h>
 #include <glib/gstdio.h>
 #include <fcntl.h>
 #include <sys/types.h>
@@ -57,9 +58,13 @@ static gboolean motion_notify_event(GtkWidget *widget, GdkEventButton *event,
         gpointer user_data);
 static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event,
         gpointer user_data);
+static void open_link_cb(GtkMenuItem *item, gpointer user_data);
+static void copy_link_cb(GtkMenuItem *item, gpointer user_data);
 
 lh_widget::lh_widget()
 {
+	GtkWidget *item;
+
 	/* scrolled window */
 	m_scrolled_window = gtk_scrolled_window_new(NULL, NULL);
 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(m_scrolled_window),
@@ -88,6 +93,17 @@ lh_widget::lh_widget()
 
 	gtk_widget_show_all(m_scrolled_window);
 
+	/* context menu */
+	m_context_menu = gtk_menu_new();
+
+	item = gtk_menu_item_new_with_label(_("Open Link"));
+	g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(open_link_cb), this);
+	gtk_menu_shell_append(GTK_MENU_SHELL(m_context_menu), item);
+
+	item = gtk_menu_item_new_with_label(_("Copy Link Location"));
+	g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(copy_link_cb), this);
+	gtk_menu_shell_append(GTK_MENU_SHELL(m_context_menu), item);
+
 	m_html = NULL;
 	m_rendered_width = 0;
 	m_context.load_master_stylesheet(master_css);
@@ -383,6 +399,20 @@ void lh_widget::print()
     gtk_widget_realize(GTK_WIDGET(m_drawing_area));
 }
 
+void lh_widget::popup_context_menu(const litehtml::tchar_t *url,
+		GdkEventButton *event)
+{
+	cm_return_if_fail(url != NULL);
+	cm_return_if_fail(event != NULL);
+
+	debug_print("lh_widget showing context menu for '%s'\n", url);
+
+	m_clicked_url = url;
+	gtk_widget_show_all(m_context_menu);
+	gtk_menu_popup(GTK_MENU(m_context_menu), NULL, NULL, NULL, NULL,
+			event->button, event->time);
+}
+
 static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
 		gpointer user_data)
 {
@@ -406,21 +436,34 @@ static void size_allocate_cb(GtkWidget *widget, GdkRectangle *allocation,
 static gboolean button_press_event(GtkWidget *widget, GdkEventButton *event,
 		gpointer user_data)
 {
-    litehtml::position::vector redraw_boxes;
-    lh_widget *w = (lh_widget *)user_data;
-    
-    debug_print("lh_widget on_button_press_event\n");
+	litehtml::position::vector redraw_boxes;
+	lh_widget *w = (lh_widget *)user_data;
 
-    if(w->m_html)
-    {    
-        if(w->m_html->on_lbutton_down((int) event->x, (int) event->y, (int) event->x, (int) event->y, redraw_boxes))
-        {
-            for(auto& pos : redraw_boxes)
-            {
-		debug_print("x: %d y:%d w: %d h: %d\n", pos.x, pos.y, pos.width, pos.height);
-                gtk_widget_queue_draw_area(widget, pos.x, pos.y, pos.width, pos.height);
-            }
-        }
+	if (w->m_html == NULL)
+		return false;
+
+	debug_print("lh_widget on_button_press_event\n");
+
+	if (event->type == GDK_2BUTTON_PRESS ||
+			event->type == GDK_3BUTTON_PRESS)
+		return true;
+
+	/* Right-click */
+	if (event->button == 3) {
+		const litehtml::tchar_t *url = w->get_href_at((gint)event->x, (gint)event->y);
+
+		if (url != NULL)
+			w->popup_context_menu(url, event);
+
+		return true;
+	}
+
+	if(w->m_html->on_lbutton_down((int) event->x, (int) event->y,
+				(int) event->x, (int) event->y, redraw_boxes)) {
+		for(auto& pos : redraw_boxes) {
+			debug_print("x: %d y:%d w: %d h: %d\n", pos.x, pos.y, pos.width, pos.height);
+			gtk_widget_queue_draw_area(widget, pos.x, pos.y, pos.width, pos.height);
+		}
 	}
 	
 	return true;
@@ -457,30 +500,51 @@ static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event,
     lh_widget *w = (lh_widget *)user_data;
     GError* error = NULL;
 
+	if (w->m_html == NULL)
+		return false;
+
 	debug_print("lh_widget on_button_release_event\n");
-	
-	if(w->m_html)
-	{
-	    w->m_clicked_url.clear();
-	    if(w->m_html->on_lbutton_up((int) event->x, (int) event->y, (int) event->x, (int) event->y, redraw_boxes))
-        {
-            for (auto& pos : redraw_boxes)
-            {
-		debug_print("x: %d y:%d w: %d h: %d\n", pos.x, pos.y, pos.width, pos.height);
-                gtk_widget_queue_draw_area(widget, pos.x, pos.y, pos.width, pos.height);
-            }
-        }
-        
-        if (!w->m_clicked_url.empty())
+
+	if (event->type == GDK_2BUTTON_PRESS ||
+			event->type == GDK_3BUTTON_PRESS)
+		return true;
+
+	/* Right-click */
+	if (event->button == 3)
+		return true;
+
+	w->m_clicked_url.clear();
+
+    if(w->m_html->on_lbutton_up((int) event->x, (int) event->y, (int) event->x, (int) event->y, redraw_boxes))
+    {
+        for (auto& pos : redraw_boxes)
         {
-                debug_print("Open in browser: %s\n", w->m_clicked_url.c_str());
-                open_uri(w->m_clicked_url.c_str(), prefs_common_get_uri_cmd());
+            debug_print("x: %d y:%d w: %d h: %d\n", pos.x, pos.y, pos.width, pos.height);
+            gtk_widget_queue_draw_area(widget, pos.x, pos.y, pos.width, pos.height);
         }
     }
 
+    if (!w->m_clicked_url.empty())
+    {
+            debug_print("Open in browser: %s\n", w->m_clicked_url.c_str());
+            open_uri(w->m_clicked_url.c_str(), prefs_common_get_uri_cmd());
+    }
+
 	return true;
 }
 
+static void open_link_cb(GtkMenuItem *item, gpointer user_data)
+{
+	lh_widget_wrapped *w = (lh_widget_wrapped *)user_data;
+
+	open_uri(w->m_clicked_url.c_str(), prefs_common_get_uri_cmd());
+}
+
+static void copy_link_cb(GtkMenuItem *item, gpointer user_data)
+{
+//	lh_widget_wrapped *w = (lh_widget_wrapped *)user_data;
+}
+
 ///////////////////////////////////////////////////////////
 extern "C" {
 
diff --git a/src/plugins/litehtml_viewer/lh_widget.h b/src/plugins/litehtml_viewer/lh_widget.h
index 8f80d95..f4060d5 100644
--- a/src/plugins/litehtml_viewer/lh_widget.h
+++ b/src/plugins/litehtml_viewer/lh_widget.h
@@ -30,6 +30,7 @@ class lh_widget : public container_linux
 		void print();
 
 		const litehtml::tchar_t *get_href_at(const gint x, const gint y) const;
+		void popup_context_menu(const litehtml::tchar_t *url, GdkEventButton *event);
 
 		litehtml::document::ptr m_html;
 		litehtml::tstring m_clicked_url;
@@ -41,6 +42,7 @@ class lh_widget : public container_linux
 		GtkWidget *m_drawing_area;
 		GtkWidget *m_scrolled_window;
 		GtkWidget *m_viewport;
+		GtkWidget *m_context_menu;
 		litehtml::context m_context;
 		gint m_height;
 		litehtml::tstring m_cursor;

commit 6e437d475fdf79fad55ff6c45b074b62cc2db8d5
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri Feb 1 16:55:15 2019 +0100

    Add lh_widget::get_href_at()

diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index fd74a3b..1cc93e9 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -319,7 +319,7 @@ void lh_widget::set_cursor(const litehtml::tchar_t* cursor)
 void lh_widget::update_cursor()
 {
 	gint x, y;
-	litehtml::element::ptr root_el, over_el, el;
+	const litehtml::tchar_t *href;
 	GdkWindow *w = gdk_display_get_window_at_pointer(gdk_display_get_default(),
 			&x, &y);
 	GdkCursorType cursType = GDK_ARROW;
@@ -337,32 +337,44 @@ void lh_widget::update_cursor()
 	if (w != gtk_widget_get_window(m_drawing_area))
 		return;
 
-	/* Find the element we are hovering over */
-	root_el = m_html->root();
-	g_return_if_fail(root_el != NULL);
-	over_el = root_el->get_element_by_point(x, y, x, y);
-	g_return_if_fail(over_el != NULL);
+	/* If it's an anchor, show its "href" attribute in statusbar,
+	 * otherwise clear statusbar. */
+	if ((href = get_href_at(x, y)) != NULL) {
+		lh_widget_statusbar_push(href);
+	} else {
+		lh_widget_statusbar_pop();
+	}
+}
+
+const litehtml::tchar_t *lh_widget::get_href_at(const gint x, const gint y) const
+{
+	litehtml::element::ptr over_el, el;
+
+	if (m_html == NULL)
+		return NULL;
+
+	over_el = m_html->root()->get_element_by_point(x, y, x, y);
+	if (over_el == NULL)
+		return NULL;
 
 	/* If it's not an anchor, check if it has a parent anchor
 	 * (e.g. it's an image within an anchor) and grab a pointer
 	 * to that. */
 	if (strcmp(over_el->get_tagName(), "a") && over_el->parent()) {
 		el = over_el->parent();
-		while (el && el != root_el && strcmp(el->get_tagName(), "a")) {
+		while (el && el != m_html->root() && strcmp(el->get_tagName(), "a")) {
 			el = el->parent();
 		}
 
-		if (el && el != root_el)
+		if (el && el != m_html->root())
 			over_el = el;
+		else
+			return NULL;
 	}
 
-	/* If it's an anchor, show its "href" attribute in statusbar,
-	 * otherwise clear statusbar. */
-	if (!strcmp(over_el->get_tagName(), "a")) {
-		lh_widget_statusbar_push(over_el->get_attr(_t("href")));
-	} else {
-		lh_widget_statusbar_pop();
-	}
+	/* At this point, over_el is pointing at an anchor tag, so let's
+	 * grab its href attribute. */
+	return over_el->get_attr(_t("href"));
 }
 
 void lh_widget::print()
diff --git a/src/plugins/litehtml_viewer/lh_widget.h b/src/plugins/litehtml_viewer/lh_widget.h
index daffcac..8f80d95 100644
--- a/src/plugins/litehtml_viewer/lh_widget.h
+++ b/src/plugins/litehtml_viewer/lh_widget.h
@@ -29,6 +29,8 @@ class lh_widget : public container_linux
 		void update_cursor();
 		void print();
 
+		const litehtml::tchar_t *get_href_at(const gint x, const gint y) const;
+
 		litehtml::document::ptr m_html;
 		litehtml::tstring m_clicked_url;
 

commit a300f65525e509204fd133292badb6836b32dc11
Author: Michael Rasmussen <mir at datanom.net>
Date:   Wed Jan 30 00:29:12 2019 +0100

    Fix possible memory leak
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/litehtml_viewer/http.cpp b/src/plugins/litehtml_viewer/http.cpp
index ff9bcad..21e53fc 100644
--- a/src/plugins/litehtml_viewer/http.cpp
+++ b/src/plugins/litehtml_viewer/http.cpp
@@ -70,11 +70,11 @@ GInputStream *http::load_url(const gchar *url, GError **error)
 	} else {
 		struct Data data;
 
-		data.memory = g_memory_input_stream_new();
-		data.size = 0;
-
 		if (!curl) return NULL;
 
+                data.memory = g_memory_input_stream_new();
+                data.size = 0;
+
 		curl_easy_setopt(curl, CURLOPT_URL, url);
 		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&data);
 		res = curl_easy_perform(curl);

commit 44fff45e2c28ef5fb224abd0b344edb18e2a4f98
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Wed Jan 30 00:09:11 2019 +0100

    Make Litehtml's curl writefunction add data directly to the GInputStream
    
    This saves us some unnecessary reallocs, as data
    inside a GMemoryInputStream do not need to be
    contiguous.

diff --git a/src/plugins/litehtml_viewer/http.cpp b/src/plugins/litehtml_viewer/http.cpp
index c6260b4..ff9bcad 100644
--- a/src/plugins/litehtml_viewer/http.cpp
+++ b/src/plugins/litehtml_viewer/http.cpp
@@ -8,25 +8,18 @@
 #include "utils.h"
 
 struct Data {
-  char *memory;
+  GInputStream *memory;
   size_t size;
 };
 
 static size_t write_data(char* ptr, size_t size, size_t nmemb, void* data_ptr) {
     struct Data* data = (struct Data *) data_ptr;
     size_t realsize = size * nmemb;
-    
-    char *input = (char *) g_realloc(data->memory, data->size + realsize + 1);
-    if(input == NULL) {
-        /* out of memory! */
-        g_warning("not enough memory (realloc returned NULL)");
-        return 0;
-    }
-    
-    data->memory = input;
-    memcpy(&(data->memory[data->size]), ptr, realsize);
-    data->size += realsize;
-    data->memory[data->size] = 0;
+
+		g_memory_input_stream_add_data((GMemoryInputStream *)data->memory,
+				g_memdup(ptr, realsize), realsize,
+				g_free);
+		data->size += realsize;
     
     return realsize;
 }
@@ -61,40 +54,41 @@ void http::destroy_giostream() {
 
 GInputStream *http::load_url(const gchar *url, GError **error)
 {
-    GError* _error = NULL;
-    CURLcode res = CURLE_OK;
-    gsize len;
-    gchar* content;
-    struct Data data;
-
-    data.memory = (char *) g_malloc(1);
-    data.size = 0;
+	GError* _error = NULL;
+	CURLcode res = CURLE_OK;
+	gsize len;
+	gchar* content;
     
-    if (!strncmp(url, "file:///", 8) || g_file_test(url, G_FILE_TEST_EXISTS)) {
-	gchar* newurl = g_filename_from_uri(url, NULL, NULL);
-	if (g_file_get_contents(newurl ? newurl : url, &content, &len, &_error)) {
-	    stream = g_memory_input_stream_new_from_data(content, len, g_free);
-	} else {
-	    debug_print("Got error: %s\n", _error->message);
-	}
-	g_free(newurl);
-    } else {
-	if (!curl) return NULL;
-	curl_easy_setopt(curl, CURLOPT_URL, url);
-	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&data);
-	res = curl_easy_perform(curl);
-	if (res != CURLE_OK) {
-	    _error = g_error_new_literal(G_FILE_ERROR, res, curl_easy_strerror(res));
+	if (!strncmp(url, "file:///", 8) || g_file_test(url, G_FILE_TEST_EXISTS)) {
+		gchar* newurl = g_filename_from_uri(url, NULL, NULL);
+		if (g_file_get_contents(newurl ? newurl : url, &content, &len, &_error)) {
+			stream = g_memory_input_stream_new_from_data(content, len, g_free);
+		} else {
+			debug_print("Got error: %s\n", _error->message);
+		}
+		g_free(newurl);
 	} else {
-	    debug_print("Image size: %d\n", data.size);
-	    stream = g_memory_input_stream_new_from_data(
-		g_memdup(data.memory, data.size), data.size, g_free);
-	    g_free(data.memory);
+		struct Data data;
+
+		data.memory = g_memory_input_stream_new();
+		data.size = 0;
+
+		if (!curl) return NULL;
+
+		curl_easy_setopt(curl, CURLOPT_URL, url);
+		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&data);
+		res = curl_easy_perform(curl);
+
+		if (res != CURLE_OK) {
+			_error = g_error_new_literal(G_FILE_ERROR, res, curl_easy_strerror(res));
+			g_object_unref(data.memory);
+		} else {
+			debug_print("Image size: %d\n", data.size);
+			stream = data.memory;
+		}
 	}
-    }
 
-    if (error && _error) *error = _error;
+	if (error && _error) *error = _error;
 
-    return stream;
+	return stream;
 }
-

commit dc6e20c6ebc652f243676cb4bd4222babb0603ac
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Jan 29 23:52:36 2019 +0100

    Make Litehtml's curl write function a regular function instead of a static member function of the http class

diff --git a/src/plugins/litehtml_viewer/http.cpp b/src/plugins/litehtml_viewer/http.cpp
index 12e8636..c6260b4 100644
--- a/src/plugins/litehtml_viewer/http.cpp
+++ b/src/plugins/litehtml_viewer/http.cpp
@@ -12,26 +12,7 @@ struct Data {
   size_t size;
 };
 
-http::http()
-{
-    curl = curl_easy_init();
-    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
-    curl_easy_setopt(curl, CURLOPT_TIMEOUT, HTTP_GET_TIMEOUT);
-    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
-    curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
-    curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);
-    curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);
-    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http::curl_write_data);
-    stream = NULL;
-}
-
-http::~http()
-{
-    curl_easy_cleanup(curl);
-    destroy_giostream();
-}
-
-size_t http::curl_write_data(char* ptr, size_t size, size_t nmemb, void* data_ptr) {
+static size_t write_data(char* ptr, size_t size, size_t nmemb, void* data_ptr) {
     struct Data* data = (struct Data *) data_ptr;
     size_t realsize = size * nmemb;
     
@@ -50,6 +31,25 @@ size_t http::curl_write_data(char* ptr, size_t size, size_t nmemb, void* data_pt
     return realsize;
 }
 
+http::http()
+{
+    curl = curl_easy_init();
+    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+    curl_easy_setopt(curl, CURLOPT_TIMEOUT, HTTP_GET_TIMEOUT);
+    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
+    curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
+    curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);
+    curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);
+    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
+    stream = NULL;
+}
+
+http::~http()
+{
+    curl_easy_cleanup(curl);
+    destroy_giostream();
+}
+
 void http::destroy_giostream() {
     debug_print("destroy_giostream called.\n");
     if (stream) {
diff --git a/src/plugins/litehtml_viewer/http.h b/src/plugins/litehtml_viewer/http.h
index d0ae4c8..0e36212 100644
--- a/src/plugins/litehtml_viewer/http.h
+++ b/src/plugins/litehtml_viewer/http.h
@@ -20,7 +20,6 @@ public:
     GInputStream *load_url(const gchar *url, GError **error);
 
 private:
-    static size_t curl_write_data(char* ptr, size_t size, size_t nmemb, void* data_ptr);
     void destroy_giostream();
 };
 

commit bd0e8d8455d44450a709065824f268f32124f19a
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Jan 29 23:13:51 2019 +0100

    Fix a memory leak in Litehtml plugin's http loader

diff --git a/src/plugins/litehtml_viewer/http.cpp b/src/plugins/litehtml_viewer/http.cpp
index bed5638..12e8636 100644
--- a/src/plugins/litehtml_viewer/http.cpp
+++ b/src/plugins/litehtml_viewer/http.cpp
@@ -73,7 +73,7 @@ GInputStream *http::load_url(const gchar *url, GError **error)
     if (!strncmp(url, "file:///", 8) || g_file_test(url, G_FILE_TEST_EXISTS)) {
 	gchar* newurl = g_filename_from_uri(url, NULL, NULL);
 	if (g_file_get_contents(newurl ? newurl : url, &content, &len, &_error)) {
-	    stream = g_memory_input_stream_new_from_data(content, len, NULL);
+	    stream = g_memory_input_stream_new_from_data(content, len, g_free);
 	} else {
 	    debug_print("Got error: %s\n", _error->message);
 	}
@@ -88,7 +88,7 @@ GInputStream *http::load_url(const gchar *url, GError **error)
 	} else {
 	    debug_print("Image size: %d\n", data.size);
 	    stream = g_memory_input_stream_new_from_data(
-		g_memdup(data.memory, data.size), data.size, NULL);
+		g_memdup(data.memory, data.size), data.size, g_free);
 	    g_free(data.memory);
 	}
     }

commit a75a6516bd962b780c7c56b07ac16ac53a2c577a
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Jan 29 22:23:54 2019 +0100

    Fix a huge memory leak in Litehtml

diff --git a/src/plugins/litehtml_viewer/container_linux.cpp b/src/plugins/litehtml_viewer/container_linux.cpp
index c34df5f..26845fb 100644
--- a/src/plugins/litehtml_viewer/container_linux.cpp
+++ b/src/plugins/litehtml_viewer/container_linux.cpp
@@ -887,6 +887,7 @@ cairo_surface_t* container_linux::surface_from_pixbuf(const GdkPixbuf *bmp)
 //	Gdk::Cairo::set_source_pixbuf(ctx, bmp, 0.0, 0.0);
 	cairo_t *ctx = cairo_create(ret);
 	cairo_paint(ctx);
+	cairo_destroy(ctx);
 
 	return ret;
 }

commit 03d8afe96798aca22400f693ceb7a42f0be3a9a2
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Jan 29 21:47:53 2019 +0100

    Properly free previous document from memory in litehtml's clear()
    
    We also call paint_white() earlier in redraw().
    This results in properly clearing the previously
    rendered html content when opening a different
    HTML part.

diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index 2998564..fd74a3b 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -240,10 +240,10 @@ void lh_widget::redraw()
 	GdkWindow *gdkwin;
 	cairo_t *cr;
 
-	if (m_html == NULL) {
-		g_warning("lh_widget::redraw: No document!");
+	paint_white();
+
+	if (m_html == NULL)
 		return;
-	}
 
 	/* Get width of the viewport. */
 	gdkwin = gtk_viewport_get_view_window(GTK_VIEWPORT(m_viewport));
@@ -269,8 +269,6 @@ void lh_widget::redraw()
 				m_html->width(), m_html->height());
 	}
 
-	paint_white();
-
 	/* Paint the rendered HTML. */
 	gdkwin = gtk_widget_get_window(m_drawing_area);
 	if (gdkwin == NULL) {
@@ -303,6 +301,7 @@ void lh_widget::paint_white()
 }
 void lh_widget::clear()
 {
+	m_html = nullptr;
 	paint_white();
 	m_rendered_width = 0;
 }

commit b31dc41035cc54ea98cbcdeec51c6ecfd020849a
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Jan 29 20:12:41 2019 +0100

    Make Litehtml plugin open links in configured way

diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index 8db070c..2998564 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -39,6 +39,10 @@
 #include "lh_widget_wrapped.h"
 #include "http.h"
 
+extern "C" {
+const gchar *prefs_common_get_uri_cmd(void);
+}
+
 char master_css[] = {
 #include "css.inc"
 };
@@ -459,13 +463,7 @@ static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event,
         if (!w->m_clicked_url.empty())
         {
                 debug_print("Open in browser: %s\n", w->m_clicked_url.c_str());
-		gtk_show_uri(gdk_screen_get_default(),
-			     w->m_clicked_url.c_str(),
-			     GDK_CURRENT_TIME, &error);
-                if (error) {
-                    g_warning("Failed opening url(%s): %s", w->m_clicked_url, error->message);
-                    g_clear_error(&error);
-                }
+                open_uri(w->m_clicked_url.c_str(), prefs_common_get_uri_cmd());
         }
     }
 

commit 8c1f502b438b009b8ef0ee2612a76923e994910d
Author: Michael Rasmussen <mir at datanom.net>
Date:   Sun Jan 27 12:21:37 2019 +0100

    Refactor http class to prevent memory leak
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/litehtml_viewer/http.cpp b/src/plugins/litehtml_viewer/http.cpp
index 7472bd7..bed5638 100644
--- a/src/plugins/litehtml_viewer/http.cpp
+++ b/src/plugins/litehtml_viewer/http.cpp
@@ -22,11 +22,13 @@ http::http()
     curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);
     curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);
     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http::curl_write_data);
+    stream = NULL;
 }
 
 http::~http()
 {
     curl_easy_cleanup(curl);
+    destroy_giostream();
 }
 
 size_t http::curl_write_data(char* ptr, size_t size, size_t nmemb, void* data_ptr) {
@@ -48,12 +50,12 @@ size_t http::curl_write_data(char* ptr, size_t size, size_t nmemb, void* data_pt
     return realsize;
 }
 
-void http::destroy_giostream(gpointer data) {
-    GInputStream* gio;
-    if (data) {
-	gio = G_INPUT_STREAM(data);
-	g_input_stream_close(gio, NULL, NULL);
-	gio = NULL;
+void http::destroy_giostream() {
+    debug_print("destroy_giostream called.\n");
+    if (stream) {
+	debug_print("Freeing input_stream\n");
+	g_input_stream_close(stream, NULL, NULL);
+	g_object_unref(stream);
     }
 }
 
@@ -63,7 +65,6 @@ GInputStream *http::load_url(const gchar *url, GError **error)
     CURLcode res = CURLE_OK;
     gsize len;
     gchar* content;
-    GInputStream* stream = NULL;
     struct Data data;
 
     data.memory = (char *) g_malloc(1);
@@ -72,7 +73,7 @@ GInputStream *http::load_url(const gchar *url, GError **error)
     if (!strncmp(url, "file:///", 8) || g_file_test(url, G_FILE_TEST_EXISTS)) {
 	gchar* newurl = g_filename_from_uri(url, NULL, NULL);
 	if (g_file_get_contents(newurl ? newurl : url, &content, &len, &_error)) {
-	    stream = g_memory_input_stream_new_from_data(content, len, http::destroy_giostream);
+	    stream = g_memory_input_stream_new_from_data(content, len, NULL);
 	} else {
 	    debug_print("Got error: %s\n", _error->message);
 	}
@@ -86,7 +87,8 @@ GInputStream *http::load_url(const gchar *url, GError **error)
 	    _error = g_error_new_literal(G_FILE_ERROR, res, curl_easy_strerror(res));
 	} else {
 	    debug_print("Image size: %d\n", data.size);
-	    stream = g_memory_input_stream_new_from_data(g_memdup(data.memory, data.size), data.size, http::destroy_giostream);
+	    stream = g_memory_input_stream_new_from_data(
+		g_memdup(data.memory, data.size), data.size, NULL);
 	    g_free(data.memory);
 	}
     }
diff --git a/src/plugins/litehtml_viewer/http.h b/src/plugins/litehtml_viewer/http.h
index c8c3bee..d0ae4c8 100644
--- a/src/plugins/litehtml_viewer/http.h
+++ b/src/plugins/litehtml_viewer/http.h
@@ -11,6 +11,7 @@
 class http
 {
     CURL*           curl;
+    GInputStream*   stream;
 
 public:
     http();
@@ -20,7 +21,7 @@ public:
 
 private:
     static size_t curl_write_data(char* ptr, size_t size, size_t nmemb, void* data_ptr);
-    static void destroy_giostream(gpointer data);
+    void destroy_giostream();
 };
 
 
diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index c561e9c..8db070c 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -92,7 +92,6 @@ lh_widget::lh_widget()
 			        GDK_BUTTON_RELEASE_MASK
 			      | GDK_BUTTON_PRESS_MASK
 			      | GDK_POINTER_MOTION_MASK);
-
 }
 
 lh_widget::~lh_widget()
@@ -153,6 +152,7 @@ GdkPixbuf *lh_widget::get_image(const litehtml::tchar_t* url, bool redraw_on_rea
 {
 	GError *error = NULL;
 	GdkPixbuf *pixbuf = NULL;
+	http* http_loader = NULL;
 
 	if (!lh_prefs_get()->enable_remote_content) {
 		debug_print("blocking download of image from '%s'\n", url);
@@ -164,8 +164,8 @@ GdkPixbuf *lh_widget::get_image(const litehtml::tchar_t* url, bool redraw_on_rea
         lh_widget_statusbar_push(msg);
 	g_free(msg);
 	
-	http http_loader;
-	GInputStream *image = http_loader.load_url(url, &error);
+	http_loader = new http();
+	GInputStream *image = http_loader->load_url(url, &error);
     
 	if (error || !image) {
 	    if (error) {
@@ -178,11 +178,9 @@ GdkPixbuf *lh_widget::get_image(const litehtml::tchar_t* url, bool redraw_on_rea
 	pixbuf = gdk_pixbuf_new_from_stream(image, NULL, &error);
 	if (error) {
 	    g_warning("lh_widget::get_image: Could not create pixbuf %s", error->message);
-	    //g_object_unref(pixbuf);
 	    pixbuf = NULL;
 	    g_clear_error(&error);
 	}
-	g_input_stream_close(image, NULL, NULL);
 
 /*	if (redraw_on_ready) {
 		redraw();
@@ -190,6 +188,9 @@ GdkPixbuf *lh_widget::get_image(const litehtml::tchar_t* url, bool redraw_on_rea
 
 statusbar_pop:
 	lh_widget_statusbar_pop();
+	if (http_loader) {
+		delete http_loader;
+	}
 	
 	return pixbuf;
 }

commit 25a07eba8f796c029fa839037c2d9920799ed8e7
Author: Michael Rasmussen <mir at datanom.net>
Date:   Sun Jan 27 01:11:24 2019 +0100

    Remove unused stuff
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/litehtml_viewer/lh_widget.h b/src/plugins/litehtml_viewer/lh_widget.h
index ed56f7d..daffcac 100644
--- a/src/plugins/litehtml_viewer/lh_widget.h
+++ b/src/plugins/litehtml_viewer/lh_widget.h
@@ -4,8 +4,6 @@
 
 #include "container_linux.h"
 
-#define HTTP_GET_TIMEOUT 5L
-
 class lh_widget : public container_linux
 {
 	public:
@@ -36,7 +34,6 @@ class lh_widget : public container_linux
 
 	private:
 		void paint_white();
-		GInputStream *load_url(const gchar *url, GError **error);
 
 		gint m_rendered_width;
 		GtkWidget *m_drawing_area;

commit c24d165f1d242d0bda1800d042c19ae2d8218c85
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sat Jan 26 21:59:15 2019 +0100

    Added preferences page to LiteHTML plugin and make it respect the enable_remote_content pref
    
    Only "enable_remote_content" pref for now.

diff --git a/src/plugins/litehtml_viewer/Makefile.am b/src/plugins/litehtml_viewer/Makefile.am
index 648960c..ded5d58 100644
--- a/src/plugins/litehtml_viewer/Makefile.am
+++ b/src/plugins/litehtml_viewer/Makefile.am
@@ -41,9 +41,11 @@ litehtml_viewer_la_CFLAGS = -std=c99
 litehtml_viewer_la_SOURCES = \
 	container_linux.cpp \
 	plugin.c \
+	lh_prefs.c \
 	lh_viewer.c \
 	lh_widget.cpp \
 	container_linux.h \
+	lh_prefs.h \
 	lh_viewer.h \
 	lh_widget.h \
 	lh_widget_wrapped.h \
@@ -62,6 +64,7 @@ litehtml_viewer_la_CPPFLAGS = \
 	$(IFLAGS) \
 	$(GLIB_CFLAGS) \
 	$(GTK_CFLAGS) \
+	$(ENCHANT_CFLAGS) \
 	$(FONTCONFIG_CFLAGS) \
 	$(CAIRO_CFLAGS) \
 	$(CURL_FLAGS)
diff --git a/src/plugins/litehtml_viewer/lh_prefs.c b/src/plugins/litehtml_viewer/lh_prefs.c
new file mode 100644
index 0000000..fec2ff5
--- /dev/null
+++ b/src/plugins/litehtml_viewer/lh_prefs.c
@@ -0,0 +1,171 @@
+/*
+ * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client
+ * Copyright(C) 2019 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 <glib.h>
+#include <glib/gi18n.h>
+
+#include "prefs_gtk.h"
+#include "common/defs.h"
+#include "common/utils.h"
+#include "gtk/gtkutils.h"
+
+#include "lh_prefs.h"
+
+#define PREFS_BLOCK_NAME "LiteHTML"
+
+static void create_lh_prefs_page(PrefsPage *page, GtkWindow *window,
+		gpointer data);
+static void destroy_lh_prefs_page(PrefsPage *page);
+static void save_lh_prefs_page(PrefsPage *page);
+static void save_prefs(void);
+
+LHPrefs lh_prefs;
+
+struct _LHPrefsPage {
+	PrefsPage page;
+	GtkWidget *enable_remote_content;
+};
+typedef struct _LHPrefsPage LHPrefsPage;
+
+static PrefParam param[] = {
+	{ "enable_remote_content", "FALSE", &lh_prefs.enable_remote_content, P_BOOL,
+		NULL, NULL, NULL },
+	{ NULL, NULL, NULL, 0, NULL, NULL, NULL }
+};
+
+static LHPrefsPage lh_prefs_page;
+
+LHPrefs *lh_prefs_get(void)
+{
+	return &lh_prefs;
+}
+
+void lh_prefs_init(void)
+{
+	static gchar *path[3];
+	gchar *rcpath;
+
+	path[0] = _("Plugins");
+	path[1] = "LiteHTML";
+	path[2] = NULL;
+
+	prefs_set_default(param);
+	rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
+	prefs_read_config(param, PREFS_BLOCK_NAME, rcpath, NULL);
+	g_free(rcpath);
+
+	lh_prefs_page.page.path = path;
+	lh_prefs_page.page.create_widget = create_lh_prefs_page;
+	lh_prefs_page.page.destroy_widget = destroy_lh_prefs_page;
+	lh_prefs_page.page.save_page = save_lh_prefs_page;
+	lh_prefs_page.page.weight = 30.0;
+	prefs_gtk_register_page((PrefsPage *) &lh_prefs_page);
+}
+
+void lh_prefs_done(void)
+{
+}
+
+static void create_lh_prefs_page(PrefsPage *page, GtkWindow *window,
+		gpointer data)
+{
+	LHPrefsPage *prefs_page = (LHPrefsPage *)page;
+	GtkWidget *vbox;
+	GtkWidget *vbox_remote;
+	GtkWidget *frame;
+	GtkWidget *label;
+	GtkWidget *enable_remote_content;
+
+	vbox = gtk_vbox_new(FALSE, 3);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), VBOX_BORDER);
+	gtk_widget_show(vbox);
+
+	/* Enable remote content */
+	vbox_remote = gtkut_get_options_frame(vbox, &frame, _("Remote resources"));
+
+	label = gtk_label_new(_("Loading remote resources can lead to some privacy issues.\n"
+				"When remote content loading is disabled, nothing will be requested\n"
+				"from the network."));
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+
+	enable_remote_content = gtk_check_button_new_with_label(_("Enable loading of remote content"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enable_remote_content),
+			lh_prefs.enable_remote_content);
+
+	gtk_box_pack_start(GTK_BOX(vbox_remote), label, FALSE, FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox_remote), enable_remote_content, FALSE, FALSE, 0);
+	gtk_widget_show_all(vbox_remote);
+
+	prefs_page->enable_remote_content = enable_remote_content;
+	prefs_page->page.widget = vbox;
+}
+
+static void destroy_lh_prefs_page(PrefsPage *page)
+{
+}
+
+static void save_lh_prefs_page(PrefsPage *page)
+{
+	LHPrefsPage *prefs_page = (LHPrefsPage *)page;
+
+	lh_prefs.enable_remote_content = gtk_toggle_button_get_active(
+			GTK_TOGGLE_BUTTON(prefs_page->enable_remote_content));
+
+	save_prefs();
+}
+
+static void save_prefs(void)
+{
+	PrefFile *pref_file;
+	gchar *rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+			COMMON_RC, NULL);
+
+	pref_file = prefs_write_open(rcpath);
+
+	if (!pref_file) {
+		g_warning("failed to open configuration file '%s' for writing", rcpath);
+		g_free(rcpath);
+		return;
+	}
+	if (prefs_set_block_label(pref_file, PREFS_BLOCK_NAME) < 0) {
+		g_warning("failed to set block label "PREFS_BLOCK_NAME);
+		g_free(rcpath);
+		return;
+	}
+
+	if (prefs_write_param(param, pref_file->fp) < 0) {
+		g_warning("failed to write LiteHTML Viewer plugin configuration");
+		prefs_file_close_revert(pref_file);
+		g_free(rcpath);
+		return;
+	}
+
+	if (fprintf(pref_file->fp, "\n") < 0) {
+		FILE_OP_ERROR(rcpath, "fprintf");
+		prefs_file_close_revert(pref_file);
+	} else {
+		debug_print("successfully saved LiteHTML Viewer plugin configuration\n");
+		prefs_file_close(pref_file);
+	}
+
+	g_free(rcpath);
+}
diff --git a/src/plugins/litehtml_viewer/lh_prefs.h b/src/plugins/litehtml_viewer/lh_prefs.h
new file mode 100644
index 0000000..25dcbd2
--- /dev/null
+++ b/src/plugins/litehtml_viewer/lh_prefs.h
@@ -0,0 +1,42 @@
+/*
+ * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client
+ * Copyright(C) 2019 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.
+ */
+
+#ifndef LH_PREFS_H
+#define LH_PREFS_H
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _LHPrefs LHPrefs;
+
+struct _LHPrefs
+{
+	gboolean enable_remote_content;
+};
+
+LHPrefs *lh_prefs_get(void);
+void lh_prefs_init(void);
+void lh_prefs_done(void);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LH_PREFS_H */
diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index 4a8551a..c561e9c 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -34,6 +34,7 @@
 
 #include "litehtml/litehtml.h"
 
+#include "lh_prefs.h"
 #include "lh_widget.h"
 #include "lh_widget_wrapped.h"
 #include "http.h"
@@ -153,6 +154,11 @@ GdkPixbuf *lh_widget::get_image(const litehtml::tchar_t* url, bool redraw_on_rea
 	GError *error = NULL;
 	GdkPixbuf *pixbuf = NULL;
 
+	if (!lh_prefs_get()->enable_remote_content) {
+		debug_print("blocking download of image from '%s'\n", url);
+		return NULL;
+	}
+
 	debug_print("Loading... %s\n", url);
 	gchar *msg = g_strdup_printf("Loading %s ...", url);
         lh_widget_statusbar_push(msg);
diff --git a/src/plugins/litehtml_viewer/plugin.c b/src/plugins/litehtml_viewer/plugin.c
index 3b0dc93..bfdc48e 100644
--- a/src/plugins/litehtml_viewer/plugin.c
+++ b/src/plugins/litehtml_viewer/plugin.c
@@ -27,11 +27,14 @@
 #include <mimeview.h>
 #include <plugin.h>
 
+#include "lh_prefs.h"
+
 extern MimeViewerFactory lh_viewer_factory;
 
 gint plugin_init(gchar **error)
 {
 	debug_print("LH: plugin_init\n");
+	lh_prefs_init();
 	mimeview_register_viewer_factory(&lh_viewer_factory);
 	return 0;
 }
@@ -40,6 +43,7 @@ gboolean plugin_done(void)
 {
 	debug_print("LH: plugin_done\n");
 	mimeview_unregister_viewer_factory(&lh_viewer_factory);
+	lh_prefs_done();
 	return TRUE;
 }
 

commit 822b482afa172bf7621a8c9b49706d8f697fc4d6
Author: Michael Rasmussen <mir at datanom.net>
Date:   Sat Jan 26 00:15:04 2019 +0100

    No need to configure CURLOPT_WRITEFUNCTION twice
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/litehtml_viewer/http.cpp b/src/plugins/litehtml_viewer/http.cpp
index ad86191..7472bd7 100644
--- a/src/plugins/litehtml_viewer/http.cpp
+++ b/src/plugins/litehtml_viewer/http.cpp
@@ -80,7 +80,6 @@ GInputStream *http::load_url(const gchar *url, GError **error)
     } else {
 	if (!curl) return NULL;
 	curl_easy_setopt(curl, CURLOPT_URL, url);
-	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_data);
 	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&data);
 	res = curl_easy_perform(curl);
 	if (res != CURLE_OK) {

commit 5446663475a6fe5881ae15f39cf503ace1cd984b
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri Jan 25 23:49:32 2019 +0100

    Use debug_print() and g_warning() instead of g_log() in litehtml_viewer

diff --git a/src/plugins/litehtml_viewer/http.cpp b/src/plugins/litehtml_viewer/http.cpp
index 92023be..ad86191 100644
--- a/src/plugins/litehtml_viewer/http.cpp
+++ b/src/plugins/litehtml_viewer/http.cpp
@@ -1,6 +1,12 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include <string.h>
 #include "http.h"
 
+#include "utils.h"
+
 struct Data {
   char *memory;
   size_t size;
@@ -30,7 +36,7 @@ size_t http::curl_write_data(char* ptr, size_t size, size_t nmemb, void* data_pt
     char *input = (char *) g_realloc(data->memory, data->size + realsize + 1);
     if(input == NULL) {
         /* out of memory! */
-        g_log(NULL, G_LOG_LEVEL_WARNING, "not enough memory (realloc returned NULL)");
+        g_warning("not enough memory (realloc returned NULL)");
         return 0;
     }
     
@@ -68,7 +74,7 @@ GInputStream *http::load_url(const gchar *url, GError **error)
 	if (g_file_get_contents(newurl ? newurl : url, &content, &len, &_error)) {
 	    stream = g_memory_input_stream_new_from_data(content, len, http::destroy_giostream);
 	} else {
-	    g_log(NULL, G_LOG_LEVEL_MESSAGE, "%s", _error->message);
+	    debug_print("Got error: %s\n", _error->message);
 	}
 	g_free(newurl);
     } else {
@@ -80,7 +86,7 @@ GInputStream *http::load_url(const gchar *url, GError **error)
 	if (res != CURLE_OK) {
 	    _error = g_error_new_literal(G_FILE_ERROR, res, curl_easy_strerror(res));
 	} else {
-	    g_log(NULL, G_LOG_LEVEL_MESSAGE, "Image size: %d", data.size);
+	    debug_print("Image size: %d\n", data.size);
 	    stream = g_memory_input_stream_new_from_data(g_memdup(data.memory, data.size), data.size, http::destroy_giostream);
 	    g_free(data.memory);
 	}
diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index 5e779fb..4a8551a 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -30,6 +30,8 @@
 #include <curl/curl.h>
 #include <gdk/gdk.h>
 
+#include "utils.h"
+
 #include "litehtml/litehtml.h"
 
 #include "lh_widget.h"
@@ -108,19 +110,19 @@ GtkWidget *lh_widget::get_widget() const
 
 void lh_widget::set_caption(const litehtml::tchar_t* caption)
 {
-	g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget set_caption");
+	debug_print("lh_widget set_caption\n");
 	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");
+	debug_print("lh_widget set_base_url\n");
 	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. url -> %s", url);
+	debug_print("lh_widget on_anchor_click. url -> %s\n", url);
 	m_clicked_url = url;
 	
 	return;
@@ -128,7 +130,7 @@ void lh_widget::on_anchor_click(const litehtml::tchar_t* url, const litehtml::el
 
 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");
+	debug_print("lh_widget import_css\n");
 	baseurl = master_css;
 }
 
@@ -142,7 +144,7 @@ void lh_widget::get_client_rect(litehtml::position& client) const
 	client.x = 0;
 	client.y = 0;
 
-//	g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget::get_client_rect: %dx%d",
+//	debug_print("lh_widget::get_client_rect: %dx%d\n",
 //			client.width, client.height);
 }
 
@@ -151,7 +153,7 @@ GdkPixbuf *lh_widget::get_image(const litehtml::tchar_t* url, bool redraw_on_rea
 	GError *error = NULL;
 	GdkPixbuf *pixbuf = NULL;
 
-	g_log(NULL, G_LOG_LEVEL_MESSAGE, "Loading... %s", url);
+	debug_print("Loading... %s\n", url);
 	gchar *msg = g_strdup_printf("Loading %s ...", url);
         lh_widget_statusbar_push(msg);
 	g_free(msg);
@@ -161,7 +163,7 @@ GdkPixbuf *lh_widget::get_image(const litehtml::tchar_t* url, bool redraw_on_rea
     
 	if (error || !image) {
 	    if (error) {
-		g_log(NULL, G_LOG_LEVEL_WARNING, "lh_widget::get_image: Could not create pixbuf %s", error->message);
+		g_warning("lh_widget::get_image: Could not create pixbuf %s", error->message);
 		g_clear_error(&error);
 	    }
 	    goto statusbar_pop;
@@ -169,7 +171,7 @@ GdkPixbuf *lh_widget::get_image(const litehtml::tchar_t* url, bool redraw_on_rea
 
 	pixbuf = gdk_pixbuf_new_from_stream(image, NULL, &error);
 	if (error) {
-	    g_log(NULL, G_LOG_LEVEL_WARNING, "lh_widget::get_image: Could not create pixbuf %s", error->message);
+	    g_warning("lh_widget::get_image: Could not create pixbuf %s", error->message);
 	    //g_object_unref(pixbuf);
 	    pixbuf = NULL;
 	    g_clear_error(&error);
@@ -192,7 +194,7 @@ 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");
+		debug_print("lh_widget::open_html created document\n");
 		redraw();
 	}
 	lh_widget_statusbar_pop();
@@ -228,7 +230,7 @@ void lh_widget::redraw()
 	cairo_t *cr;
 
 	if (m_html == NULL) {
-		g_log(NULL, G_LOG_LEVEL_WARNING, "lh_widget::redraw: No document!");
+		g_warning("lh_widget::redraw: No document!");
 		return;
 	}
 
@@ -238,8 +240,7 @@ void lh_widget::redraw()
 
 	/* 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",
+		debug_print("lh_widget::redraw: width changed: %d != %d\n",
 				m_rendered_width, width);
 
 		/* Update our internally stored width, mainly so that
@@ -250,8 +251,7 @@ void lh_widget::redraw()
 		/* 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());
+		debug_print("render is %dx%d\n", m_html->width(), m_html->height());
 
 		/* Change drawing area's size to match what was rendered. */
 		gtk_widget_set_size_request(m_drawing_area,
@@ -263,7 +263,7 @@ void lh_widget::redraw()
 	/* 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!");
+		g_warning("lh_widget::redraw: No GdkWindow to draw on!");
 		return;
 	}
 	cr = gdk_cairo_create(GDK_DRAWABLE(gdkwin));
@@ -276,7 +276,7 @@ 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!");
+		g_warning("lh_widget::clear: No GdkWindow to draw on!");
 		return;
 	}
 	cairo_t *cr = gdk_cairo_create(GDK_DRAWABLE(gdkwin));
@@ -357,7 +357,7 @@ void lh_widget::update_cursor()
 
 void lh_widget::print()
 {
-    g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget print");
+    debug_print("lh_widget print\n");
     gtk_widget_realize(GTK_WIDGET(m_drawing_area));
 }
 
@@ -374,7 +374,7 @@ static void size_allocate_cb(GtkWidget *widget, GdkRectangle *allocation,
 {
 	lh_widget *w = (lh_widget *)user_data;
 
-	g_log(NULL, G_LOG_LEVEL_MESSAGE, "size_allocate_cb: %dx%d",
+	debug_print("size_allocate_cb: %dx%d\n",
 			allocation->width, allocation->height);
 
 	w->setHeight(allocation->height);
@@ -387,7 +387,7 @@ static gboolean button_press_event(GtkWidget *widget, GdkEventButton *event,
     litehtml::position::vector redraw_boxes;
     lh_widget *w = (lh_widget *)user_data;
     
-    g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget on_button_press_event");
+    debug_print("lh_widget on_button_press_event\n");
 
     if(w->m_html)
     {    
@@ -395,7 +395,7 @@ static gboolean button_press_event(GtkWidget *widget, GdkEventButton *event,
         {
             for(auto& pos : redraw_boxes)
             {
-		g_log(NULL, G_LOG_LEVEL_MESSAGE, "x: %d y:%d w: %d h: %d", pos.x, pos.y, pos.width, pos.height);
+		debug_print("x: %d y:%d w: %d h: %d\n", pos.x, pos.y, pos.width, pos.height);
                 gtk_widget_queue_draw_area(widget, pos.x, pos.y, pos.width, pos.height);
             }
         }
@@ -410,7 +410,7 @@ static gboolean motion_notify_event(GtkWidget *widget, GdkEventButton *event,
     litehtml::position::vector redraw_boxes;
     lh_widget *w = (lh_widget *)user_data;
     
-    //g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget on_motion_notify_event");
+    //debug_print("lh_widget on_motion_notify_event\n");
 
     if(w->m_html)
     {    
@@ -419,7 +419,7 @@ static gboolean motion_notify_event(GtkWidget *widget, GdkEventButton *event,
         {
             for (auto& pos : redraw_boxes)
             {
-		g_log(NULL, G_LOG_LEVEL_MESSAGE, "x: %d y:%d w: %d h: %d", pos.x, pos.y, pos.width, pos.height);
+		debug_print("x: %d y:%d w: %d h: %d\n", pos.x, pos.y, pos.width, pos.height);
                 gtk_widget_queue_draw_area(widget, pos.x, pos.y, pos.width, pos.height);
             }
         }
@@ -435,7 +435,7 @@ static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event,
     lh_widget *w = (lh_widget *)user_data;
     GError* error = NULL;
 
-	g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget on_button_release_event");
+	debug_print("lh_widget on_button_release_event\n");
 	
 	if(w->m_html)
 	{
@@ -444,19 +444,19 @@ static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event,
         {
             for (auto& pos : redraw_boxes)
             {
-		g_log(NULL, G_LOG_LEVEL_MESSAGE, "x: %d y:%d w: %d h: %d", pos.x, pos.y, pos.width, pos.height);
+		debug_print("x: %d y:%d w: %d h: %d\n", pos.x, pos.y, pos.width, pos.height);
                 gtk_widget_queue_draw_area(widget, pos.x, pos.y, pos.width, pos.height);
             }
         }
         
         if (!w->m_clicked_url.empty())
         {
-                g_log(NULL, G_LOG_LEVEL_MESSAGE, "Open in browser: %s", w->m_clicked_url.c_str());
+                debug_print("Open in browser: %s\n", w->m_clicked_url.c_str());
 		gtk_show_uri(gdk_screen_get_default(),
 			     w->m_clicked_url.c_str(),
 			     GDK_CURRENT_TIME, &error);
                 if (error) {
-                    g_log(NULL, G_LOG_LEVEL_WARNING, "Failed opening url(%s): %s", w->m_clicked_url, error->message);
+                    g_warning("Failed opening url(%s): %s", w->m_clicked_url, error->message);
                     g_clear_error(&error);
                 }
         }

commit d6e19f9d606e89e2d6eeca737623ef4b42da2947
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri Jan 25 22:49:49 2019 +0100

    Fix URL display in statusbar when hovering over a link in litehtml_viewer

diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index 42b96dc..5e779fb 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -29,6 +29,9 @@
 #include <sys/stat.h>
 #include <curl/curl.h>
 #include <gdk/gdk.h>
+
+#include "litehtml/litehtml.h"
+
 #include "lh_widget.h"
 #include "lh_widget_wrapped.h"
 #include "http.h"
@@ -295,36 +298,61 @@ void lh_widget::clear()
 
 void lh_widget::set_cursor(const litehtml::tchar_t* cursor)
 {
-    //g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget set_cursor %s:%s", m_cursor, cursor);
-    if (cursor)
-    {
-	if (m_cursor != cursor)
-	{
-	    m_cursor = cursor;
-	    update_cursor();
+	if (cursor) {
+		if (m_cursor != cursor) {
+			m_cursor = cursor;
+			update_cursor();
+		}
 	}
-    }
 }
 
 void lh_widget::update_cursor()
 {
-    //g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget update_cursor %s", m_cursor);
-    GdkCursorType cursType = GDK_ARROW;
-    if(m_cursor == _t("pointer"))
-    {
-        cursType = GDK_HAND2;
-    }
-    if(cursType == GDK_ARROW)
-    {
-	lh_widget_statusbar_pop();
-        gdk_window_set_cursor(gtk_widget_get_window(m_drawing_area), NULL);
-    } else
-    {
-	if (!m_clicked_url.empty()) {
-	    lh_widget_statusbar_push(m_clicked_url.c_str());
+	gint x, y;
+	litehtml::element::ptr root_el, over_el, el;
+	GdkWindow *w = gdk_display_get_window_at_pointer(gdk_display_get_default(),
+			&x, &y);
+	GdkCursorType cursType = GDK_ARROW;
+
+	if (m_cursor == _t("pointer")) {
+		cursType = GDK_HAND2;
+	}
+
+	if (cursType == GDK_ARROW) {
+		gdk_window_set_cursor(gtk_widget_get_window(m_drawing_area), NULL);
+	} else {
+		gdk_window_set_cursor(gtk_widget_get_window(m_drawing_area), gdk_cursor_new(cursType));
+	}
+
+	if (w != gtk_widget_get_window(m_drawing_area))
+		return;
+
+	/* Find the element we are hovering over */
+	root_el = m_html->root();
+	g_return_if_fail(root_el != NULL);
+	over_el = root_el->get_element_by_point(x, y, x, y);
+	g_return_if_fail(over_el != NULL);
+
+	/* If it's not an anchor, check if it has a parent anchor
+	 * (e.g. it's an image within an anchor) and grab a pointer
+	 * to that. */
+	if (strcmp(over_el->get_tagName(), "a") && over_el->parent()) {
+		el = over_el->parent();
+		while (el && el != root_el && strcmp(el->get_tagName(), "a")) {
+			el = el->parent();
+		}
+
+		if (el && el != root_el)
+			over_el = el;
+	}
+
+	/* If it's an anchor, show its "href" attribute in statusbar,
+	 * otherwise clear statusbar. */
+	if (!strcmp(over_el->get_tagName(), "a")) {
+		lh_widget_statusbar_push(over_el->get_attr(_t("href")));
+	} else {
+		lh_widget_statusbar_pop();
 	}
-        gdk_window_set_cursor(gtk_widget_get_window(m_drawing_area), gdk_cursor_new(cursType));
-    }
 }
 
 void lh_widget::print()

commit 882efa14e4b171edd5550ec98f23a14e251983c4
Author: Michael Rasmussen <mir at datanom.net>
Date:   Sat Dec 1 18:36:46 2018 +0100

    Update current version of litehtml. Fix a crash when document contains no fonts
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/litehtml_viewer/container_linux.cpp b/src/plugins/litehtml_viewer/container_linux.cpp
index 2341da5..c34df5f 100644
--- a/src/plugins/litehtml_viewer/container_linux.cpp
+++ b/src/plugins/litehtml_viewer/container_linux.cpp
@@ -50,7 +50,9 @@ litehtml::uint_ptr container_linux::create_font( const litehtml::tchar_t* faceNa
 {
 	litehtml::string_vector fonts;
 	litehtml::split_string(faceName, fonts, ",");
-	litehtml::trim(fonts[0]);
+	if (! fonts.empty()) {
+	    litehtml::trim(fonts[0]);
+	}
 
 	cairo_font_face_t* fnt = 0;
 
@@ -140,8 +142,10 @@ int container_linux::text_width( const litehtml::tchar_t* text, litehtml::uint_p
 
 	cairo_save(m_temp_cr);
 
-	cairo_set_font_size(m_temp_cr, fnt->size);
-	cairo_set_font_face(m_temp_cr, fnt->font);
+	if (fnt) {
+	    cairo_set_font_size(m_temp_cr, fnt->size);
+	    cairo_set_font_face(m_temp_cr, fnt->font);
+	}
 	cairo_text_extents_t ext;
 	cairo_text_extents(m_temp_cr, text, &ext);
 
@@ -158,8 +162,10 @@ void container_linux::draw_text( litehtml::uint_ptr hdc, const litehtml::tchar_t
 
 	apply_clip(cr);
 
-	cairo_set_font_face(cr, fnt->font);
-	cairo_set_font_size(cr, fnt->size);
+	if (fnt) {
+	    cairo_set_font_face(cr, fnt->font);
+	    cairo_set_font_size(cr, fnt->size);
+	}
 	cairo_font_extents_t ext;
 	cairo_font_extents(cr, &ext);
 
@@ -173,20 +179,21 @@ void container_linux::draw_text( litehtml::uint_ptr hdc, const litehtml::tchar_t
 
 	int tw = 0;
 
-	if(fnt->underline || fnt->strikeout)
-	{
+	if (fnt) {
+	    if(fnt->underline || fnt->strikeout)
+	    {
 		tw = text_width(text, hFont);
-	}
+	    }
 
-	if(fnt->underline)
-	{
+	    if(fnt->underline)
+	    {
 		cairo_set_line_width(cr, 1);
 		cairo_move_to(cr, x, y + 1.5);
 		cairo_line_to(cr, x + tw, y + 1.5);
 		cairo_stroke(cr);
-	}
-	if(fnt->strikeout)
-	{
+	    }
+	    if(fnt->strikeout)
+	    {
 		cairo_text_extents_t tex;
 		cairo_text_extents(cr, "x", &tex);
 
@@ -196,7 +203,8 @@ void container_linux::draw_text( litehtml::uint_ptr hdc, const litehtml::tchar_t
 		cairo_move_to(cr, x, (double) ln_y - 0.5);
 		cairo_line_to(cr, x + tw, (double) ln_y - 0.5);
 		cairo_stroke(cr);
-	}
+	    }
+	}   
 
 	cairo_restore(cr);
 }
diff --git a/src/plugins/litehtml_viewer/lh_viewer.c b/src/plugins/litehtml_viewer/lh_viewer.c
index f127917..fe5727f 100644
--- a/src/plugins/litehtml_viewer/lh_viewer.c
+++ b/src/plugins/litehtml_viewer/lh_viewer.c
@@ -171,11 +171,10 @@ MimeViewer *lh_viewer_create()
 	return (MimeViewer *)viewer;
 }
 
-void lh_widget_statusbar_push(gchar* msg)
+void lh_widget_statusbar_push(const gchar* msg)
 {
 	MainWindow *mainwin = mainwindow_get_mainwindow();
 	STATUSBAR_PUSH(mainwin, msg);
-        g_free(msg);
 }
 
 void lh_widget_statusbar_pop()
diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index a4528c0..42b96dc 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -149,7 +149,9 @@ GdkPixbuf *lh_widget::get_image(const litehtml::tchar_t* url, bool redraw_on_rea
 	GdkPixbuf *pixbuf = NULL;
 
 	g_log(NULL, G_LOG_LEVEL_MESSAGE, "Loading... %s", url);
-        lh_widget_statusbar_push(g_strconcat("Loading ", url, " ...", NULL));
+	gchar *msg = g_strdup_printf("Loading %s ...", url);
+        lh_widget_statusbar_push(msg);
+	g_free(msg);
 	
 	http http_loader;
 	GInputStream *image = http_loader.load_url(url, &error);
@@ -183,7 +185,7 @@ statusbar_pop:
 
 void lh_widget::open_html(const gchar *contents)
 {
-	lh_widget_statusbar_push(g_strconcat("Loading HTML part", " ...", NULL));
+	lh_widget_statusbar_push("Loading HTML part ...");
 	m_html = litehtml::document::createFromString(contents, this, &m_context);
 	m_rendered_width = 0;
 	if (m_html != NULL) {
@@ -314,9 +316,13 @@ void lh_widget::update_cursor()
     }
     if(cursType == GDK_ARROW)
     {
+	lh_widget_statusbar_pop();
         gdk_window_set_cursor(gtk_widget_get_window(m_drawing_area), NULL);
     } else
     {
+	if (!m_clicked_url.empty()) {
+	    lh_widget_statusbar_push(m_clicked_url.c_str());
+	}
         gdk_window_set_cursor(gtk_widget_get_window(m_drawing_area), gdk_cursor_new(cursType));
     }
 }
@@ -380,6 +386,7 @@ static gboolean motion_notify_event(GtkWidget *widget, GdkEventButton *event,
 
     if(w->m_html)
     {    
+	//if(m_cursor == _t("pointer"))
         if(w->m_html->on_mouse_over((int) event->x, (int) event->y, (int) event->x, (int) event->y, redraw_boxes))
         {
             for (auto& pos : redraw_boxes)
@@ -405,7 +412,7 @@ static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event,
 	if(w->m_html)
 	{
 	    w->m_clicked_url.clear();
-        if(w->m_html->on_lbutton_up((int) event->x, (int) event->y, (int) event->x, (int) event->y, redraw_boxes))
+	    if(w->m_html->on_lbutton_up((int) event->x, (int) event->y, (int) event->x, (int) event->y, redraw_boxes))
         {
             for (auto& pos : redraw_boxes)
             {
diff --git a/src/plugins/litehtml_viewer/lh_widget_wrapped.h b/src/plugins/litehtml_viewer/lh_widget_wrapped.h
index 64085fa..24dcb57 100644
--- a/src/plugins/litehtml_viewer/lh_widget_wrapped.h
+++ b/src/plugins/litehtml_viewer/lh_widget_wrapped.h
@@ -12,7 +12,7 @@ GtkWidget *lh_widget_get_widget(lh_widget_wrapped *w);
 void lh_widget_open_html(lh_widget_wrapped *w, const gchar *path);
 void lh_widget_clear(lh_widget_wrapped *w);
 void lh_widget_destroy(lh_widget_wrapped *w);
-void lh_widget_statusbar_push(gchar* msg);
+void lh_widget_statusbar_push(const gchar* msg);
 void lh_widget_statusbar_pop();
 void lh_widget_print(lh_widget_wrapped *w);
 
diff --git a/src/plugins/litehtml_viewer/litehtml/attributes.h b/src/plugins/litehtml_viewer/litehtml/attributes.h
index ca1c9a7..98487f0 100644
--- a/src/plugins/litehtml_viewer/litehtml/attributes.h
+++ b/src/plugins/litehtml_viewer/litehtml/attributes.h
@@ -1,32 +1,35 @@
-#pragma once
-
-namespace litehtml
-{
-	struct attr_color
-	{
-		unsigned char    rgbBlue;
-		unsigned char    rgbGreen;
-		unsigned char    rgbRed;
-		unsigned char    rgbAlpha;
-		attr_color()
-		{
-			rgbAlpha	= 255;
-			rgbBlue		= 0;
-			rgbGreen	= 0;
-			rgbRed		= 0;
-		}
-	};
-
-	struct attr_border
-	{
-		style_border	border;
-		int				width;
-		attr_color		color;
-
-		attr_border()
-		{
-			border	= borderNone;
-			width	= 0;
-		}
-	};
-}
\ No newline at end of file
+#ifndef LH_ATTRIBUTES_H
+#define LH_ATTRIBUTES_H
+
+namespace litehtml
+{
+	struct attr_color
+	{
+		unsigned char    rgbBlue;
+		unsigned char    rgbGreen;
+		unsigned char    rgbRed;
+		unsigned char    rgbAlpha;
+		attr_color()
+		{
+			rgbAlpha	= 255;
+			rgbBlue		= 0;
+			rgbGreen	= 0;
+			rgbRed		= 0;
+		}
+	};
+
+	struct attr_border
+	{
+		style_border	border;
+		int				width;
+		attr_color		color;
+
+		attr_border()
+		{
+			border	= borderNone;
+			width	= 0;
+		}
+	};
+}
+
+#endif  // LH_ATTRIBUTES_H
diff --git a/src/plugins/litehtml_viewer/litehtml/background.cpp b/src/plugins/litehtml_viewer/litehtml/background.cpp
index 87ce59e..1c65e30 100644
--- a/src/plugins/litehtml_viewer/litehtml/background.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/background.cpp
@@ -1,79 +1,79 @@
-#include "html.h"
-#include "background.h"
-
-litehtml::background::background(void)
-{
-	m_attachment	= background_attachment_scroll;
-	m_repeat		= background_repeat_repeat;
-	m_clip			= background_box_border;
-	m_origin		= background_box_padding;
-	m_color.alpha	= 0;
-	m_color.red		= 0;
-	m_color.green	= 0;
-	m_color.blue	= 0;
-}
-
-litehtml::background::background( const background& val )
-{
-	m_image			= val.m_image;
-	m_baseurl		= val.m_baseurl;
-	m_color			= val.m_color;
-	m_attachment	= val.m_attachment;
-	m_position		= val.m_position;
-	m_repeat		= val.m_repeat;
-	m_clip			= val.m_clip;
-	m_origin		= val.m_origin;
-}
-
-litehtml::background::~background(void)
-{
-}
-
-litehtml::background& litehtml::background::operator=( const background& val )
-{
-	m_image			= val.m_image;
-	m_baseurl		= val.m_baseurl;
-	m_color			= val.m_color;
-	m_attachment	= val.m_attachment;
-	m_position		= val.m_position;
-	m_repeat		= val.m_repeat;
-	m_clip			= val.m_clip;
-	m_origin		= val.m_origin;
-	return *this;
-}
-
-
-litehtml::background_paint::background_paint() : color(0, 0, 0, 0)
-{
-	position_x		= 0;
-	position_y		= 0;
-	attachment		= background_attachment_scroll;
-	repeat			= background_repeat_repeat;
-	is_root			= false;
-}
-
-litehtml::background_paint::background_paint( const background_paint& val )
-{
-	image			= val.image;
-	baseurl			= val.baseurl;
-	attachment		= val.attachment;
-	repeat			= val.repeat;
-	color			= val.color;
-	clip_box		= val.clip_box;
-	origin_box		= val.origin_box;
-	border_box		= val.border_box;
-	border_radius	= val.border_radius;
-	image_size		= val.image_size;
-	position_x		= val.position_x;
-	position_y		= val.position_y;
-	is_root			= val.is_root;
-}
-
-void litehtml::background_paint::operator=( const background& val )
-{
-	attachment	= val.m_attachment;
-	baseurl		= val.m_baseurl;
-	image		= val.m_image;
-	repeat		= val.m_repeat;
-	color		= val.m_color;
-}
+#include "html.h"
+#include "background.h"
+
+litehtml::background::background(void)
+{
+	m_attachment	= background_attachment_scroll;
+	m_repeat		= background_repeat_repeat;
+	m_clip			= background_box_border;
+	m_origin		= background_box_padding;
+	m_color.alpha	= 0;
+	m_color.red		= 0;
+	m_color.green	= 0;
+	m_color.blue	= 0;
+}
+
+litehtml::background::background( const background& val )
+{
+	m_image			= val.m_image;
+	m_baseurl		= val.m_baseurl;
+	m_color			= val.m_color;
+	m_attachment	= val.m_attachment;
+	m_position		= val.m_position;
+	m_repeat		= val.m_repeat;
+	m_clip			= val.m_clip;
+	m_origin		= val.m_origin;
+}
+
+litehtml::background::~background(void)
+{
+}
+
+litehtml::background& litehtml::background::operator=( const background& val )
+{
+	m_image			= val.m_image;
+	m_baseurl		= val.m_baseurl;
+	m_color			= val.m_color;
+	m_attachment	= val.m_attachment;
+	m_position		= val.m_position;
+	m_repeat		= val.m_repeat;
+	m_clip			= val.m_clip;
+	m_origin		= val.m_origin;
+	return *this;
+}
+
+
+litehtml::background_paint::background_paint() : color(0, 0, 0, 0)
+{
+	position_x		= 0;
+	position_y		= 0;
+	attachment		= background_attachment_scroll;
+	repeat			= background_repeat_repeat;
+	is_root			= false;
+}
+
+litehtml::background_paint::background_paint( const background_paint& val )
+{
+	image			= val.image;
+	baseurl			= val.baseurl;
+	attachment		= val.attachment;
+	repeat			= val.repeat;
+	color			= val.color;
+	clip_box		= val.clip_box;
+	origin_box		= val.origin_box;
+	border_box		= val.border_box;
+	border_radius	= val.border_radius;
+	image_size		= val.image_size;
+	position_x		= val.position_x;
+	position_y		= val.position_y;
+	is_root			= val.is_root;
+}
+
+void litehtml::background_paint::operator=( const background& val )
+{
+	attachment	= val.m_attachment;
+	baseurl		= val.m_baseurl;
+	image		= val.m_image;
+	repeat		= val.m_repeat;
+	color		= val.m_color;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/background.h b/src/plugins/litehtml_viewer/litehtml/background.h
index e3fc2f6..ce0b69a 100644
--- a/src/plugins/litehtml_viewer/litehtml/background.h
+++ b/src/plugins/litehtml_viewer/litehtml/background.h
@@ -1,54 +1,58 @@
-#pragma once
-#include "types.h"
-#include "attributes.h"
-#include "css_length.h"
-#include "css_position.h"
-#include "web_color.h"
-#include "borders.h"
-
-namespace litehtml
-{
-	class background
-	{
-	public:
-		tstring					m_image;
-		tstring					m_baseurl;
-		web_color				m_color;
-		background_attachment	m_attachment;
-		css_position			m_position;
-		background_repeat		m_repeat;
-		background_box			m_clip;
-		background_box			m_origin;
-		css_border_radius		m_radius;
-
-	public:
-		background(void);
-		background(const background& val);
-		~background(void);
-
-		background& operator=(const background& val);
-	};
-
-	class background_paint
-	{
-	public:
-		tstring					image;
-		tstring					baseurl;
-		background_attachment	attachment;
-		background_repeat		repeat;
-		web_color				color;
-		position				clip_box;
-		position				origin_box;
-		position				border_box;
-		border_radiuses			border_radius;
-		size					image_size;
-		int						position_x;
-		int						position_y;
-		bool					is_root;
-	public:
-		background_paint();
-		background_paint(const background_paint& val);
-		void operator=(const background& val);
-	};
-
-}
\ No newline at end of file
+#ifndef LH_BACKGROUND_H
+#define LH_BACKGROUND_H
+
+#include "types.h"
+#include "attributes.h"
+#include "css_length.h"
+#include "css_position.h"
+#include "web_color.h"
+#include "borders.h"
+
+namespace litehtml
+{
+	class background
+	{
+	public:
+		tstring					m_image;
+		tstring					m_baseurl;
+		web_color				m_color;
+		background_attachment	m_attachment;
+		css_position			m_position;
+		background_repeat		m_repeat;
+		background_box			m_clip;
+		background_box			m_origin;
+		css_border_radius		m_radius;
+
+	public:
+		background(void);
+		background(const background& val);
+		~background(void);
+
+		background& operator=(const background& val);
+	};
+
+	class background_paint
+	{
+	public:
+		tstring					image;
+		tstring					baseurl;
+		background_attachment	attachment;
+		background_repeat		repeat;
+		web_color				color;
+		position				clip_box;
+		position				origin_box;
+		position				border_box;
+		border_radiuses			border_radius;
+		size					image_size;
+		int						position_x;
+		int						position_y;
+		bool					is_root;
+	public:
+		background_paint();
+		background_paint(const background_paint& val);
+		void operator=(const background& val);
+	};
+
+}
+
+#endif  // LH_BACKGROUND_H
diff --git a/src/plugins/litehtml_viewer/litehtml/borders.h b/src/plugins/litehtml_viewer/litehtml/borders.h
index a46a9f8..859b852 100644
--- a/src/plugins/litehtml_viewer/litehtml/borders.h
+++ b/src/plugins/litehtml_viewer/litehtml/borders.h
@@ -1,296 +1,300 @@
-#pragma once
-#include "css_length.h"
-#include "types.h"
-
-namespace litehtml
-{
-	struct css_border
-	{
-		css_length		width;
-		border_style	style;
-		web_color		color;
-
-		css_border()
-		{
-			style = border_style_none;
-		}
-
-		css_border(const css_border& val)
-		{
-			width	= val.width;
-			style	= val.style;
-			color	= val.color;
-		}
-
-		css_border& operator=(const css_border& val)
-		{
-			width	= val.width;
-			style	= val.style;
-			color	= val.color;
-			return *this;
-		}
-	};
-
-	struct border
-	{
-		int				width;
-		border_style	style;
-		web_color		color;
-
-		border()
-		{
-			width = 0;
-		}
-		border(const border& val)
-		{
-			width = val.width;
-			style = val.style;
-			color = val.color;
-		}
-		border(const css_border& val)
-		{
-			width = (int) val.width.val();
-			style = val.style;
-			color = val.color;
-		}
-		border& operator=(const border& val)
-		{
-			width = val.width;
-			style = val.style;
-			color = val.color;
-			return *this;
-		}
-		border& operator=(const css_border& val)
-		{
-			width = (int) val.width.val();
-			style = val.style;
-			color = val.color;
-			return *this;
-		}
-	};
-
-	struct border_radiuses
-	{
-		int	top_left_x;
-		int	top_left_y;
-
-		int	top_right_x;
-		int	top_right_y;
-
-		int	bottom_right_x;
-		int	bottom_right_y;
-
-		int	bottom_left_x;
-		int	bottom_left_y;
-
-		border_radiuses()
-		{
-			top_left_x = 0;
-			top_left_y = 0;
-			top_right_x = 0;
-			top_right_y = 0;
-			bottom_right_x = 0;
-			bottom_right_y = 0;
-			bottom_left_x = 0;
-			bottom_left_y = 0;
-		}
-		border_radiuses(const border_radiuses& val)
-		{
-			top_left_x = val.top_left_x;
-			top_left_y = val.top_left_y;
-			top_right_x = val.top_right_x;
-			top_right_y = val.top_right_y;
-			bottom_right_x = val.bottom_right_x;
-			bottom_right_y = val.bottom_right_y;
-			bottom_left_x = val.bottom_left_x;
-			bottom_left_y = val.bottom_left_y;
-		}
-		border_radiuses& operator = (const border_radiuses& val)
-		{
-			top_left_x = val.top_left_x;
-			top_left_y = val.top_left_y;
-			top_right_x = val.top_right_x;
-			top_right_y = val.top_right_y;
-			bottom_right_x = val.bottom_right_x;
-			bottom_right_y = val.bottom_right_y;
-			bottom_left_x = val.bottom_left_x;
-			bottom_left_y = val.bottom_left_y;
-			return *this;
-		}
-		void operator += (const margins& mg)
-		{
-			top_left_x += mg.left;
-			top_left_y += mg.top;
-			top_right_x += mg.right;
-			top_right_y += mg.top;
-			bottom_right_x += mg.right;
-			bottom_right_y += mg.bottom;
-			bottom_left_x += mg.left;
-			bottom_left_y += mg.bottom;
-			fix_values();
-		}
-		void operator -= (const margins& mg)
-		{
-			top_left_x -= mg.left;
-			top_left_y -= mg.top;
-			top_right_x -= mg.right;
-			top_right_y -= mg.top;
-			bottom_right_x -= mg.right;
-			bottom_right_y -= mg.bottom;
-			bottom_left_x -= mg.left;
-			bottom_left_y -= mg.bottom;
-			fix_values();
-		}
-		void fix_values()
-		{
-			if (top_left_x < 0)	top_left_x = 0;
-			if (top_left_y < 0)	top_left_y = 0;
-			if (top_right_x < 0) top_right_x = 0;
-			if (bottom_right_x < 0) bottom_right_x = 0;
-			if (bottom_right_y < 0) bottom_right_y = 0;
-			if (bottom_left_x < 0) bottom_left_x = 0;
-			if (bottom_left_y < 0) bottom_left_y = 0;
-		}
-	};
-
-	struct css_border_radius
-	{
-		css_length	top_left_x;
-		css_length	top_left_y;
-
-		css_length	top_right_x;
-		css_length	top_right_y;
-
-		css_length	bottom_right_x;
-		css_length	bottom_right_y;
-
-		css_length	bottom_left_x;
-		css_length	bottom_left_y;
-
-		css_border_radius()
-		{
-
-		}
-
-		css_border_radius(const css_border_radius& val)
-		{
-			top_left_x		= val.top_left_x;
-			top_left_y		= val.top_left_y;
-			top_right_x		= val.top_right_x;
-			top_right_y		= val.top_right_y;
-			bottom_left_x	= val.bottom_left_x;
-			bottom_left_y	= val.bottom_left_y;
-			bottom_right_x	= val.bottom_right_x;
-			bottom_right_y	= val.bottom_right_y;
-		}
-
-		css_border_radius& operator=(const css_border_radius& val)
-		{
-			top_left_x		= val.top_left_x;
-			top_left_y		= val.top_left_y;
-			top_right_x		= val.top_right_x;
-			top_right_y		= val.top_right_y;
-			bottom_left_x	= val.bottom_left_x;
-			bottom_left_y	= val.bottom_left_y;
-			bottom_right_x	= val.bottom_right_x;
-			bottom_right_y	= val.bottom_right_y;
-			return *this;
-		}
-		border_radiuses calc_percents(int width, int height)
-		{
-			border_radiuses ret;
-			ret.bottom_left_x = bottom_left_x.calc_percent(width);
-			ret.bottom_left_y = bottom_left_y.calc_percent(height);
-			ret.top_left_x = top_left_x.calc_percent(width);
-			ret.top_left_y = top_left_y.calc_percent(height);
-			ret.top_right_x = top_right_x.calc_percent(width);
-			ret.top_right_y = top_right_y.calc_percent(height);
-			ret.bottom_right_x = bottom_right_x.calc_percent(width);
-			ret.bottom_right_y = bottom_right_y.calc_percent(height);
-			return ret;
-		}
-	};
-
-	struct css_borders
-	{
-		css_border			left;
-		css_border			top;
-		css_border			right;
-		css_border			bottom;
-		css_border_radius	radius;
-
-		css_borders()
-		{
-
-		}
-
-		css_borders(const css_borders& val)
-		{
-			left	= val.left;
-			right	= val.right;
-			top		= val.top;
-			bottom	= val.bottom;
-			radius	= val.radius;
-		}
-
-		css_borders& operator=(const css_borders& val)
-		{
-			left	= val.left;
-			right	= val.right;
-			top		= val.top;
-			bottom	= val.bottom;
-			radius	= val.radius;
-			return *this;
-		}
-	};
-
-	struct borders
-	{
-		border			left;
-		border			top;
-		border			right;
-		border			bottom;
-		border_radiuses	radius;
-
-		borders()
-		{
-
-		}
-
-		borders(const borders& val)
-		{
-			left = val.left;
-			right = val.right;
-			top = val.top;
-			bottom = val.bottom;
-			radius = val.radius;
-		}
-
-		borders(const css_borders& val)
-		{
-			left = val.left;
-			right = val.right;
-			top = val.top;
-			bottom = val.bottom;
-		}
-
-		borders& operator=(const borders& val)
-		{
-			left = val.left;
-			right = val.right;
-			top = val.top;
-			bottom = val.bottom;
-			radius = val.radius;
-			return *this;
-		}
-
-		borders& operator=(const css_borders& val)
-		{
-			left = val.left;
-			right = val.right;
-			top = val.top;
-			bottom = val.bottom;
-			return *this;
-		}
-	};
-}
+#ifndef LH_BORDERS_H
+#define LH_BORDERS_H
+
+#include "css_length.h"
+#include "types.h"
+
+namespace litehtml
+{
+	struct css_border
+	{
+		css_length		width;
+		border_style	style;
+		web_color		color;
+
+		css_border()
+		{
+			style = border_style_none;
+		}
+
+		css_border(const css_border& val)
+		{
+			width	= val.width;
+			style	= val.style;
+			color	= val.color;
+		}
+
+		css_border& operator=(const css_border& val)
+		{
+			width	= val.width;
+			style	= val.style;
+			color	= val.color;
+			return *this;
+		}
+	};
+
+	struct border
+	{
+		int				width;
+		border_style	style;
+		web_color		color;
+
+		border()
+		{
+			width = 0;
+		}
+		border(const border& val)
+		{
+			width = val.width;
+			style = val.style;
+			color = val.color;
+		}
+		border(const css_border& val)
+		{
+			width = (int) val.width.val();
+			style = val.style;
+			color = val.color;
+		}
+		border& operator=(const border& val)
+		{
+			width = val.width;
+			style = val.style;
+			color = val.color;
+			return *this;
+		}
+		border& operator=(const css_border& val)
+		{
+			width = (int) val.width.val();
+			style = val.style;
+			color = val.color;
+			return *this;
+		}
+	};
+
+	struct border_radiuses
+	{
+		int	top_left_x;
+		int	top_left_y;
+
+		int	top_right_x;
+		int	top_right_y;
+
+		int	bottom_right_x;
+		int	bottom_right_y;
+
+		int	bottom_left_x;
+		int	bottom_left_y;
+
+		border_radiuses()
+		{
+			top_left_x = 0;
+			top_left_y = 0;
+			top_right_x = 0;
+			top_right_y = 0;
+			bottom_right_x = 0;
+			bottom_right_y = 0;
+			bottom_left_x = 0;
+			bottom_left_y = 0;
+		}
+		border_radiuses(const border_radiuses& val)
+		{
+			top_left_x = val.top_left_x;
+			top_left_y = val.top_left_y;
+			top_right_x = val.top_right_x;
+			top_right_y = val.top_right_y;
+			bottom_right_x = val.bottom_right_x;
+			bottom_right_y = val.bottom_right_y;
+			bottom_left_x = val.bottom_left_x;
+			bottom_left_y = val.bottom_left_y;
+		}
+		border_radiuses& operator = (const border_radiuses& val)
+		{
+			top_left_x = val.top_left_x;
+			top_left_y = val.top_left_y;
+			top_right_x = val.top_right_x;
+			top_right_y = val.top_right_y;
+			bottom_right_x = val.bottom_right_x;
+			bottom_right_y = val.bottom_right_y;
+			bottom_left_x = val.bottom_left_x;
+			bottom_left_y = val.bottom_left_y;
+			return *this;
+		}
+		void operator += (const margins& mg)
+		{
+			top_left_x += mg.left;
+			top_left_y += mg.top;
+			top_right_x += mg.right;
+			top_right_y += mg.top;
+			bottom_right_x += mg.right;
+			bottom_right_y += mg.bottom;
+			bottom_left_x += mg.left;
+			bottom_left_y += mg.bottom;
+			fix_values();
+		}
+		void operator -= (const margins& mg)
+		{
+			top_left_x -= mg.left;
+			top_left_y -= mg.top;
+			top_right_x -= mg.right;
+			top_right_y -= mg.top;
+			bottom_right_x -= mg.right;
+			bottom_right_y -= mg.bottom;
+			bottom_left_x -= mg.left;
+			bottom_left_y -= mg.bottom;
+			fix_values();
+		}
+		void fix_values()
+		{
+			if (top_left_x < 0)	top_left_x = 0;
+			if (top_left_y < 0)	top_left_y = 0;
+			if (top_right_x < 0) top_right_x = 0;
+			if (bottom_right_x < 0) bottom_right_x = 0;
+			if (bottom_right_y < 0) bottom_right_y = 0;
+			if (bottom_left_x < 0) bottom_left_x = 0;
+			if (bottom_left_y < 0) bottom_left_y = 0;
+		}
+	};
+
+	struct css_border_radius
+	{
+		css_length	top_left_x;
+		css_length	top_left_y;
+
+		css_length	top_right_x;
+		css_length	top_right_y;
+
+		css_length	bottom_right_x;
+		css_length	bottom_right_y;
+
+		css_length	bottom_left_x;
+		css_length	bottom_left_y;
+
+		css_border_radius()
+		{
+
+		}
+
+		css_border_radius(const css_border_radius& val)
+		{
+			top_left_x		= val.top_left_x;
+			top_left_y		= val.top_left_y;
+			top_right_x		= val.top_right_x;
+			top_right_y		= val.top_right_y;
+			bottom_left_x	= val.bottom_left_x;
+			bottom_left_y	= val.bottom_left_y;
+			bottom_right_x	= val.bottom_right_x;
+			bottom_right_y	= val.bottom_right_y;
+		}
+
+		css_border_radius& operator=(const css_border_radius& val)
+		{
+			top_left_x		= val.top_left_x;
+			top_left_y		= val.top_left_y;
+			top_right_x		= val.top_right_x;
+			top_right_y		= val.top_right_y;
+			bottom_left_x	= val.bottom_left_x;
+			bottom_left_y	= val.bottom_left_y;
+			bottom_right_x	= val.bottom_right_x;
+			bottom_right_y	= val.bottom_right_y;
+			return *this;
+		}
+		border_radiuses calc_percents(int width, int height)
+		{
+			border_radiuses ret;
+			ret.bottom_left_x = bottom_left_x.calc_percent(width);
+			ret.bottom_left_y = bottom_left_y.calc_percent(height);
+			ret.top_left_x = top_left_x.calc_percent(width);
+			ret.top_left_y = top_left_y.calc_percent(height);
+			ret.top_right_x = top_right_x.calc_percent(width);
+			ret.top_right_y = top_right_y.calc_percent(height);
+			ret.bottom_right_x = bottom_right_x.calc_percent(width);
+			ret.bottom_right_y = bottom_right_y.calc_percent(height);
+			return ret;
+		}
+	};
+
+	struct css_borders
+	{
+		css_border			left;
+		css_border			top;
+		css_border			right;
+		css_border			bottom;
+		css_border_radius	radius;
+
+		css_borders()
+		{
+
+		}
+
+		css_borders(const css_borders& val)
+		{
+			left	= val.left;
+			right	= val.right;
+			top		= val.top;
+			bottom	= val.bottom;
+			radius	= val.radius;
+		}
+
+		css_borders& operator=(const css_borders& val)
+		{
+			left	= val.left;
+			right	= val.right;
+			top		= val.top;
+			bottom	= val.bottom;
+			radius	= val.radius;
+			return *this;
+		}
+	};
+
+	struct borders
+	{
+		border			left;
+		border			top;
+		border			right;
+		border			bottom;
+		border_radiuses	radius;
+
+		borders()
+		{
+
+		}
+
+		borders(const borders& val)
+		{
+			left = val.left;
+			right = val.right;
+			top = val.top;
+			bottom = val.bottom;
+			radius = val.radius;
+		}
+
+		borders(const css_borders& val)
+		{
+			left = val.left;
+			right = val.right;
+			top = val.top;
+			bottom = val.bottom;
+		}
+
+		borders& operator=(const borders& val)
+		{
+			left = val.left;
+			right = val.right;
+			top = val.top;
+			bottom = val.bottom;
+			radius = val.radius;
+			return *this;
+		}
+
+		borders& operator=(const css_borders& val)
+		{
+			left = val.left;
+			right = val.right;
+			top = val.top;
+			bottom = val.bottom;
+			return *this;
+		}
+	};
+}
+
+#endif  // LH_BORDERS_H
diff --git a/src/plugins/litehtml_viewer/litehtml/box.cpp b/src/plugins/litehtml_viewer/litehtml/box.cpp
index 023d15c..4ad23c5 100644
--- a/src/plugins/litehtml_viewer/litehtml/box.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/box.cpp
@@ -1,434 +1,434 @@
-#include "html.h"
-#include "box.h"
-#include "html_tag.h"
-
-
-litehtml::box_type litehtml::block_box::get_type()
-{
-	return box_block;
-}
-
-int litehtml::block_box::height()
-{
-	return m_element->height();
-}
-
-int litehtml::block_box::width()
-{
-	return m_element->width();
-}
-
-void litehtml::block_box::add_element(const element::ptr &el)
-{
-	m_element = el;
-	el->m_box = this;
-}
-
-void litehtml::block_box::finish(bool last_box)
-{
-	if(!m_element) return;
-	m_element->apply_relative_shift(m_box_right - m_box_left);
-}
-
-bool litehtml::block_box::can_hold(const element::ptr &el, white_space ws)
-{
-	if(m_element || el->is_inline_box())
-	{
-		return false;
-	}
-	return true;
-}
-
-bool litehtml::block_box::is_empty()
-{
-	if(m_element)
-	{
-		return false;
-	}
-	return true;
-}
-
-int litehtml::block_box::baseline()
-{
-	if(m_element)
-	{
-		return m_element->get_base_line();
-	}
-	return 0;
-}
-
-void litehtml::block_box::get_elements( elements_vector& els )
-{
-	els.push_back(m_element);
-}
-
-int litehtml::block_box::top_margin()
-{
-	if(m_element && m_element->collapse_top_margin())
-	{
-		return m_element->m_margins.top;
-	}
-	return 0;
-}
-
-int litehtml::block_box::bottom_margin()
-{
-	if(m_element && m_element->collapse_bottom_margin())
-	{
-		return m_element->m_margins.bottom;
-	}
-	return 0;
-}
-
-void litehtml::block_box::y_shift( int shift )
-{
-	m_box_top += shift;
-	if(m_element)
-	{
-		m_element->m_pos.y += shift;
-	}
-}
-
-void litehtml::block_box::new_width( int left, int right, elements_vector& els )
-{
-
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-litehtml::box_type litehtml::line_box::get_type()
-{
-	return box_line;
-}
-
-int litehtml::line_box::height()
-{
-	return m_height;
-}
-
-int litehtml::line_box::width()
-{
-	return m_width;
-}
-
-void litehtml::line_box::add_element(const element::ptr &el)
-{
-	el->m_skip	= false;
-	el->m_box	= 0;
-	bool add	= true;
-	if( (m_items.empty() && el->is_white_space()) || el->is_break() )
-	{
-		el->m_skip = true;
-	} else if(el->is_white_space())
-	{
-		if (have_last_space())
-		{
-			add = false;
-			el->m_skip = true;
-		}
-	}
-
-	if(add)
-	{
-		el->m_box = this;
-		m_items.push_back(el);
-
-		if(!el->m_skip)
-		{
-			int el_shift_left	= el->get_inline_shift_left();
-			int el_shift_right	= el->get_inline_shift_right();
-
-			el->m_pos.x	= m_box_left + m_width + el_shift_left + el->content_margins_left();
-			el->m_pos.y	= m_box_top + el->content_margins_top();
-			m_width		+= el->width() + el_shift_left + el_shift_right;
-		}
-	}
-}
-
-void litehtml::line_box::finish(bool last_box)
-{
-	if( is_empty() || (!is_empty() && last_box && is_break_only()) )
-	{
-		m_height = 0;
-		return;
-	}
-
-	for(auto i = m_items.rbegin(); i != m_items.rend(); i++)
-	{
-		if((*i)->is_white_space() || (*i)->is_break())
-		{
-			if(!(*i)->m_skip)
-			{
-				(*i)->m_skip = true;
-				m_width -= (*i)->width();
-			}
-		} else
-		{
-			break;
-		}
-	}
-
-	int base_line	= m_font_metrics.base_line();
-	int line_height = m_line_height;
-
-	int add_x = 0;
-	switch(m_text_align)
-	{
-	case text_align_right:
-		if(m_width < (m_box_right - m_box_left))
-		{
-			add_x = (m_box_right - m_box_left) - m_width;
-		}
-		break;
-	case text_align_center:
-		if(m_width < (m_box_right - m_box_left))
-		{
-			add_x = ((m_box_right - m_box_left) - m_width) / 2;
-		}
-		break;
-	default:
-		add_x = 0;
-	}
-
-	m_height = 0;
-	// find line box baseline and line-height
-	for(const auto& el : m_items)
-	{
-		if(el->get_display() == display_inline_text)
-		{
-			font_metrics fm;
-			el->get_font(&fm);
-			base_line	= std::max(base_line,	fm.base_line());
-			line_height = std::max(line_height, el->line_height());
-			m_height = std::max(m_height, fm.height);
-		}
-		el->m_pos.x += add_x;
-	}
-
-	if(m_height)
-	{
-		base_line += (line_height - m_height) / 2;
-	}
-
-	m_height = line_height;
-
-	int y1	= 0;
-	int y2	= m_height;
-
-	for (const auto& el : m_items)
-	{
-		if(el->get_display() == display_inline_text)
-		{
-			font_metrics fm;
-			el->get_font(&fm);
-			el->m_pos.y = m_height - base_line - fm.ascent;
-		} else
-		{
-			switch(el->get_vertical_align())
-			{
-			case va_super:
-			case va_sub:
-			case va_baseline:
-				el->m_pos.y = m_height - base_line - el->height() + el->get_base_line() + el->content_margins_top();
-				break;
-			case va_top:
-				el->m_pos.y = y1 + el->content_margins_top();
-				break;
-			case va_text_top:
-				el->m_pos.y = m_height - base_line - m_font_metrics.ascent + el->content_margins_top();
-				break;
-			case va_middle:
-				el->m_pos.y = m_height - base_line - m_font_metrics.x_height / 2 - el->height() / 2 + el->content_margins_top();
-				break;
-			case va_bottom:
-				el->m_pos.y = y2 - el->height() + el->content_margins_top();
-				break;
-			case va_text_bottom:
-				el->m_pos.y = m_height - base_line + m_font_metrics.descent - el->height() + el->content_margins_top();
-				break;
-			}
-			y1 = std::min(y1, el->top());
-			y2 = std::max(y2, el->bottom());
-		}
-	}
-
-	css_offsets offsets;
-
-	for (const auto& el : m_items)
-	{
-		el->m_pos.y -= y1;
-		el->m_pos.y += m_box_top;
-		if(el->get_display() != display_inline_text)
-		{
-			switch(el->get_vertical_align())
-			{
-			case va_top:
-				el->m_pos.y = m_box_top + el->content_margins_top();
-				break;
-			case va_bottom:
-				el->m_pos.y = m_box_top + (y2 - y1) - el->height() + el->content_margins_top();
-				break;
-			case va_baseline:
-				//TODO: process vertical align "baseline"
-				break;
-			case va_middle:
-				//TODO: process vertical align "middle"
-				break;
-			case va_sub:
-				//TODO: process vertical align "sub"
-				break;
-			case va_super:
-				//TODO: process vertical align "super"
-				break;
-			case va_text_bottom:
-				//TODO: process vertical align "text-bottom"
-				break;
-			case va_text_top:
-				//TODO: process vertical align "text-top"
-				break;
-			}
-		}
-
-		el->apply_relative_shift(m_box_right - m_box_left);
-	}
-	m_height = y2 - y1;
-	m_baseline = (base_line - y1) - (m_height - line_height);
-}
-
-bool litehtml::line_box::can_hold(const element::ptr &el, white_space ws)
-{
-	if(!el->is_inline_box()) return false;
-
-	if(el->is_break())
-	{
-		return false;
-	}
-
-	if(ws == white_space_nowrap || ws == white_space_pre)
-	{
-		return true;
-	}
-
-	if(m_box_left + m_width + el->width() + el->get_inline_shift_left() + el->get_inline_shift_right() > m_box_right)
-	{
-		return false;
-	}
-
-	return true;
-}
-
-bool litehtml::line_box::have_last_space()
-{
-	bool ret = false;
-	for (auto i = m_items.rbegin(); i != m_items.rend() && !ret; i++)
-	{
-		if((*i)->is_white_space() || (*i)->is_break())
-		{
-			ret = true;
-		} else
-		{
-			break;
-		}
-	}
-	return ret;
-}
-
-bool litehtml::line_box::is_empty()
-{
-	if(m_items.empty()) return true;
-	for (auto i = m_items.rbegin(); i != m_items.rend(); i++)
-	{
-		if(!(*i)->m_skip || (*i)->is_break())
-		{
-			return false;
-		}
-	}
-	return true;
-}
-
-int litehtml::line_box::baseline()
-{
-	return m_baseline;
-}
-
-void litehtml::line_box::get_elements( elements_vector& els )
-{
-	els.insert(els.begin(), m_items.begin(), m_items.end());
-}
-
-int litehtml::line_box::top_margin()
-{
-	return 0;
-}
-
-int litehtml::line_box::bottom_margin()
-{
-	return 0;
-}
-
-void litehtml::line_box::y_shift( int shift )
-{
-	m_box_top += shift;
-	for (auto& el : m_items)
-	{
-		el->m_pos.y += shift;
-	}
-}
-
-bool litehtml::line_box::is_break_only()
-{
-	if(m_items.empty()) return true;
-
-	if(m_items.front()->is_break())
-	{
-		for (auto& el : m_items)
-		{
-			if(!el->m_skip)
-			{
-				return false;
-			}
-		}
-		return true;
-	}
-	return false;
-}
-
-void litehtml::line_box::new_width( int left, int right, elements_vector& els )
-{
-	int add = left - m_box_left;
-	if(add)
-	{
-		m_box_left	= left;
-		m_box_right	= right;
-		m_width = 0;
-		auto remove_begin = m_items.end();
-		for (auto i = m_items.begin() + 1; i != m_items.end(); i++)
-		{
-			element::ptr el = (*i);
-
-			if(!el->m_skip)
-			{
-				if(m_box_left + m_width + el->width() + el->get_inline_shift_right() + el->get_inline_shift_left() > m_box_right)
-				{
-					remove_begin = i;
-					break;
-				} else
-				{
-					el->m_pos.x += add;
-					m_width += el->width() + el->get_inline_shift_right() + el->get_inline_shift_left();
-				}
-			}
-		}
-		if(remove_begin != m_items.end())
-		{
-			els.insert(els.begin(), remove_begin, m_items.end());
-			m_items.erase(remove_begin, m_items.end());
-
-			for(const auto& el : els)
-			{
-				el->m_box = 0;
-			}
-		}
-	}
-}
-
+#include "html.h"
+#include "box.h"
+#include "html_tag.h"
+
+
+litehtml::box_type litehtml::block_box::get_type()
+{
+	return box_block;
+}
+
+int litehtml::block_box::height()
+{
+	return m_element->height();
+}
+
+int litehtml::block_box::width()
+{
+	return m_element->width();
+}
+
+void litehtml::block_box::add_element(const element::ptr &el)
+{
+	m_element = el;
+	el->m_box = this;
+}
+
+void litehtml::block_box::finish(bool last_box)
+{
+	if(!m_element) return;
+	m_element->apply_relative_shift(m_box_right - m_box_left);
+}
+
+bool litehtml::block_box::can_hold(const element::ptr &el, white_space ws)
+{
+	if(m_element || el->is_inline_box())
+	{
+		return false;
+	}
+	return true;
+}
+
+bool litehtml::block_box::is_empty()
+{
+	if(m_element)
+	{
+		return false;
+	}
+	return true;
+}
+
+int litehtml::block_box::baseline()
+{
+	if(m_element)
+	{
+		return m_element->get_base_line();
+	}
+	return 0;
+}
+
+void litehtml::block_box::get_elements( elements_vector& els )
+{
+	els.push_back(m_element);
+}
+
+int litehtml::block_box::top_margin()
+{
+	if(m_element && m_element->collapse_top_margin())
+	{
+		return m_element->m_margins.top;
+	}
+	return 0;
+}
+
+int litehtml::block_box::bottom_margin()
+{
+	if(m_element && m_element->collapse_bottom_margin())
+	{
+		return m_element->m_margins.bottom;
+	}
+	return 0;
+}
+
+void litehtml::block_box::y_shift( int shift )
+{
+	m_box_top += shift;
+	if(m_element)
+	{
+		m_element->m_pos.y += shift;
+	}
+}
+
+void litehtml::block_box::new_width( int left, int right, elements_vector& els )
+{
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+litehtml::box_type litehtml::line_box::get_type()
+{
+	return box_line;
+}
+
+int litehtml::line_box::height()
+{
+	return m_height;
+}
+
+int litehtml::line_box::width()
+{
+	return m_width;
+}
+
+void litehtml::line_box::add_element(const element::ptr &el)
+{
+	el->m_skip	= false;
+	el->m_box	= 0;
+	bool add	= true;
+	if( (m_items.empty() && el->is_white_space()) || el->is_break() )
+	{
+		el->m_skip = true;
+	} else if(el->is_white_space())
+	{
+		if (have_last_space())
+		{
+			add = false;
+			el->m_skip = true;
+		}
+	}
+
+	if(add)
+	{
+		el->m_box = this;
+		m_items.push_back(el);
+
+		if(!el->m_skip)
+		{
+			int el_shift_left	= el->get_inline_shift_left();
+			int el_shift_right	= el->get_inline_shift_right();
+
+			el->m_pos.x	= m_box_left + m_width + el_shift_left + el->content_margins_left();
+			el->m_pos.y	= m_box_top + el->content_margins_top();
+			m_width		+= el->width() + el_shift_left + el_shift_right;
+		}
+	}
+}
+
+void litehtml::line_box::finish(bool last_box)
+{
+	if( is_empty() || (!is_empty() && last_box && is_break_only()) )
+	{
+		m_height = 0;
+		return;
+	}
+
+	for(auto i = m_items.rbegin(); i != m_items.rend(); i++)
+	{
+		if((*i)->is_white_space() || (*i)->is_break())
+		{
+			if(!(*i)->m_skip)
+			{
+				(*i)->m_skip = true;
+				m_width -= (*i)->width();
+			}
+		} else
+		{
+			break;
+		}
+	}
+
+	int base_line	= m_font_metrics.base_line();
+	int line_height = m_line_height;
+
+	int add_x = 0;
+	switch(m_text_align)
+	{
+	case text_align_right:
+		if(m_width < (m_box_right - m_box_left))
+		{
+			add_x = (m_box_right - m_box_left) - m_width;
+		}
+		break;
+	case text_align_center:
+		if(m_width < (m_box_right - m_box_left))
+		{
+			add_x = ((m_box_right - m_box_left) - m_width) / 2;
+		}
+		break;
+	default:
+		add_x = 0;
+	}
+
+	m_height = 0;
+	// find line box baseline and line-height
+	for(const auto& el : m_items)
+	{
+		if(el->get_display() == display_inline_text)
+		{
+			font_metrics fm;
+			el->get_font(&fm);
+			base_line	= std::max(base_line,	fm.base_line());
+			line_height = std::max(line_height, el->line_height());
+			m_height = std::max(m_height, fm.height);
+		}
+		el->m_pos.x += add_x;
+	}
+
+	if(m_height)
+	{
+		base_line += (line_height - m_height) / 2;
+	}
+
+	m_height = line_height;
+
+	int y1	= 0;
+	int y2	= m_height;
+
+	for (const auto& el : m_items)
+	{
+		if(el->get_display() == display_inline_text)
+		{
+			font_metrics fm;
+			el->get_font(&fm);
+			el->m_pos.y = m_height - base_line - fm.ascent;
+		} else
+		{
+			switch(el->get_vertical_align())
+			{
+			case va_super:
+			case va_sub:
+			case va_baseline:
+				el->m_pos.y = m_height - base_line - el->height() + el->get_base_line() + el->content_margins_top();
+				break;
+			case va_top:
+				el->m_pos.y = y1 + el->content_margins_top();
+				break;
+			case va_text_top:
+				el->m_pos.y = m_height - base_line - m_font_metrics.ascent + el->content_margins_top();
+				break;
+			case va_middle:
+				el->m_pos.y = m_height - base_line - m_font_metrics.x_height / 2 - el->height() / 2 + el->content_margins_top();
+				break;
+			case va_bottom:
+				el->m_pos.y = y2 - el->height() + el->content_margins_top();
+				break;
+			case va_text_bottom:
+				el->m_pos.y = m_height - base_line + m_font_metrics.descent - el->height() + el->content_margins_top();
+				break;
+			}
+			y1 = std::min(y1, el->top());
+			y2 = std::max(y2, el->bottom());
+		}
+	}
+
+	css_offsets offsets;
+
+	for (const auto& el : m_items)
+	{
+		el->m_pos.y -= y1;
+		el->m_pos.y += m_box_top;
+		if(el->get_display() != display_inline_text)
+		{
+			switch(el->get_vertical_align())
+			{
+			case va_top:
+				el->m_pos.y = m_box_top + el->content_margins_top();
+				break;
+			case va_bottom:
+				el->m_pos.y = m_box_top + (y2 - y1) - el->height() + el->content_margins_top();
+				break;
+			case va_baseline:
+				//TODO: process vertical align "baseline"
+				break;
+			case va_middle:
+				//TODO: process vertical align "middle"
+				break;
+			case va_sub:
+				//TODO: process vertical align "sub"
+				break;
+			case va_super:
+				//TODO: process vertical align "super"
+				break;
+			case va_text_bottom:
+				//TODO: process vertical align "text-bottom"
+				break;
+			case va_text_top:
+				//TODO: process vertical align "text-top"
+				break;
+			}
+		}
+
+		el->apply_relative_shift(m_box_right - m_box_left);
+	}
+	m_height = y2 - y1;
+	m_baseline = (base_line - y1) - (m_height - line_height);
+}
+
+bool litehtml::line_box::can_hold(const element::ptr &el, white_space ws)
+{
+	if(!el->is_inline_box()) return false;
+
+	if(el->is_break())
+	{
+		return false;
+	}
+
+	if(ws == white_space_nowrap || ws == white_space_pre)
+	{
+		return true;
+	}
+
+	if(m_box_left + m_width + el->width() + el->get_inline_shift_left() + el->get_inline_shift_right() > m_box_right)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+bool litehtml::line_box::have_last_space()
+{
+	bool ret = false;
+	for (auto i = m_items.rbegin(); i != m_items.rend() && !ret; i++)
+	{
+		if((*i)->is_white_space() || (*i)->is_break())
+		{
+			ret = true;
+		} else
+		{
+			break;
+		}
+	}
+	return ret;
+}
+
+bool litehtml::line_box::is_empty()
+{
+	if(m_items.empty()) return true;
+	for (auto i = m_items.rbegin(); i != m_items.rend(); i++)
+	{
+		if(!(*i)->m_skip || (*i)->is_break())
+		{
+			return false;
+		}
+	}
+	return true;
+}
+
+int litehtml::line_box::baseline()
+{
+	return m_baseline;
+}
+
+void litehtml::line_box::get_elements( elements_vector& els )
+{
+	els.insert(els.begin(), m_items.begin(), m_items.end());
+}
+
+int litehtml::line_box::top_margin()
+{
+	return 0;
+}
+
+int litehtml::line_box::bottom_margin()
+{
+	return 0;
+}
+
+void litehtml::line_box::y_shift( int shift )
+{
+	m_box_top += shift;
+	for (auto& el : m_items)
+	{
+		el->m_pos.y += shift;
+	}
+}
+
+bool litehtml::line_box::is_break_only()
+{
+	if(m_items.empty()) return true;
+
+	if(m_items.front()->is_break())
+	{
+		for (auto& el : m_items)
+		{
+			if(!el->m_skip)
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+	return false;
+}
+
+void litehtml::line_box::new_width( int left, int right, elements_vector& els )
+{
+	int add = left - m_box_left;
+	if(add)
+	{
+		m_box_left	= left;
+		m_box_right	= right;
+		m_width = 0;
+		auto remove_begin = m_items.end();
+		for (auto i = m_items.begin() + 1; i != m_items.end(); i++)
+		{
+			element::ptr el = (*i);
+
+			if(!el->m_skip)
+			{
+				if(m_box_left + m_width + el->width() + el->get_inline_shift_right() + el->get_inline_shift_left() > m_box_right)
+				{
+					remove_begin = i;
+					break;
+				} else
+				{
+					el->m_pos.x += add;
+					m_width += el->width() + el->get_inline_shift_right() + el->get_inline_shift_left();
+				}
+			}
+		}
+		if(remove_begin != m_items.end())
+		{
+			els.insert(els.begin(), remove_begin, m_items.end());
+			m_items.erase(remove_begin, m_items.end());
+
+			for(const auto& el : els)
+			{
+				el->m_box = 0;
+			}
+		}
+	}
+}
+
diff --git a/src/plugins/litehtml_viewer/litehtml/box.h b/src/plugins/litehtml_viewer/litehtml/box.h
index d15a528..eeeea51 100644
--- a/src/plugins/litehtml_viewer/litehtml/box.h
+++ b/src/plugins/litehtml_viewer/litehtml/box.h
@@ -1,117 +1,120 @@
-#pragma once
-
-namespace litehtml
-{
-	class html_tag;
-
-	enum box_type
-	{
-		box_block,
-		box_line
-	};
-
-	class box
-	{
-	public:
-		typedef std::unique_ptr<litehtml::box>	ptr;
-		typedef std::vector< box::ptr >			vector;
-	protected:
-		int		m_box_top;
-		int		m_box_left;
-		int		m_box_right;
-	public:
-		box(int top, int left, int right)
-		{
-			m_box_top	= top;
-			m_box_left	= left;
-			m_box_right	= right;
-		}
-		virtual ~box() {}
-
-		int		bottom()	{ return m_box_top + height();	}
-		int		top()		{ return m_box_top;				}
-		int		right()		{ return m_box_left + width();	}
-		int		left()		{ return m_box_left;			}
-
-		virtual litehtml::box_type	get_type() = 0;
-		virtual int					height() = 0;
-		virtual int					width() = 0;
-		virtual void				add_element(const element::ptr &el) = 0;
-		virtual bool				can_hold(const element::ptr &el, white_space ws) = 0;
-		virtual void				finish(bool last_box = false) = 0;
-		virtual bool				is_empty() = 0;
-		virtual int					baseline() = 0;
-		virtual void				get_elements(elements_vector& els) = 0;
-		virtual int					top_margin() = 0;
-		virtual int					bottom_margin() = 0;
-		virtual void				y_shift(int shift) = 0;
-		virtual void				new_width(int left, int right, elements_vector& els) = 0;
-	};
-
-	//////////////////////////////////////////////////////////////////////////
-
-	class block_box : public box
-	{
-		element::ptr m_element;
-	public:
-		block_box(int top, int left, int right) : box(top, left, right)
-		{
-			m_element = 0;
-		}
-
-		virtual litehtml::box_type	get_type();
-		virtual int					height();
-		virtual int					width();
-		virtual void				add_element(const element::ptr &el);
-		virtual bool				can_hold(const element::ptr &el, white_space ws);
-		virtual void				finish(bool last_box = false);
-		virtual bool				is_empty();
-		virtual int					baseline();
-		virtual void				get_elements(elements_vector& els);
-		virtual int					top_margin();
-		virtual int					bottom_margin();
-		virtual void				y_shift(int shift);
-		virtual void				new_width(int left, int right, elements_vector& els);
-	};
-
-	//////////////////////////////////////////////////////////////////////////
-
-	class line_box : public box
-	{
-		elements_vector			m_items;
-		int						m_height;
-		int						m_width;
-		int						m_line_height;
-		font_metrics			m_font_metrics;
-		int						m_baseline;
-		text_align				m_text_align;
-	public:
-		line_box(int top, int left, int right, int line_height, font_metrics& fm, text_align align) : box(top, left, right)
-		{
-			m_height		= 0;
-			m_width			= 0;
-			m_font_metrics	= fm;
-			m_line_height	= line_height;
-			m_baseline		= 0;
-			m_text_align	= align;
-		}
-
-		virtual litehtml::box_type	get_type();
-		virtual int					height();
-		virtual int					width();
-		virtual void				add_element(const element::ptr &el);
-		virtual bool				can_hold(const element::ptr &el, white_space ws);
-		virtual void				finish(bool last_box = false);
-		virtual bool				is_empty();
-		virtual int					baseline();
-		virtual void				get_elements(elements_vector& els);
-		virtual int					top_margin();
-		virtual int					bottom_margin();
-		virtual void				y_shift(int shift);
-		virtual void				new_width(int left, int right, elements_vector& els);
-
-	private:
-		bool						have_last_space();
-		bool						is_break_only();
-	};
-}
\ No newline at end of file
+#ifndef LH_BOX_H
+#define LH_BOX_H
+
+namespace litehtml
+{
+	class html_tag;
+
+	enum box_type
+	{
+		box_block,
+		box_line
+	};
+
+	class box
+	{
+	public:
+		typedef std::unique_ptr<litehtml::box>	ptr;
+		typedef std::vector< box::ptr >			vector;
+	protected:
+		int		m_box_top;
+		int		m_box_left;
+		int		m_box_right;
+	public:
+		box(int top, int left, int right)
+		{
+			m_box_top	= top;
+			m_box_left	= left;
+			m_box_right	= right;
+		}
+		virtual ~box() {}
+
+		int		bottom()	{ return m_box_top + height();	}
+		int		top()		{ return m_box_top;				}
+		int		right()		{ return m_box_left + width();	}
+		int		left()		{ return m_box_left;			}
+
+		virtual litehtml::box_type	get_type() = 0;
+		virtual int					height() = 0;
+		virtual int					width() = 0;
+		virtual void				add_element(const element::ptr &el) = 0;
+		virtual bool				can_hold(const element::ptr &el, white_space ws) = 0;
+		virtual void				finish(bool last_box = false) = 0;
+		virtual bool				is_empty() = 0;
+		virtual int					baseline() = 0;
+		virtual void				get_elements(elements_vector& els) = 0;
+		virtual int					top_margin() = 0;
+		virtual int					bottom_margin() = 0;
+		virtual void				y_shift(int shift) = 0;
+		virtual void				new_width(int left, int right, elements_vector& els) = 0;
+	};
+
+	//////////////////////////////////////////////////////////////////////////
+
+	class block_box : public box
+	{
+		element::ptr m_element;
+	public:
+		block_box(int top, int left, int right) : box(top, left, right)
+		{
+			m_element = 0;
+		}
+
+		virtual litehtml::box_type	get_type();
+		virtual int					height();
+		virtual int					width();
+		virtual void				add_element(const element::ptr &el);
+		virtual bool				can_hold(const element::ptr &el, white_space ws);
+		virtual void				finish(bool last_box = false);
+		virtual bool				is_empty();
+		virtual int					baseline();
+		virtual void				get_elements(elements_vector& els);
+		virtual int					top_margin();
+		virtual int					bottom_margin();
+		virtual void				y_shift(int shift);
+		virtual void				new_width(int left, int right, elements_vector& els);
+	};
+
+	//////////////////////////////////////////////////////////////////////////
+
+	class line_box : public box
+	{
+		elements_vector			m_items;
+		int						m_height;
+		int						m_width;
+		int						m_line_height;
+		font_metrics			m_font_metrics;
+		int						m_baseline;
+		text_align				m_text_align;
+	public:
+		line_box(int top, int left, int right, int line_height, font_metrics& fm, text_align align) : box(top, left, right)
+		{
+			m_height		= 0;
+			m_width			= 0;
+			m_font_metrics	= fm;
+			m_line_height	= line_height;
+			m_baseline		= 0;
+			m_text_align	= align;
+		}
+
+		virtual litehtml::box_type	get_type();
+		virtual int					height();
+		virtual int					width();
+		virtual void				add_element(const element::ptr &el);
+		virtual bool				can_hold(const element::ptr &el, white_space ws);
+		virtual void				finish(bool last_box = false);
+		virtual bool				is_empty();
+		virtual int					baseline();
+		virtual void				get_elements(elements_vector& els);
+		virtual int					top_margin();
+		virtual int					bottom_margin();
+		virtual void				y_shift(int shift);
+		virtual void				new_width(int left, int right, elements_vector& els);
+
+	private:
+		bool						have_last_space();
+		bool						is_break_only();
+	};
+}
+
+#endif  // LH_BOX_H
diff --git a/src/plugins/litehtml_viewer/litehtml/context.cpp b/src/plugins/litehtml_viewer/litehtml/context.cpp
index 5f26269..4cea5d3 100644
--- a/src/plugins/litehtml_viewer/litehtml/context.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/context.cpp
@@ -1,12 +1,12 @@
-#include "html.h"
-#include "context.h"
-#include "stylesheet.h"
-
-
-void litehtml::context::load_master_stylesheet( const tchar_t* str )
-{
-	media_query_list::ptr media;
-
-	m_master_css.parse_stylesheet(str, 0, std::shared_ptr<litehtml::document>(), media_query_list::ptr());
-	m_master_css.sort_selectors();
-}
+#include "html.h"
+#include "context.h"
+#include "stylesheet.h"
+
+
+void litehtml::context::load_master_stylesheet( const tchar_t* str )
+{
+	media_query_list::ptr media;
+
+	m_master_css.parse_stylesheet(str, 0, std::shared_ptr<litehtml::document>(), media_query_list::ptr());
+	m_master_css.sort_selectors();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/context.h b/src/plugins/litehtml_viewer/litehtml/context.h
index ce62991..b6450f8 100644
--- a/src/plugins/litehtml_viewer/litehtml/context.h
+++ b/src/plugins/litehtml_viewer/litehtml/context.h
@@ -1,16 +1,20 @@
-#pragma once
-#include "stylesheet.h"
-
-namespace litehtml
-{
-	class context
-	{
-		litehtml::css	m_master_css;
-	public:
-		void			load_master_stylesheet(const tchar_t* str);
-		litehtml::css&	master_css()
-		{
-			return m_master_css;
-		}
-	};
-}
\ No newline at end of file
+#ifndef LH_CONTEXT_H
+#define LH_CONTEXT_H
+
+#include "stylesheet.h"
+
+namespace litehtml
+{
+	class context
+	{
+		litehtml::css	m_master_css;
+	public:
+		void			load_master_stylesheet(const tchar_t* str);
+		litehtml::css&	master_css()
+		{
+			return m_master_css;
+		}
+	};
+}
+
+#endif  // LH_CONTEXT_H
diff --git a/src/plugins/litehtml_viewer/litehtml/css_length.cpp b/src/plugins/litehtml_viewer/litehtml/css_length.cpp
index 06d5580..472cd54 100644
--- a/src/plugins/litehtml_viewer/litehtml/css_length.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/css_length.cpp
@@ -1,54 +1,54 @@
-#include "html.h"
-#include "css_length.h"
-
-void litehtml::css_length::fromString( const tstring& str, const tstring& predefs, int defValue )
-{
-	// TODO: Make support for calc
-	if(str.substr(0, 4) == _t("calc"))
-	{
-		m_is_predefined = true;
-		m_predef		= 0;
-		return;
-	}
-
-	int predef = value_index(str.c_str(), predefs.c_str(), -1);
-	if(predef >= 0)
-	{
-		m_is_predefined = true;
-		m_predef		= predef;
-	} else
-	{
-		m_is_predefined = false;
-
-		tstring num;
-		tstring un;
-		bool is_unit = false;
-		for(tstring::const_iterator chr = str.begin(); chr != str.end(); chr++)
-		{
-			if(!is_unit)
-			{
-				if(t_isdigit(*chr) || *chr == _t('.') || *chr == _t('+') || *chr == _t('-'))
-				{
-					num += *chr;
-				} else
-				{
-					is_unit = true;
-				}
-			}
-			if(is_unit)
-			{
-				un += *chr;
-			}
-		}
-		if(!num.empty())
-		{
-			m_value = (float) t_strtod(num.c_str(), 0);
-			m_units	= (css_units) value_index(un.c_str(), css_units_strings, css_units_none);
-		} else
-		{
-			// not a number so it is predefined
-			m_is_predefined = true;
-			m_predef = defValue;
-		}
-	}
-}
+#include "html.h"
+#include "css_length.h"
+
+void litehtml::css_length::fromString( const tstring& str, const tstring& predefs, int defValue )
+{
+	// TODO: Make support for calc
+	if(str.substr(0, 4) == _t("calc"))
+	{
+		m_is_predefined = true;
+		m_predef		= 0;
+		return;
+	}
+
+	int predef = value_index(str.c_str(), predefs.c_str(), -1);
+	if(predef >= 0)
+	{
+		m_is_predefined = true;
+		m_predef		= predef;
+	} else
+	{
+		m_is_predefined = false;
+
+		tstring num;
+		tstring un;
+		bool is_unit = false;
+		for(tstring::const_iterator chr = str.begin(); chr != str.end(); chr++)
+		{
+			if(!is_unit)
+			{
+				if(t_isdigit(*chr) || *chr == _t('.') || *chr == _t('+') || *chr == _t('-'))
+				{
+					num += *chr;
+				} else
+				{
+					is_unit = true;
+				}
+			}
+			if(is_unit)
+			{
+				un += *chr;
+			}
+		}
+		if(!num.empty())
+		{
+			m_value = (float) t_strtod(num.c_str(), 0);
+			m_units	= (css_units) value_index(un.c_str(), css_units_strings, css_units_none);
+		} else
+		{
+			// not a number so it is predefined
+			m_is_predefined = true;
+			m_predef = defValue;
+		}
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/css_length.h b/src/plugins/litehtml_viewer/litehtml/css_length.h
index 078f9dd..13a3d77 100644
--- a/src/plugins/litehtml_viewer/litehtml/css_length.h
+++ b/src/plugins/litehtml_viewer/litehtml/css_length.h
@@ -1,131 +1,135 @@
-#pragma once
-#include "types.h"
-
-namespace litehtml
-{
-	class css_length
-	{
-		union
-		{
-			float	m_value;
-			int		m_predef;
-		};
-		css_units	m_units;
-		bool		m_is_predefined;
-	public:
-		css_length();
-		css_length(const css_length& val);
-
-		css_length&	operator=(const css_length& val);
-		css_length&	operator=(float val);
-		bool		is_predefined() const;
-		void		predef(int val);
-		int			predef() const;
-		void		set_value(float val, css_units units);
-		float		val() const;
-		css_units	units() const;
-		int			calc_percent(int width) const;
-		void		fromString(const tstring& str, const tstring& predefs = _t(""), int defValue = 0);
-	};
-
-	// css_length inlines
-
-	inline css_length::css_length()
-	{
-		m_value			= 0;
-		m_predef		= 0;
-		m_units			= css_units_none;
-		m_is_predefined	= false;
-	}
-
-	inline css_length::css_length(const css_length& val)
-	{
-		if(val.is_predefined())
-		{
-			m_predef	= val.m_predef;
-		} else
-		{
-			m_value		= val.m_value;
-		}
-		m_units			= val.m_units;
-		m_is_predefined	= val.m_is_predefined;
-	}
-
-	inline css_length&	css_length::operator=(const css_length& val)
-	{
-		if(val.is_predefined())
-		{
-			m_predef	= val.m_predef;
-		} else
-		{
-			m_value		= val.m_value;
-		}
-		m_units			= val.m_units;
-		m_is_predefined	= val.m_is_predefined;
-		return *this;
-	}
-
-	inline css_length&	css_length::operator=(float val)
-	{
-		m_value = val;
-		m_units = css_units_px;
-		m_is_predefined = false;
-		return *this;
-	}
-
-	inline bool css_length::is_predefined() const
-	{ 
-		return m_is_predefined;					
-	}
-
-	inline void css_length::predef(int val)		
-	{ 
-		m_predef		= val; 
-		m_is_predefined = true;	
-	}
-
-	inline int css_length::predef() const
-	{ 
-		if(m_is_predefined)
-		{
-			return m_predef; 
-		}
-		return 0;
-	}
-
-	inline void css_length::set_value(float val, css_units units)		
-	{ 
-		m_value			= val; 
-		m_is_predefined = false;	
-		m_units			= units;
-	}
-
-	inline float css_length::val() const
-	{
-		if(!m_is_predefined)
-		{
-			return m_value;
-		}
-		return 0;
-	}
-
-	inline css_units css_length::units() const
-	{
-		return m_units;
-	}
-
-	inline int css_length::calc_percent(int width) const
-	{
-		if(!is_predefined())
-		{
-			if(units() == css_units_percentage)
-			{
-				return (int) ((double) width * (double) m_value / 100.0);
-			} else
-			{
-				return (int) val();
-			}
-		}
-		return 0;
-	}
-}
\ No newline at end of file
+#ifndef LH_CSS_LENGTH_H
+#define LH_CSS_LENGTH_H
+
+#include "types.h"
+
+namespace litehtml
+{
+	class css_length
+	{
+		union
+		{
+			float	m_value;
+			int		m_predef;
+		};
+		css_units	m_units;
+		bool		m_is_predefined;
+	public:
+		css_length();
+		css_length(const css_length& val);
+
+		css_length&	operator=(const css_length& val);
+		css_length&	operator=(float val);
+		bool		is_predefined() const;
+		void		predef(int val);
+		int			predef() const;
+		void		set_value(float val, css_units units);
+		float		val() const;
+		css_units	units() const;
+		int			calc_percent(int width) const;
+		void		fromString(const tstring& str, const tstring& predefs = _t(""), int defValue = 0);
+	};
+
+	// css_length inlines
+
+	inline css_length::css_length()
+	{
+		m_value			= 0;
+		m_predef		= 0;
+		m_units			= css_units_none;
+		m_is_predefined	= false;
+	}
+
+	inline css_length::css_length(const css_length& val)
+	{
+		if(val.is_predefined())
+		{
+			m_predef	= val.m_predef;
+		} else
+		{
+			m_value		= val.m_value;
+		}
+		m_units			= val.m_units;
+		m_is_predefined	= val.m_is_predefined;
+	}
+
+	inline css_length&	css_length::operator=(const css_length& val)
+	{
+		if(val.is_predefined())
+		{
+			m_predef	= val.m_predef;
+		} else
+		{
+			m_value		= val.m_value;
+		}
+		m_units			= val.m_units;
+		m_is_predefined	= val.m_is_predefined;
+		return *this;
+	}
+
+	inline css_length&	css_length::operator=(float val)
+	{
+		m_value = val;
+		m_units = css_units_px;
+		m_is_predefined = false;
+		return *this;
+	}
+
+	inline bool css_length::is_predefined() const
+	{ 
+		return m_is_predefined;					
+	}
+
+	inline void css_length::predef(int val)		
+	{ 
+		m_predef		= val; 
+		m_is_predefined = true;	
+	}
+
+	inline int css_length::predef() const
+	{ 
+		if(m_is_predefined)
+		{
+			return m_predef; 
+		}
+		return 0;
+	}
+
+	inline void css_length::set_value(float val, css_units units)		
+	{ 
+		m_value			= val; 
+		m_is_predefined = false;	
+		m_units			= units;
+	}
+
+	inline float css_length::val() const
+	{
+		if(!m_is_predefined)
+		{
+			return m_value;
+		}
+		return 0;
+	}
+
+	inline css_units css_length::units() const
+	{
+		return m_units;
+	}
+
+	inline int css_length::calc_percent(int width) const
+	{
+		if(!is_predefined())
+		{
+			if(units() == css_units_percentage)
+			{
+				return (int) ((double) width * (double) m_value / 100.0);
+			} else
+			{
+				return (int) val();
+			}
+		}
+		return 0;
+	}
+}
+
+#endif  // LH_CSS_LENGTH_H
diff --git a/src/plugins/litehtml_viewer/litehtml/css_margins.h b/src/plugins/litehtml_viewer/litehtml/css_margins.h
index fbe1d40..5c99a8b 100644
--- a/src/plugins/litehtml_viewer/litehtml/css_margins.h
+++ b/src/plugins/litehtml_viewer/litehtml/css_margins.h
@@ -1,35 +1,39 @@
-#pragma once
-#include "css_length.h"
-
-namespace litehtml
-{
-	struct css_margins
-	{
-		css_length	left;
-		css_length	right;
-		css_length	top;
-		css_length	bottom;
-
-		css_margins()
-		{
-
-		}
-
-		css_margins(const css_margins& val)
-		{
-			left	= val.left;
-			right	= val.right;
-			top		= val.top;
-			bottom	= val.bottom;
-		}
-
-		css_margins& operator=(const css_margins& val)
-		{
-			left	= val.left;
-			right	= val.right;
-			top		= val.top;
-			bottom	= val.bottom;
-			return *this;
-		}
-	};
-}
\ No newline at end of file
+#ifndef LH_CSS_MARGINS_H
+#define LH_CSS_MARGINS_H
+
+#include "css_length.h"
+
+namespace litehtml
+{
+	struct css_margins
+	{
+		css_length	left;
+		css_length	right;
+		css_length	top;
+		css_length	bottom;
+
+		css_margins()
+		{
+
+		}
+
+		css_margins(const css_margins& val)
+		{
+			left	= val.left;
+			right	= val.right;
+			top		= val.top;
+			bottom	= val.bottom;
+		}
+
+		css_margins& operator=(const css_margins& val)
+		{
+			left	= val.left;
+			right	= val.right;
+			top		= val.top;
+			bottom	= val.bottom;
+			return *this;
+		}
+	};
+}
+
+#endif  // LH_CSS_MARGINS_H
diff --git a/src/plugins/litehtml_viewer/litehtml/css_offsets.h b/src/plugins/litehtml_viewer/litehtml/css_offsets.h
index e4ca723..18d7f26 100644
--- a/src/plugins/litehtml_viewer/litehtml/css_offsets.h
+++ b/src/plugins/litehtml_viewer/litehtml/css_offsets.h
@@ -1,35 +1,39 @@
-#pragma once
-#include "css_length.h"
-
-namespace litehtml
-{
-	struct css_offsets
-	{
-		css_length	left;
-		css_length	top;
-		css_length	right;
-		css_length	bottom;
-
-		css_offsets()
-		{
-
-		}
-
-		css_offsets(const css_offsets& val)
-		{
-			left	= val.left;
-			top		= val.top;
-			right	= val.right;
-			bottom	= val.bottom;
-		}
-
-		css_offsets& operator=(const css_offsets& val)
-		{
-			left	= val.left;
-			top		= val.top;
-			right	= val.right;
-			bottom	= val.bottom;
-			return *this;
-		}
-	};
-}
\ No newline at end of file
+#ifndef LH_CSS_OFFSETS_H
+#define LH_CSS_OFFSETS_H
+
+#include "css_length.h"
+
+namespace litehtml
+{
+	struct css_offsets
+	{
+		css_length	left;
+		css_length	top;
+		css_length	right;
+		css_length	bottom;
+
+		css_offsets()
+		{
+
+		}
+
+		css_offsets(const css_offsets& val)
+		{
+			left	= val.left;
+			top		= val.top;
+			right	= val.right;
+			bottom	= val.bottom;
+		}
+
+		css_offsets& operator=(const css_offsets& val)
+		{
+			left	= val.left;
+			top		= val.top;
+			right	= val.right;
+			bottom	= val.bottom;
+			return *this;
+		}
+	};
+}
+
+#endif  // LH_CSS_OFFSETS_H
diff --git a/src/plugins/litehtml_viewer/litehtml/css_position.h b/src/plugins/litehtml_viewer/litehtml/css_position.h
index 05f046d..308a14f 100644
--- a/src/plugins/litehtml_viewer/litehtml/css_position.h
+++ b/src/plugins/litehtml_viewer/litehtml/css_position.h
@@ -1,35 +1,39 @@
-#pragma once
-#include "css_length.h"
-
-namespace litehtml
-{
-	struct css_position
-	{
-		css_length	x;
-		css_length	y;
-		css_length	width;
-		css_length	height;
-
-		css_position()
-		{
-
-		}
-
-		css_position(const css_position& val)
-		{
-			x		= val.x;
-			y		= val.y;
-			width	= val.width;
-			height	= val.height;
-		}
-
-		css_position& operator=(const css_position& val)
-		{
-			x		= val.x;
-			y		= val.y;
-			width	= val.width;
-			height	= val.height;
-			return *this;
-		}
-	};
-}
\ No newline at end of file
+#ifndef LH_CSS_POSITION_H
+#define LH_CSS_POSITION_H
+
+#include "css_length.h"
+
+namespace litehtml
+{
+	struct css_position
+	{
+		css_length	x;
+		css_length	y;
+		css_length	width;
+		css_length	height;
+
+		css_position()
+		{
+
+		}
+
+		css_position(const css_position& val)
+		{
+			x		= val.x;
+			y		= val.y;
+			width	= val.width;
+			height	= val.height;
+		}
+
+		css_position& operator=(const css_position& val)
+		{
+			x		= val.x;
+			y		= val.y;
+			width	= val.width;
+			height	= val.height;
+			return *this;
+		}
+	};
+}
+
+#endif  // LH_CSS_POSITION_H
diff --git a/src/plugins/litehtml_viewer/litehtml/css_selector.cpp b/src/plugins/litehtml_viewer/litehtml/css_selector.cpp
index a8e5f41..dc40088 100644
--- a/src/plugins/litehtml_viewer/litehtml/css_selector.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/css_selector.cpp
@@ -1,266 +1,266 @@
-#include "html.h"
-#include "css_selector.h"
-#include "document.h"
-
-void litehtml::css_element_selector::parse( const tstring& txt )
-{
-	tstring::size_type el_end = txt.find_first_of(_t(".#[:"));
-	m_tag = txt.substr(0, el_end);
-	litehtml::lcase(m_tag);
-	while(el_end != tstring::npos)
-	{
-		if(txt[el_end] == _t('.'))
-		{
-			css_attribute_selector attribute;
-
-			tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);
-			attribute.val		= txt.substr(el_end + 1, pos - el_end - 1);
-			split_string( attribute.val, attribute.class_val, _t(" ") );
-			attribute.condition	= select_equal;
-			attribute.attribute	= _t("class");
-			m_attrs.push_back(attribute);
-			el_end = pos;
-		} else if(txt[el_end] == _t(':'))
-		{
-			css_attribute_selector attribute;
-
-			if(txt[el_end + 1] == _t(':'))
-			{
-				tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 2);
-				attribute.val		= txt.substr(el_end + 2, pos - el_end - 2);
-				attribute.condition	= select_pseudo_element;
-				litehtml::lcase(attribute.val);
-				attribute.attribute	= _t("pseudo-el");
-				m_attrs.push_back(attribute);
-				el_end = pos;
-			} else
-			{
-				tstring::size_type pos = txt.find_first_of(_t(".#[:("), el_end + 1);
-				if(pos != tstring::npos && txt.at(pos) == _t('('))
-				{
-					pos = find_close_bracket(txt, pos);
-					if(pos != tstring::npos)
-					{
-						pos++;
-					} else
-					{
-						int iii = 0;
-						iii++;
-					}
-				}
-				if(pos != tstring::npos)
-				{
-					attribute.val		= txt.substr(el_end + 1, pos - el_end - 1);
-				} else
-				{
-					attribute.val		= txt.substr(el_end + 1);
-				}
-				litehtml::lcase(attribute.val);
-				if(attribute.val == _t("after") || attribute.val == _t("before"))
-				{
-					attribute.condition	= select_pseudo_element;
-				} else
-				{
-					attribute.condition	= select_pseudo_class;
-				}
-				attribute.attribute	= _t("pseudo");
-				m_attrs.push_back(attribute);
-				el_end = pos;
-			}
-		} else if(txt[el_end] == _t('#'))
-		{
-			css_attribute_selector attribute;
-
-			tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);
-			attribute.val		= txt.substr(el_end + 1, pos - el_end - 1);
-			attribute.condition	= select_equal;
-			attribute.attribute	= _t("id");
-			m_attrs.push_back(attribute);
-			el_end = pos;
-		} else if(txt[el_end] == _t('['))
-		{
-			css_attribute_selector attribute;
-
-			tstring::size_type pos = txt.find_first_of(_t("]~=|$*^"), el_end + 1);
-			tstring attr = txt.substr(el_end + 1, pos - el_end - 1);
-			trim(attr);
-			litehtml::lcase(attr);
-			if(pos != tstring::npos)
-			{
-				if(txt[pos] == _t(']'))
-				{
-					attribute.condition = select_exists;
-				} else if(txt[pos] == _t('='))
-				{
-					attribute.condition = select_equal;
-					pos++;
-				} else if(txt.substr(pos, 2) == _t("~="))
-				{
-					attribute.condition = select_contain_str;
-					pos += 2;
-				} else if(txt.substr(pos, 2) == _t("|="))
-				{
-					attribute.condition = select_start_str;
-					pos += 2;
-				} else if(txt.substr(pos, 2) == _t("^="))
-				{
-					attribute.condition = select_start_str;
-					pos += 2;
-				} else if(txt.substr(pos, 2) == _t("$="))
-				{
-					attribute.condition = select_end_str;
-					pos += 2;
-				} else if(txt.substr(pos, 2) == _t("*="))
-				{
-					attribute.condition = select_contain_str;
-					pos += 2;
-				} else
-				{
-					attribute.condition = select_exists;
-					pos += 1;
-				}
-				pos = txt.find_first_not_of(_t(" \t"), pos);
-				if(pos != tstring::npos)
-				{
-					if(txt[pos] == _t('"'))
-					{
-						tstring::size_type pos2 = txt.find_first_of(_t("\""), pos + 1);
-						attribute.val = txt.substr(pos + 1, pos2 == tstring::npos ? pos2 : (pos2 - pos - 1));
-						pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);
-					} else if(txt[pos] == _t(']'))
-					{
-						pos ++;
-					} else
-					{
-						tstring::size_type pos2 = txt.find_first_of(_t("]"), pos + 1);
-						attribute.val = txt.substr(pos, pos2 == tstring::npos ? pos2 : (pos2 - pos));
-						trim(attribute.val);
-						pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);
-					}
-				}
-			} else
-			{
-				attribute.condition = select_exists;
-			}
-			attribute.attribute	= attr;
-			m_attrs.push_back(attribute);
-			el_end = pos;
-		} else
-		{
-			el_end++;
-		}
-		el_end = txt.find_first_of(_t(".#[:"), el_end);
-	}
-}
-
-
-bool litehtml::css_selector::parse( const tstring& text )
-{
-	if(text.empty())
-	{
-		return false;
-	}
-	string_vector tokens;
-	split_string(text, tokens, _t(""), _t(" \t>+~"), _t("(["));
-
-	if(tokens.empty())
-	{
-		return false;
-	}
-
-	tstring left;
-	tstring right = tokens.back();
-	tchar_t combinator = 0;
-
-	tokens.pop_back();
-	while(!tokens.empty() && (tokens.back() == _t(" ") || tokens.back() == _t("\t") || tokens.back() == _t("+") || tokens.back() == _t("~") || tokens.back() == _t(">")))
-	{
-		if(combinator == _t(' ') || combinator == 0)
-		{
-			combinator = tokens.back()[0];
-		}
-		tokens.pop_back();
-	}
-
-	for(string_vector::const_iterator i = tokens.begin(); i != tokens.end(); i++)
-	{
-		left += *i;
-	}
-
-	trim(left);
-	trim(right);
-
-	if(right.empty())
-	{
-		return false;
-	}
-
-	m_right.parse(right);
-
-	switch(combinator)
-	{
-	case _t('>'):
-		m_combinator	= combinator_child;
-		break;
-	case _t('+'):
-		m_combinator	= combinator_adjacent_sibling;
-		break;
-	case _t('~'):
-		m_combinator	= combinator_general_sibling;
-		break;
-	default:
-		m_combinator	= combinator_descendant;
-		break;
-	}
-
-	m_left = 0;
-
-	if(!left.empty())
-	{
-		m_left = std::make_shared<css_selector>(media_query_list::ptr(0));
-		if(!m_left->parse(left))
-		{
-			return false;
-		}
-	}
-
-	return true;
-}
-
-void litehtml::css_selector::calc_specificity()
-{
-	if(!m_right.m_tag.empty() && m_right.m_tag != _t("*"))
-	{
-		m_specificity.d = 1;
-	}
-	for(css_attribute_selector::vector::iterator i = m_right.m_attrs.begin(); i != m_right.m_attrs.end(); i++)
-	{
-		if(i->attribute == _t("id"))
-		{
-			m_specificity.b++;
-		} else
-		{
-			if(i->attribute == _t("class"))
-			{
-				m_specificity.c += (int) i->class_val.size();
-			} else
-			{
-				m_specificity.c++;
-			}
-		}	
-	}
-	if(m_left)
-	{
-		m_left->calc_specificity();
-		m_specificity += m_left->m_specificity;
-	}
-}
-
-void litehtml::css_selector::add_media_to_doc( document* doc ) const
-{
-	if(m_media_query && doc)
-	{
-		doc->add_media_list(m_media_query);
-	}
-}
-
+#include "html.h"
+#include "css_selector.h"
+#include "document.h"
+
+void litehtml::css_element_selector::parse( const tstring& txt )
+{
+	tstring::size_type el_end = txt.find_first_of(_t(".#[:"));
+	m_tag = txt.substr(0, el_end);
+	litehtml::lcase(m_tag);
+	while(el_end != tstring::npos)
+	{
+		if(txt[el_end] == _t('.'))
+		{
+			css_attribute_selector attribute;
+
+			tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);
+			attribute.val		= txt.substr(el_end + 1, pos - el_end - 1);
+			split_string( attribute.val, attribute.class_val, _t(" ") );
+			attribute.condition	= select_equal;
+			attribute.attribute	= _t("class");
+			m_attrs.push_back(attribute);
+			el_end = pos;
+		} else if(txt[el_end] == _t(':'))
+		{
+			css_attribute_selector attribute;
+
+			if(txt[el_end + 1] == _t(':'))
+			{
+				tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 2);
+				attribute.val		= txt.substr(el_end + 2, pos - el_end - 2);
+				attribute.condition	= select_pseudo_element;
+				litehtml::lcase(attribute.val);
+				attribute.attribute	= _t("pseudo-el");
+				m_attrs.push_back(attribute);
+				el_end = pos;
+			} else
+			{
+				tstring::size_type pos = txt.find_first_of(_t(".#[:("), el_end + 1);
+				if(pos != tstring::npos && txt.at(pos) == _t('('))
+				{
+					pos = find_close_bracket(txt, pos);
+					if(pos != tstring::npos)
+					{
+						pos++;
+					} else
+					{
+						int iii = 0;
+						iii++;
+					}
+				}
+				if(pos != tstring::npos)
+				{
+					attribute.val		= txt.substr(el_end + 1, pos - el_end - 1);
+				} else
+				{
+					attribute.val		= txt.substr(el_end + 1);
+				}
+				litehtml::lcase(attribute.val);
+				if(attribute.val == _t("after") || attribute.val == _t("before"))
+				{
+					attribute.condition	= select_pseudo_element;
+				} else
+				{
+					attribute.condition	= select_pseudo_class;
+				}
+				attribute.attribute	= _t("pseudo");
+				m_attrs.push_back(attribute);
+				el_end = pos;
+			}
+		} else if(txt[el_end] == _t('#'))
+		{
+			css_attribute_selector attribute;
+
+			tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);
+			attribute.val		= txt.substr(el_end + 1, pos - el_end - 1);
+			attribute.condition	= select_equal;
+			attribute.attribute	= _t("id");
+			m_attrs.push_back(attribute);
+			el_end = pos;
+		} else if(txt[el_end] == _t('['))
+		{
+			css_attribute_selector attribute;
+
+			tstring::size_type pos = txt.find_first_of(_t("]~=|$*^"), el_end + 1);
+			tstring attr = txt.substr(el_end + 1, pos - el_end - 1);
+			trim(attr);
+			litehtml::lcase(attr);
+			if(pos != tstring::npos)
+			{
+				if(txt[pos] == _t(']'))
+				{
+					attribute.condition = select_exists;
+				} else if(txt[pos] == _t('='))
+				{
+					attribute.condition = select_equal;
+					pos++;
+				} else if(txt.substr(pos, 2) == _t("~="))
+				{
+					attribute.condition = select_contain_str;
+					pos += 2;
+				} else if(txt.substr(pos, 2) == _t("|="))
+				{
+					attribute.condition = select_start_str;
+					pos += 2;
+				} else if(txt.substr(pos, 2) == _t("^="))
+				{
+					attribute.condition = select_start_str;
+					pos += 2;
+				} else if(txt.substr(pos, 2) == _t("$="))
+				{
+					attribute.condition = select_end_str;
+					pos += 2;
+				} else if(txt.substr(pos, 2) == _t("*="))
+				{
+					attribute.condition = select_contain_str;
+					pos += 2;
+				} else
+				{
+					attribute.condition = select_exists;
+					pos += 1;
+				}
+				pos = txt.find_first_not_of(_t(" \t"), pos);
+				if(pos != tstring::npos)
+				{
+					if(txt[pos] == _t('"'))
+					{
+						tstring::size_type pos2 = txt.find_first_of(_t("\""), pos + 1);
+						attribute.val = txt.substr(pos + 1, pos2 == tstring::npos ? pos2 : (pos2 - pos - 1));
+						pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);
+					} else if(txt[pos] == _t(']'))
+					{
+						pos ++;
+					} else
+					{
+						tstring::size_type pos2 = txt.find_first_of(_t("]"), pos + 1);
+						attribute.val = txt.substr(pos, pos2 == tstring::npos ? pos2 : (pos2 - pos));
+						trim(attribute.val);
+						pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);
+					}
+				}
+			} else
+			{
+				attribute.condition = select_exists;
+			}
+			attribute.attribute	= attr;
+			m_attrs.push_back(attribute);
+			el_end = pos;
+		} else
+		{
+			el_end++;
+		}
+		el_end = txt.find_first_of(_t(".#[:"), el_end);
+	}
+}
+
+
+bool litehtml::css_selector::parse( const tstring& text )
+{
+	if(text.empty())
+	{
+		return false;
+	}
+	string_vector tokens;
+	split_string(text, tokens, _t(""), _t(" \t>+~"), _t("(["));
+
+	if(tokens.empty())
+	{
+		return false;
+	}
+
+	tstring left;
+	tstring right = tokens.back();
+	tchar_t combinator = 0;
+
+	tokens.pop_back();
+	while(!tokens.empty() && (tokens.back() == _t(" ") || tokens.back() == _t("\t") || tokens.back() == _t("+") || tokens.back() == _t("~") || tokens.back() == _t(">")))
+	{
+		if(combinator == _t(' ') || combinator == 0)
+		{
+			combinator = tokens.back()[0];
+		}
+		tokens.pop_back();
+	}
+
+	for(string_vector::const_iterator i = tokens.begin(); i != tokens.end(); i++)
+	{
+		left += *i;
+	}
+
+	trim(left);
+	trim(right);
+
+	if(right.empty())
+	{
+		return false;
+	}
+
+	m_right.parse(right);
+
+	switch(combinator)
+	{
+	case _t('>'):
+		m_combinator	= combinator_child;
+		break;
+	case _t('+'):
+		m_combinator	= combinator_adjacent_sibling;
+		break;
+	case _t('~'):
+		m_combinator	= combinator_general_sibling;
+		break;
+	default:
+		m_combinator	= combinator_descendant;
+		break;
+	}
+
+	m_left = 0;
+
+	if(!left.empty())
+	{
+		m_left = std::make_shared<css_selector>(media_query_list::ptr(0));
+		if(!m_left->parse(left))
+		{
+			return false;
+		}
+	}
+
+	return true;
+}
+
+void litehtml::css_selector::calc_specificity()
+{
+	if(!m_right.m_tag.empty() && m_right.m_tag != _t("*"))
+	{
+		m_specificity.d = 1;
+	}
+	for(css_attribute_selector::vector::iterator i = m_right.m_attrs.begin(); i != m_right.m_attrs.end(); i++)
+	{
+		if(i->attribute == _t("id"))
+		{
+			m_specificity.b++;
+		} else
+		{
+			if(i->attribute == _t("class"))
+			{
+				m_specificity.c += (int) i->class_val.size();
+			} else
+			{
+				m_specificity.c++;
+			}
+		}	
+	}
+	if(m_left)
+	{
+		m_left->calc_specificity();
+		m_specificity += m_left->m_specificity;
+	}
+}
+
+void litehtml::css_selector::add_media_to_doc( document* doc ) const
+{
+	if(m_media_query && doc)
+	{
+		doc->add_media_list(m_media_query);
+	}
+}
+
diff --git a/src/plugins/litehtml_viewer/litehtml/css_selector.h b/src/plugins/litehtml_viewer/litehtml/css_selector.h
index ae8f9c9..d9a0274 100644
--- a/src/plugins/litehtml_viewer/litehtml/css_selector.h
+++ b/src/plugins/litehtml_viewer/litehtml/css_selector.h
@@ -1,274 +1,278 @@
-#pragma once
-#include "style.h"
-#include "media_query.h"
-
-namespace litehtml
-{
-	//////////////////////////////////////////////////////////////////////////
-
-	struct selector_specificity
-	{
-		int		a;
-		int		b;
-		int		c;
-		int		d;
-
-		selector_specificity(int va = 0, int vb = 0, int vc = 0, int vd = 0)
-		{
-			a	= va;
-			b	= vb;
-			c	= vc;
-			d	= vd;
-		}
-
-		void operator += (const selector_specificity& val)
-		{
-			a	+= val.a;
-			b	+= val.b;
-			c	+= val.c;
-			d	+= val.d;
-		}
-
-		bool operator==(const selector_specificity& val) const
-		{
-			if(a == val.a && b == val.b && c == val.c && d == val.d)
-			{
-				return true;
-			}
-			return false;
-		}
-
-		bool operator!=(const selector_specificity& val) const
-		{
-			if(a != val.a || b != val.b || c != val.c || d != val.d)
-			{
-				return true;
-			}
-			return false;
-		}
-
-		bool operator > (const selector_specificity& val) const
-		{
-			if(a > val.a)
-			{
-				return true;
-			} else if(a < val.a)
-			{
-				return false;
-			} else
-			{
-				if(b > val.b)
-				{
-					return true;
-				} else if(b < val.b)
-				{
-					return false;
-				} else
-				{
-					if(c > val.c)
-					{
-						return true;
-					} else if(c < val.c)
-					{
-						return false;
-					} else
-					{
-						if(d > val.d)
-						{
-							return true;
-						} else if(d < val.d)
-						{
-							return false;
-						}
-					}
-				}
-			}
-			return false;
-		}
-
-		bool operator >= (const selector_specificity& val) const
-		{
-			if((*this) == val) return true;
-			if((*this) > val) return true;
-			return false;
-		}
-
-		bool operator <= (const selector_specificity& val) const
-		{
-			if((*this) > val)
-			{
-				return false;
-			}
-			return true;
-		}
-
-		bool operator < (const selector_specificity& val) const
-		{
-			if((*this) <= val && (*this) != val)
-			{
-				return true;
-			}
-			return false;
-		}
-
-	};
-
-	//////////////////////////////////////////////////////////////////////////
-
-	enum attr_select_condition
-	{
-		select_exists,
-		select_equal,
-		select_contain_str,
-		select_start_str,
-		select_end_str,
-		select_pseudo_class,
-		select_pseudo_element,
-	};
-
-	//////////////////////////////////////////////////////////////////////////
-
-	struct css_attribute_selector
-	{
-		typedef std::vector<css_attribute_selector>	vector;
-
-		tstring					attribute;
-		tstring					val;
-		string_vector			class_val;
-		attr_select_condition	condition;
-
-		css_attribute_selector()
-		{
-			condition = select_exists;
-		}
-	};
-
-	//////////////////////////////////////////////////////////////////////////
-
-	class css_element_selector
-	{
-	public:
-		tstring							m_tag;
-		css_attribute_selector::vector	m_attrs;
-	public:
-
-		void parse(const tstring& txt);
-	};
-
-	//////////////////////////////////////////////////////////////////////////
-
-	enum css_combinator
-	{
-		combinator_descendant,
-		combinator_child,
-		combinator_adjacent_sibling,
-		combinator_general_sibling
-	};
-
-	//////////////////////////////////////////////////////////////////////////
-
-	class css_selector
-	{
-	public:
-		typedef std::shared_ptr<css_selector>	ptr;
-		typedef std::vector<css_selector::ptr>	vector;
-	public:
-		selector_specificity	m_specificity;
-		css_element_selector	m_right;
-		css_selector::ptr		m_left;
-		css_combinator			m_combinator;
-		style::ptr				m_style;
-		int						m_order;
-		media_query_list::ptr	m_media_query;
-	public:
-		css_selector(media_query_list::ptr media)
-		{
-			m_media_query	= media;
-			m_combinator	= combinator_descendant;
-			m_order			= 0;
-		}
-
-		~css_selector()
-		{
-		}
-
-		css_selector(const css_selector& val)
-		{
-			m_right			= val.m_right;
-			if(val.m_left)
-			{
-				m_left			= std::make_shared<css_selector>(*val.m_left);
-			} else
-			{
-				m_left = 0;
-			}
-			m_combinator	= val.m_combinator;
-			m_specificity	= val.m_specificity;
-			m_order			= val.m_order;
-			m_media_query	= val.m_media_query;
-		}
-
-		bool parse(const tstring& text);
-		void calc_specificity();
-		bool is_media_valid() const;
-		void add_media_to_doc(document* doc) const;
-	};
-
-	inline bool css_selector::is_media_valid() const
-	{
-		if(!m_media_query)
-		{
-			return true;
-		}
-		return m_media_query->is_used();
-	}
-
-
-	//////////////////////////////////////////////////////////////////////////
-
-	inline bool operator > (const css_selector& v1, const css_selector& v2)
-	{
-		if(v1.m_specificity == v2.m_specificity)
-		{
-			return (v1.m_order > v2.m_order);
-		}
-		return (v1.m_specificity > v2.m_specificity);
-	}
-
-	inline bool operator < (const css_selector& v1, const css_selector& v2)
-	{
-		if(v1.m_specificity == v2.m_specificity)
-		{
-			return (v1.m_order < v2.m_order);
-		}
-		return (v1.m_specificity < v2.m_specificity);
-	}
-
-	inline bool operator >(const css_selector::ptr& v1, const css_selector::ptr& v2)
-	{
-		return (*v1 > *v2);
-	}
-
-	inline bool operator < (const css_selector::ptr& v1, const css_selector::ptr& v2)
-	{
-		return (*v1 < *v2);
-	}
-
-	//////////////////////////////////////////////////////////////////////////
-
-	class used_selector
-	{
-	public:
-		typedef std::unique_ptr<used_selector>	ptr;
-		typedef std::vector<used_selector::ptr>	vector;
-
-		css_selector::ptr	m_selector;
-		bool				m_used;
-
-		used_selector(const css_selector::ptr& selector, bool used)
-		{
-			m_used		= used;
-			m_selector	= selector;
-		}
-	};
-}
\ No newline at end of file
+#ifndef LH_CSS_SELECTOR_H
+#define LH_CSS_SELECTOR_H
+
+#include "style.h"
+#include "media_query.h"
+
+namespace litehtml
+{
+	//////////////////////////////////////////////////////////////////////////
+
+	struct selector_specificity
+	{
+		int		a;
+		int		b;
+		int		c;
+		int		d;
+
+		selector_specificity(int va = 0, int vb = 0, int vc = 0, int vd = 0)
+		{
+			a	= va;
+			b	= vb;
+			c	= vc;
+			d	= vd;
+		}
+
+		void operator += (const selector_specificity& val)
+		{
+			a	+= val.a;
+			b	+= val.b;
+			c	+= val.c;
+			d	+= val.d;
+		}
+
+		bool operator==(const selector_specificity& val) const
+		{
+			if(a == val.a && b == val.b && c == val.c && d == val.d)
+			{
+				return true;
+			}
+			return false;
+		}
+
+		bool operator!=(const selector_specificity& val) const
+		{
+			if(a != val.a || b != val.b || c != val.c || d != val.d)
+			{
+				return true;
+			}
+			return false;
+		}
+
+		bool operator > (const selector_specificity& val) const
+		{
+			if(a > val.a)
+			{
+				return true;
+			} else if(a < val.a)
+			{
+				return false;
+			} else
+			{
+				if(b > val.b)
+				{
+					return true;
+				} else if(b < val.b)
+				{
+					return false;
+				} else
+				{
+					if(c > val.c)
+					{
+						return true;
+					} else if(c < val.c)
+					{
+						return false;
+					} else
+					{
+						if(d > val.d)
+						{
+							return true;
+						} else if(d < val.d)
+						{
+							return false;
+						}
+					}
+				}
+			}
+			return false;
+		}
+
+		bool operator >= (const selector_specificity& val) const
+		{
+			if((*this) == val) return true;
+			if((*this) > val) return true;
+			return false;
+		}
+
+		bool operator <= (const selector_specificity& val) const
+		{
+			if((*this) > val)
+			{
+				return false;
+			}
+			return true;
+		}
+
+		bool operator < (const selector_specificity& val) const
+		{
+			if((*this) <= val && (*this) != val)
+			{
+				return true;
+			}
+			return false;
+		}
+
+	};
+
+	//////////////////////////////////////////////////////////////////////////
+
+	enum attr_select_condition
+	{
+		select_exists,
+		select_equal,
+		select_contain_str,
+		select_start_str,
+		select_end_str,
+		select_pseudo_class,
+		select_pseudo_element,
+	};
+
+	//////////////////////////////////////////////////////////////////////////
+
+	struct css_attribute_selector
+	{
+		typedef std::vector<css_attribute_selector>	vector;
+
+		tstring					attribute;
+		tstring					val;
+		string_vector			class_val;
+		attr_select_condition	condition;
+
+		css_attribute_selector()
+		{
+			condition = select_exists;
+		}
+	};
+
+	//////////////////////////////////////////////////////////////////////////
+
+	class css_element_selector
+	{
+	public:
+		tstring							m_tag;
+		css_attribute_selector::vector	m_attrs;
+	public:
+
+		void parse(const tstring& txt);
+	};
+
+	//////////////////////////////////////////////////////////////////////////
+
+	enum css_combinator
+	{
+		combinator_descendant,
+		combinator_child,
+		combinator_adjacent_sibling,
+		combinator_general_sibling
+	};
+
+	//////////////////////////////////////////////////////////////////////////
+
+	class css_selector
+	{
+	public:
+		typedef std::shared_ptr<css_selector>	ptr;
+		typedef std::vector<css_selector::ptr>	vector;
+	public:
+		selector_specificity	m_specificity;
+		css_element_selector	m_right;
+		css_selector::ptr		m_left;
+		css_combinator			m_combinator;
+		style::ptr				m_style;
+		int						m_order;
+		media_query_list::ptr	m_media_query;
+	public:
+		css_selector(media_query_list::ptr media)
+		{
+			m_media_query	= media;
+			m_combinator	= combinator_descendant;
+			m_order			= 0;
+		}
+
+		~css_selector()
+		{
+		}
+
+		css_selector(const css_selector& val)
+		{
+			m_right			= val.m_right;
+			if(val.m_left)
+			{
+				m_left			= std::make_shared<css_selector>(*val.m_left);
+			} else
+			{
+				m_left = 0;
+			}
+			m_combinator	= val.m_combinator;
+			m_specificity	= val.m_specificity;
+			m_order			= val.m_order;
+			m_media_query	= val.m_media_query;
+		}
+
+		bool parse(const tstring& text);
+		void calc_specificity();
+		bool is_media_valid() const;
+		void add_media_to_doc(document* doc) const;
+	};
+
+	inline bool css_selector::is_media_valid() const
+	{
+		if(!m_media_query)
+		{
+			return true;
+		}
+		return m_media_query->is_used();
+	}
+
+
+	//////////////////////////////////////////////////////////////////////////
+
+	inline bool operator > (const css_selector& v1, const css_selector& v2)
+	{
+		if(v1.m_specificity == v2.m_specificity)
+		{
+			return (v1.m_order > v2.m_order);
+		}
+		return (v1.m_specificity > v2.m_specificity);
+	}
+
+	inline bool operator < (const css_selector& v1, const css_selector& v2)
+	{
+		if(v1.m_specificity == v2.m_specificity)
+		{
+			return (v1.m_order < v2.m_order);
+		}
+		return (v1.m_specificity < v2.m_specificity);
+	}
+
+	inline bool operator >(const css_selector::ptr& v1, const css_selector::ptr& v2)
+	{
+		return (*v1 > *v2);
+	}
+
+	inline bool operator < (const css_selector::ptr& v1, const css_selector::ptr& v2)
+	{
+		return (*v1 < *v2);
+	}
+
+	//////////////////////////////////////////////////////////////////////////
+
+	class used_selector
+	{
+	public:
+		typedef std::unique_ptr<used_selector>	ptr;
+		typedef std::vector<used_selector::ptr>	vector;
+
+		css_selector::ptr	m_selector;
+		bool				m_used;
+
+		used_selector(const css_selector::ptr& selector, bool used)
+		{
+			m_used		= used;
+			m_selector	= selector;
+		}
+	};
+}
+
+#endif  // LH_CSS_SELECTOR_H
diff --git a/src/plugins/litehtml_viewer/litehtml/document.cpp b/src/plugins/litehtml_viewer/litehtml/document.cpp
index e9775aa..0be0ea7 100644
--- a/src/plugins/litehtml_viewer/litehtml/document.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/document.cpp
@@ -1,930 +1,930 @@
-#include "html.h"
-#include "document.h"
-#include "stylesheet.h"
-#include "html_tag.h"
-#include "el_text.h"
-#include "el_para.h"
-#include "el_space.h"
-#include "el_body.h"
-#include "el_image.h"
-#include "el_table.h"
-#include "el_td.h"
-#include "el_link.h"
-#include "el_title.h"
-#include "el_style.h"
-#include "el_script.h"
-#include "el_comment.h"
-#include "el_cdata.h"
-#include "el_base.h"
-#include "el_anchor.h"
-#include "el_break.h"
-#include "el_div.h"
-#include "el_font.h"
-#include "el_tr.h"
-#include <math.h>
-#include <stdio.h>
-#include <algorithm>
-#include "gumbo.h"
-#include "utf8_strings.h"
-
-litehtml::document::document(litehtml::document_container* objContainer, litehtml::context* ctx)
-{
-	m_container	= objContainer;
-	m_context	= ctx;
-}
-
-litehtml::document::~document()
-{
-	m_over_element = 0;
-	if(m_container)
-	{
-		for(fonts_map::iterator f = m_fonts.begin(); f != m_fonts.end(); f++)
-		{
-			m_container->delete_font(f->second.font);
-		}
-	}
-}
-
-litehtml::document::ptr litehtml::document::createFromString( const tchar_t* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles)
-{
-	return createFromUTF8(litehtml_to_utf8(str), objPainter, ctx, user_styles);
-}
-
-litehtml::document::ptr litehtml::document::createFromUTF8(const char* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles)
-{
-	// parse document into GumboOutput
-	GumboOutput* output = gumbo_parse((const char*) str);
-
-	// Create litehtml::document
-	litehtml::document::ptr doc = std::make_shared<litehtml::document>(objPainter, ctx);
-
-	// Create litehtml::elements.
-	elements_vector root_elements;
-	doc->create_node(output->root, root_elements);
-	if (!root_elements.empty())
-	{
-		doc->m_root = root_elements.back();
-	}
-	// Destroy GumboOutput
-	gumbo_destroy_output(&kGumboDefaultOptions, output);
-
-	// Let's process created elements tree
-	if (doc->m_root)
-	{
-		doc->container()->get_media_features(doc->m_media);
-
-		// apply master CSS
-		doc->m_root->apply_stylesheet(ctx->master_css());
-
-		// parse elements attributes
-		doc->m_root->parse_attributes();
-
-		// parse style sheets linked in document
-		media_query_list::ptr media;
-		for (css_text::vector::iterator css = doc->m_css.begin(); css != doc->m_css.end(); css++)
-		{
-			if (!css->media.empty())
-			{
-				media = media_query_list::create_from_string(css->media, doc);
-			}
-			else
-			{
-				media = 0;
-			}
-			doc->m_styles.parse_stylesheet(css->text.c_str(), css->baseurl.c_str(), doc, media);
-		}
-		// Sort css selectors using CSS rules.
-		doc->m_styles.sort_selectors();
-
-		// get current media features
-		if (!doc->m_media_lists.empty())
-		{
-			doc->update_media_lists(doc->m_media);
-		}
-
-		// Apply parsed styles.
-		doc->m_root->apply_stylesheet(doc->m_styles);
-
-		// Apply user styles if any
-		if (user_styles)
-		{
-			doc->m_root->apply_stylesheet(*user_styles);
-		}
-
-		// Parse applied styles in the elements
-		doc->m_root->parse_styles();
-
-		// Now the m_tabular_elements is filled with tabular elements.
-		// We have to check the tabular elements for missing table elements 
-		// and create the anonymous boxes in visual table layout
-		doc->fix_tables_layout();
-
-		// Fanaly initialize elements
-		doc->m_root->init();
-	}
-
-	return doc;
-}
-
-litehtml::uint_ptr litehtml::document::add_font( const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm )
-{
-	uint_ptr ret = 0;
-
-	if( !name || (name && !t_strcasecmp(name, _t("inherit"))) )
-	{
-		name = m_container->get_default_font_name();
-	}
-
-	if(!size)
-	{
-		size = container()->get_default_font_size();
-	}
-
-	tchar_t strSize[20];
-	t_itoa(size, strSize, 20, 10);
-
-	tstring key = name;
-	key += _t(":");
-	key += strSize;
-	key += _t(":");
-	key += weight;
-	key += _t(":");
-	key += style;
-	key += _t(":");
-	key += decoration;
-
-	if(m_fonts.find(key) == m_fonts.end())
-	{
-		font_style fs = (font_style) value_index(style, font_style_strings, fontStyleNormal);
-		int	fw = value_index(weight, font_weight_strings, -1);
-		if(fw >= 0)
-		{
-			switch(fw)
-			{
-			case litehtml::fontWeightBold:
-				fw = 700;
-				break;
-			case litehtml::fontWeightBolder:
-				fw = 600;
-				break;
-			case litehtml::fontWeightLighter:
-				fw = 300;
-				break;
-			default:
-				fw = 400;
-				break;
-			}
-		} else
-		{
-			fw = t_atoi(weight);
-			if(fw < 100)
-			{
-				fw = 400;
-			}
-		}
-
-		unsigned int decor = 0;
-
-		if(decoration)
-		{
-			std::vector<tstring> tokens;
-			split_string(decoration, tokens, _t(" "));
-			for(std::vector<tstring>::iterator i = tokens.begin(); i != tokens.end(); i++)
-			{
-				if(!t_strcasecmp(i->c_str(), _t("underline")))
-				{
-					decor |= font_decoration_underline;
-				} else if(!t_strcasecmp(i->c_str(), _t("line-through")))
-				{
-					decor |= font_decoration_linethrough;
-				} else if(!t_strcasecmp(i->c_str(), _t("overline")))
-				{
-					decor |= font_decoration_overline;
-				}
-			}
-		}
-
-		font_item fi= {0};
-
-		fi.font = m_container->create_font(name, size, fw, fs, decor, &fi.metrics);
-		m_fonts[key] = fi;
-		ret = fi.font;
-		if(fm)
-		{
-			*fm = fi.metrics;
-		}
-	}
-	return ret;
-}
-
-litehtml::uint_ptr litehtml::document::get_font( const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm )
-{
-	if( !name || (name && !t_strcasecmp(name, _t("inherit"))) )
-	{
-		name = m_container->get_default_font_name();
-	}
-
-	if(!size)
-	{
-		size = container()->get_default_font_size();
-	}
-
-	tchar_t strSize[20];
-	t_itoa(size, strSize, 20, 10);
-
-	tstring key = name;
-	key += _t(":");
-	key += strSize;
-	key += _t(":");
-	key += weight;
-	key += _t(":");
-	key += style;
-	key += _t(":");
-	key += decoration;
-
-	fonts_map::iterator el = m_fonts.find(key);
-
-	if(el != m_fonts.end())
-	{
-		if(fm)
-		{
-			*fm = el->second.metrics;
-		}
-		return el->second.font;
-	}
-	return add_font(name, size, weight, style, decoration, fm);
-}
-
-int litehtml::document::render( int max_width, render_type rt )
-{
-	int ret = 0;
-	if(m_root)
-	{
-		if(rt == render_fixed_only)
-		{
-			m_fixed_boxes.clear();
-			m_root->render_positioned(rt);
-		} else
-		{
-			ret = m_root->render(0, 0, max_width);
-			if(m_root->fetch_positioned())
-			{
-				m_fixed_boxes.clear();
-				m_root->render_positioned(rt);
-			}
-			m_size.width	= 0;
-			m_size.height	= 0;
-			m_root->calc_document_size(m_size);
-		}
-	}
-	return ret;
-}
-
-void litehtml::document::draw( uint_ptr hdc, int x, int y, const position* clip )
-{
-	if(m_root)
-	{
-		m_root->draw(hdc, x, y, clip);
-		m_root->draw_stacking_context(hdc, x, y, clip, true);
-	}
-}
-
-int litehtml::document::cvt_units( const tchar_t* str, int fontSize, bool* is_percent/*= 0*/ ) const
-{
-	if(!str)	return 0;
-	
-	css_length val;
-	val.fromString(str);
-	if(is_percent && val.units() == css_units_percentage && !val.is_predefined())
-	{
-		*is_percent = true;
-	}
-	return cvt_units(val, fontSize);
-}
-
-int litehtml::document::cvt_units( css_length& val, int fontSize, int size ) const
-{
-	if(val.is_predefined())
-	{
-		return 0;
-	}
-	int ret = 0;
-	switch(val.units())
-	{
-	case css_units_percentage:
-		ret = val.calc_percent(size);
-		break;
-	case css_units_em:
-		ret = round_f(val.val() * fontSize);
-		val.set_value((float) ret, css_units_px);
-		break;
-	case css_units_pt:
-		ret = m_container->pt_to_px((int) val.val());
-		val.set_value((float) ret, css_units_px);
-		break;
-	case css_units_in:
-		ret = m_container->pt_to_px((int) (val.val() * 72));
-		val.set_value((float) ret, css_units_px);
-		break;
-	case css_units_cm:
-		ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72));
-		val.set_value((float) ret, css_units_px);
-		break;
-	case css_units_mm:
-		ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72) / 10);
-		val.set_value((float) ret, css_units_px);
-		break;
-	case css_units_vw:
-		ret = (int)((double)m_media.width * (double)val.val() / 100.0);
-		break;
-	case css_units_vh:
-		ret = (int)((double)m_media.height * (double)val.val() / 100.0);
-		break;
-	case css_units_vmin:
-		ret = (int)((double)std::min(m_media.height, m_media.width) * (double)val.val() / 100.0);
-		break;
-	case css_units_vmax:
-		ret = (int)((double)std::max(m_media.height, m_media.width) * (double)val.val() / 100.0);
-		break;
-	default:
-		ret = (int) val.val();
-		break;
-	}
-	return ret;
-}
-
-int litehtml::document::width() const
-{
-	return m_size.width;
-}
-
-int litehtml::document::height() const
-{
-	return m_size.height;
-}
-
-void litehtml::document::add_stylesheet( const tchar_t* str, const tchar_t* baseurl, const tchar_t* media )
-{
-	if(str && str[0])
-	{
-		m_css.push_back(css_text(str, baseurl, media));
-	}
-}
-
-bool litehtml::document::on_mouse_over( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )
-{
-	if(!m_root)
-	{
-		return false;
-	}
-
-	element::ptr over_el = m_root->get_element_by_point(x, y, client_x, client_y);
-
-	bool state_was_changed = false;
-
-	if(over_el != m_over_element)
-	{
-		if(m_over_element)
-		{
-			if(m_over_element->on_mouse_leave())
-			{
-				state_was_changed = true;
-			}
-		}
-		m_over_element = over_el;
-	}
-
-	const tchar_t* cursor = 0;
-
-	if(m_over_element)
-	{
-		if(m_over_element->on_mouse_over())
-		{
-			state_was_changed = true;
-		}
-		cursor = m_over_element->get_cursor();
-	}
-	
-	m_container->set_cursor(cursor ? cursor : _t("auto"));
-	
-	if(state_was_changed)
-	{
-		return m_root->find_styles_changes(redraw_boxes, 0, 0);
-	}
-	return false;
-}
-
-bool litehtml::document::on_mouse_leave( position::vector& redraw_boxes )
-{
-	if(!m_root)
-	{
-		return false;
-	}
-	if(m_over_element)
-	{
-		if(m_over_element->on_mouse_leave())
-		{
-			return m_root->find_styles_changes(redraw_boxes, 0, 0);
-		}
-	}
-	return false;
-}
-
-bool litehtml::document::on_lbutton_down( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )
-{
-	if(!m_root)
-	{
-		return false;
-	}
-
-	element::ptr over_el = m_root->get_element_by_point(x, y, client_x, client_y);
-
-	bool state_was_changed = false;
-
-	if(over_el != m_over_element)
-	{
-		if(m_over_element)
-		{
-			if(m_over_element->on_mouse_leave())
-			{
-				state_was_changed = true;
-			}
-		}
-		m_over_element = over_el;
-		if(m_over_element)
-		{
-			if(m_over_element->on_mouse_over())
-			{
-				state_was_changed = true;
-			}
-		}
-	}
-
-	const tchar_t* cursor = 0;
-
-	if(m_over_element)
-	{
-		if(m_over_element->on_lbutton_down())
-		{
-			state_was_changed = true;
-		}
-		cursor = m_over_element->get_cursor();
-	}
-
-	m_container->set_cursor(cursor ? cursor : _t("auto"));
-
-	if(state_was_changed)
-	{
-		return m_root->find_styles_changes(redraw_boxes, 0, 0);
-	}
-
-	return false;
-}
-
-bool litehtml::document::on_lbutton_up( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )
-{
-	if(!m_root)
-	{
-		return false;
-	}
-	if(m_over_element)
-	{
-		if(m_over_element->on_lbutton_up())
-		{
-			return m_root->find_styles_changes(redraw_boxes, 0, 0);
-		}
-	}
-	return false;
-}
-
-litehtml::element::ptr litehtml::document::create_element(const tchar_t* tag_name, const string_map& attributes)
-{
-	element::ptr newTag;
-	document::ptr this_doc = shared_from_this();
-	if(m_container)
-	{
-		newTag = m_container->create_element(tag_name, attributes, this_doc);
-	}
-	if(!newTag)
-	{
-		if(!t_strcmp(tag_name, _t("br")))
-		{
-			newTag = std::make_shared<litehtml::el_break>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("p")))
-		{
-			newTag = std::make_shared<litehtml::el_para>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("img")))
-		{
-			newTag = std::make_shared<litehtml::el_image>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("table")))
-		{
-			newTag = std::make_shared<litehtml::el_table>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("td")) || !t_strcmp(tag_name, _t("th")))
-		{
-			newTag = std::make_shared<litehtml::el_td>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("link")))
-		{
-			newTag = std::make_shared<litehtml::el_link>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("title")))
-		{
-			newTag = std::make_shared<litehtml::el_title>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("a")))
-		{
-			newTag = std::make_shared<litehtml::el_anchor>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("tr")))
-		{
-			newTag = std::make_shared<litehtml::el_tr>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("style")))
-		{
-			newTag = std::make_shared<litehtml::el_style>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("base")))
-		{
-			newTag = std::make_shared<litehtml::el_base>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("body")))
-		{
-			newTag = std::make_shared<litehtml::el_body>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("div")))
-		{
-			newTag = std::make_shared<litehtml::el_div>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("script")))
-		{
-			newTag = std::make_shared<litehtml::el_script>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("font")))
-		{
-			newTag = std::make_shared<litehtml::el_font>(this_doc);
-		} else
-		{
-			newTag = std::make_shared<litehtml::html_tag>(this_doc);
-		}
-	}
-
-	if(newTag)
-	{
-		newTag->set_tagName(tag_name);
-		for (string_map::const_iterator iter = attributes.begin(); iter != attributes.end(); iter++)
-		{
-			newTag->set_attr(iter->first.c_str(), iter->second.c_str());
-		}
-	}
-
-	return newTag;
-}
-
-void litehtml::document::get_fixed_boxes( position::vector& fixed_boxes )
-{
-	fixed_boxes = m_fixed_boxes;
-}
-
-void litehtml::document::add_fixed_box( const position& pos )
-{
-	m_fixed_boxes.push_back(pos);
-}
-
-bool litehtml::document::media_changed()
-{
-	if(!m_media_lists.empty())
-	{
-		container()->get_media_features(m_media);
-		if (update_media_lists(m_media))
-		{
-			m_root->refresh_styles();
-			m_root->parse_styles();
-			return true;
-		}
-	}
-	return false;
-}
-
-bool litehtml::document::lang_changed()
-{
-	if(!m_media_lists.empty())
-	{
-		tstring culture;
-		container()->get_language(m_lang, culture);
-		if(!culture.empty())
-		{
-			m_culture = m_lang + _t('-') + culture;
-		}
-		else
-		{
-			m_culture.clear();
-		}
-		m_root->refresh_styles();
-		m_root->parse_styles();
-		return true;
-	}
-	return false;
-}
-
-bool litehtml::document::update_media_lists(const media_features& features)
-{
-	bool update_styles = false;
-	for(media_query_list::vector::iterator iter = m_media_lists.begin(); iter != m_media_lists.end(); iter++)
-	{
-		if((*iter)->apply_media_features(features))
-		{
-			update_styles = true;
-		}
-	}
-	return update_styles;
-}
-
-void litehtml::document::add_media_list( media_query_list::ptr list )
-{
-	if(list)
-	{
-		if(std::find(m_media_lists.begin(), m_media_lists.end(), list) == m_media_lists.end())
-		{
-			m_media_lists.push_back(list);
-		}
-	}
-}
-
-void litehtml::document::create_node(GumboNode* node, elements_vector& elements)
-{
-	switch (node->type)
-	{
-	case GUMBO_NODE_ELEMENT:
-		{
-			string_map attrs;
-			GumboAttribute* attr;
-			for (unsigned int i = 0; i < node->v.element.attributes.length; i++)
-			{
-				attr = (GumboAttribute*)node->v.element.attributes.data[i];
-				attrs[tstring(litehtml_from_utf8(attr->name))] = litehtml_from_utf8(attr->value);
-			}
-
-
-			element::ptr ret;
-			const char* tag = gumbo_normalized_tagname(node->v.element.tag);
-			if (tag[0])
-			{
-				ret = create_element(litehtml_from_utf8(tag), attrs);
-			}
-			else
-			{
-				if (node->v.element.original_tag.data && node->v.element.original_tag.length)
-				{
-					std::string strA;
-					gumbo_tag_from_original_text(&node->v.element.original_tag);
-					strA.append(node->v.element.original_tag.data, node->v.element.original_tag.length);
-					ret = create_element(litehtml_from_utf8(strA.c_str()), attrs);
-				}
-			}
-			if (ret)
-			{
-				elements_vector child;
-				for (unsigned int i = 0; i < node->v.element.children.length; i++)
-				{
-					child.clear();
-					create_node(static_cast<GumboNode*> (node->v.element.children.data[i]), child);
-					std::for_each(child.begin(), child.end(), 
-						[&ret](element::ptr& el)
-						{
-							ret->appendChild(el);
-						}
-					);
-				}
-				elements.push_back(ret);
-			}
-		}
-		break;
-	case GUMBO_NODE_TEXT:
-		{
-			std::wstring str;
-			std::wstring str_in = (const wchar_t*) (utf8_to_wchar(node->v.text.text));
-			ucode_t c;
-			for (size_t i = 0; i < str_in.length(); i++)
-			{
-				c = (ucode_t) str_in[i];
-				if (c <= ' ' && (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f'))
-				{
-					if (!str.empty())
-					{
-						elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
-						str.clear();
-					}
-					str += c;
-					elements.push_back(std::make_shared<el_space>(litehtml_from_wchar(str.c_str()), shared_from_this()));
-					str.clear();
-				}
-				// CJK character range
-				else if (c >= 0x4E00 && c <= 0x9FCC)
-				{
-					if (!str.empty())
-					{
-						elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
-						str.clear();
-					}
-					str += c;
-					elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
-					str.clear();
-				}
-				else
-				{
-					str += c;
-				}
-			}
-			if (!str.empty())
-			{
-				elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
-			}
-		}
-		break;
-	case GUMBO_NODE_CDATA:
-		{
-			element::ptr ret = std::make_shared<el_cdata>(shared_from_this());
-			ret->set_data(litehtml_from_utf8(node->v.text.text));
-			elements.push_back(ret);
-		}
-		break;
-	case GUMBO_NODE_COMMENT:
-		{
-			element::ptr ret = std::make_shared<el_comment>(shared_from_this());
-			ret->set_data(litehtml_from_utf8(node->v.text.text));
-			elements.push_back(ret);
-		}
-		break;
-	case GUMBO_NODE_WHITESPACE:
-		{
-			tstring str = litehtml_from_utf8(node->v.text.text);
-			for (size_t i = 0; i < str.length(); i++)
-			{
-				elements.push_back(std::make_shared<el_space>(str.substr(i, 1).c_str(), shared_from_this()));
-			}
-		}
-		break;
-	default:
-		break;
-	}
-}
-
-void litehtml::document::fix_tables_layout()
-{
-	size_t i = 0;
-	while (i < m_tabular_elements.size())
-	{
-		element::ptr el_ptr = m_tabular_elements[i];
-
-		switch (el_ptr->get_display())
-		{
-		case display_inline_table:
-		case display_table:
-			fix_table_children(el_ptr, display_table_row_group, _t("table-row-group"));
-			break;
-		case display_table_footer_group:
-		case display_table_row_group:
-		case display_table_header_group:
-			fix_table_parent(el_ptr, display_table, _t("table"));
-			fix_table_children(el_ptr, display_table_row, _t("table-row"));
-			break;
-		case display_table_row:
-			fix_table_parent(el_ptr, display_table_row_group, _t("table-row-group"));
-			fix_table_children(el_ptr, display_table_cell, _t("table-cell"));
-			break;
-		case display_table_cell:
-			fix_table_parent(el_ptr, display_table_row, _t("table-row"));
-			break;
-		// TODO: make table layout fix for table-caption, table-column etc. elements
-		case display_table_caption:
-		case display_table_column:
-		case display_table_column_group:
-		default:
-			break;
-		}
-		i++;
-	}
-}
-
-void litehtml::document::fix_table_children(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str)
-{
-	elements_vector tmp;
-	elements_vector::iterator first_iter = el_ptr->m_children.begin();
-	elements_vector::iterator cur_iter = el_ptr->m_children.begin();
-
-	auto flush_elements = [&]()
-	{
-		element::ptr annon_tag = std::make_shared<html_tag>(shared_from_this());
-		style st;
-		st.add_property(_t("display"), disp_str, 0, false);
-		annon_tag->add_style(st);
-		annon_tag->parent(el_ptr);
-		annon_tag->parse_styles();
-		std::for_each(tmp.begin(), tmp.end(),
-			[&annon_tag](element::ptr& el)
-			{
-				annon_tag->appendChild(el);
-			}
-		);
-		first_iter = el_ptr->m_children.insert(first_iter, annon_tag);
-		cur_iter = first_iter + 1;
-		while (cur_iter != el_ptr->m_children.end() && (*cur_iter)->parent() != el_ptr)
-		{
-			cur_iter = el_ptr->m_children.erase(cur_iter);
-		}
-		first_iter = cur_iter;
-		tmp.clear();
-	};
-
-	while (cur_iter != el_ptr->m_children.end())
-	{
-		if ((*cur_iter)->get_display() != disp)
-		{
-			if (!(*cur_iter)->is_white_space() || ((*cur_iter)->is_white_space() && !tmp.empty()))
-			{
-				if (tmp.empty())
-				{
-					first_iter = cur_iter;
-				}
-				tmp.push_back((*cur_iter));
-			}
-			cur_iter++;
-		}
-		else if (!tmp.empty())
-		{
-			flush_elements();
-		}
-		else
-		{
-			cur_iter++;
-		}
-	}
-	if (!tmp.empty())
-	{
-		flush_elements();
-	}
-}
-
-void litehtml::document::fix_table_parent(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str)
-{
-	element::ptr parent = el_ptr->parent();
-
-	if (parent->get_display() != disp)
-	{
-		elements_vector::iterator this_element = std::find_if(parent->m_children.begin(), parent->m_children.end(),
-			[&](element::ptr& el)
-			{
-				if (el == el_ptr)
-				{
-					return true;
-				}
-				return false;
-			}
-		);
-		if (this_element != parent->m_children.end())
-		{
-			style_display el_disp = el_ptr->get_display();
-			elements_vector::iterator first = this_element;
-			elements_vector::iterator last = this_element;
-			elements_vector::iterator cur = this_element;
-
-			// find first element with same display
-			while (true)
-			{
-				if (cur == parent->m_children.begin()) break;
-				cur--;
-				if ((*cur)->is_white_space() || (*cur)->get_display() == el_disp)
-				{
-					first = cur;
-				}
-				else
-				{
-					break;
-				}
-			}
-
-			// find last element with same display
-			cur = this_element;
-			while (true)
-			{
-				cur++;
-				if (cur == parent->m_children.end()) break;
-
-				if ((*cur)->is_white_space() || (*cur)->get_display() == el_disp)
-				{
-					last = cur;
-				}
-				else
-				{
-					break;
-				}
-			}
-
-			// extract elements with the same display and wrap them with anonymous object
-			element::ptr annon_tag = std::make_shared<html_tag>(shared_from_this());
-			style st;
-			st.add_property(_t("display"), disp_str, 0, false);
-			annon_tag->add_style(st);
-			annon_tag->parent(parent);
-			annon_tag->parse_styles();
-			std::for_each(first, last + 1,
-				[&annon_tag](element::ptr& el)
-				{
-					annon_tag->appendChild(el);
-				}
-			);
-			first = parent->m_children.erase(first, last + 1);
-			parent->m_children.insert(first, annon_tag);
-		}
-	}
-}
+#include "html.h"
+#include "document.h"
+#include "stylesheet.h"
+#include "html_tag.h"
+#include "el_text.h"
+#include "el_para.h"
+#include "el_space.h"
+#include "el_body.h"
+#include "el_image.h"
+#include "el_table.h"
+#include "el_td.h"
+#include "el_link.h"
+#include "el_title.h"
+#include "el_style.h"
+#include "el_script.h"
+#include "el_comment.h"
+#include "el_cdata.h"
+#include "el_base.h"
+#include "el_anchor.h"
+#include "el_break.h"
+#include "el_div.h"
+#include "el_font.h"
+#include "el_tr.h"
+#include <math.h>
+#include <stdio.h>
+#include <algorithm>
+#include "gumbo.h"
+#include "utf8_strings.h"
+
+litehtml::document::document(litehtml::document_container* objContainer, litehtml::context* ctx)
+{
+	m_container	= objContainer;
+	m_context	= ctx;
+}
+
+litehtml::document::~document()
+{
+	m_over_element = 0;
+	if(m_container)
+	{
+		for(fonts_map::iterator f = m_fonts.begin(); f != m_fonts.end(); f++)
+		{
+			m_container->delete_font(f->second.font);
+		}
+	}
+}
+
+litehtml::document::ptr litehtml::document::createFromString( const tchar_t* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles)
+{
+	return createFromUTF8(litehtml_to_utf8(str), objPainter, ctx, user_styles);
+}
+
+litehtml::document::ptr litehtml::document::createFromUTF8(const char* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles)
+{
+	// parse document into GumboOutput
+	GumboOutput* output = gumbo_parse((const char*) str);
+
+	// Create litehtml::document
+	litehtml::document::ptr doc = std::make_shared<litehtml::document>(objPainter, ctx);
+
+	// Create litehtml::elements.
+	elements_vector root_elements;
+	doc->create_node(output->root, root_elements);
+	if (!root_elements.empty())
+	{
+		doc->m_root = root_elements.back();
+	}
+	// Destroy GumboOutput
+	gumbo_destroy_output(&kGumboDefaultOptions, output);
+
+	// Let's process created elements tree
+	if (doc->m_root)
+	{
+		doc->container()->get_media_features(doc->m_media);
+
+		// apply master CSS
+		doc->m_root->apply_stylesheet(ctx->master_css());
+
+		// parse elements attributes
+		doc->m_root->parse_attributes();
+
+		// parse style sheets linked in document
+		media_query_list::ptr media;
+		for (css_text::vector::iterator css = doc->m_css.begin(); css != doc->m_css.end(); css++)
+		{
+			if (!css->media.empty())
+			{
+				media = media_query_list::create_from_string(css->media, doc);
+			}
+			else
+			{
+				media = 0;
+			}
+			doc->m_styles.parse_stylesheet(css->text.c_str(), css->baseurl.c_str(), doc, media);
+		}
+		// Sort css selectors using CSS rules.
+		doc->m_styles.sort_selectors();
+
+		// get current media features
+		if (!doc->m_media_lists.empty())
+		{
+			doc->update_media_lists(doc->m_media);
+		}
+
+		// Apply parsed styles.
+		doc->m_root->apply_stylesheet(doc->m_styles);
+
+		// Apply user styles if any
+		if (user_styles)
+		{
+			doc->m_root->apply_stylesheet(*user_styles);
+		}
+
+		// Parse applied styles in the elements
+		doc->m_root->parse_styles();
+
+		// Now the m_tabular_elements is filled with tabular elements.
+		// We have to check the tabular elements for missing table elements 
+		// and create the anonymous boxes in visual table layout
+		doc->fix_tables_layout();
+
+		// Fanaly initialize elements
+		doc->m_root->init();
+	}
+
+	return doc;
+}
+
+litehtml::uint_ptr litehtml::document::add_font( const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm )
+{
+	uint_ptr ret = 0;
+
+	if( !name || (name && !t_strcasecmp(name, _t("inherit"))) )
+	{
+		name = m_container->get_default_font_name();
+	}
+
+	if(!size)
+	{
+		size = container()->get_default_font_size();
+	}
+
+	tchar_t strSize[20];
+	t_itoa(size, strSize, 20, 10);
+
+	tstring key = name;
+	key += _t(":");
+	key += strSize;
+	key += _t(":");
+	key += weight;
+	key += _t(":");
+	key += style;
+	key += _t(":");
+	key += decoration;
+
+	if(m_fonts.find(key) == m_fonts.end())
+	{
+		font_style fs = (font_style) value_index(style, font_style_strings, fontStyleNormal);
+		int	fw = value_index(weight, font_weight_strings, -1);
+		if(fw >= 0)
+		{
+			switch(fw)
+			{
+			case litehtml::fontWeightBold:
+				fw = 700;
+				break;
+			case litehtml::fontWeightBolder:
+				fw = 600;
+				break;
+			case litehtml::fontWeightLighter:
+				fw = 300;
+				break;
+			default:
+				fw = 400;
+				break;
+			}
+		} else
+		{
+			fw = t_atoi(weight);
+			if(fw < 100)
+			{
+				fw = 400;
+			}
+		}
+
+		unsigned int decor = 0;
+
+		if(decoration)
+		{
+			std::vector<tstring> tokens;
+			split_string(decoration, tokens, _t(" "));
+			for(std::vector<tstring>::iterator i = tokens.begin(); i != tokens.end(); i++)
+			{
+				if(!t_strcasecmp(i->c_str(), _t("underline")))
+				{
+					decor |= font_decoration_underline;
+				} else if(!t_strcasecmp(i->c_str(), _t("line-through")))
+				{
+					decor |= font_decoration_linethrough;
+				} else if(!t_strcasecmp(i->c_str(), _t("overline")))
+				{
+					decor |= font_decoration_overline;
+				}
+			}
+		}
+
+		font_item fi= {0};
+
+		fi.font = m_container->create_font(name, size, fw, fs, decor, &fi.metrics);
+		m_fonts[key] = fi;
+		ret = fi.font;
+		if(fm)
+		{
+			*fm = fi.metrics;
+		}
+	}
+	return ret;
+}
+
+litehtml::uint_ptr litehtml::document::get_font( const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm )
+{
+	if( !name || (name && !t_strcasecmp(name, _t("inherit"))) )
+	{
+		name = m_container->get_default_font_name();
+	}
+
+	if(!size)
+	{
+		size = container()->get_default_font_size();
+	}
+
+	tchar_t strSize[20];
+	t_itoa(size, strSize, 20, 10);
+
+	tstring key = name;
+	key += _t(":");
+	key += strSize;
+	key += _t(":");
+	key += weight;
+	key += _t(":");
+	key += style;
+	key += _t(":");
+	key += decoration;
+
+	fonts_map::iterator el = m_fonts.find(key);
+
+	if(el != m_fonts.end())
+	{
+		if(fm)
+		{
+			*fm = el->second.metrics;
+		}
+		return el->second.font;
+	}
+	return add_font(name, size, weight, style, decoration, fm);
+}
+
+int litehtml::document::render( int max_width, render_type rt )
+{
+	int ret = 0;
+	if(m_root)
+	{
+		if(rt == render_fixed_only)
+		{
+			m_fixed_boxes.clear();
+			m_root->render_positioned(rt);
+		} else
+		{
+			ret = m_root->render(0, 0, max_width);
+			if(m_root->fetch_positioned())
+			{
+				m_fixed_boxes.clear();
+				m_root->render_positioned(rt);
+			}
+			m_size.width	= 0;
+			m_size.height	= 0;
+			m_root->calc_document_size(m_size);
+		}
+	}
+	return ret;
+}
+
+void litehtml::document::draw( uint_ptr hdc, int x, int y, const position* clip )
+{
+	if(m_root)
+	{
+		m_root->draw(hdc, x, y, clip);
+		m_root->draw_stacking_context(hdc, x, y, clip, true);
+	}
+}
+
+int litehtml::document::cvt_units( const tchar_t* str, int fontSize, bool* is_percent/*= 0*/ ) const
+{
+	if(!str)	return 0;
+	
+	css_length val;
+	val.fromString(str);
+	if(is_percent && val.units() == css_units_percentage && !val.is_predefined())
+	{
+		*is_percent = true;
+	}
+	return cvt_units(val, fontSize);
+}
+
+int litehtml::document::cvt_units( css_length& val, int fontSize, int size ) const
+{
+	if(val.is_predefined())
+	{
+		return 0;
+	}
+	int ret = 0;
+	switch(val.units())
+	{
+	case css_units_percentage:
+		ret = val.calc_percent(size);
+		break;
+	case css_units_em:
+		ret = round_f(val.val() * fontSize);
+		val.set_value((float) ret, css_units_px);
+		break;
+	case css_units_pt:
+		ret = m_container->pt_to_px((int) val.val());
+		val.set_value((float) ret, css_units_px);
+		break;
+	case css_units_in:
+		ret = m_container->pt_to_px((int) (val.val() * 72));
+		val.set_value((float) ret, css_units_px);
+		break;
+	case css_units_cm:
+		ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72));
+		val.set_value((float) ret, css_units_px);
+		break;
+	case css_units_mm:
+		ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72) / 10);
+		val.set_value((float) ret, css_units_px);
+		break;
+	case css_units_vw:
+		ret = (int)((double)m_media.width * (double)val.val() / 100.0);
+		break;
+	case css_units_vh:
+		ret = (int)((double)m_media.height * (double)val.val() / 100.0);
+		break;
+	case css_units_vmin:
+		ret = (int)((double)std::min(m_media.height, m_media.width) * (double)val.val() / 100.0);
+		break;
+	case css_units_vmax:
+		ret = (int)((double)std::max(m_media.height, m_media.width) * (double)val.val() / 100.0);
+		break;
+	default:
+		ret = (int) val.val();
+		break;
+	}
+	return ret;
+}
+
+int litehtml::document::width() const
+{
+	return m_size.width;
+}
+
+int litehtml::document::height() const
+{
+	return m_size.height;
+}
+
+void litehtml::document::add_stylesheet( const tchar_t* str, const tchar_t* baseurl, const tchar_t* media )
+{
+	if(str && str[0])
+	{
+		m_css.push_back(css_text(str, baseurl, media));
+	}
+}
+
+bool litehtml::document::on_mouse_over( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )
+{
+	if(!m_root)
+	{
+		return false;
+	}
+
+	element::ptr over_el = m_root->get_element_by_point(x, y, client_x, client_y);
+
+	bool state_was_changed = false;
+
+	if(over_el != m_over_element)
+	{
+		if(m_over_element)
+		{
+			if(m_over_element->on_mouse_leave())
+			{
+				state_was_changed = true;
+			}
+		}
+		m_over_element = over_el;
+	}
+
+	const tchar_t* cursor = 0;
+
+	if(m_over_element)
+	{
+		if(m_over_element->on_mouse_over())
+		{
+			state_was_changed = true;
+		}
+		cursor = m_over_element->get_cursor();
+	}
+	
+	m_container->set_cursor(cursor ? cursor : _t("auto"));
+	
+	if(state_was_changed)
+	{
+		return m_root->find_styles_changes(redraw_boxes, 0, 0);
+	}
+	return false;
+}
+
+bool litehtml::document::on_mouse_leave( position::vector& redraw_boxes )
+{
+	if(!m_root)
+	{
+		return false;
+	}
+	if(m_over_element)
+	{
+		if(m_over_element->on_mouse_leave())
+		{
+			return m_root->find_styles_changes(redraw_boxes, 0, 0);
+		}
+	}
+	return false;
+}
+
+bool litehtml::document::on_lbutton_down( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )
+{
+	if(!m_root)
+	{
+		return false;
+	}
+
+	element::ptr over_el = m_root->get_element_by_point(x, y, client_x, client_y);
+
+	bool state_was_changed = false;
+
+	if(over_el != m_over_element)
+	{
+		if(m_over_element)
+		{
+			if(m_over_element->on_mouse_leave())
+			{
+				state_was_changed = true;
+			}
+		}
+		m_over_element = over_el;
+		if(m_over_element)
+		{
+			if(m_over_element->on_mouse_over())
+			{
+				state_was_changed = true;
+			}
+		}
+	}
+
+	const tchar_t* cursor = 0;
+
+	if(m_over_element)
+	{
+		if(m_over_element->on_lbutton_down())
+		{
+			state_was_changed = true;
+		}
+		cursor = m_over_element->get_cursor();
+	}
+
+	m_container->set_cursor(cursor ? cursor : _t("auto"));
+
+	if(state_was_changed)
+	{
+		return m_root->find_styles_changes(redraw_boxes, 0, 0);
+	}
+
+	return false;
+}
+
+bool litehtml::document::on_lbutton_up( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )
+{
+	if(!m_root)
+	{
+		return false;
+	}
+	if(m_over_element)
+	{
+		if(m_over_element->on_lbutton_up())
+		{
+			return m_root->find_styles_changes(redraw_boxes, 0, 0);
+		}
+	}
+	return false;
+}
+
+litehtml::element::ptr litehtml::document::create_element(const tchar_t* tag_name, const string_map& attributes)
+{
+	element::ptr newTag;
+	document::ptr this_doc = shared_from_this();
+	if(m_container)
+	{
+		newTag = m_container->create_element(tag_name, attributes, this_doc);
+	}
+	if(!newTag)
+	{
+		if(!t_strcmp(tag_name, _t("br")))
+		{
+			newTag = std::make_shared<litehtml::el_break>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("p")))
+		{
+			newTag = std::make_shared<litehtml::el_para>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("img")))
+		{
+			newTag = std::make_shared<litehtml::el_image>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("table")))
+		{
+			newTag = std::make_shared<litehtml::el_table>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("td")) || !t_strcmp(tag_name, _t("th")))
+		{
+			newTag = std::make_shared<litehtml::el_td>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("link")))
+		{
+			newTag = std::make_shared<litehtml::el_link>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("title")))
+		{
+			newTag = std::make_shared<litehtml::el_title>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("a")))
+		{
+			newTag = std::make_shared<litehtml::el_anchor>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("tr")))
+		{
+			newTag = std::make_shared<litehtml::el_tr>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("style")))
+		{
+			newTag = std::make_shared<litehtml::el_style>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("base")))
+		{
+			newTag = std::make_shared<litehtml::el_base>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("body")))
+		{
+			newTag = std::make_shared<litehtml::el_body>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("div")))
+		{
+			newTag = std::make_shared<litehtml::el_div>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("script")))
+		{
+			newTag = std::make_shared<litehtml::el_script>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("font")))
+		{
+			newTag = std::make_shared<litehtml::el_font>(this_doc);
+		} else
+		{
+			newTag = std::make_shared<litehtml::html_tag>(this_doc);
+		}
+	}
+
+	if(newTag)
+	{
+		newTag->set_tagName(tag_name);
+		for (string_map::const_iterator iter = attributes.begin(); iter != attributes.end(); iter++)
+		{
+			newTag->set_attr(iter->first.c_str(), iter->second.c_str());
+		}
+	}
+
+	return newTag;
+}
+
+void litehtml::document::get_fixed_boxes( position::vector& fixed_boxes )
+{
+	fixed_boxes = m_fixed_boxes;
+}
+
+void litehtml::document::add_fixed_box( const position& pos )
+{
+	m_fixed_boxes.push_back(pos);
+}
+
+bool litehtml::document::media_changed()
+{
+	if(!m_media_lists.empty())
+	{
+		container()->get_media_features(m_media);
+		if (update_media_lists(m_media))
+		{
+			m_root->refresh_styles();
+			m_root->parse_styles();
+			return true;
+		}
+	}
+	return false;
+}
+
+bool litehtml::document::lang_changed()
+{
+	if(!m_media_lists.empty())
+	{
+		tstring culture;
+		container()->get_language(m_lang, culture);
+		if(!culture.empty())
+		{
+			m_culture = m_lang + _t('-') + culture;
+		}
+		else
+		{
+			m_culture.clear();
+		}
+		m_root->refresh_styles();
+		m_root->parse_styles();
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::document::update_media_lists(const media_features& features)
+{
+	bool update_styles = false;
+	for(media_query_list::vector::iterator iter = m_media_lists.begin(); iter != m_media_lists.end(); iter++)
+	{
+		if((*iter)->apply_media_features(features))
+		{
+			update_styles = true;
+		}
+	}
+	return update_styles;
+}
+
+void litehtml::document::add_media_list( media_query_list::ptr list )
+{
+	if(list)
+	{
+		if(std::find(m_media_lists.begin(), m_media_lists.end(), list) == m_media_lists.end())
+		{
+			m_media_lists.push_back(list);
+		}
+	}
+}
+
+void litehtml::document::create_node(GumboNode* node, elements_vector& elements)
+{
+	switch (node->type)
+	{
+	case GUMBO_NODE_ELEMENT:
+		{
+			string_map attrs;
+			GumboAttribute* attr;
+			for (unsigned int i = 0; i < node->v.element.attributes.length; i++)
+			{
+				attr = (GumboAttribute*)node->v.element.attributes.data[i];
+				attrs[tstring(litehtml_from_utf8(attr->name))] = litehtml_from_utf8(attr->value);
+			}
+
+
+			element::ptr ret;
+			const char* tag = gumbo_normalized_tagname(node->v.element.tag);
+			if (tag[0])
+			{
+				ret = create_element(litehtml_from_utf8(tag), attrs);
+			}
+			else
+			{
+				if (node->v.element.original_tag.data && node->v.element.original_tag.length)
+				{
+					std::string strA;
+					gumbo_tag_from_original_text(&node->v.element.original_tag);
+					strA.append(node->v.element.original_tag.data, node->v.element.original_tag.length);
+					ret = create_element(litehtml_from_utf8(strA.c_str()), attrs);
+				}
+			}
+			if (ret)
+			{
+				elements_vector child;
+				for (unsigned int i = 0; i < node->v.element.children.length; i++)
+				{
+					child.clear();
+					create_node(static_cast<GumboNode*> (node->v.element.children.data[i]), child);
+					std::for_each(child.begin(), child.end(), 
+						[&ret](element::ptr& el)
+						{
+							ret->appendChild(el);
+						}
+					);
+				}
+				elements.push_back(ret);
+			}
+		}
+		break;
+	case GUMBO_NODE_TEXT:
+		{
+			std::wstring str;
+			std::wstring str_in = (const wchar_t*) (utf8_to_wchar(node->v.text.text));
+			ucode_t c;
+			for (size_t i = 0; i < str_in.length(); i++)
+			{
+				c = (ucode_t) str_in[i];
+				if (c <= ' ' && (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f'))
+				{
+					if (!str.empty())
+					{
+						elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
+						str.clear();
+					}
+					str += c;
+					elements.push_back(std::make_shared<el_space>(litehtml_from_wchar(str.c_str()), shared_from_this()));
+					str.clear();
+				}
+				// CJK character range
+				else if (c >= 0x4E00 && c <= 0x9FCC)
+				{
+					if (!str.empty())
+					{
+						elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
+						str.clear();
+					}
+					str += c;
+					elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
+					str.clear();
+				}
+				else
+				{
+					str += c;
+				}
+			}
+			if (!str.empty())
+			{
+				elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
+			}
+		}
+		break;
+	case GUMBO_NODE_CDATA:
+		{
+			element::ptr ret = std::make_shared<el_cdata>(shared_from_this());
+			ret->set_data(litehtml_from_utf8(node->v.text.text));
+			elements.push_back(ret);
+		}
+		break;
+	case GUMBO_NODE_COMMENT:
+		{
+			element::ptr ret = std::make_shared<el_comment>(shared_from_this());
+			ret->set_data(litehtml_from_utf8(node->v.text.text));
+			elements.push_back(ret);
+		}
+		break;
+	case GUMBO_NODE_WHITESPACE:
+		{
+			tstring str = litehtml_from_utf8(node->v.text.text);
+			for (size_t i = 0; i < str.length(); i++)
+			{
+				elements.push_back(std::make_shared<el_space>(str.substr(i, 1).c_str(), shared_from_this()));
+			}
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+void litehtml::document::fix_tables_layout()
+{
+	size_t i = 0;
+	while (i < m_tabular_elements.size())
+	{
+		element::ptr el_ptr = m_tabular_elements[i];
+
+		switch (el_ptr->get_display())
+		{
+		case display_inline_table:
+		case display_table:
+			fix_table_children(el_ptr, display_table_row_group, _t("table-row-group"));
+			break;
+		case display_table_footer_group:
+		case display_table_row_group:
+		case display_table_header_group:
+			fix_table_parent(el_ptr, display_table, _t("table"));
+			fix_table_children(el_ptr, display_table_row, _t("table-row"));
+			break;
+		case display_table_row:
+			fix_table_parent(el_ptr, display_table_row_group, _t("table-row-group"));
+			fix_table_children(el_ptr, display_table_cell, _t("table-cell"));
+			break;
+		case display_table_cell:
+			fix_table_parent(el_ptr, display_table_row, _t("table-row"));
+			break;
+		// TODO: make table layout fix for table-caption, table-column etc. elements
+		case display_table_caption:
+		case display_table_column:
+		case display_table_column_group:
+		default:
+			break;
+		}
+		i++;
+	}
+}
+
+void litehtml::document::fix_table_children(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str)
+{
+	elements_vector tmp;
+	elements_vector::iterator first_iter = el_ptr->m_children.begin();
+	elements_vector::iterator cur_iter = el_ptr->m_children.begin();
+
+	auto flush_elements = [&]()
+	{
+		element::ptr annon_tag = std::make_shared<html_tag>(shared_from_this());
+		style st;
+		st.add_property(_t("display"), disp_str, 0, false);
+		annon_tag->add_style(st);
+		annon_tag->parent(el_ptr);
+		annon_tag->parse_styles();
+		std::for_each(tmp.begin(), tmp.end(),
+			[&annon_tag](element::ptr& el)
+			{
+				annon_tag->appendChild(el);
+			}
+		);
+		first_iter = el_ptr->m_children.insert(first_iter, annon_tag);
+		cur_iter = first_iter + 1;
+		while (cur_iter != el_ptr->m_children.end() && (*cur_iter)->parent() != el_ptr)
+		{
+			cur_iter = el_ptr->m_children.erase(cur_iter);
+		}
+		first_iter = cur_iter;
+		tmp.clear();
+	};
+
+	while (cur_iter != el_ptr->m_children.end())
+	{
+		if ((*cur_iter)->get_display() != disp)
+		{
+			if (!(*cur_iter)->is_white_space() || ((*cur_iter)->is_white_space() && !tmp.empty()))
+			{
+				if (tmp.empty())
+				{
+					first_iter = cur_iter;
+				}
+				tmp.push_back((*cur_iter));
+			}
+			cur_iter++;
+		}
+		else if (!tmp.empty())
+		{
+			flush_elements();
+		}
+		else
+		{
+			cur_iter++;
+		}
+	}
+	if (!tmp.empty())
+	{
+		flush_elements();
+	}
+}
+
+void litehtml::document::fix_table_parent(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str)
+{
+	element::ptr parent = el_ptr->parent();
+
+	if (parent->get_display() != disp)
+	{
+		elements_vector::iterator this_element = std::find_if(parent->m_children.begin(), parent->m_children.end(),
+			[&](element::ptr& el)
+			{
+				if (el == el_ptr)
+				{
+					return true;
+				}
+				return false;
+			}
+		);
+		if (this_element != parent->m_children.end())
+		{
+			style_display el_disp = el_ptr->get_display();
+			elements_vector::iterator first = this_element;
+			elements_vector::iterator last = this_element;
+			elements_vector::iterator cur = this_element;
+
+			// find first element with same display
+			while (true)
+			{
+				if (cur == parent->m_children.begin()) break;
+				cur--;
+				if ((*cur)->is_white_space() || (*cur)->get_display() == el_disp)
+				{
+					first = cur;
+				}
+				else
+				{
+					break;
+				}
+			}
+
+			// find last element with same display
+			cur = this_element;
+			while (true)
+			{
+				cur++;
+				if (cur == parent->m_children.end()) break;
+
+				if ((*cur)->is_white_space() || (*cur)->get_display() == el_disp)
+				{
+					last = cur;
+				}
+				else
+				{
+					break;
+				}
+			}
+
+			// extract elements with the same display and wrap them with anonymous object
+			element::ptr annon_tag = std::make_shared<html_tag>(shared_from_this());
+			style st;
+			st.add_property(_t("display"), disp_str, 0, false);
+			annon_tag->add_style(st);
+			annon_tag->parent(parent);
+			annon_tag->parse_styles();
+			std::for_each(first, last + 1,
+				[&annon_tag](element::ptr& el)
+				{
+					annon_tag->appendChild(el);
+				}
+			);
+			first = parent->m_children.erase(first, last + 1);
+			parent->m_children.insert(first, annon_tag);
+		}
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/document.h b/src/plugins/litehtml_viewer/litehtml/document.h
index 33287f4..db30793 100644
--- a/src/plugins/litehtml_viewer/litehtml/document.h
+++ b/src/plugins/litehtml_viewer/litehtml/document.h
@@ -1,124 +1,128 @@
-#pragma once
-#include "style.h"
-#include "types.h"
-#include "context.h"
-#include "gumbo.h"
-
-namespace litehtml
-{
-	struct css_text
-	{
-		typedef std::vector<css_text>	vector;
-
-		tstring	text;
-		tstring	baseurl;
-		tstring	media;
-		
-		css_text()
-		{
-		}
-
-		css_text(const tchar_t* txt, const tchar_t* url, const tchar_t* media_str)
-		{
-			text	= txt ? txt : _t("");
-			baseurl	= url ? url : _t("");
-			media	= media_str ? media_str : _t("");
-		}
-
-		css_text(const css_text& val)
-		{
-			text	= val.text;
-			baseurl	= val.baseurl;
-			media	= val.media;
-		}
-	};
-
-	struct stop_tags_t
-	{
-		const litehtml::tchar_t*	tags;
-		const litehtml::tchar_t*	stop_parent;
-	};
-
-	struct ommited_end_tags_t
-	{
-		const litehtml::tchar_t*	tag;
-		const litehtml::tchar_t*	followed_tags;
-	};
-
-	class html_tag;
-
-	class document : public std::enable_shared_from_this<document>
-	{
-	public:
-		typedef std::shared_ptr<document>	ptr;
-		typedef std::weak_ptr<document>		weak_ptr;
-	private:
-		std::shared_ptr<element>			m_root;
-		document_container*					m_container;
-		fonts_map							m_fonts;
-		css_text::vector					m_css;
-		litehtml::css						m_styles;
-		litehtml::web_color					m_def_color;
-		litehtml::context*					m_context;
-		litehtml::size						m_size;
-		position::vector					m_fixed_boxes;
-		media_query_list::vector			m_media_lists;
-		element::ptr						m_over_element;
-		elements_vector						m_tabular_elements;
-		media_features						m_media;
-		tstring                             m_lang;
-		tstring                             m_culture;
-	public:
-		document(litehtml::document_container* objContainer, litehtml::context* ctx);
-		virtual ~document();
-
-		litehtml::document_container*	container()	{ return m_container; }
-		uint_ptr						get_font(const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm);
-		int								render(int max_width, render_type rt = render_all);
-		void							draw(uint_ptr hdc, int x, int y, const position* clip);
-		web_color						get_def_color()	{ return m_def_color; }
-		int								cvt_units(const tchar_t* str, int fontSize, bool* is_percent = 0) const;
-		int								cvt_units(css_length& val, int fontSize, int size = 0) const;
-		int								width() const;
-		int								height() const;
-		void							add_stylesheet(const tchar_t* str, const tchar_t* baseurl, const tchar_t* media);
-		bool							on_mouse_over(int x, int y, int client_x, int client_y, position::vector& redraw_boxes);
-		bool							on_lbutton_down(int x, int y, int client_x, int client_y, position::vector& redraw_boxes);
-		bool							on_lbutton_up(int x, int y, int client_x, int client_y, position::vector& redraw_boxes);
-		bool							on_mouse_leave(position::vector& redraw_boxes);
-		litehtml::element::ptr			create_element(const tchar_t* tag_name, const string_map& attributes);
-		element::ptr					root();
-		void							get_fixed_boxes(position::vector& fixed_boxes);
-		void							add_fixed_box(const position& pos);
-		void							add_media_list(media_query_list::ptr list);
-		bool							media_changed();
-		bool							lang_changed();
-		bool                            match_lang(const tstring & lang);
-		void							add_tabular(const element::ptr& el);
-
-		static litehtml::document::ptr createFromString(const tchar_t* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles = 0);
-		static litehtml::document::ptr createFromUTF8(const char* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles = 0);
-	
-	private:
-		litehtml::uint_ptr	add_font(const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm);
-
-		void create_node(GumboNode* node, elements_vector& elements);
-		bool update_media_lists(const media_features& features);
-		void fix_tables_layout();
-		void fix_table_children(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str);
-		void fix_table_parent(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str);
-	};
-
-	inline element::ptr document::root()
-	{
-		return m_root;
-	}
-	inline void document::add_tabular(const element::ptr& el)
-	{
-		m_tabular_elements.push_back(el);
-	}
-	inline bool document::match_lang(const tstring & lang)
-	{
-		return lang == m_lang || lang == m_culture;
-	}
-}
+#ifndef LH_DOCUMENT_H
+#define LH_DOCUMENT_H
+
+#include "style.h"
+#include "types.h"
+#include "context.h"
+#include "gumbo.h"
+
+namespace litehtml
+{
+	struct css_text
+	{
+		typedef std::vector<css_text>	vector;
+
+		tstring	text;
+		tstring	baseurl;
+		tstring	media;
+		
+		css_text()
+		{
+		}
+
+		css_text(const tchar_t* txt, const tchar_t* url, const tchar_t* media_str)
+		{
+			text	= txt ? txt : _t("");
+			baseurl	= url ? url : _t("");
+			media	= media_str ? media_str : _t("");
+		}
+
+		css_text(const css_text& val)
+		{
+			text	= val.text;
+			baseurl	= val.baseurl;
+			media	= val.media;
+		}
+	};
+
+	struct stop_tags_t
+	{
+		const litehtml::tchar_t*	tags;
+		const litehtml::tchar_t*	stop_parent;
+	};
+
+	struct ommited_end_tags_t
+	{
+		const litehtml::tchar_t*	tag;
+		const litehtml::tchar_t*	followed_tags;
+	};
+
+	class html_tag;
+
+	class document : public std::enable_shared_from_this<document>
+	{
+	public:
+		typedef std::shared_ptr<document>	ptr;
+		typedef std::weak_ptr<document>		weak_ptr;
+	private:
+		std::shared_ptr<element>			m_root;
+		document_container*					m_container;
+		fonts_map							m_fonts;
+		css_text::vector					m_css;
+		litehtml::css						m_styles;
+		litehtml::web_color					m_def_color;
+		litehtml::context*					m_context;
+		litehtml::size						m_size;
+		position::vector					m_fixed_boxes;
+		media_query_list::vector			m_media_lists;
+		element::ptr						m_over_element;
+		elements_vector						m_tabular_elements;
+		media_features						m_media;
+		tstring                             m_lang;
+		tstring                             m_culture;
+	public:
+		document(litehtml::document_container* objContainer, litehtml::context* ctx);
+		virtual ~document();
+
+		litehtml::document_container*	container()	{ return m_container; }
+		uint_ptr						get_font(const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm);
+		int								render(int max_width, render_type rt = render_all);
+		void							draw(uint_ptr hdc, int x, int y, const position* clip);
+		web_color						get_def_color()	{ return m_def_color; }
+		int								cvt_units(const tchar_t* str, int fontSize, bool* is_percent = 0) const;
+		int								cvt_units(css_length& val, int fontSize, int size = 0) const;
+		int								width() const;
+		int								height() const;
+		void							add_stylesheet(const tchar_t* str, const tchar_t* baseurl, const tchar_t* media);
+		bool							on_mouse_over(int x, int y, int client_x, int client_y, position::vector& redraw_boxes);
+		bool							on_lbutton_down(int x, int y, int client_x, int client_y, position::vector& redraw_boxes);
+		bool							on_lbutton_up(int x, int y, int client_x, int client_y, position::vector& redraw_boxes);
+		bool							on_mouse_leave(position::vector& redraw_boxes);
+		litehtml::element::ptr			create_element(const tchar_t* tag_name, const string_map& attributes);
+		element::ptr					root();
+		void							get_fixed_boxes(position::vector& fixed_boxes);
+		void							add_fixed_box(const position& pos);
+		void							add_media_list(media_query_list::ptr list);
+		bool							media_changed();
+		bool							lang_changed();
+		bool                            match_lang(const tstring & lang);
+		void							add_tabular(const element::ptr& el);
+
+		static litehtml::document::ptr createFromString(const tchar_t* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles = 0);
+		static litehtml::document::ptr createFromUTF8(const char* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles = 0);
+	
+	private:
+		litehtml::uint_ptr	add_font(const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm);
+
+		void create_node(GumboNode* node, elements_vector& elements);
+		bool update_media_lists(const media_features& features);
+		void fix_tables_layout();
+		void fix_table_children(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str);
+		void fix_table_parent(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str);
+	};
+
+	inline element::ptr document::root()
+	{
+		return m_root;
+	}
+	inline void document::add_tabular(const element::ptr& el)
+	{
+		m_tabular_elements.push_back(el);
+	}
+	inline bool document::match_lang(const tstring & lang)
+	{
+		return lang == m_lang || lang == m_culture;
+	}
+}
+
+#endif  // LH_DOCUMENT_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_anchor.cpp b/src/plugins/litehtml_viewer/litehtml/el_anchor.cpp
index b48b3f9..a120eb1 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_anchor.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_anchor.cpp
@@ -1,31 +1,31 @@
-#include "html.h"
-#include "el_anchor.h"
-#include "document.h"
-
-litehtml::el_anchor::el_anchor(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
-{
-}
-
-litehtml::el_anchor::~el_anchor()
-{
-
-}
-
-void litehtml::el_anchor::on_click()
-{
-	const tchar_t* href = get_attr(_t("href"));
-
-	if(href)
-	{
-		get_document()->container()->on_anchor_click(href, shared_from_this());
-	}
-}
-
-void litehtml::el_anchor::apply_stylesheet( const litehtml::css& stylesheet )
-{
-	if( get_attr(_t("href")) )
-	{
-		m_pseudo_classes.push_back(_t("link"));
-	}
-	html_tag::apply_stylesheet(stylesheet);
-}
+#include "html.h"
+#include "el_anchor.h"
+#include "document.h"
+
+litehtml::el_anchor::el_anchor(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+}
+
+litehtml::el_anchor::~el_anchor()
+{
+
+}
+
+void litehtml::el_anchor::on_click()
+{
+	const tchar_t* href = get_attr(_t("href"));
+
+	if(href)
+	{
+		get_document()->container()->on_anchor_click(href, shared_from_this());
+	}
+}
+
+void litehtml::el_anchor::apply_stylesheet( const litehtml::css& stylesheet )
+{
+	if( get_attr(_t("href")) )
+	{
+		m_pseudo_classes.push_back(_t("link"));
+	}
+	html_tag::apply_stylesheet(stylesheet);
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_anchor.h b/src/plugins/litehtml_viewer/litehtml/el_anchor.h
index 4e351ff..140d195 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_anchor.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_anchor.h
@@ -1,15 +1,19 @@
-#pragma once
-#include "html_tag.h"
-
-namespace litehtml
-{
-	class el_anchor : public html_tag
-	{
-	public:
-		el_anchor(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_anchor();
-
-		virtual void	on_click() override;
-		virtual void	apply_stylesheet(const litehtml::css& stylesheet) override;
-	};
-}
\ No newline at end of file
+#ifndef LH_EL_ANCHOR_H
+#define LH_EL_ANCHOR_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_anchor : public html_tag
+	{
+	public:
+		el_anchor(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_anchor();
+
+		virtual void	on_click() override;
+		virtual void	apply_stylesheet(const litehtml::css& stylesheet) override;
+	};
+}
+
+#endif  // LH_EL_ANCHOR_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_base.cpp b/src/plugins/litehtml_viewer/litehtml/el_base.cpp
index 928bc2e..dffc6af 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_base.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_base.cpp
@@ -1,18 +1,18 @@
-#include "html.h"
-#include "el_base.h"
-#include "document.h"
-
-litehtml::el_base::el_base(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
-{
-	
-}
-
-litehtml::el_base::~el_base()
-{
-
-}
-
-void litehtml::el_base::parse_attributes()
-{
-	get_document()->container()->set_base_url(get_attr(_t("href")));
-}
+#include "html.h"
+#include "el_base.h"
+#include "document.h"
+
+litehtml::el_base::el_base(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+	
+}
+
+litehtml::el_base::~el_base()
+{
+
+}
+
+void litehtml::el_base::parse_attributes()
+{
+	get_document()->container()->set_base_url(get_attr(_t("href")));
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_base.h b/src/plugins/litehtml_viewer/litehtml/el_base.h
index c4c388f..57ba87d 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_base.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_base.h
@@ -1,14 +1,18 @@
-#pragma once
-#include "html_tag.h"
-
-namespace litehtml
-{
-	class el_base : public html_tag
-	{
-	public:
-		el_base(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_base();
-
-		virtual void	parse_attributes() override;
-	};
-}
+#ifndef LH_EL_BASE_H
+#define LH_EL_BASE_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_base : public html_tag
+	{
+	public:
+		el_base(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_base();
+
+		virtual void	parse_attributes() override;
+	};
+}
+
+#endif  // LH_EL_BASE_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_before_after.cpp b/src/plugins/litehtml_viewer/litehtml/el_before_after.cpp
index 5c9ca34..bf0127d 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_before_after.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_before_after.cpp
@@ -1,200 +1,200 @@
-#include "html.h"
-#include "el_before_after.h"
-#include "el_text.h"
-#include "el_space.h"
-#include "el_image.h"
-
-litehtml::el_before_after_base::el_before_after_base(const std::shared_ptr<litehtml::document>& doc, bool before) : html_tag(doc)
-{
-	if(before)
-	{
-		set_tagName(_t("::before"));
-	} else
-	{
-		set_tagName(_t("::after"));
-	}
-}
-
-litehtml::el_before_after_base::~el_before_after_base()
-{
-
-}
-
-void litehtml::el_before_after_base::add_style(const litehtml::style& st)
-{
-	html_tag::add_style(st);
-
-	tstring content = get_style_property(_t("content"), false, _t(""));
-	if(!content.empty())
-	{
-		int idx = value_index(content.c_str(), content_property_string);
-		if(idx < 0)
-		{
-			tstring fnc;
-			tstring::size_type i = 0;
-			while(i < content.length() && i != tstring::npos)
-			{
-				if(content.at(i) == _t('"'))
-				{
-					fnc.clear();
-					i++;
-					tstring::size_type pos = content.find(_t('"'), i);
-					tstring txt;
-					if(pos == tstring::npos)
-					{
-						txt = content.substr(i);
-						i = tstring::npos;
-					} else
-					{
-						txt = content.substr(i, pos - i);
-						i = pos + 1;
-					}
-					add_text(txt);
-				} else if(content.at(i) == _t('('))
-				{
-					i++;
-					litehtml::trim(fnc);
-					litehtml::lcase(fnc);
-					tstring::size_type pos = content.find(_t(')'), i);
-					tstring params;
-					if(pos == tstring::npos)
-					{
-						params = content.substr(i);
-						i = tstring::npos;
-					} else
-					{
-						params = content.substr(i, pos - i);
-						i = pos + 1;
-					}
-					add_function(fnc, params);
-					fnc.clear();
-				} else
-				{
-					fnc += content.at(i);
-					i++;
-				}
-			}
-		}
-	}
-}
-
-void litehtml::el_before_after_base::add_text( const tstring& txt )
-{
-	tstring word;
-	tstring esc;
-	for(tstring::size_type i = 0; i < txt.length(); i++)
-	{
-		if( (txt.at(i) == _t(' ')) || (txt.at(i) == _t('\t')) || (txt.at(i) == _t('\\') && !esc.empty()) )
-		{
-			if(esc.empty())
-			{
-				if(!word.empty())
-				{
-					element::ptr el = std::make_shared<el_text>(word.c_str(), get_document());
-					appendChild(el);
-					word.clear();
-				}
-
-				element::ptr el = std::make_shared<el_space>(txt.substr(i, 1).c_str(), get_document());
-				appendChild(el);
-			} else
-			{
-				word += convert_escape(esc.c_str() + 1);
-				esc.clear();
-				if(txt.at(i) == _t('\\'))
-				{
-					esc += txt.at(i);
-				}
-			}
-		} else
-		{
-			if(!esc.empty() || txt.at(i) == _t('\\'))
-			{
-				esc += txt.at(i);
-			} else
-			{
-				word += txt.at(i);
-			}
-		}
-	}
-
-	if(!esc.empty())
-	{
-		word += convert_escape(esc.c_str() + 1);
-	}
-	if(!word.empty())
-	{
-		element::ptr el = std::make_shared<el_text>(word.c_str(), get_document());
-		appendChild(el);
-		word.clear();
-	}
-}
-
-void litehtml::el_before_after_base::add_function( const tstring& fnc, const tstring& params )
-{
-	int idx = value_index(fnc.c_str(), _t("attr;counter;url"));
-	switch(idx)
-	{
-	// attr
-	case 0:
-		{
-			tstring p_name = params;
-			trim(p_name);
-			lcase(p_name);
-			element::ptr el_parent = parent();
-			if (el_parent)
-			{
-				const tchar_t* attr_value = el_parent->get_attr(p_name.c_str());
-				if (attr_value)
-				{
-					add_text(attr_value);
-				}
-			}
-		}
-		break;
-	// counter
-	case 1:
-		break;
-	// url
-	case 2:
-		{
-			tstring p_url = params;
-			trim(p_url);
-			if(!p_url.empty())
-			{
-				if(p_url.at(0) == _t('\'') || p_url.at(0) == _t('\"'))
-				{
-					p_url.erase(0, 1);
-				}
-			}
-			if(!p_url.empty())
-			{
-				if(p_url.at(p_url.length() - 1) == _t('\'') || p_url.at(p_url.length() - 1) == _t('\"'))
-				{
-					p_url.erase(p_url.length() - 1, 1);
-				}
-			}
-			if(!p_url.empty())
-			{
-				element::ptr el = std::make_shared<el_image>(get_document());
-				el->set_attr(_t("src"), p_url.c_str());
-				el->set_attr(_t("style"), _t("display:inline-block"));
-				el->set_tagName(_t("img"));
-				appendChild(el);
-				el->parse_attributes();
-			}
-		}
-		break;
-	}
-}
-
-litehtml::tchar_t litehtml::el_before_after_base::convert_escape( const tchar_t* txt )
-{
-	tchar_t* sss = 0;
-	return (tchar_t) t_strtol(txt, &sss, 16);
-}
-
-void litehtml::el_before_after_base::apply_stylesheet( const litehtml::css& stylesheet )
-{
-
-}
+#include "html.h"
+#include "el_before_after.h"
+#include "el_text.h"
+#include "el_space.h"
+#include "el_image.h"
+
+litehtml::el_before_after_base::el_before_after_base(const std::shared_ptr<litehtml::document>& doc, bool before) : html_tag(doc)
+{
+	if(before)
+	{
+		set_tagName(_t("::before"));
+	} else
+	{
+		set_tagName(_t("::after"));
+	}
+}
+
+litehtml::el_before_after_base::~el_before_after_base()
+{
+
+}
+
+void litehtml::el_before_after_base::add_style(const litehtml::style& st)
+{
+	html_tag::add_style(st);
+
+	tstring content = get_style_property(_t("content"), false, _t(""));
+	if(!content.empty())
+	{
+		int idx = value_index(content.c_str(), content_property_string);
+		if(idx < 0)
+		{
+			tstring fnc;
+			tstring::size_type i = 0;
+			while(i < content.length() && i != tstring::npos)
+			{
+				if(content.at(i) == _t('"'))
+				{
+					fnc.clear();
+					i++;
+					tstring::size_type pos = content.find(_t('"'), i);
+					tstring txt;
+					if(pos == tstring::npos)
+					{
+						txt = content.substr(i);
+						i = tstring::npos;
+					} else
+					{
+						txt = content.substr(i, pos - i);
+						i = pos + 1;
+					}
+					add_text(txt);
+				} else if(content.at(i) == _t('('))
+				{
+					i++;
+					litehtml::trim(fnc);
+					litehtml::lcase(fnc);
+					tstring::size_type pos = content.find(_t(')'), i);
+					tstring params;
+					if(pos == tstring::npos)
+					{
+						params = content.substr(i);
+						i = tstring::npos;
+					} else
+					{
+						params = content.substr(i, pos - i);
+						i = pos + 1;
+					}
+					add_function(fnc, params);
+					fnc.clear();
+				} else
+				{
+					fnc += content.at(i);
+					i++;
+				}
+			}
+		}
+	}
+}
+
+void litehtml::el_before_after_base::add_text( const tstring& txt )
+{
+	tstring word;
+	tstring esc;
+	for(tstring::size_type i = 0; i < txt.length(); i++)
+	{
+		if( (txt.at(i) == _t(' ')) || (txt.at(i) == _t('\t')) || (txt.at(i) == _t('\\') && !esc.empty()) )
+		{
+			if(esc.empty())
+			{
+				if(!word.empty())
+				{
+					element::ptr el = std::make_shared<el_text>(word.c_str(), get_document());
+					appendChild(el);
+					word.clear();
+				}
+
+				element::ptr el = std::make_shared<el_space>(txt.substr(i, 1).c_str(), get_document());
+				appendChild(el);
+			} else
+			{
+				word += convert_escape(esc.c_str() + 1);
+				esc.clear();
+				if(txt.at(i) == _t('\\'))
+				{
+					esc += txt.at(i);
+				}
+			}
+		} else
+		{
+			if(!esc.empty() || txt.at(i) == _t('\\'))
+			{
+				esc += txt.at(i);
+			} else
+			{
+				word += txt.at(i);
+			}
+		}
+	}
+
+	if(!esc.empty())
+	{
+		word += convert_escape(esc.c_str() + 1);
+	}
+	if(!word.empty())
+	{
+		element::ptr el = std::make_shared<el_text>(word.c_str(), get_document());
+		appendChild(el);
+		word.clear();
+	}
+}
+
+void litehtml::el_before_after_base::add_function( const tstring& fnc, const tstring& params )
+{
+	int idx = value_index(fnc.c_str(), _t("attr;counter;url"));
+	switch(idx)
+	{
+	// attr
+	case 0:
+		{
+			tstring p_name = params;
+			trim(p_name);
+			lcase(p_name);
+			element::ptr el_parent = parent();
+			if (el_parent)
+			{
+				const tchar_t* attr_value = el_parent->get_attr(p_name.c_str());
+				if (attr_value)
+				{
+					add_text(attr_value);
+				}
+			}
+		}
+		break;
+	// counter
+	case 1:
+		break;
+	// url
+	case 2:
+		{
+			tstring p_url = params;
+			trim(p_url);
+			if(!p_url.empty())
+			{
+				if(p_url.at(0) == _t('\'') || p_url.at(0) == _t('\"'))
+				{
+					p_url.erase(0, 1);
+				}
+			}
+			if(!p_url.empty())
+			{
+				if(p_url.at(p_url.length() - 1) == _t('\'') || p_url.at(p_url.length() - 1) == _t('\"'))
+				{
+					p_url.erase(p_url.length() - 1, 1);
+				}
+			}
+			if(!p_url.empty())
+			{
+				element::ptr el = std::make_shared<el_image>(get_document());
+				el->set_attr(_t("src"), p_url.c_str());
+				el->set_attr(_t("style"), _t("display:inline-block"));
+				el->set_tagName(_t("img"));
+				appendChild(el);
+				el->parse_attributes();
+			}
+		}
+		break;
+	}
+}
+
+litehtml::tchar_t litehtml::el_before_after_base::convert_escape( const tchar_t* txt )
+{
+	tchar_t* sss = 0;
+	return (tchar_t) t_strtol(txt, &sss, 16);
+}
+
+void litehtml::el_before_after_base::apply_stylesheet( const litehtml::css& stylesheet )
+{
+
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_before_after.h b/src/plugins/litehtml_viewer/litehtml/el_before_after.h
index 5d0e9cb..1bb55f3 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_before_after.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_before_after.h
@@ -1,37 +1,41 @@
-#pragma once
-#include "html_tag.h"
-
-namespace litehtml
-{
-	class el_before_after_base : public html_tag
-	{
-	public:
-		el_before_after_base(const std::shared_ptr<litehtml::document>& doc, bool before);
-		virtual ~el_before_after_base();
-
-		virtual void add_style(const litehtml::style& st) override;
-		virtual void apply_stylesheet(const litehtml::css& stylesheet) override;
-	private:
-		void	add_text(const tstring& txt);
-		void	add_function(const tstring& fnc, const tstring& params);
-		tchar_t convert_escape(const tchar_t* txt);
-	};
-
-	class el_before : public el_before_after_base
-	{
-	public:
-		el_before(const std::shared_ptr<litehtml::document>& doc) : el_before_after_base(doc, true)
-		{
-
-		}
-	};
-
-	class el_after : public el_before_after_base
-	{
-	public:
-		el_after(const std::shared_ptr<litehtml::document>& doc) : el_before_after_base(doc, false)
-		{
-
-		}
-	};
-}
\ No newline at end of file
+#ifndef LH_EL_BEFORE_AFTER_H
+#define LH_EL_BEFORE_AFTER_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_before_after_base : public html_tag
+	{
+	public:
+		el_before_after_base(const std::shared_ptr<litehtml::document>& doc, bool before);
+		virtual ~el_before_after_base();
+
+		virtual void add_style(const litehtml::style& st) override;
+		virtual void apply_stylesheet(const litehtml::css& stylesheet) override;
+	private:
+		void	add_text(const tstring& txt);
+		void	add_function(const tstring& fnc, const tstring& params);
+		tchar_t convert_escape(const tchar_t* txt);
+	};
+
+	class el_before : public el_before_after_base
+	{
+	public:
+		el_before(const std::shared_ptr<litehtml::document>& doc) : el_before_after_base(doc, true)
+		{
+
+		}
+	};
+
+	class el_after : public el_before_after_base
+	{
+	public:
+		el_after(const std::shared_ptr<litehtml::document>& doc) : el_before_after_base(doc, false)
+		{
+
+		}
+	};
+}
+
+#endif  // LH_EL_BEFORE_AFTER_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_body.cpp b/src/plugins/litehtml_viewer/litehtml/el_body.cpp
index 7ada94b..61376d5 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_body.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_body.cpp
@@ -1,17 +1,17 @@
-#include "html.h"
-#include "el_body.h"
-#include "document.h"
-
-litehtml::el_body::el_body(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
-{
-}
-
-litehtml::el_body::~el_body()
-{
-
-}
-
-bool litehtml::el_body::is_body()  const
-{
-	return true;
-}
+#include "html.h"
+#include "el_body.h"
+#include "document.h"
+
+litehtml::el_body::el_body(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
+{
+}
+
+litehtml::el_body::~el_body()
+{
+
+}
+
+bool litehtml::el_body::is_body()  const
+{
+	return true;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_body.h b/src/plugins/litehtml_viewer/litehtml/el_body.h
index 2248bbc..d03d5df 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_body.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_body.h
@@ -1,14 +1,18 @@
-#pragma once
-#include "html_tag.h"
-
-namespace litehtml
-{
-	class el_body : public html_tag
-	{
-	public:
-		el_body(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_body();
-
-		virtual bool is_body() const override;
-	};
-}
\ No newline at end of file
+#ifndef LH_EL_BODY_H
+#define LH_EL_BODY_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_body : public html_tag
+	{
+	public:
+		el_body(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_body();
+
+		virtual bool is_body() const override;
+	};
+}
+
+#endif  // LH_EL_BODY_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_break.cpp b/src/plugins/litehtml_viewer/litehtml/el_break.cpp
index a798912..5523b41 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_break.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_break.cpp
@@ -1,18 +1,18 @@
-#include "html.h"
-#include "el_break.h"
-
-litehtml::el_break::el_break(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
-{
-
-}
-
-litehtml::el_break::~el_break()
-{
-
-}
-
-bool litehtml::el_break::is_break() const
-{
-	return true;
-}
-
+#include "html.h"
+#include "el_break.h"
+
+litehtml::el_break::el_break(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+
+}
+
+litehtml::el_break::~el_break()
+{
+
+}
+
+bool litehtml::el_break::is_break() const
+{
+	return true;
+}
+
diff --git a/src/plugins/litehtml_viewer/litehtml/el_break.h b/src/plugins/litehtml_viewer/litehtml/el_break.h
index dac1789..70fab32 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_break.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_break.h
@@ -1,14 +1,18 @@
-#pragma once
-#include "html_tag.h"
-
-namespace litehtml
-{
-	class el_break : public html_tag
-	{
-	public:
-		el_break(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_break();
-
-		virtual bool is_break() const override;
-	};
-}
+#ifndef LH_EL_BREAK_H
+#define LH_EL_BREAK_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_break : public html_tag
+	{
+	public:
+		el_break(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_break();
+
+		virtual bool is_break() const override;
+	};
+}
+
+#endif  // LH_EL_BREAK_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_cdata.cpp b/src/plugins/litehtml_viewer/litehtml/el_cdata.cpp
index 6e785d1..bb21eab 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_cdata.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_cdata.cpp
@@ -1,25 +1,25 @@
-#include "html.h"
-#include "el_cdata.h"
-
-litehtml::el_cdata::el_cdata(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
-{
-	m_skip = true;
-}
-
-litehtml::el_cdata::~el_cdata()
-{
-
-}
-
-void litehtml::el_cdata::get_text( tstring& text )
-{
-	text += m_text;
-}
-
-void litehtml::el_cdata::set_data( const tchar_t* data )
-{
-	if(data)
-	{
-		m_text += data;
-	}
-}
+#include "html.h"
+#include "el_cdata.h"
+
+litehtml::el_cdata::el_cdata(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
+{
+	m_skip = true;
+}
+
+litehtml::el_cdata::~el_cdata()
+{
+
+}
+
+void litehtml::el_cdata::get_text( tstring& text )
+{
+	text += m_text;
+}
+
+void litehtml::el_cdata::set_data( const tchar_t* data )
+{
+	if(data)
+	{
+		m_text += data;
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_cdata.h b/src/plugins/litehtml_viewer/litehtml/el_cdata.h
index e138f9d..33bdfe3 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_cdata.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_cdata.h
@@ -1,16 +1,20 @@
-#pragma once
-#include "html_tag.h"
-
-namespace litehtml
-{
-	class el_cdata : public element
-	{
-		tstring	m_text;
-	public:
-		el_cdata(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_cdata();
-
-		virtual void	get_text(tstring& text) override;
-		virtual void	set_data(const tchar_t* data) override;
-	};
-}
+#ifndef LH_EL_CDATA_H
+#define LH_EL_CDATA_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_cdata : public element
+	{
+		tstring	m_text;
+	public:
+		el_cdata(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_cdata();
+
+		virtual void	get_text(tstring& text) override;
+		virtual void	set_data(const tchar_t* data) override;
+	};
+}
+
+#endif  // LH_EL_CDATA_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_comment.cpp b/src/plugins/litehtml_viewer/litehtml/el_comment.cpp
index 3b46e2a..638c960 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_comment.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_comment.cpp
@@ -1,25 +1,25 @@
-#include "html.h"
-#include "el_comment.h"
-
-litehtml::el_comment::el_comment(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
-{
-	m_skip = true;
-}
-
-litehtml::el_comment::~el_comment()
-{
-
-}
-
-void litehtml::el_comment::get_text( tstring& text )
-{
-	text += m_text;
-}
-
-void litehtml::el_comment::set_data( const tchar_t* data )
-{
-	if(data)
-	{
-		m_text += data;
-	}
-}
+#include "html.h"
+#include "el_comment.h"
+
+litehtml::el_comment::el_comment(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
+{
+	m_skip = true;
+}
+
+litehtml::el_comment::~el_comment()
+{
+
+}
+
+void litehtml::el_comment::get_text( tstring& text )
+{
+	text += m_text;
+}
+
+void litehtml::el_comment::set_data( const tchar_t* data )
+{
+	if(data)
+	{
+		m_text += data;
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_comment.h b/src/plugins/litehtml_viewer/litehtml/el_comment.h
index 5b8459d..ceffd2c 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_comment.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_comment.h
@@ -1,16 +1,20 @@
-#pragma once
-#include "html_tag.h"
-
-namespace litehtml
-{
-	class el_comment : public element
-	{
-		tstring	m_text;
-	public:
-		el_comment(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_comment();
-
-		virtual void	get_text(tstring& text) override;
-		virtual void	set_data(const tchar_t* data) override;
-	};
-}
+#ifndef LH_EL_COMMENT_H
+#define LH_EL_COMMENT_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_comment : public element
+	{
+		tstring	m_text;
+	public:
+		el_comment(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_comment();
+
+		virtual void	get_text(tstring& text) override;
+		virtual void	set_data(const tchar_t* data) override;
+	};
+}
+
+#endif  // LH_EL_COMMENT_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_div.cpp b/src/plugins/litehtml_viewer/litehtml/el_div.cpp
index ec63963..c4ee3c0 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_div.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_div.cpp
@@ -1,23 +1,23 @@
-#include "html.h"
-#include "el_div.h"
-
-
-litehtml::el_div::el_div(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
-{
-
-}
-
-litehtml::el_div::~el_div()
-{
-
-}
-
-void litehtml::el_div::parse_attributes()
-{
-	const tchar_t* str = get_attr(_t("align"));
-	if(str)
-	{
-		m_style.add_property(_t("text-align"), str, 0, false);
-	}
-	html_tag::parse_attributes();
-}
+#include "html.h"
+#include "el_div.h"
+
+
+litehtml::el_div::el_div(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+
+}
+
+litehtml::el_div::~el_div()
+{
+
+}
+
+void litehtml::el_div::parse_attributes()
+{
+	const tchar_t* str = get_attr(_t("align"));
+	if(str)
+	{
+		m_style.add_property(_t("text-align"), str, 0, false);
+	}
+	html_tag::parse_attributes();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_div.h b/src/plugins/litehtml_viewer/litehtml/el_div.h
index 54eed84..ece762f 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_div.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_div.h
@@ -1,14 +1,18 @@
-#pragma once
-#include "html_tag.h"
-
-namespace litehtml
-{
-	class el_div : public html_tag
-	{
-	public:
-		el_div(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_div();
-
-		virtual void parse_attributes() override;
-	};
-}
\ No newline at end of file
+#ifndef LH_EL_DIV_H
+#define LH_EL_DIV_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_div : public html_tag
+	{
+	public:
+		el_div(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_div();
+
+		virtual void parse_attributes() override;
+	};
+}
+
+#endif  // LH_EL_DIV_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_font.cpp b/src/plugins/litehtml_viewer/litehtml/el_font.cpp
index cef9aae..da6bae9 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_font.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_font.cpp
@@ -1,60 +1,60 @@
-#include "html.h"
-#include "el_font.h"
-
-
-litehtml::el_font::el_font(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
-{
-
-}
-
-litehtml::el_font::~el_font()
-{
-
-}
-
-void litehtml::el_font::parse_attributes()
-{
-	const tchar_t* str = get_attr(_t("color"));
-	if(str)
-	{
-		m_style.add_property(_t("color"), str, 0, false);
-	}
-
-	str = get_attr(_t("face"));
-	if(str)
-	{
-		m_style.add_property(_t("font-face"), str, 0, false);
-	}
-
-	str = get_attr(_t("size"));
-	if(str)
-	{
-		int sz = t_atoi(str);
-		if(sz <= 1)
-		{
-			m_style.add_property(_t("font-size"), _t("x-small"), 0, false);
-		} else if(sz >= 6)
-		{
-			m_style.add_property(_t("font-size"), _t("xx-large"), 0, false);
-		} else
-		{
-			switch(sz)
-			{
-			case 2:
-				m_style.add_property(_t("font-size"), _t("small"), 0, false);
-				break;
-			case 3:
-				m_style.add_property(_t("font-size"), _t("medium"), 0, false);
-				break;
-			case 4:
-				m_style.add_property(_t("font-size"), _t("large"), 0, false);
-				break;
-			case 5:
-				m_style.add_property(_t("font-size"), _t("x-large"), 0, false);
-				break;
-			}
-		}
-	}
-
-	html_tag::parse_attributes();
-}
+#include "html.h"
+#include "el_font.h"
+
+
+litehtml::el_font::el_font(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+
+}
+
+litehtml::el_font::~el_font()
+{
+
+}
+
+void litehtml::el_font::parse_attributes()
+{
+	const tchar_t* str = get_attr(_t("color"));
+	if(str)
+	{
+		m_style.add_property(_t("color"), str, 0, false);
+	}
+
+	str = get_attr(_t("face"));
+	if(str)
+	{
+		m_style.add_property(_t("font-face"), str, 0, false);
+	}
+
+	str = get_attr(_t("size"));
+	if(str)
+	{
+		int sz = t_atoi(str);
+		if(sz <= 1)
+		{
+			m_style.add_property(_t("font-size"), _t("x-small"), 0, false);
+		} else if(sz >= 6)
+		{
+			m_style.add_property(_t("font-size"), _t("xx-large"), 0, false);
+		} else
+		{
+			switch(sz)
+			{
+			case 2:
+				m_style.add_property(_t("font-size"), _t("small"), 0, false);
+				break;
+			case 3:
+				m_style.add_property(_t("font-size"), _t("medium"), 0, false);
+				break;
+			case 4:
+				m_style.add_property(_t("font-size"), _t("large"), 0, false);
+				break;
+			case 5:
+				m_style.add_property(_t("font-size"), _t("x-large"), 0, false);
+				break;
+			}
+		}
+	}
+
+	html_tag::parse_attributes();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_font.h b/src/plugins/litehtml_viewer/litehtml/el_font.h
index 9d5e4a1..a0f391e 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_font.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_font.h
@@ -1,14 +1,18 @@
-#pragma once
-#include "html_tag.h"
-
-namespace litehtml
-{
-	class el_font : public html_tag
-	{
-	public:
-		el_font(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_font();
-
-		virtual void parse_attributes() override;
-	};
-}
\ No newline at end of file
+#ifndef LH_EL_FONT_H
+#define LH_EL_FONT_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_font : public html_tag
+	{
+	public:
+		el_font(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_font();
+
+		virtual void parse_attributes() override;
+	};
+}
+
+#endif  // LH_EL_FONT_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_image.cpp b/src/plugins/litehtml_viewer/litehtml/el_image.cpp
index 4d5486b..7de47a1 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_image.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_image.cpp
@@ -1,255 +1,255 @@
-#include "html.h"
-#include "el_image.h"
-#include "document.h"
-
-litehtml::el_image::el_image(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
-{
-	m_display = display_inline_block;
-}
-
-litehtml::el_image::~el_image( void )
-{
-
-}
-
-void litehtml::el_image::get_content_size( size& sz, int max_width )
-{
-	get_document()->container()->get_image_size(m_src.c_str(), 0, sz);
-}
-
-int litehtml::el_image::line_height() const
-{
-	return height();
-}
-
-bool litehtml::el_image::is_replaced() const
-{
-	return true;
-}
-
-int litehtml::el_image::render( int x, int y, int max_width, bool second_pass )
-{
-	int parent_width = max_width;
-
-	calc_outlines(parent_width);
-
-	m_pos.move_to(x, y);
-
-	document::ptr doc = get_document();
-
-	litehtml::size sz;
-	doc->container()->get_image_size(m_src.c_str(), 0, sz);
-
-	m_pos.width		= sz.width;
-	m_pos.height	= sz.height;
-
-	if(m_css_height.is_predefined() && m_css_width.is_predefined())
-	{
-		m_pos.height	= sz.height;
-		m_pos.width		= sz.width;
-
-		// check for max-height
-		if(!m_css_max_width.is_predefined())
-		{
-			int max_width = doc->cvt_units(m_css_max_width, m_font_size, parent_width);
-			if(m_pos.width > max_width)
-			{
-				m_pos.width = max_width;
-			}
-			if(sz.width)
-			{
-				m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width);
-			} else
-			{
-				m_pos.height = sz.height;
-			}
-		}
-
-		// check for max-height
-		if(!m_css_max_height.is_predefined())
-		{
-			int max_height = doc->cvt_units(m_css_max_height, m_font_size);
-			if(m_pos.height > max_height)
-			{
-				m_pos.height = max_height;
-			}
-			if(sz.height)
-			{
-				m_pos.width = (int) (m_pos.height * (float)sz.width / (float)sz.height);
-			} else
-			{
-				m_pos.width = sz.width;
-			}
-		}
-	} else if(!m_css_height.is_predefined() && m_css_width.is_predefined())
-	{
-		if (!get_predefined_height(m_pos.height))
-		{
-			m_pos.height = (int)m_css_height.val();
-		}
-
-		// check for max-height
-		if(!m_css_max_height.is_predefined())
-		{
-			int max_height = doc->cvt_units(m_css_max_height, m_font_size);
-			if(m_pos.height > max_height)
-			{
-				m_pos.height = max_height;
-			}
-		}
-
-		if(sz.height)
-		{
-			m_pos.width = (int) (m_pos.height * (float)sz.width / (float)sz.height);
-		} else
-		{
-			m_pos.width = sz.width;
-		}
-	} else if(m_css_height.is_predefined() && !m_css_width.is_predefined())
-	{
-		m_pos.width = (int) m_css_width.calc_percent(parent_width);
-
-		// check for max-width
-		if(!m_css_max_width.is_predefined())
-		{
-			int max_width = doc->cvt_units(m_css_max_width, m_font_size, parent_width);
-			if(m_pos.width > max_width)
-			{
-				m_pos.width = max_width;
-			}
-		}
-
-		if(sz.width)
-		{
-			m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width);
-		} else
-		{
-			m_pos.height = sz.height;
-		}
-	} else
-	{
-		m_pos.width		= (int) m_css_width.calc_percent(parent_width);
-		m_pos.height	= 0;
-		if (!get_predefined_height(m_pos.height))
-		{
-			m_pos.height = (int)m_css_height.val();
-		}
-
-		// check for max-height
-		if(!m_css_max_height.is_predefined())
-		{
-			int max_height = doc->cvt_units(m_css_max_height, m_font_size);
-			if(m_pos.height > max_height)
-			{
-				m_pos.height = max_height;
-			}
-		}
-
-		// check for max-height
-		if(!m_css_max_width.is_predefined())
-		{
-			int max_width = doc->cvt_units(m_css_max_width, m_font_size, parent_width);
-			if(m_pos.width > max_width)
-			{
-				m_pos.width = max_width;
-			}
-		}
-	}
-
-	calc_auto_margins(parent_width);
-
-	m_pos.x	+= content_margins_left();
-	m_pos.y += content_margins_top();
-
-	return m_pos.width + content_margins_left() + content_margins_right();
-}
-
-void litehtml::el_image::parse_attributes()
-{
-	m_src = get_attr(_t("src"), _t(""));
-
-	const tchar_t* attr_height = get_attr(_t("height"));
-	if(attr_height)
-	{
-		m_style.add_property(_t("height"), attr_height, 0, false);
-	}
-	const tchar_t* attr_width = get_attr(_t("width"));
-	if(attr_width)
-	{
-		m_style.add_property(_t("width"), attr_width, 0, false);
-	}
-}
-
-void litehtml::el_image::draw( uint_ptr hdc, int x, int y, const position* clip )
-{
-	position pos = m_pos;
-	pos.x += x;
-	pos.y += y;
-
-	position el_pos = pos;
-	el_pos += m_padding;
-	el_pos += m_borders;
-
-	// draw standard background here
-	if (el_pos.does_intersect(clip))
-	{
-		const background* bg = get_background();
-		if (bg)
-		{
-			background_paint bg_paint;
-			init_background_paint(pos, bg_paint, bg);
-
-			get_document()->container()->draw_background(hdc, bg_paint);
-		}
-	}
-
-	// draw image as background
-	if(pos.does_intersect(clip))
-	{
-		if (pos.width > 0 && pos.height > 0) {
-			background_paint bg;
-			bg.image				= m_src;
-			bg.clip_box				= pos;
-			bg.origin_box			= pos;
-			bg.border_box			= pos;
-			bg.border_box			+= m_padding;
-			bg.border_box			+= m_borders;
-			bg.repeat				= background_repeat_no_repeat;
-			bg.image_size.width		= pos.width;
-			bg.image_size.height	= pos.height;
-			bg.border_radius		= m_css_borders.radius.calc_percents(bg.border_box.width, bg.border_box.height);
-			bg.position_x			= pos.x;
-			bg.position_y			= pos.y;
-			get_document()->container()->draw_background(hdc, bg);
-		}
-	}
-
-	// draw borders
-	if (el_pos.does_intersect(clip))
-	{
-		position border_box = pos;
-		border_box += m_padding;
-		border_box += m_borders;
-
-		borders bdr = m_css_borders;
-		bdr.radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
-
-		get_document()->container()->draw_borders(hdc, bdr, border_box, have_parent() ? false : true);
-	}
-}
-
-void litehtml::el_image::parse_styles( bool is_reparse /*= false*/ )
-{
-	html_tag::parse_styles(is_reparse);
-
-	if(!m_src.empty())
-	{
-		if(!m_css_height.is_predefined() && !m_css_width.is_predefined())
-		{
-			get_document()->container()->load_image(m_src.c_str(), 0, true);
-		} else
-		{
-			get_document()->container()->load_image(m_src.c_str(), 0, false);
-		}
-	}
-}
+#include "html.h"
+#include "el_image.h"
+#include "document.h"
+
+litehtml::el_image::el_image(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+	m_display = display_inline_block;
+}
+
+litehtml::el_image::~el_image( void )
+{
+
+}
+
+void litehtml::el_image::get_content_size( size& sz, int max_width )
+{
+	get_document()->container()->get_image_size(m_src.c_str(), 0, sz);
+}
+
+int litehtml::el_image::line_height() const
+{
+	return height();
+}
+
+bool litehtml::el_image::is_replaced() const
+{
+	return true;
+}
+
+int litehtml::el_image::render( int x, int y, int max_width, bool second_pass )
+{
+	int parent_width = max_width;
+
+	calc_outlines(parent_width);
+
+	m_pos.move_to(x, y);
+
+	document::ptr doc = get_document();
+
+	litehtml::size sz;
+	doc->container()->get_image_size(m_src.c_str(), 0, sz);
+
+	m_pos.width		= sz.width;
+	m_pos.height	= sz.height;
+
+	if(m_css_height.is_predefined() && m_css_width.is_predefined())
+	{
+		m_pos.height	= sz.height;
+		m_pos.width		= sz.width;
+
+		// check for max-height
+		if(!m_css_max_width.is_predefined())
+		{
+			int max_width = doc->cvt_units(m_css_max_width, m_font_size, parent_width);
+			if(m_pos.width > max_width)
+			{
+				m_pos.width = max_width;
+			}
+			if(sz.width)
+			{
+				m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width);
+			} else
+			{
+				m_pos.height = sz.height;
+			}
+		}
+
+		// check for max-height
+		if(!m_css_max_height.is_predefined())
+		{
+			int max_height = doc->cvt_units(m_css_max_height, m_font_size);
+			if(m_pos.height > max_height)
+			{
+				m_pos.height = max_height;
+			}
+			if(sz.height)
+			{
+				m_pos.width = (int) (m_pos.height * (float)sz.width / (float)sz.height);
+			} else
+			{
+				m_pos.width = sz.width;
+			}
+		}
+	} else if(!m_css_height.is_predefined() && m_css_width.is_predefined())
+	{
+		if (!get_predefined_height(m_pos.height))
+		{
+			m_pos.height = (int)m_css_height.val();
+		}
+
+		// check for max-height
+		if(!m_css_max_height.is_predefined())
+		{
+			int max_height = doc->cvt_units(m_css_max_height, m_font_size);
+			if(m_pos.height > max_height)
+			{
+				m_pos.height = max_height;
+			}
+		}
+
+		if(sz.height)
+		{
+			m_pos.width = (int) (m_pos.height * (float)sz.width / (float)sz.height);
+		} else
+		{
+			m_pos.width = sz.width;
+		}
+	} else if(m_css_height.is_predefined() && !m_css_width.is_predefined())
+	{
+		m_pos.width = (int) m_css_width.calc_percent(parent_width);
+
+		// check for max-width
+		if(!m_css_max_width.is_predefined())
+		{
+			int max_width = doc->cvt_units(m_css_max_width, m_font_size, parent_width);
+			if(m_pos.width > max_width)
+			{
+				m_pos.width = max_width;
+			}
+		}
+
+		if(sz.width)
+		{
+			m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width);
+		} else
+		{
+			m_pos.height = sz.height;
+		}
+	} else
+	{
+		m_pos.width		= (int) m_css_width.calc_percent(parent_width);
+		m_pos.height	= 0;
+		if (!get_predefined_height(m_pos.height))
+		{
+			m_pos.height = (int)m_css_height.val();
+		}
+
+		// check for max-height
+		if(!m_css_max_height.is_predefined())
+		{
+			int max_height = doc->cvt_units(m_css_max_height, m_font_size);
+			if(m_pos.height > max_height)
+			{
+				m_pos.height = max_height;
+			}
+		}
+
+		// check for max-height
+		if(!m_css_max_width.is_predefined())
+		{
+			int max_width = doc->cvt_units(m_css_max_width, m_font_size, parent_width);
+			if(m_pos.width > max_width)
+			{
+				m_pos.width = max_width;
+			}
+		}
+	}
+
+	calc_auto_margins(parent_width);
+
+	m_pos.x	+= content_margins_left();
+	m_pos.y += content_margins_top();
+
+	return m_pos.width + content_margins_left() + content_margins_right();
+}
+
+void litehtml::el_image::parse_attributes()
+{
+	m_src = get_attr(_t("src"), _t(""));
+
+	const tchar_t* attr_height = get_attr(_t("height"));
+	if(attr_height)
+	{
+		m_style.add_property(_t("height"), attr_height, 0, false);
+	}
+	const tchar_t* attr_width = get_attr(_t("width"));
+	if(attr_width)
+	{
+		m_style.add_property(_t("width"), attr_width, 0, false);
+	}
+}
+
+void litehtml::el_image::draw( uint_ptr hdc, int x, int y, const position* clip )
+{
+	position pos = m_pos;
+	pos.x += x;
+	pos.y += y;
+
+	position el_pos = pos;
+	el_pos += m_padding;
+	el_pos += m_borders;
+
+	// draw standard background here
+	if (el_pos.does_intersect(clip))
+	{
+		const background* bg = get_background();
+		if (bg)
+		{
+			background_paint bg_paint;
+			init_background_paint(pos, bg_paint, bg);
+
+			get_document()->container()->draw_background(hdc, bg_paint);
+		}
+	}
+
+	// draw image as background
+	if(pos.does_intersect(clip))
+	{
+		if (pos.width > 0 && pos.height > 0) {
+			background_paint bg;
+			bg.image				= m_src;
+			bg.clip_box				= pos;
+			bg.origin_box			= pos;
+			bg.border_box			= pos;
+			bg.border_box			+= m_padding;
+			bg.border_box			+= m_borders;
+			bg.repeat				= background_repeat_no_repeat;
+			bg.image_size.width		= pos.width;
+			bg.image_size.height	= pos.height;
+			bg.border_radius		= m_css_borders.radius.calc_percents(bg.border_box.width, bg.border_box.height);
+			bg.position_x			= pos.x;
+			bg.position_y			= pos.y;
+			get_document()->container()->draw_background(hdc, bg);
+		}
+	}
+
+	// draw borders
+	if (el_pos.does_intersect(clip))
+	{
+		position border_box = pos;
+		border_box += m_padding;
+		border_box += m_borders;
+
+		borders bdr = m_css_borders;
+		bdr.radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
+
+		get_document()->container()->draw_borders(hdc, bdr, border_box, have_parent() ? false : true);
+	}
+}
+
+void litehtml::el_image::parse_styles( bool is_reparse /*= false*/ )
+{
+	html_tag::parse_styles(is_reparse);
+
+	if(!m_src.empty())
+	{
+		if(!m_css_height.is_predefined() && !m_css_width.is_predefined())
+		{
+			get_document()->container()->load_image(m_src.c_str(), 0, true);
+		} else
+		{
+			get_document()->container()->load_image(m_src.c_str(), 0, false);
+		}
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_image.h b/src/plugins/litehtml_viewer/litehtml/el_image.h
index 670aa66..377ddf8 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_image.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_image.h
@@ -1,23 +1,26 @@
-#pragma once
-
-#include "html_tag.h"
-
-namespace litehtml
-{
-
-	class el_image : public html_tag
-	{
-		tstring	m_src;
-	public:
-		el_image(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_image(void);
-
-		virtual int		line_height() const override;
-		virtual bool	is_replaced() const override;
-		virtual int		render(int x, int y, int max_width, bool second_pass = false) override;
-		virtual void	parse_attributes() override;
-		virtual void	parse_styles(bool is_reparse = false) override;
-		virtual void	draw(uint_ptr hdc, int x, int y, const position* clip) override;
-		virtual void	get_content_size(size& sz, int max_width) override;
-	};
-}
+#ifndef LH_EL_IMAGE_H
+#define LH_EL_IMAGE_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+
+	class el_image : public html_tag
+	{
+		tstring	m_src;
+	public:
+		el_image(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_image(void);
+
+		virtual int		line_height() const override;
+		virtual bool	is_replaced() const override;
+		virtual int		render(int x, int y, int max_width, bool second_pass = false) override;
+		virtual void	parse_attributes() override;
+		virtual void	parse_styles(bool is_reparse = false) override;
+		virtual void	draw(uint_ptr hdc, int x, int y, const position* clip) override;
+		virtual void	get_content_size(size& sz, int max_width) override;
+	};
+}
+
+#endif  // LH_EL_IMAGE_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_link.cpp b/src/plugins/litehtml_viewer/litehtml/el_link.cpp
index 709c399..01561ab 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_link.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_link.cpp
@@ -1,44 +1,44 @@
-#include "html.h"
-#include "el_link.h"
-#include "document.h"
-
-
-litehtml::el_link::el_link(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
-{
-
-}
-
-litehtml::el_link::~el_link()
-{
-
-}
-
-void litehtml::el_link::parse_attributes()
-{
-	bool processed = false;
-
-	document::ptr doc = get_document();
-
-	const tchar_t* rel = get_attr(_t("rel"));
-	if(rel && !t_strcmp(rel, _t("stylesheet")))
-	{
-		const tchar_t* media	= get_attr(_t("media"));
-		const tchar_t* href		= get_attr(_t("href"));
-		if(href && href[0])
-		{
-			tstring css_text;
-			tstring css_baseurl;
-			doc->container()->import_css(css_text, href, css_baseurl);
-			if(!css_text.empty())
-			{
-				doc->add_stylesheet(css_text.c_str(), css_baseurl.c_str(), media);
-				processed = true;
-			}
-		}
-	}
-
-	if(!processed)
-	{
-		doc->container()->link(doc, shared_from_this());
-	}
-}
+#include "html.h"
+#include "el_link.h"
+#include "document.h"
+
+
+litehtml::el_link::el_link(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
+{
+
+}
+
+litehtml::el_link::~el_link()
+{
+
+}
+
+void litehtml::el_link::parse_attributes()
+{
+	bool processed = false;
+
+	document::ptr doc = get_document();
+
+	const tchar_t* rel = get_attr(_t("rel"));
+	if(rel && !t_strcmp(rel, _t("stylesheet")))
+	{
+		const tchar_t* media	= get_attr(_t("media"));
+		const tchar_t* href		= get_attr(_t("href"));
+		if(href && href[0])
+		{
+			tstring css_text;
+			tstring css_baseurl;
+			doc->container()->import_css(css_text, href, css_baseurl);
+			if(!css_text.empty())
+			{
+				doc->add_stylesheet(css_text.c_str(), css_baseurl.c_str(), media);
+				processed = true;
+			}
+		}
+	}
+
+	if(!processed)
+	{
+		doc->container()->link(doc, shared_from_this());
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_link.h b/src/plugins/litehtml_viewer/litehtml/el_link.h
index ef94fb1..6795760 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_link.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_link.h
@@ -1,15 +1,19 @@
-#pragma once
-#include "html_tag.h"
-
-namespace litehtml
-{
-	class el_link : public html_tag
-	{
-	public:
-		el_link(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_link();
-
-	protected:
-		virtual void	parse_attributes() override;
-	};
-}
+#ifndef LH_EL_LINK_H
+#define LH_EL_LINK_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_link : public html_tag
+	{
+	public:
+		el_link(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_link();
+
+	protected:
+		virtual void	parse_attributes() override;
+	};
+}
+
+#endif  // LH_EL_LINK_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_para.cpp b/src/plugins/litehtml_viewer/litehtml/el_para.cpp
index f38baa1..0986e5c 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_para.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_para.cpp
@@ -1,23 +1,23 @@
-#include "html.h"
-#include "el_para.h"
-#include "document.h"
-
-litehtml::el_para::el_para(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
-{
-}
-
-litehtml::el_para::~el_para()
-{
-
-}
-
-void litehtml::el_para::parse_attributes()
-{
-	const tchar_t* str = get_attr(_t("align"));
-	if(str)
-	{
-		m_style.add_property(_t("text-align"), str, 0, false);
-	}
-
-	html_tag::parse_attributes();
-}
+#include "html.h"
+#include "el_para.h"
+#include "document.h"
+
+litehtml::el_para::el_para(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
+{
+}
+
+litehtml::el_para::~el_para()
+{
+
+}
+
+void litehtml::el_para::parse_attributes()
+{
+	const tchar_t* str = get_attr(_t("align"));
+	if(str)
+	{
+		m_style.add_property(_t("text-align"), str, 0, false);
+	}
+
+	html_tag::parse_attributes();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_para.h b/src/plugins/litehtml_viewer/litehtml/el_para.h
index cee990e..82e964b 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_para.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_para.h
@@ -1,15 +1,19 @@
-#pragma once
-#include "html_tag.h"
-
-namespace litehtml
-{
-	class el_para : public html_tag
-	{
-	public:
-		el_para(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_para();
-
-		virtual void	parse_attributes() override;
-
-	};
-}
\ No newline at end of file
+#ifndef LH_EL_PARA_H
+#define LH_EL_PARA_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_para : public html_tag
+	{
+	public:
+		el_para(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_para();
+
+		virtual void	parse_attributes() override;
+
+	};
+}
+
+#endif  // LH_EL_PARA_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_script.cpp b/src/plugins/litehtml_viewer/litehtml/el_script.cpp
index 312c794..603a46d 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_script.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_script.cpp
@@ -1,30 +1,30 @@
-#include "html.h"
-#include "el_script.h"
-#include "document.h"
-
-
-litehtml::el_script::el_script(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
-{
-
-}
-
-litehtml::el_script::~el_script()
-{
-
-}
-
-void litehtml::el_script::parse_attributes()
-{
-	//TODO: pass script text to document container
-}
-
-bool litehtml::el_script::appendChild(const ptr &el)
-{
-	el->get_text(m_text);
-	return true;
-}
-
-const litehtml::tchar_t* litehtml::el_script::get_tagName() const
-{
-	return _t("script");
-}
+#include "html.h"
+#include "el_script.h"
+#include "document.h"
+
+
+litehtml::el_script::el_script(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
+{
+
+}
+
+litehtml::el_script::~el_script()
+{
+
+}
+
+void litehtml::el_script::parse_attributes()
+{
+	//TODO: pass script text to document container
+}
+
+bool litehtml::el_script::appendChild(const ptr &el)
+{
+	el->get_text(m_text);
+	return true;
+}
+
+const litehtml::tchar_t* litehtml::el_script::get_tagName() const
+{
+	return _t("script");
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_script.h b/src/plugins/litehtml_viewer/litehtml/el_script.h
index 7c4c372..b8fed36 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_script.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_script.h
@@ -1,17 +1,21 @@
-#pragma once
-#include "html_tag.h"
-
-namespace litehtml
-{
-	class el_script : public element
-	{
-		tstring m_text;
-	public:
-		el_script(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_script();
-
-		virtual void			parse_attributes() override;
-		virtual bool			appendChild(const ptr &el) override;
-		virtual const tchar_t*	get_tagName() const override;
-	};
-}
+#ifndef LH_EL_SCRIPT_H
+#define LH_EL_SCRIPT_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_script : public element
+	{
+		tstring m_text;
+	public:
+		el_script(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_script();
+
+		virtual void			parse_attributes() override;
+		virtual bool			appendChild(const ptr &el) override;
+		virtual const tchar_t*	get_tagName() const override;
+	};
+}
+
+#endif  // LH_EL_SCRIPT_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_space.cpp b/src/plugins/litehtml_viewer/litehtml/el_space.cpp
index 7114121..5178255 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_space.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_space.cpp
@@ -1,39 +1,39 @@
-#include "html.h"
-#include "document.h"
-#include "el_space.h"
-
-litehtml::el_space::el_space(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc) : el_text(text, doc)
-{
-}
-
-litehtml::el_space::~el_space()
-{
-
-}
-
-bool litehtml::el_space::is_white_space() const
-{
-	white_space ws = get_white_space();
-	if(	ws == white_space_normal || 
-		ws == white_space_nowrap ||
-		ws == white_space_pre_line )
-	{
-		return true;
-	}
-	return false;
-}
-
-bool litehtml::el_space::is_break() const
-{
-	white_space ws = get_white_space();
-	if(	ws == white_space_pre ||
-		ws == white_space_pre_line ||
-		ws == white_space_pre_wrap)
-	{
-		if(m_text == _t("\n"))
-		{
-			return true;
-		}
-	}
-	return false;
-}
+#include "html.h"
+#include "document.h"
+#include "el_space.h"
+
+litehtml::el_space::el_space(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc) : el_text(text, doc)
+{
+}
+
+litehtml::el_space::~el_space()
+{
+
+}
+
+bool litehtml::el_space::is_white_space() const
+{
+	white_space ws = get_white_space();
+	if(	ws == white_space_normal || 
+		ws == white_space_nowrap ||
+		ws == white_space_pre_line )
+	{
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::el_space::is_break() const
+{
+	white_space ws = get_white_space();
+	if(	ws == white_space_pre ||
+		ws == white_space_pre_line ||
+		ws == white_space_pre_wrap)
+	{
+		if(m_text == _t("\n"))
+		{
+			return true;
+		}
+	}
+	return false;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_space.h b/src/plugins/litehtml_viewer/litehtml/el_space.h
index 7fd9ef1..35ce885 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_space.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_space.h
@@ -1,16 +1,20 @@
-#pragma once
-#include "html_tag.h"
-#include "el_text.h"
-
-namespace litehtml
-{
-	class el_space : public el_text
-	{
-	public:
-		el_space(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_space();
-
-		virtual bool	is_white_space() const override;
-		virtual bool	is_break() const override;
-	};
-}
\ No newline at end of file
+#ifndef LH_EL_SPACE_H
+#define LH_EL_SPACE_H
+
+#include "html_tag.h"
+#include "el_text.h"
+
+namespace litehtml
+{
+	class el_space : public el_text
+	{
+	public:
+		el_space(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_space();
+
+		virtual bool	is_white_space() const override;
+		virtual bool	is_break() const override;
+	};
+}
+
+#endif  // LH_EL_SPACE_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_style.cpp b/src/plugins/litehtml_viewer/litehtml/el_style.cpp
index 26a640f..1b1bb0e 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_style.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_style.cpp
@@ -1,36 +1,36 @@
-#include "html.h"
-#include "el_style.h"
-#include "document.h"
-
-
-litehtml::el_style::el_style(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
-{
-
-}
-
-litehtml::el_style::~el_style()
-{
-
-}
-
-void litehtml::el_style::parse_attributes()
-{
-	tstring text;
-
-	for(auto& el : m_children)
-	{
-		el->get_text(text);
-	}
-	get_document()->add_stylesheet( text.c_str(), 0, get_attr(_t("media")) );
-}
-
-bool litehtml::el_style::appendChild(const ptr &el)
-{
-	m_children.push_back(el);
-	return true;
-}
-
-const litehtml::tchar_t* litehtml::el_style::get_tagName() const
-{
-	return _t("style");
-}
+#include "html.h"
+#include "el_style.h"
+#include "document.h"
+
+
+litehtml::el_style::el_style(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
+{
+
+}
+
+litehtml::el_style::~el_style()
+{
+
+}
+
+void litehtml::el_style::parse_attributes()
+{
+	tstring text;
+
+	for(auto& el : m_children)
+	{
+		el->get_text(text);
+	}
+	get_document()->add_stylesheet( text.c_str(), 0, get_attr(_t("media")) );
+}
+
+bool litehtml::el_style::appendChild(const ptr &el)
+{
+	m_children.push_back(el);
+	return true;
+}
+
+const litehtml::tchar_t* litehtml::el_style::get_tagName() const
+{
+	return _t("style");
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_style.h b/src/plugins/litehtml_viewer/litehtml/el_style.h
index 3f7b41d..8407b4b 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_style.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_style.h
@@ -1,17 +1,21 @@
-#pragma once
-#include "html_tag.h"
-
-namespace litehtml
-{
-	class el_style : public element
-	{
-		elements_vector		m_children;
-	public:
-		el_style(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_style();
-
-		virtual void			parse_attributes() override;
-		virtual bool			appendChild(const ptr &el) override;
-		virtual const tchar_t*	get_tagName() const override;
-	};
-}
+#ifndef LH_EL_STYLE_H
+#define LH_EL_STYLE_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_style : public element
+	{
+		elements_vector		m_children;
+	public:
+		el_style(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_style();
+
+		virtual void			parse_attributes() override;
+		virtual bool			appendChild(const ptr &el) override;
+		virtual const tchar_t*	get_tagName() const override;
+	};
+}
+
+#endif  // LH_EL_STYLE_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_table.cpp b/src/plugins/litehtml_viewer/litehtml/el_table.cpp
index 4f5ff75..06d77be 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_table.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_table.cpp
@@ -1,108 +1,108 @@
-#include "html.h"
-#include "el_table.h"
-#include "document.h"
-#include "iterators.h"
-#include <algorithm>
-
-
-litehtml::el_table::el_table(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
-{
-	m_border_spacing_x	= 0;
-	m_border_spacing_y	= 0;
-	m_border_collapse	= border_collapse_separate;
-}
-
-
-litehtml::el_table::~el_table()
-{
-
-}
-
-bool litehtml::el_table::appendChild(const litehtml::element::ptr& el)
-{
-	if(!el)	return false;
-	if(!t_strcmp(el->get_tagName(), _t("tbody")) || !t_strcmp(el->get_tagName(), _t("thead")) || !t_strcmp(el->get_tagName(), _t("tfoot")))
-	{
-		return html_tag::appendChild(el);
-	}
-	return false;
-}
-
-void litehtml::el_table::parse_styles(bool is_reparse)
-{
-	html_tag::parse_styles(is_reparse);
-
-	m_border_collapse = (border_collapse) value_index(get_style_property(_t("border-collapse"), true, _t("separate")), border_collapse_strings, border_collapse_separate);
-
-	if(m_border_collapse == border_collapse_separate)
-	{
-		m_css_border_spacing_x.fromString(get_style_property(_t("-litehtml-border-spacing-x"), true, _t("0px")));
-		m_css_border_spacing_y.fromString(get_style_property(_t("-litehtml-border-spacing-y"), true, _t("0px")));
-
-		int fntsz = get_font_size();
-		document::ptr doc = get_document();
-		m_border_spacing_x = doc->cvt_units(m_css_border_spacing_x, fntsz);
-		m_border_spacing_y = doc->cvt_units(m_css_border_spacing_y, fntsz);
-	} else
-	{
-		m_border_spacing_x	= 0;
-		m_border_spacing_y	= 0;
-		m_padding.bottom	= 0;
-		m_padding.top		= 0;
-		m_padding.left		= 0;
-		m_padding.right		= 0;
-		m_css_padding.bottom.set_value(0, css_units_px);
-		m_css_padding.top.set_value(0, css_units_px);
-		m_css_padding.left.set_value(0, css_units_px);
-		m_css_padding.right.set_value(0, css_units_px);
-	}
-}
-
-void litehtml::el_table::parse_attributes()
-{
-	const tchar_t* str = get_attr(_t("width"));
-	if(str)
-	{
-		m_style.add_property(_t("width"), str, 0, false);
-	}
-
-	str = get_attr(_t("align"));
-	if(str)
-	{
-		int align = value_index(str, _t("left;center;right"));
-		switch(align)
-		{
-		case 1:
-			m_style.add_property(_t("margin-left"), _t("auto"), 0, false);
-			m_style.add_property(_t("margin-right"), _t("auto"), 0, false);
-			break;
-		case 2:
-			m_style.add_property(_t("margin-left"), _t("auto"), 0, false);
-			m_style.add_property(_t("margin-right"), _t("0"), 0, false);
-			break;
-		}
-	}
-
-	str = get_attr(_t("cellspacing"));
-	if(str)
-	{
-		tstring val = str;
-		val += _t(" ");
-		val += str;
-		m_style.add_property(_t("border-spacing"), val.c_str(), 0, false);
-	}
-	
-	str = get_attr(_t("border"));
-	if(str)
-	{
-		m_style.add_property(_t("border-width"), str, 0, false);
-	}
-
-	str = get_attr(_t("bgcolor"));
-	if (str)
-	{
-		m_style.add_property(_t("background-color"), str, 0, false);
-	}
-
-	html_tag::parse_attributes();
-}
+#include "html.h"
+#include "el_table.h"
+#include "document.h"
+#include "iterators.h"
+#include <algorithm>
+
+
+litehtml::el_table::el_table(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+	m_border_spacing_x	= 0;
+	m_border_spacing_y	= 0;
+	m_border_collapse	= border_collapse_separate;
+}
+
+
+litehtml::el_table::~el_table()
+{
+
+}
+
+bool litehtml::el_table::appendChild(const litehtml::element::ptr& el)
+{
+	if(!el)	return false;
+	if(!t_strcmp(el->get_tagName(), _t("tbody")) || !t_strcmp(el->get_tagName(), _t("thead")) || !t_strcmp(el->get_tagName(), _t("tfoot")))
+	{
+		return html_tag::appendChild(el);
+	}
+	return false;
+}
+
+void litehtml::el_table::parse_styles(bool is_reparse)
+{
+	html_tag::parse_styles(is_reparse);
+
+	m_border_collapse = (border_collapse) value_index(get_style_property(_t("border-collapse"), true, _t("separate")), border_collapse_strings, border_collapse_separate);
+
+	if(m_border_collapse == border_collapse_separate)
+	{
+		m_css_border_spacing_x.fromString(get_style_property(_t("-litehtml-border-spacing-x"), true, _t("0px")));
+		m_css_border_spacing_y.fromString(get_style_property(_t("-litehtml-border-spacing-y"), true, _t("0px")));
+
+		int fntsz = get_font_size();
+		document::ptr doc = get_document();
+		m_border_spacing_x = doc->cvt_units(m_css_border_spacing_x, fntsz);
+		m_border_spacing_y = doc->cvt_units(m_css_border_spacing_y, fntsz);
+	} else
+	{
+		m_border_spacing_x	= 0;
+		m_border_spacing_y	= 0;
+		m_padding.bottom	= 0;
+		m_padding.top		= 0;
+		m_padding.left		= 0;
+		m_padding.right		= 0;
+		m_css_padding.bottom.set_value(0, css_units_px);
+		m_css_padding.top.set_value(0, css_units_px);
+		m_css_padding.left.set_value(0, css_units_px);
+		m_css_padding.right.set_value(0, css_units_px);
+	}
+}
+
+void litehtml::el_table::parse_attributes()
+{
+	const tchar_t* str = get_attr(_t("width"));
+	if(str)
+	{
+		m_style.add_property(_t("width"), str, 0, false);
+	}
+
+	str = get_attr(_t("align"));
+	if(str)
+	{
+		int align = value_index(str, _t("left;center;right"));
+		switch(align)
+		{
+		case 1:
+			m_style.add_property(_t("margin-left"), _t("auto"), 0, false);
+			m_style.add_property(_t("margin-right"), _t("auto"), 0, false);
+			break;
+		case 2:
+			m_style.add_property(_t("margin-left"), _t("auto"), 0, false);
+			m_style.add_property(_t("margin-right"), _t("0"), 0, false);
+			break;
+		}
+	}
+
+	str = get_attr(_t("cellspacing"));
+	if(str)
+	{
+		tstring val = str;
+		val += _t(" ");
+		val += str;
+		m_style.add_property(_t("border-spacing"), val.c_str(), 0, false);
+	}
+	
+	str = get_attr(_t("border"));
+	if(str)
+	{
+		m_style.add_property(_t("border-width"), str, 0, false);
+	}
+
+	str = get_attr(_t("bgcolor"));
+	if (str)
+	{
+		m_style.add_property(_t("background-color"), str, 0, false);
+	}
+
+	html_tag::parse_attributes();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_table.h b/src/plugins/litehtml_viewer/litehtml/el_table.h
index b298526..f1ef973 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_table.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_table.h
@@ -1,23 +1,27 @@
-#pragma once
-#include "html_tag.h"
-
-namespace litehtml
-{
-	struct col_info
-	{
-		int		width;
-		bool	is_auto;
-	};
-
-
-	class el_table : public html_tag
-	{
-	public:
-		el_table(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_table();
-
-		virtual bool	appendChild(const litehtml::element::ptr& el) override;
-		virtual void	parse_styles(bool is_reparse = false) override;
-		virtual void	parse_attributes() override;
-	};
-}
\ No newline at end of file
+#ifndef LH_EL_TABLE_H
+#define LH_EL_TABLE_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	struct col_info
+	{
+		int		width;
+		bool	is_auto;
+	};
+
+
+	class el_table : public html_tag
+	{
+	public:
+		el_table(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_table();
+
+		virtual bool	appendChild(const litehtml::element::ptr& el) override;
+		virtual void	parse_styles(bool is_reparse = false) override;
+		virtual void	parse_attributes() override;
+	};
+}
+
+#endif  // LH_EL_TABLE_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_td.cpp b/src/plugins/litehtml_viewer/litehtml/el_td.cpp
index f32cbcd..ca21440 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_td.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_td.cpp
@@ -1,49 +1,49 @@
-#include "html.h"
-#include "el_td.h"
-
-
-litehtml::el_td::el_td(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
-{
-
-}
-
-litehtml::el_td::~el_td()
-{
-
-}
-
-void litehtml::el_td::parse_attributes()
-{
-	const tchar_t* str = get_attr(_t("width"));
-	if(str)
-	{
-		m_style.add_property(_t("width"), str, 0, false);
-	}
-	str = get_attr(_t("background"));
-	if(str)
-	{
-		tstring url = _t("url('");
-		url += str;
-		url += _t("')");
-		m_style.add_property(_t("background-image"), url.c_str(), 0, false);
-	}
-	str = get_attr(_t("align"));
-	if(str)
-	{
-		m_style.add_property(_t("text-align"), str, 0, false);
-	}
-
-	str = get_attr(_t("bgcolor"));
-	if (str)
-	{
-		m_style.add_property(_t("background-color"), str, 0, false);
-	}
-
-	str = get_attr(_t("valign"));
-	if(str)
-	{
-		m_style.add_property(_t("vertical-align"), str, 0, false);
-	}
-	html_tag::parse_attributes();
-}
-
+#include "html.h"
+#include "el_td.h"
+
+
+litehtml::el_td::el_td(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+
+}
+
+litehtml::el_td::~el_td()
+{
+
+}
+
+void litehtml::el_td::parse_attributes()
+{
+	const tchar_t* str = get_attr(_t("width"));
+	if(str)
+	{
+		m_style.add_property(_t("width"), str, 0, false);
+	}
+	str = get_attr(_t("background"));
+	if(str)
+	{
+		tstring url = _t("url('");
+		url += str;
+		url += _t("')");
+		m_style.add_property(_t("background-image"), url.c_str(), 0, false);
+	}
+	str = get_attr(_t("align"));
+	if(str)
+	{
+		m_style.add_property(_t("text-align"), str, 0, false);
+	}
+
+	str = get_attr(_t("bgcolor"));
+	if (str)
+	{
+		m_style.add_property(_t("background-color"), str, 0, false);
+	}
+
+	str = get_attr(_t("valign"));
+	if(str)
+	{
+		m_style.add_property(_t("vertical-align"), str, 0, false);
+	}
+	html_tag::parse_attributes();
+}
+
diff --git a/src/plugins/litehtml_viewer/litehtml/el_td.h b/src/plugins/litehtml_viewer/litehtml/el_td.h
index 88d8d68..5dce950 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_td.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_td.h
@@ -1,14 +1,18 @@
-#pragma once
-#include "html_tag.h"
-
-namespace litehtml
-{
-	class el_td : public html_tag
-	{
-	public:
-		el_td(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_td();
-
-		virtual void parse_attributes() override;
-	};
-}
\ No newline at end of file
+#ifndef LH_EL_TD_H
+#define LH_EL_TD_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_td : public html_tag
+	{
+	public:
+		el_td(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_td();
+
+		virtual void parse_attributes() override;
+	};
+}
+
+#endif  // LH_EL_TD_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_text.cpp b/src/plugins/litehtml_viewer/litehtml/el_text.cpp
index f29e2aa..9fad2a4 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_text.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_text.cpp
@@ -1,188 +1,188 @@
-#include "html.h"
-#include "el_text.h"
-#include "document.h"
-
-litehtml::el_text::el_text(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc) : element(doc)
-{
-	if(text)
-	{
-		m_text = text;
-	}
-	m_text_transform	= text_transform_none;
-	m_use_transformed	= false;
-	m_draw_spaces		= true;
-}
-
-litehtml::el_text::~el_text()
-{
-
-}
-
-void litehtml::el_text::get_content_size( size& sz, int max_width )
-{
-	sz = m_size;
-}
-
-void litehtml::el_text::get_text( tstring& text )
-{
-	text += m_text;
-}
-
-const litehtml::tchar_t* litehtml::el_text::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ )
-{
-	if(inherited)
-	{
-		element::ptr el_parent = parent();
-		if (el_parent)
-		{
-			return el_parent->get_style_property(name, inherited, def);
-		}
-	}
-	return def;
-}
-
-void litehtml::el_text::parse_styles(bool is_reparse)
-{
-	m_text_transform	= (text_transform)	value_index(get_style_property(_t("text-transform"), true,	_t("none")),	text_transform_strings,	text_transform_none);
-	if(m_text_transform != text_transform_none)
-	{
-		m_transformed_text	= m_text;
-		m_use_transformed = true;
-		get_document()->container()->transform_text(m_transformed_text, m_text_transform);
-	}
-
-	if(is_white_space())
-	{
-		m_transformed_text = _t(" ");
-		m_use_transformed = true;
-	} else
-	{
-		if(m_text == _t("\t"))
-		{
-			m_transformed_text = _t("    ");
-			m_use_transformed = true;
-		}
-		if(m_text == _t("\n") || m_text == _t("\r"))
-		{
-			m_transformed_text = _t("");
-			m_use_transformed = true;
-		}
-	}
-
-	font_metrics fm;
-	uint_ptr font = 0;
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		font = el_parent->get_font(&fm);
-	}
-	if(is_break())
-	{
-		m_size.height	= 0;
-		m_size.width	= 0;
-	} else
-	{
-		m_size.height	= fm.height;
-		m_size.width	= get_document()->container()->text_width(m_use_transformed ? m_transformed_text.c_str() : m_text.c_str(), font);
-	}
-	m_draw_spaces = fm.draw_spaces;
-}
-
-int litehtml::el_text::get_base_line()
-{
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		return el_parent->get_base_line();
-	}
-	return 0;
-}
-
-void litehtml::el_text::draw( uint_ptr hdc, int x, int y, const position* clip )
-{
-	if(is_white_space() && !m_draw_spaces)
-	{
-		return;
-	}
-
-	position pos = m_pos;
-	pos.x	+= x;
-	pos.y	+= y;
-
-	if(pos.does_intersect(clip))
-	{
-		element::ptr el_parent = parent();
-		if (el_parent)
-		{
-			document::ptr doc = get_document();
-
-			uint_ptr font = el_parent->get_font();
-			litehtml::web_color color = el_parent->get_color(_t("color"), true, doc->get_def_color());
-			doc->container()->draw_text(hdc, m_use_transformed ? m_transformed_text.c_str() : m_text.c_str(), font, color, pos);
-		}
-	}
-}
-
-int litehtml::el_text::line_height() const
-{
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		return el_parent->line_height();
-	}
-	return 0;
-}
-
-litehtml::uint_ptr litehtml::el_text::get_font( font_metrics* fm /*= 0*/ )
-{
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		return el_parent->get_font(fm);
-	}
-	return 0;
-}
-
-litehtml::style_display litehtml::el_text::get_display() const
-{
-	return display_inline_text;
-}
-
-litehtml::white_space litehtml::el_text::get_white_space() const
-{
-	element::ptr el_parent = parent();
-	if (el_parent) return el_parent->get_white_space();
-	return white_space_normal;
-}
-
-litehtml::element_position litehtml::el_text::get_element_position(css_offsets* offsets) const
-{
-	element::ptr p = parent();
-	while(p && p->get_display() == display_inline)
-	{
-		if(p->get_element_position() == element_position_relative)
-		{
-			if(offsets)
-			{
-				*offsets = p->get_css_offsets();
-			}
-			return element_position_relative;
-		}
-		p = p->parent();
-	}
-	return element_position_static;
-}
-
-litehtml::css_offsets litehtml::el_text::get_css_offsets() const
-{
-	element::ptr p = parent();
-	while(p && p->get_display() == display_inline)
-	{
-		if(p->get_element_position() == element_position_relative)
-		{
-			return p->get_css_offsets();
-		}
-		p = p->parent();
-	}
-	return css_offsets();
-}
+#include "html.h"
+#include "el_text.h"
+#include "document.h"
+
+litehtml::el_text::el_text(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc) : element(doc)
+{
+	if(text)
+	{
+		m_text = text;
+	}
+	m_text_transform	= text_transform_none;
+	m_use_transformed	= false;
+	m_draw_spaces		= true;
+}
+
+litehtml::el_text::~el_text()
+{
+
+}
+
+void litehtml::el_text::get_content_size( size& sz, int max_width )
+{
+	sz = m_size;
+}
+
+void litehtml::el_text::get_text( tstring& text )
+{
+	text += m_text;
+}
+
+const litehtml::tchar_t* litehtml::el_text::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ )
+{
+	if(inherited)
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			return el_parent->get_style_property(name, inherited, def);
+		}
+	}
+	return def;
+}
+
+void litehtml::el_text::parse_styles(bool is_reparse)
+{
+	m_text_transform	= (text_transform)	value_index(get_style_property(_t("text-transform"), true,	_t("none")),	text_transform_strings,	text_transform_none);
+	if(m_text_transform != text_transform_none)
+	{
+		m_transformed_text	= m_text;
+		m_use_transformed = true;
+		get_document()->container()->transform_text(m_transformed_text, m_text_transform);
+	}
+
+	if(is_white_space())
+	{
+		m_transformed_text = _t(" ");
+		m_use_transformed = true;
+	} else
+	{
+		if(m_text == _t("\t"))
+		{
+			m_transformed_text = _t("    ");
+			m_use_transformed = true;
+		}
+		if(m_text == _t("\n") || m_text == _t("\r"))
+		{
+			m_transformed_text = _t("");
+			m_use_transformed = true;
+		}
+	}
+
+	font_metrics fm;
+	uint_ptr font = 0;
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		font = el_parent->get_font(&fm);
+	}
+	if(is_break())
+	{
+		m_size.height	= 0;
+		m_size.width	= 0;
+	} else
+	{
+		m_size.height	= fm.height;
+		m_size.width	= get_document()->container()->text_width(m_use_transformed ? m_transformed_text.c_str() : m_text.c_str(), font);
+	}
+	m_draw_spaces = fm.draw_spaces;
+}
+
+int litehtml::el_text::get_base_line()
+{
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		return el_parent->get_base_line();
+	}
+	return 0;
+}
+
+void litehtml::el_text::draw( uint_ptr hdc, int x, int y, const position* clip )
+{
+	if(is_white_space() && !m_draw_spaces)
+	{
+		return;
+	}
+
+	position pos = m_pos;
+	pos.x	+= x;
+	pos.y	+= y;
+
+	if(pos.does_intersect(clip))
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			document::ptr doc = get_document();
+
+			uint_ptr font = el_parent->get_font();
+			litehtml::web_color color = el_parent->get_color(_t("color"), true, doc->get_def_color());
+			doc->container()->draw_text(hdc, m_use_transformed ? m_transformed_text.c_str() : m_text.c_str(), font, color, pos);
+		}
+	}
+}
+
+int litehtml::el_text::line_height() const
+{
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		return el_parent->line_height();
+	}
+	return 0;
+}
+
+litehtml::uint_ptr litehtml::el_text::get_font( font_metrics* fm /*= 0*/ )
+{
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		return el_parent->get_font(fm);
+	}
+	return 0;
+}
+
+litehtml::style_display litehtml::el_text::get_display() const
+{
+	return display_inline_text;
+}
+
+litehtml::white_space litehtml::el_text::get_white_space() const
+{
+	element::ptr el_parent = parent();
+	if (el_parent) return el_parent->get_white_space();
+	return white_space_normal;
+}
+
+litehtml::element_position litehtml::el_text::get_element_position(css_offsets* offsets) const
+{
+	element::ptr p = parent();
+	while(p && p->get_display() == display_inline)
+	{
+		if(p->get_element_position() == element_position_relative)
+		{
+			if(offsets)
+			{
+				*offsets = p->get_css_offsets();
+			}
+			return element_position_relative;
+		}
+		p = p->parent();
+	}
+	return element_position_static;
+}
+
+litehtml::css_offsets litehtml::el_text::get_css_offsets() const
+{
+	element::ptr p = parent();
+	while(p && p->get_display() == display_inline)
+	{
+		if(p->get_element_position() == element_position_relative)
+		{
+			return p->get_css_offsets();
+		}
+		p = p->parent();
+	}
+	return css_offsets();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_text.h b/src/plugins/litehtml_viewer/litehtml/el_text.h
index 82c42bc..d2149de 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_text.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_text.h
@@ -1,35 +1,38 @@
-#pragma once
-
-#include "html_tag.h"
-
-namespace litehtml
-{
-	class el_text : public element
-	{
-	protected:
-		tstring			m_text;
-		tstring			m_transformed_text;
-		size			m_size;
-		text_transform	m_text_transform;
-		bool			m_use_transformed;
-		bool			m_draw_spaces;
-	public:
-		el_text(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_text();
-
-		virtual void				get_text(tstring& text) override;
-		virtual const tchar_t*		get_style_property(const tchar_t* name, bool inherited, const tchar_t* def = 0) override;
-		virtual void				parse_styles(bool is_reparse) override;
-		virtual int					get_base_line() override;
-		virtual void				draw(uint_ptr hdc, int x, int y, const position* clip) override;
-		virtual int					line_height() const override;
-		virtual uint_ptr			get_font(font_metrics* fm = 0) override;
-		virtual style_display		get_display() const override;
-		virtual white_space			get_white_space() const override;
-		virtual element_position	get_element_position(css_offsets* offsets = 0) const override;
-		virtual css_offsets			get_css_offsets() const override;
-
-	protected:
-		virtual void				get_content_size(size& sz, int max_width) override;
-	};
-}
\ No newline at end of file
+#ifndef LH_EL_TEXT_H
+#define LH_EL_TEXT_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_text : public element
+	{
+	protected:
+		tstring			m_text;
+		tstring			m_transformed_text;
+		size			m_size;
+		text_transform	m_text_transform;
+		bool			m_use_transformed;
+		bool			m_draw_spaces;
+	public:
+		el_text(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_text();
+
+		virtual void				get_text(tstring& text) override;
+		virtual const tchar_t*		get_style_property(const tchar_t* name, bool inherited, const tchar_t* def = 0) override;
+		virtual void				parse_styles(bool is_reparse) override;
+		virtual int					get_base_line() override;
+		virtual void				draw(uint_ptr hdc, int x, int y, const position* clip) override;
+		virtual int					line_height() const override;
+		virtual uint_ptr			get_font(font_metrics* fm = 0) override;
+		virtual style_display		get_display() const override;
+		virtual white_space			get_white_space() const override;
+		virtual element_position	get_element_position(css_offsets* offsets = 0) const override;
+		virtual css_offsets			get_css_offsets() const override;
+
+	protected:
+		virtual void				get_content_size(size& sz, int max_width) override;
+	};
+}
+
+#endif  // LH_EL_TEXT_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_title.cpp b/src/plugins/litehtml_viewer/litehtml/el_title.cpp
index 399421f..7a9590d 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_title.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_title.cpp
@@ -1,20 +1,20 @@
-#include "html.h"
-#include "el_title.h"
-#include "document.h"
-
-litehtml::el_title::el_title(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
-{
-
-}
-
-litehtml::el_title::~el_title()
-{
-
-}
-
-void litehtml::el_title::parse_attributes()
-{
-	tstring text;
-	get_text(text);
-	get_document()->container()->set_caption(text.c_str());
-}
+#include "html.h"
+#include "el_title.h"
+#include "document.h"
+
+litehtml::el_title::el_title(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
+{
+
+}
+
+litehtml::el_title::~el_title()
+{
+
+}
+
+void litehtml::el_title::parse_attributes()
+{
+	tstring text;
+	get_text(text);
+	get_document()->container()->set_caption(text.c_str());
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_title.h b/src/plugins/litehtml_viewer/litehtml/el_title.h
index b1c7139..20dc8cd 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_title.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_title.h
@@ -1,15 +1,19 @@
-#pragma once
-#include "html_tag.h"
-
-namespace litehtml
-{
-	class el_title : public html_tag
-	{
-	public:
-		el_title(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_title();
-
-	protected:
-		virtual void	parse_attributes() override;
-	};
-}
+#ifndef LH_EL_TITLE_H
+#define LH_EL_TITLE_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_title : public html_tag
+	{
+	public:
+		el_title(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_title();
+
+	protected:
+		virtual void	parse_attributes() override;
+	};
+}
+
+#endif  // LH_EL_TITLE_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_tr.cpp b/src/plugins/litehtml_viewer/litehtml/el_tr.cpp
index a80dde4..0ef0675 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_tr.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_tr.cpp
@@ -1,51 +1,51 @@
-#include "html.h"
-#include "el_tr.h"
-
-
-litehtml::el_tr::el_tr(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
-{
-
-}
-
-litehtml::el_tr::~el_tr()
-{
-
-}
-
-void litehtml::el_tr::parse_attributes()
-{
-	const tchar_t* str = get_attr(_t("align"));
-	if(str)
-	{
-		m_style.add_property(_t("text-align"), str, 0, false);
-	}
-	str = get_attr(_t("valign"));
-	if(str)
-	{
-		m_style.add_property(_t("vertical-align"), str, 0, false);
-	}
-	str = get_attr(_t("bgcolor"));
-	if (str)
-	{
-		m_style.add_property(_t("background-color"), str, 0, false);
-	}
-	html_tag::parse_attributes();
-}
-
-void litehtml::el_tr::get_inline_boxes( position::vector& boxes )
-{
-	position pos;
-	for(auto& el : m_children)
-	{
-		if(el->get_display() == display_table_cell)
-		{
-			pos.x		= el->left() + el->margin_left();
-			pos.y		= el->top() - m_padding.top - m_borders.top;
-
-			pos.width	= el->right() - pos.x - el->margin_right() - el->margin_left();
-			pos.height	= el->height() + m_padding.top + m_padding.bottom + m_borders.top + m_borders.bottom;
-
-			boxes.push_back(pos);
-		}
-	}
-}
+#include "html.h"
+#include "el_tr.h"
+
+
+litehtml::el_tr::el_tr(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+
+}
+
+litehtml::el_tr::~el_tr()
+{
+
+}
+
+void litehtml::el_tr::parse_attributes()
+{
+	const tchar_t* str = get_attr(_t("align"));
+	if(str)
+	{
+		m_style.add_property(_t("text-align"), str, 0, false);
+	}
+	str = get_attr(_t("valign"));
+	if(str)
+	{
+		m_style.add_property(_t("vertical-align"), str, 0, false);
+	}
+	str = get_attr(_t("bgcolor"));
+	if (str)
+	{
+		m_style.add_property(_t("background-color"), str, 0, false);
+	}
+	html_tag::parse_attributes();
+}
+
+void litehtml::el_tr::get_inline_boxes( position::vector& boxes )
+{
+	position pos;
+	for(auto& el : m_children)
+	{
+		if(el->get_display() == display_table_cell)
+		{
+			pos.x		= el->left() + el->margin_left();
+			pos.y		= el->top() - m_padding.top - m_borders.top;
+
+			pos.width	= el->right() - pos.x - el->margin_right() - el->margin_left();
+			pos.height	= el->height() + m_padding.top + m_padding.bottom + m_borders.top + m_borders.bottom;
+
+			boxes.push_back(pos);
+		}
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_tr.h b/src/plugins/litehtml_viewer/litehtml/el_tr.h
index f4e50aa..0fbb6c2 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_tr.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_tr.h
@@ -1,15 +1,19 @@
-#pragma once
-#include "html_tag.h"
-
-namespace litehtml
-{
-	class el_tr : public html_tag
-	{
-	public:
-		el_tr(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_tr();
-
-		virtual void	parse_attributes() override;
-		virtual void	get_inline_boxes(position::vector& boxes) override;
-	};
-}
\ No newline at end of file
+#ifndef LH_EL_TR_H
+#define LH_EL_TR_H
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_tr : public html_tag
+	{
+	public:
+		el_tr(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_tr();
+
+		virtual void	parse_attributes() override;
+		virtual void	get_inline_boxes(position::vector& boxes) override;
+	};
+}
+
+#endif  // LH_EL_TR_H
diff --git a/src/plugins/litehtml_viewer/litehtml/element.cpp b/src/plugins/litehtml_viewer/litehtml/element.cpp
index 41a69e7..9055cc1 100644
--- a/src/plugins/litehtml_viewer/litehtml/element.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/element.cpp
@@ -1,409 +1,409 @@
-#include "html.h"
-#include "element.h"
-#include "document.h"
-
-#define LITEHTML_EMPTY_FUNC			{}
-#define LITEHTML_RETURN_FUNC(ret)	{return ret;}
-
-litehtml::element::element(const std::shared_ptr<litehtml::document>& doc) : m_doc(doc)
-{
-	m_box		= 0;
-	m_skip		= false;
-}
-
-litehtml::element::~element()
-{
-
-}
-
-
-bool litehtml::element::is_point_inside( int x, int y )
-{
-	if(get_display() != display_inline && get_display() != display_table_row)
-	{
-		position pos = m_pos;
-		pos += m_padding;
-		pos += m_borders;
-		if(pos.is_point_inside(x, y))
-		{
-			return true;
-		} else
-		{
-			return false;
-		}
-	} else
-	{
-		position::vector boxes;
-		get_inline_boxes(boxes);
-		for(position::vector::iterator box = boxes.begin(); box != boxes.end(); box++)
-		{
-			if(box->is_point_inside(x, y))
-			{
-				return true;
-			}
-		}
-	}
-	return false;
-}
-
-litehtml::web_color litehtml::element::get_color( const tchar_t* prop_name, bool inherited, const litehtml::web_color& def_color )
-{
-	const tchar_t* clrstr = get_style_property(prop_name, inherited, 0);
-	if(!clrstr)
-	{
-		return def_color;
-	}
-	return web_color::from_string(clrstr);
-}
-
-litehtml::position litehtml::element::get_placement() const
-{
-	litehtml::position pos = m_pos;
-	element::ptr cur_el = parent();
-	while(cur_el)
-	{
-		pos.x += cur_el->m_pos.x;
-		pos.y += cur_el->m_pos.y;
-		cur_el = cur_el->parent();
-	}
-	return pos;
-}
-
-bool litehtml::element::is_inline_box() const
-{
-	style_display d = get_display();
-	if(	d == display_inline || 
-		d == display_inline_block || 
-		d == display_inline_text)
-	{
-		return true;
-	}
-	return false;
-}
-
-bool litehtml::element::collapse_top_margin() const
-{
-	if(!m_borders.top && !m_padding.top && in_normal_flow() && get_float() == float_none && m_margins.top >= 0 && have_parent())
-	{
-		return true;
-	}
-	return false;
-}
-
-bool litehtml::element::collapse_bottom_margin() const
-{
-	if(!m_borders.bottom && !m_padding.bottom && in_normal_flow() && get_float() == float_none && m_margins.bottom >= 0 && have_parent())
-	{
-		return true;
-	}
-	return false;
-}
-
-bool litehtml::element::get_predefined_height(int& p_height) const
-{
-	css_length h = get_css_height();
-	if(h.is_predefined())
-	{
-		p_height = m_pos.height;
-		return false;
-	}
-	if(h.units() == css_units_percentage)
-	{
-		element::ptr el_parent = parent();
-		if (!el_parent)
-		{
-			position client_pos;
-			get_document()->container()->get_client_rect(client_pos);
-			p_height = h.calc_percent(client_pos.height);
-			return true;
-		} else
-		{
-			int ph = 0;
-			if (el_parent->get_predefined_height(ph))
-			{
-				p_height = h.calc_percent(ph);
-				if (is_body())
-				{
-					p_height -= content_margins_height();
-				}
-				return true;
-			} else
-			{
-				p_height = m_pos.height;
-				return false;
-			}
-		}
-	}
-	p_height = get_document()->cvt_units(h, get_font_size());
-	return true;
-}
-
-void litehtml::element::calc_document_size( litehtml::size& sz, int x /*= 0*/, int y /*= 0*/ )
-{
-	if(is_visible())
-	{
-		sz.width	= std::max(sz.width,	x + right());
-		sz.height	= std::max(sz.height,	y + bottom());
-	}
-}
-
-void litehtml::element::get_redraw_box(litehtml::position& pos, int x /*= 0*/, int y /*= 0*/)
-{
-	if(is_visible())
-	{
-		int p_left		= std::min(pos.left(),	x + m_pos.left() - m_padding.left - m_borders.left);
-		int p_right		= std::max(pos.right(), x + m_pos.right() + m_padding.left + m_borders.left);
-		int p_top		= std::min(pos.top(), y + m_pos.top() - m_padding.top - m_borders.top);
-		int p_bottom	= std::max(pos.bottom(), y + m_pos.bottom() + m_padding.bottom + m_borders.bottom);
-
-		pos.x = p_left;
-		pos.y = p_top;
-		pos.width	= p_right - p_left;
-		pos.height	= p_bottom - p_top;
-	}
-}
-
-int litehtml::element::calc_width(int defVal) const
-{
-	css_length w = get_css_width();
-	if(w.is_predefined())
-	{
-		return defVal;
-	}
-	if(w.units() == css_units_percentage)
-	{
-		element::ptr el_parent = parent();
-		if (!el_parent)
-		{
-			position client_pos;
-			get_document()->container()->get_client_rect(client_pos);
-			return w.calc_percent(client_pos.width);
-		} else
-		{
-			int pw = el_parent->calc_width(defVal);
-			if (is_body())
-			{
-				pw -= content_margins_width();
-			}
-			return w.calc_percent(pw);
-		}
-	}
-	return 	get_document()->cvt_units(w, get_font_size());
-}
-
-bool litehtml::element::is_ancestor(const ptr &el) const
-{
-	element::ptr el_parent = parent();
-	while(el_parent && el_parent != el)
-	{
-		el_parent = el_parent->parent();
-	}
-	if(el_parent)
-	{
-		return true;
-	}
-	return false;
-}
-
-int litehtml::element::get_inline_shift_left()
-{
-	int ret = 0;
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		if (el_parent->get_display() == display_inline)
-		{
-			style_display disp = get_display();
-
-			if (disp == display_inline_text || disp == display_inline_block)
-			{
-				element::ptr el = shared_from_this();
-				while (el_parent && el_parent->get_display() == display_inline)
-				{
-					if (el_parent->is_first_child_inline(el))
-					{
-						ret += el_parent->padding_left() + el_parent->border_left() + el_parent->margin_left();
-					}
-					el = el_parent;
-					el_parent = el_parent->parent();
-				}
-			}
-		}
-	}
-
-	return ret;
-}
-
-int litehtml::element::get_inline_shift_right()
-{
-	int ret = 0;
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		if (el_parent->get_display() == display_inline)
-		{
-			style_display disp = get_display();
-
-			if (disp == display_inline_text || disp == display_inline_block)
-			{
-				element::ptr el = shared_from_this();
-				while (el_parent && el_parent->get_display() == display_inline)
-				{
-					if (el_parent->is_last_child_inline(el))
-					{
-						ret += el_parent->padding_right() + el_parent->border_right() + el_parent->margin_right();
-					}
-					el = el_parent;
-					el_parent = el_parent->parent();
-				}
-			}
-		}
-	}
-
-	return ret;
-}
-
-void litehtml::element::apply_relative_shift(int parent_width)
-{
-	css_offsets offsets;
-	if (get_element_position(&offsets) == element_position_relative)
-	{
-		element::ptr parent_ptr = parent();
-		if (!offsets.left.is_predefined())
-		{
-			m_pos.x += offsets.left.calc_percent(parent_width);
-		}
-		else if (!offsets.right.is_predefined())
-		{
-			m_pos.x -= offsets.right.calc_percent(parent_width);
-		}
-		if (!offsets.top.is_predefined())
-		{
-			int h = 0;
-
-			if (offsets.top.units() == css_units_percentage)
-			{
-				element::ptr el_parent = parent();
-				if (el_parent)
-				{
-					el_parent->get_predefined_height(h);
-				}
-			}
-
-			m_pos.y += offsets.top.calc_percent(h);
-		}
-		else if (!offsets.bottom.is_predefined())
-		{
-			int h = 0;
-
-			if (offsets.top.units() == css_units_percentage)
-			{
-				element::ptr el_parent = parent();
-				if (el_parent)
-				{
-					el_parent->get_predefined_height(h);
-				}
-			}
-
-			m_pos.y -= offsets.bottom.calc_percent(h);
-		}
-	}
-}
-
-void litehtml::element::calc_auto_margins(int parent_width)							LITEHTML_EMPTY_FUNC
-const litehtml::background* litehtml::element::get_background(bool own_only)		LITEHTML_RETURN_FUNC(0)
-litehtml::element::ptr litehtml::element::get_element_by_point(int x, int y, int client_x, int client_y)	LITEHTML_RETURN_FUNC(0)
-litehtml::element::ptr litehtml::element::get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex) LITEHTML_RETURN_FUNC(0)
-void litehtml::element::get_line_left_right( int y, int def_right, int& ln_left, int& ln_right ) LITEHTML_EMPTY_FUNC
-void litehtml::element::add_style( const litehtml::style& st )						LITEHTML_EMPTY_FUNC
-void litehtml::element::select_all(const css_selector& selector, litehtml::elements_vector& res)	LITEHTML_EMPTY_FUNC
-litehtml::elements_vector litehtml::element::select_all(const litehtml::css_selector& selector)	 LITEHTML_RETURN_FUNC(litehtml::elements_vector())
-litehtml::elements_vector litehtml::element::select_all(const litehtml::tstring& selector)			 LITEHTML_RETURN_FUNC(litehtml::elements_vector())
-litehtml::element::ptr litehtml::element::select_one( const css_selector& selector ) LITEHTML_RETURN_FUNC(0)
-litehtml::element::ptr litehtml::element::select_one( const tstring& selector )		LITEHTML_RETURN_FUNC(0)
-litehtml::element::ptr litehtml::element::find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/) LITEHTML_RETURN_FUNC(0)
-litehtml::element::ptr litehtml::element::find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/) LITEHTML_RETURN_FUNC(0)
-bool litehtml::element::is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const		LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::is_nth_child(const element::ptr&, int num, int off, bool of_type) const		LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::is_only_child(const element::ptr& el, bool of_type)	 const	LITEHTML_RETURN_FUNC(false)
-litehtml::overflow litehtml::element::get_overflow() const							LITEHTML_RETURN_FUNC(overflow_visible)
-void litehtml::element::draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex ) LITEHTML_EMPTY_FUNC
-void litehtml::element::draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned ) LITEHTML_EMPTY_FUNC
-void litehtml::element::render_positioned(render_type rt)							LITEHTML_EMPTY_FUNC
-int litehtml::element::get_zindex() const											LITEHTML_RETURN_FUNC(0)
-bool litehtml::element::fetch_positioned()											LITEHTML_RETURN_FUNC(false)
-litehtml::visibility litehtml::element::get_visibility() const						LITEHTML_RETURN_FUNC(visibility_visible)
-void litehtml::element::apply_vertical_align()										LITEHTML_EMPTY_FUNC
-void litehtml::element::set_css_width( css_length& w )								LITEHTML_EMPTY_FUNC
-litehtml::element::ptr litehtml::element::get_child( int idx ) const				LITEHTML_RETURN_FUNC(0)
-size_t litehtml::element::get_children_count() const								LITEHTML_RETURN_FUNC(0)
-void litehtml::element::calc_outlines( int parent_width )							LITEHTML_EMPTY_FUNC
-litehtml::css_length litehtml::element::get_css_width() const						LITEHTML_RETURN_FUNC(css_length())
-litehtml::css_length litehtml::element::get_css_height() const						LITEHTML_RETURN_FUNC(css_length())
-litehtml::element_clear litehtml::element::get_clear() const						LITEHTML_RETURN_FUNC(clear_none)
-litehtml::css_length litehtml::element::get_css_left() const						LITEHTML_RETURN_FUNC(css_length())
-litehtml::css_length litehtml::element::get_css_right() const						LITEHTML_RETURN_FUNC(css_length())
-litehtml::css_length litehtml::element::get_css_top() const							LITEHTML_RETURN_FUNC(css_length())
-litehtml::css_length litehtml::element::get_css_bottom() const						LITEHTML_RETURN_FUNC(css_length())
-litehtml::css_offsets litehtml::element::get_css_offsets() const					LITEHTML_RETURN_FUNC(css_offsets())
-litehtml::vertical_align litehtml::element::get_vertical_align() const				LITEHTML_RETURN_FUNC(va_baseline)
-int litehtml::element::place_element(const ptr &el, int max_width)					LITEHTML_RETURN_FUNC(0)
-int litehtml::element::render_inline(const ptr &container, int max_width)			LITEHTML_RETURN_FUNC(0)
-void litehtml::element::add_positioned(const ptr &el)							LITEHTML_EMPTY_FUNC
-int litehtml::element::find_next_line_top( int top, int width, int def_right )		LITEHTML_RETURN_FUNC(0)
-litehtml::element_float litehtml::element::get_float() const						LITEHTML_RETURN_FUNC(float_none)
-void litehtml::element::add_float(const ptr &el, int x, int y)					LITEHTML_EMPTY_FUNC
-void litehtml::element::update_floats(int dy, const ptr &parent)					LITEHTML_EMPTY_FUNC
-int litehtml::element::get_line_left( int y )										LITEHTML_RETURN_FUNC(0)
-int litehtml::element::get_line_right( int y, int def_right )						LITEHTML_RETURN_FUNC(def_right)
-int litehtml::element::get_left_floats_height() const								LITEHTML_RETURN_FUNC(0)
-int litehtml::element::get_right_floats_height() const								LITEHTML_RETURN_FUNC(0)
-int litehtml::element::get_floats_height(element_float el_float) const				LITEHTML_RETURN_FUNC(0)
-bool litehtml::element::is_floats_holder() const									LITEHTML_RETURN_FUNC(false)
-void litehtml::element::get_content_size( size& sz, int max_width )					LITEHTML_EMPTY_FUNC
-void litehtml::element::init()														LITEHTML_EMPTY_FUNC
-int litehtml::element::render( int x, int y, int max_width, bool second_pass )		LITEHTML_RETURN_FUNC(0)
-bool litehtml::element::appendChild(const ptr &el)						LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::removeChild(const ptr &el)						LITEHTML_RETURN_FUNC(false)
-void litehtml::element::clearRecursive()											LITEHTML_EMPTY_FUNC
-const litehtml::tchar_t* litehtml::element::get_tagName() const						LITEHTML_RETURN_FUNC(_t(""))
-void litehtml::element::set_tagName( const tchar_t* tag )							LITEHTML_EMPTY_FUNC
-void litehtml::element::set_data( const tchar_t* data )								LITEHTML_EMPTY_FUNC
-void litehtml::element::set_attr( const tchar_t* name, const tchar_t* val )			LITEHTML_EMPTY_FUNC
-void litehtml::element::apply_stylesheet( const litehtml::css& stylesheet )			LITEHTML_EMPTY_FUNC
-void litehtml::element::refresh_styles()											LITEHTML_EMPTY_FUNC
-void litehtml::element::on_click()													LITEHTML_EMPTY_FUNC
-void litehtml::element::init_font()													LITEHTML_EMPTY_FUNC
-void litehtml::element::get_inline_boxes( position::vector& boxes )					LITEHTML_EMPTY_FUNC
-void litehtml::element::parse_styles( bool is_reparse /*= false*/ )					LITEHTML_EMPTY_FUNC
-const litehtml::tchar_t* litehtml::element::get_attr( const tchar_t* name, const tchar_t* def /*= 0*/ )	LITEHTML_RETURN_FUNC(def)
-bool litehtml::element::is_white_space() const										LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::is_body() const												LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::is_break() const											LITEHTML_RETURN_FUNC(false)
-int litehtml::element::get_base_line()												LITEHTML_RETURN_FUNC(0)
-bool litehtml::element::on_mouse_over()												LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::on_mouse_leave()											LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::on_lbutton_down()											LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::on_lbutton_up()												LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::find_styles_changes( position::vector& redraw_boxes, int x, int y )	LITEHTML_RETURN_FUNC(false)
-const litehtml::tchar_t* litehtml::element::get_cursor()							LITEHTML_RETURN_FUNC(0)
-litehtml::white_space litehtml::element::get_white_space() const					LITEHTML_RETURN_FUNC(white_space_normal)
-litehtml::style_display litehtml::element::get_display() const						LITEHTML_RETURN_FUNC(display_none)
-bool litehtml::element::set_pseudo_class( const tchar_t* pclass, bool add )			LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::set_class( const tchar_t* pclass, bool add )				LITEHTML_RETURN_FUNC(false)
-litehtml::element_position litehtml::element::get_element_position(css_offsets* offsets) const			LITEHTML_RETURN_FUNC(element_position_static)
-bool litehtml::element::is_replaced() const											LITEHTML_RETURN_FUNC(false)
-int litehtml::element::line_height() const											LITEHTML_RETURN_FUNC(0)
-void litehtml::element::draw( uint_ptr hdc, int x, int y, const position* clip )	LITEHTML_EMPTY_FUNC
-void litehtml::element::draw_background( uint_ptr hdc, int x, int y, const position* clip )	LITEHTML_EMPTY_FUNC
-const litehtml::tchar_t* litehtml::element::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ )	LITEHTML_RETURN_FUNC(0)
-litehtml::uint_ptr litehtml::element::get_font( font_metrics* fm /*= 0*/ )			LITEHTML_RETURN_FUNC(0)
-int litehtml::element::get_font_size()	const										LITEHTML_RETURN_FUNC(0)
-void litehtml::element::get_text( tstring& text )									LITEHTML_EMPTY_FUNC
-void litehtml::element::parse_attributes()											LITEHTML_EMPTY_FUNC
-int litehtml::element::select( const css_selector& selector, bool apply_pseudo)		LITEHTML_RETURN_FUNC(select_no_match)
-int litehtml::element::select( const css_element_selector& selector, bool apply_pseudo /*= true*/ )	LITEHTML_RETURN_FUNC(select_no_match)
-litehtml::element::ptr litehtml::element::find_ancestor(const css_selector& selector, bool apply_pseudo, bool* is_pseudo)	LITEHTML_RETURN_FUNC(0)
-bool litehtml::element::is_first_child_inline(const element::ptr& el) const			LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::is_last_child_inline(const element::ptr& el)				LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::have_inline_child() const									LITEHTML_RETURN_FUNC(false)
+#include "html.h"
+#include "element.h"
+#include "document.h"
+
+#define LITEHTML_EMPTY_FUNC			{}
+#define LITEHTML_RETURN_FUNC(ret)	{return ret;}
+
+litehtml::element::element(const std::shared_ptr<litehtml::document>& doc) : m_doc(doc)
+{
+	m_box		= 0;
+	m_skip		= false;
+}
+
+litehtml::element::~element()
+{
+
+}
+
+
+bool litehtml::element::is_point_inside( int x, int y )
+{
+	if(get_display() != display_inline && get_display() != display_table_row)
+	{
+		position pos = m_pos;
+		pos += m_padding;
+		pos += m_borders;
+		if(pos.is_point_inside(x, y))
+		{
+			return true;
+		} else
+		{
+			return false;
+		}
+	} else
+	{
+		position::vector boxes;
+		get_inline_boxes(boxes);
+		for(position::vector::iterator box = boxes.begin(); box != boxes.end(); box++)
+		{
+			if(box->is_point_inside(x, y))
+			{
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+litehtml::web_color litehtml::element::get_color( const tchar_t* prop_name, bool inherited, const litehtml::web_color& def_color )
+{
+	const tchar_t* clrstr = get_style_property(prop_name, inherited, 0);
+	if(!clrstr)
+	{
+		return def_color;
+	}
+	return web_color::from_string(clrstr, get_document()->container());
+}
+
+litehtml::position litehtml::element::get_placement() const
+{
+	litehtml::position pos = m_pos;
+	element::ptr cur_el = parent();
+	while(cur_el)
+	{
+		pos.x += cur_el->m_pos.x;
+		pos.y += cur_el->m_pos.y;
+		cur_el = cur_el->parent();
+	}
+	return pos;
+}
+
+bool litehtml::element::is_inline_box() const
+{
+	style_display d = get_display();
+	if(	d == display_inline || 
+		d == display_inline_block || 
+		d == display_inline_text)
+	{
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::element::collapse_top_margin() const
+{
+	if(!m_borders.top && !m_padding.top && in_normal_flow() && get_float() == float_none && m_margins.top >= 0 && have_parent())
+	{
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::element::collapse_bottom_margin() const
+{
+	if(!m_borders.bottom && !m_padding.bottom && in_normal_flow() && get_float() == float_none && m_margins.bottom >= 0 && have_parent())
+	{
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::element::get_predefined_height(int& p_height) const
+{
+	css_length h = get_css_height();
+	if(h.is_predefined())
+	{
+		p_height = m_pos.height;
+		return false;
+	}
+	if(h.units() == css_units_percentage)
+	{
+		element::ptr el_parent = parent();
+		if (!el_parent)
+		{
+			position client_pos;
+			get_document()->container()->get_client_rect(client_pos);
+			p_height = h.calc_percent(client_pos.height);
+			return true;
+		} else
+		{
+			int ph = 0;
+			if (el_parent->get_predefined_height(ph))
+			{
+				p_height = h.calc_percent(ph);
+				if (is_body())
+				{
+					p_height -= content_margins_height();
+				}
+				return true;
+			} else
+			{
+				p_height = m_pos.height;
+				return false;
+			}
+		}
+	}
+	p_height = get_document()->cvt_units(h, get_font_size());
+	return true;
+}
+
+void litehtml::element::calc_document_size( litehtml::size& sz, int x /*= 0*/, int y /*= 0*/ )
+{
+	if(is_visible())
+	{
+		sz.width	= std::max(sz.width,	x + right());
+		sz.height	= std::max(sz.height,	y + bottom());
+	}
+}
+
+void litehtml::element::get_redraw_box(litehtml::position& pos, int x /*= 0*/, int y /*= 0*/)
+{
+	if(is_visible())
+	{
+		int p_left		= std::min(pos.left(),	x + m_pos.left() - m_padding.left - m_borders.left);
+		int p_right		= std::max(pos.right(), x + m_pos.right() + m_padding.left + m_borders.left);
+		int p_top		= std::min(pos.top(), y + m_pos.top() - m_padding.top - m_borders.top);
+		int p_bottom	= std::max(pos.bottom(), y + m_pos.bottom() + m_padding.bottom + m_borders.bottom);
+
+		pos.x = p_left;
+		pos.y = p_top;
+		pos.width	= p_right - p_left;
+		pos.height	= p_bottom - p_top;
+	}
+}
+
+int litehtml::element::calc_width(int defVal) const
+{
+	css_length w = get_css_width();
+	if(w.is_predefined())
+	{
+		return defVal;
+	}
+	if(w.units() == css_units_percentage)
+	{
+		element::ptr el_parent = parent();
+		if (!el_parent)
+		{
+			position client_pos;
+			get_document()->container()->get_client_rect(client_pos);
+			return w.calc_percent(client_pos.width);
+		} else
+		{
+			int pw = el_parent->calc_width(defVal);
+			if (is_body())
+			{
+				pw -= content_margins_width();
+			}
+			return w.calc_percent(pw);
+		}
+	}
+	return 	get_document()->cvt_units(w, get_font_size());
+}
+
+bool litehtml::element::is_ancestor(const ptr &el) const
+{
+	element::ptr el_parent = parent();
+	while(el_parent && el_parent != el)
+	{
+		el_parent = el_parent->parent();
+	}
+	if(el_parent)
+	{
+		return true;
+	}
+	return false;
+}
+
+int litehtml::element::get_inline_shift_left()
+{
+	int ret = 0;
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		if (el_parent->get_display() == display_inline)
+		{
+			style_display disp = get_display();
+
+			if (disp == display_inline_text || disp == display_inline_block)
+			{
+				element::ptr el = shared_from_this();
+				while (el_parent && el_parent->get_display() == display_inline)
+				{
+					if (el_parent->is_first_child_inline(el))
+					{
+						ret += el_parent->padding_left() + el_parent->border_left() + el_parent->margin_left();
+					}
+					el = el_parent;
+					el_parent = el_parent->parent();
+				}
+			}
+		}
+	}
+
+	return ret;
+}
+
+int litehtml::element::get_inline_shift_right()
+{
+	int ret = 0;
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		if (el_parent->get_display() == display_inline)
+		{
+			style_display disp = get_display();
+
+			if (disp == display_inline_text || disp == display_inline_block)
+			{
+				element::ptr el = shared_from_this();
+				while (el_parent && el_parent->get_display() == display_inline)
+				{
+					if (el_parent->is_last_child_inline(el))
+					{
+						ret += el_parent->padding_right() + el_parent->border_right() + el_parent->margin_right();
+					}
+					el = el_parent;
+					el_parent = el_parent->parent();
+				}
+			}
+		}
+	}
+
+	return ret;
+}
+
+void litehtml::element::apply_relative_shift(int parent_width)
+{
+	css_offsets offsets;
+	if (get_element_position(&offsets) == element_position_relative)
+	{
+		element::ptr parent_ptr = parent();
+		if (!offsets.left.is_predefined())
+		{
+			m_pos.x += offsets.left.calc_percent(parent_width);
+		}
+		else if (!offsets.right.is_predefined())
+		{
+			m_pos.x -= offsets.right.calc_percent(parent_width);
+		}
+		if (!offsets.top.is_predefined())
+		{
+			int h = 0;
+
+			if (offsets.top.units() == css_units_percentage)
+			{
+				element::ptr el_parent = parent();
+				if (el_parent)
+				{
+					el_parent->get_predefined_height(h);
+				}
+			}
+
+			m_pos.y += offsets.top.calc_percent(h);
+		}
+		else if (!offsets.bottom.is_predefined())
+		{
+			int h = 0;
+
+			if (offsets.top.units() == css_units_percentage)
+			{
+				element::ptr el_parent = parent();
+				if (el_parent)
+				{
+					el_parent->get_predefined_height(h);
+				}
+			}
+
+			m_pos.y -= offsets.bottom.calc_percent(h);
+		}
+	}
+}
+
+void litehtml::element::calc_auto_margins(int parent_width)							LITEHTML_EMPTY_FUNC
+const litehtml::background* litehtml::element::get_background(bool own_only)		LITEHTML_RETURN_FUNC(0)
+litehtml::element::ptr litehtml::element::get_element_by_point(int x, int y, int client_x, int client_y)	LITEHTML_RETURN_FUNC(0)
+litehtml::element::ptr litehtml::element::get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex) LITEHTML_RETURN_FUNC(0)
+void litehtml::element::get_line_left_right( int y, int def_right, int& ln_left, int& ln_right ) LITEHTML_EMPTY_FUNC
+void litehtml::element::add_style( const litehtml::style& st )						LITEHTML_EMPTY_FUNC
+void litehtml::element::select_all(const css_selector& selector, litehtml::elements_vector& res)	LITEHTML_EMPTY_FUNC
+litehtml::elements_vector litehtml::element::select_all(const litehtml::css_selector& selector)	 LITEHTML_RETURN_FUNC(litehtml::elements_vector())
+litehtml::elements_vector litehtml::element::select_all(const litehtml::tstring& selector)			 LITEHTML_RETURN_FUNC(litehtml::elements_vector())
+litehtml::element::ptr litehtml::element::select_one( const css_selector& selector ) LITEHTML_RETURN_FUNC(0)
+litehtml::element::ptr litehtml::element::select_one( const tstring& selector )		LITEHTML_RETURN_FUNC(0)
+litehtml::element::ptr litehtml::element::find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/) LITEHTML_RETURN_FUNC(0)
+litehtml::element::ptr litehtml::element::find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/) LITEHTML_RETURN_FUNC(0)
+bool litehtml::element::is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const		LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::is_nth_child(const element::ptr&, int num, int off, bool of_type) const		LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::is_only_child(const element::ptr& el, bool of_type)	 const	LITEHTML_RETURN_FUNC(false)
+litehtml::overflow litehtml::element::get_overflow() const							LITEHTML_RETURN_FUNC(overflow_visible)
+void litehtml::element::draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex ) LITEHTML_EMPTY_FUNC
+void litehtml::element::draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned ) LITEHTML_EMPTY_FUNC
+void litehtml::element::render_positioned(render_type rt)							LITEHTML_EMPTY_FUNC
+int litehtml::element::get_zindex() const											LITEHTML_RETURN_FUNC(0)
+bool litehtml::element::fetch_positioned()											LITEHTML_RETURN_FUNC(false)
+litehtml::visibility litehtml::element::get_visibility() const						LITEHTML_RETURN_FUNC(visibility_visible)
+void litehtml::element::apply_vertical_align()										LITEHTML_EMPTY_FUNC
+void litehtml::element::set_css_width( css_length& w )								LITEHTML_EMPTY_FUNC
+litehtml::element::ptr litehtml::element::get_child( int idx ) const				LITEHTML_RETURN_FUNC(0)
+size_t litehtml::element::get_children_count() const								LITEHTML_RETURN_FUNC(0)
+void litehtml::element::calc_outlines( int parent_width )							LITEHTML_EMPTY_FUNC
+litehtml::css_length litehtml::element::get_css_width() const						LITEHTML_RETURN_FUNC(css_length())
+litehtml::css_length litehtml::element::get_css_height() const						LITEHTML_RETURN_FUNC(css_length())
+litehtml::element_clear litehtml::element::get_clear() const						LITEHTML_RETURN_FUNC(clear_none)
+litehtml::css_length litehtml::element::get_css_left() const						LITEHTML_RETURN_FUNC(css_length())
+litehtml::css_length litehtml::element::get_css_right() const						LITEHTML_RETURN_FUNC(css_length())
+litehtml::css_length litehtml::element::get_css_top() const							LITEHTML_RETURN_FUNC(css_length())
+litehtml::css_length litehtml::element::get_css_bottom() const						LITEHTML_RETURN_FUNC(css_length())
+litehtml::css_offsets litehtml::element::get_css_offsets() const					LITEHTML_RETURN_FUNC(css_offsets())
+litehtml::vertical_align litehtml::element::get_vertical_align() const				LITEHTML_RETURN_FUNC(va_baseline)
+int litehtml::element::place_element(const ptr &el, int max_width)					LITEHTML_RETURN_FUNC(0)
+int litehtml::element::render_inline(const ptr &container, int max_width)			LITEHTML_RETURN_FUNC(0)
+void litehtml::element::add_positioned(const ptr &el)							LITEHTML_EMPTY_FUNC
+int litehtml::element::find_next_line_top( int top, int width, int def_right )		LITEHTML_RETURN_FUNC(0)
+litehtml::element_float litehtml::element::get_float() const						LITEHTML_RETURN_FUNC(float_none)
+void litehtml::element::add_float(const ptr &el, int x, int y)					LITEHTML_EMPTY_FUNC
+void litehtml::element::update_floats(int dy, const ptr &parent)					LITEHTML_EMPTY_FUNC
+int litehtml::element::get_line_left( int y )										LITEHTML_RETURN_FUNC(0)
+int litehtml::element::get_line_right( int y, int def_right )						LITEHTML_RETURN_FUNC(def_right)
+int litehtml::element::get_left_floats_height() const								LITEHTML_RETURN_FUNC(0)
+int litehtml::element::get_right_floats_height() const								LITEHTML_RETURN_FUNC(0)
+int litehtml::element::get_floats_height(element_float el_float) const				LITEHTML_RETURN_FUNC(0)
+bool litehtml::element::is_floats_holder() const									LITEHTML_RETURN_FUNC(false)
+void litehtml::element::get_content_size( size& sz, int max_width )					LITEHTML_EMPTY_FUNC
+void litehtml::element::init()														LITEHTML_EMPTY_FUNC
+int litehtml::element::render( int x, int y, int max_width, bool second_pass )		LITEHTML_RETURN_FUNC(0)
+bool litehtml::element::appendChild(const ptr &el)						LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::removeChild(const ptr &el)						LITEHTML_RETURN_FUNC(false)
+void litehtml::element::clearRecursive()											LITEHTML_EMPTY_FUNC
+const litehtml::tchar_t* litehtml::element::get_tagName() const						LITEHTML_RETURN_FUNC(_t(""))
+void litehtml::element::set_tagName( const tchar_t* tag )							LITEHTML_EMPTY_FUNC
+void litehtml::element::set_data( const tchar_t* data )								LITEHTML_EMPTY_FUNC
+void litehtml::element::set_attr( const tchar_t* name, const tchar_t* val )			LITEHTML_EMPTY_FUNC
+void litehtml::element::apply_stylesheet( const litehtml::css& stylesheet )			LITEHTML_EMPTY_FUNC
+void litehtml::element::refresh_styles()											LITEHTML_EMPTY_FUNC
+void litehtml::element::on_click()													LITEHTML_EMPTY_FUNC
+void litehtml::element::init_font()													LITEHTML_EMPTY_FUNC
+void litehtml::element::get_inline_boxes( position::vector& boxes )					LITEHTML_EMPTY_FUNC
+void litehtml::element::parse_styles( bool is_reparse /*= false*/ )					LITEHTML_EMPTY_FUNC
+const litehtml::tchar_t* litehtml::element::get_attr( const tchar_t* name, const tchar_t* def /*= 0*/ )	LITEHTML_RETURN_FUNC(def)
+bool litehtml::element::is_white_space() const										LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::is_body() const												LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::is_break() const											LITEHTML_RETURN_FUNC(false)
+int litehtml::element::get_base_line()												LITEHTML_RETURN_FUNC(0)
+bool litehtml::element::on_mouse_over()												LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::on_mouse_leave()											LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::on_lbutton_down()											LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::on_lbutton_up()												LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::find_styles_changes( position::vector& redraw_boxes, int x, int y )	LITEHTML_RETURN_FUNC(false)
+const litehtml::tchar_t* litehtml::element::get_cursor()							LITEHTML_RETURN_FUNC(0)
+litehtml::white_space litehtml::element::get_white_space() const					LITEHTML_RETURN_FUNC(white_space_normal)
+litehtml::style_display litehtml::element::get_display() const						LITEHTML_RETURN_FUNC(display_none)
+bool litehtml::element::set_pseudo_class( const tchar_t* pclass, bool add )			LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::set_class( const tchar_t* pclass, bool add )				LITEHTML_RETURN_FUNC(false)
+litehtml::element_position litehtml::element::get_element_position(css_offsets* offsets) const			LITEHTML_RETURN_FUNC(element_position_static)
+bool litehtml::element::is_replaced() const											LITEHTML_RETURN_FUNC(false)
+int litehtml::element::line_height() const											LITEHTML_RETURN_FUNC(0)
+void litehtml::element::draw( uint_ptr hdc, int x, int y, const position* clip )	LITEHTML_EMPTY_FUNC
+void litehtml::element::draw_background( uint_ptr hdc, int x, int y, const position* clip )	LITEHTML_EMPTY_FUNC
+const litehtml::tchar_t* litehtml::element::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ )	LITEHTML_RETURN_FUNC(0)
+litehtml::uint_ptr litehtml::element::get_font( font_metrics* fm /*= 0*/ )			LITEHTML_RETURN_FUNC(0)
+int litehtml::element::get_font_size()	const										LITEHTML_RETURN_FUNC(0)
+void litehtml::element::get_text( tstring& text )									LITEHTML_EMPTY_FUNC
+void litehtml::element::parse_attributes()											LITEHTML_EMPTY_FUNC
+int litehtml::element::select( const css_selector& selector, bool apply_pseudo)		LITEHTML_RETURN_FUNC(select_no_match)
+int litehtml::element::select( const css_element_selector& selector, bool apply_pseudo /*= true*/ )	LITEHTML_RETURN_FUNC(select_no_match)
+litehtml::element::ptr litehtml::element::find_ancestor(const css_selector& selector, bool apply_pseudo, bool* is_pseudo)	LITEHTML_RETURN_FUNC(0)
+bool litehtml::element::is_first_child_inline(const element::ptr& el) const			LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::is_last_child_inline(const element::ptr& el)				LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::have_inline_child() const									LITEHTML_RETURN_FUNC(false)
diff --git a/src/plugins/litehtml_viewer/litehtml/element.h b/src/plugins/litehtml_viewer/litehtml/element.h
index f1af05b..37abc34 100644
--- a/src/plugins/litehtml_viewer/litehtml/element.h
+++ b/src/plugins/litehtml_viewer/litehtml/element.h
@@ -1,399 +1,403 @@
-#pragma once
-#include <memory>
-#include "stylesheet.h"
-#include "css_offsets.h"
-
-namespace litehtml
-{
-	class box;
-
-	class element : public std::enable_shared_from_this<element>
-	{
-		friend class block_box;
-		friend class line_box;
-		friend class html_tag;
-		friend class el_table;
-		friend class document;
-	public:
-		typedef std::shared_ptr<litehtml::element>		ptr;
-		typedef std::weak_ptr<litehtml::element>		weak_ptr;
-	protected:
-		std::weak_ptr<element>		m_parent;
-		std::weak_ptr<litehtml::document>	m_doc;
-		litehtml::box*				m_box;
-		elements_vector				m_children;
-		position					m_pos;
-		margins						m_margins;
-		margins						m_padding;
-		margins						m_borders;
-		bool						m_skip;
-		
-		virtual void select_all(const css_selector& selector, elements_vector& res);
-	public:
-		element(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~element();
-
-		// returns refer to m_pos member;
-		position&					get_position();
-
-		int							left()						const;
-		int							right()						const;
-		int							top()						const;
-		int							bottom()					const;
-		int							height()					const;
-		int							width()						const;
-
-		int							content_margins_top()		const;
-		int							content_margins_bottom()	const;
-		int							content_margins_left()		const;
-		int							content_margins_right()		const;
-		int							content_margins_width()		const;
-		int							content_margins_height()	const;
-
-		int							margin_top()				const;
-		int							margin_bottom()				const;
-		int							margin_left()				const;
-		int							margin_right()				const;
-		margins						get_margins()				const;
-
-		int							padding_top()				const;
-		int							padding_bottom()			const;
-		int							padding_left()				const;
-		int							padding_right()				const;
-		margins						get_paddings()				const;
-
-		int							border_top()				const;
-		int							border_bottom()				const;
-		int							border_left()				const;
-		int							border_right()				const;
-		margins						get_borders()				const;
-
-		bool						in_normal_flow()			const;
-		litehtml::web_color			get_color(const tchar_t* prop_name, bool inherited, const litehtml::web_color& def_color = litehtml::web_color());
-		bool						is_inline_box()				const;
-		position					get_placement()				const;
-		bool						collapse_top_margin()		const;
-		bool						collapse_bottom_margin()	const;
-		bool						is_positioned()				const;
-
-		bool						skip();
-		void						skip(bool val);
-		bool						have_parent() const;
-		element::ptr				parent() const;
-		void						parent(element::ptr par);
-		bool						is_visible() const;
-		int							calc_width(int defVal) const;
-		int							get_inline_shift_left();
-		int							get_inline_shift_right();
-		void						apply_relative_shift(int parent_width);
-
-		std::shared_ptr<document>	get_document() const;
-
-		virtual elements_vector		select_all(const tstring& selector);
-		virtual elements_vector		select_all(const css_selector& selector);
-
-		virtual element::ptr		select_one(const tstring& selector);
-		virtual element::ptr		select_one(const css_selector& selector);
-
-		virtual int					render(int x, int y, int max_width, bool second_pass = false);
-		virtual int					render_inline(const ptr &container, int max_width);
-		virtual int					place_element(const ptr &el, int max_width);
-		virtual void				calc_outlines( int parent_width );
-		virtual void				calc_auto_margins(int parent_width);
-		virtual void				apply_vertical_align();
-		virtual bool				fetch_positioned();
-		virtual void				render_positioned(render_type rt = render_all);
-
-		virtual bool				appendChild(const ptr &el);
-		virtual bool				removeChild(const ptr &el);
-		virtual void				clearRecursive();
-
-		virtual const tchar_t*		get_tagName() const;
-		virtual void				set_tagName(const tchar_t* tag);
-		virtual void				set_data(const tchar_t* data);
-		virtual element_float		get_float() const;
-		virtual vertical_align		get_vertical_align() const;
-		virtual element_clear		get_clear() const;
-		virtual size_t				get_children_count() const;
-		virtual element::ptr		get_child(int idx) const;
-		virtual overflow			get_overflow() const;
-
-		virtual css_length			get_css_left() const;
-		virtual css_length			get_css_right() const;
-		virtual css_length			get_css_top() const;
-		virtual css_length			get_css_bottom() const;
-		virtual css_offsets			get_css_offsets() const;
-		virtual css_length			get_css_width() const;
-		virtual void				set_css_width(css_length& w);
-		virtual css_length			get_css_height() const;
-
-		virtual void				set_attr(const tchar_t* name, const tchar_t* val);
-		virtual const tchar_t*		get_attr(const tchar_t* name, const tchar_t* def = 0);
-		virtual void				apply_stylesheet(const litehtml::css& stylesheet);
-		virtual void				refresh_styles();
-		virtual bool				is_white_space() const;
-		virtual bool				is_body() const;
-		virtual bool				is_break() const;
-		virtual int					get_base_line();
-		virtual bool				on_mouse_over();
-		virtual bool				on_mouse_leave();
-		virtual bool				on_lbutton_down();
-		virtual bool				on_lbutton_up();
-		virtual void				on_click();
-		virtual bool				find_styles_changes(position::vector& redraw_boxes, int x, int y);
-		virtual const tchar_t*		get_cursor();
-		virtual void				init_font();
-		virtual bool				is_point_inside(int x, int y);
-		virtual bool				set_pseudo_class(const tchar_t* pclass, bool add);
-		virtual bool				set_class(const tchar_t* pclass, bool add);
-		virtual bool				is_replaced() const;
-		virtual int					line_height() const;
-		virtual white_space			get_white_space() const;
-		virtual style_display		get_display() const;
-		virtual visibility			get_visibility() const;
-		virtual element_position	get_element_position(css_offsets* offsets = 0) const;
-		virtual void				get_inline_boxes(position::vector& boxes);
-		virtual void				parse_styles(bool is_reparse = false);
-		virtual void				draw(uint_ptr hdc, int x, int y, const position* clip);
-		virtual void				draw_background( uint_ptr hdc, int x, int y, const position* clip );
-		virtual const tchar_t*		get_style_property(const tchar_t* name, bool inherited, const tchar_t* def = 0);
-		virtual uint_ptr			get_font(font_metrics* fm = 0);
-		virtual int					get_font_size() const;
-		virtual void				get_text(tstring& text);
-		virtual void				parse_attributes();
-		virtual int					select(const css_selector& selector, bool apply_pseudo = true);
-		virtual int					select(const css_element_selector& selector, bool apply_pseudo = true);
-		virtual element::ptr		find_ancestor(const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0);
-		virtual bool				is_ancestor(const ptr &el) const;
-		virtual element::ptr		find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0);
-		virtual element::ptr		find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0);
-		virtual bool				is_first_child_inline(const element::ptr& el) const;
-		virtual bool				is_last_child_inline(const element::ptr& el);
-		virtual bool				have_inline_child() const;
-		virtual void				get_content_size(size& sz, int max_width);
-		virtual void				init();
-		virtual bool				is_floats_holder() const;
-		virtual int					get_floats_height(element_float el_float = float_none) const;
-		virtual int					get_left_floats_height() const;
-		virtual int					get_right_floats_height() const;
-		virtual int					get_line_left(int y);
-		virtual int					get_line_right(int y, int def_right);
-		virtual void				get_line_left_right(int y, int def_right, int& ln_left, int& ln_right);
-		virtual void				add_float(const ptr &el, int x, int y);
-		virtual void				update_floats(int dy, const ptr &parent);
-		virtual void				add_positioned(const ptr &el);
-		virtual int					find_next_line_top(int top, int width, int def_right);
-		virtual int					get_zindex() const;
-		virtual void				draw_stacking_context(uint_ptr hdc, int x, int y, const position* clip, bool with_positioned);
-		virtual void				draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex );
-		virtual bool				is_nth_child(const element::ptr& el, int num, int off, bool of_type) const;
-		virtual bool				is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const;
-		virtual bool				is_only_child(const element::ptr& el, bool of_type) const;
-		virtual bool				get_predefined_height(int& p_height) const;
-		virtual void				calc_document_size(litehtml::size& sz, int x = 0, int y = 0);
-		virtual void				get_redraw_box(litehtml::position& pos, int x = 0, int y = 0);
-		virtual void				add_style(const litehtml::style& st);
-		virtual element::ptr		get_element_by_point(int x, int y, int client_x, int client_y);
-		virtual element::ptr		get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex);
-		virtual const background*	get_background(bool own_only = false);
-	};
-
-	//////////////////////////////////////////////////////////////////////////
-	//							INLINE FUNCTIONS							//
-	//////////////////////////////////////////////////////////////////////////
-
-	inline int litehtml::element::right() const
-	{
-		return left() + width();
-	}
-
-	inline int litehtml::element::left() const
-	{
-		return m_pos.left() - margin_left() - m_padding.left - m_borders.left;
-	}
-
-	inline int litehtml::element::top() const
-	{
-		return m_pos.top() - margin_top() - m_padding.top - m_borders.top;
-	}
-
-	inline int litehtml::element::bottom() const
-	{
-		return top() + height();
-	}
-
-	inline int litehtml::element::height() const
-	{
-		return m_pos.height + margin_top() + margin_bottom() + m_padding.height() + m_borders.height();
-	}
-
-	inline int litehtml::element::width() const
-	{
-		return m_pos.width + margin_left() + margin_right() + m_padding.width() + m_borders.width();
-	}
-
-	inline int litehtml::element::content_margins_top() const
-	{
-		return margin_top() + m_padding.top + m_borders.top;
-	}
-
-	inline int litehtml::element::content_margins_bottom() const
-	{
-		return margin_bottom() + m_padding.bottom + m_borders.bottom;
-	}
-
-	inline int litehtml::element::content_margins_left() const
-	{
-		return margin_left() + m_padding.left + m_borders.left;
-	}
-
-	inline int litehtml::element::content_margins_right() const
-	{
-		return margin_right() + m_padding.right + m_borders.right;
-	}
-
-	inline int litehtml::element::content_margins_width() const
-	{
-		return content_margins_left() + content_margins_right();
-	}
-
-	inline int litehtml::element::content_margins_height() const
-	{
-		return content_margins_top() + content_margins_bottom();
-	}
-
-	inline litehtml::margins litehtml::element::get_paddings()	const
-	{
-		return m_padding;
-	}
-
-	inline litehtml::margins litehtml::element::get_borders()	const
-	{
-		return m_borders;
-	}
-
-	inline int litehtml::element::padding_top() const
-	{
-		return m_padding.top;
-	}
-
-	inline int litehtml::element::padding_bottom() const
-	{
-		return m_padding.bottom;
-	}
-
-	inline int litehtml::element::padding_left() const
-	{
-		return m_padding.left;
-	}
-
-	inline int litehtml::element::padding_right() const
-	{
-		return m_padding.right;
-	}
-
-	inline bool litehtml::element::in_normal_flow() const
-	{
-		if(get_element_position() != element_position_absolute && get_display() != display_none)
-		{
-			return true;
-		}
-		return false;
-	}
-
-	inline int litehtml::element::border_top() const
-	{
-		return m_borders.top;
-	}
-
-	inline int litehtml::element::border_bottom() const
-	{
-		return m_borders.bottom;
-	}
-
-	inline int litehtml::element::border_left() const
-	{
-		return m_borders.left;
-	}
-
-	inline int litehtml::element::border_right() const
-	{
-		return m_borders.right;
-	}
-
-	inline bool litehtml::element::skip()
-	{
-		return m_skip;
-	}
-
-	inline void litehtml::element::skip(bool val)
-	{
-		m_skip = val;
-	}
-
-	inline bool litehtml::element::have_parent() const
-	{
-		return !m_parent.expired();
-	}
-
-	inline element::ptr litehtml::element::parent() const
-	{
-		return m_parent.lock();
-	}
-
-	inline void litehtml::element::parent(element::ptr par)
-	{
-		m_parent = par;
-	}
-
-	inline int litehtml::element::margin_top() const
-	{
-		return m_margins.top;
-	}
-
-	inline int litehtml::element::margin_bottom() const
-	{
-		return m_margins.bottom;
-	}
-
-	inline int litehtml::element::margin_left() const
-	{
-		return m_margins.left;
-	}
-
-	inline int litehtml::element::margin_right() const
-	{
-		return m_margins.right;
-	}
-
-	inline litehtml::margins litehtml::element::get_margins() const
-	{
-		margins ret;
-		ret.left	= margin_left();
-		ret.right	= margin_right();
-		ret.top		= margin_top();
-		ret.bottom	= margin_bottom();
-
-		return ret;
-	}
-
-	inline bool litehtml::element::is_positioned()	const
-	{
-		return (get_element_position() > element_position_static);
-	}
-
-	inline bool litehtml::element::is_visible() const
-	{
-		return !(m_skip || get_display() == display_none || get_visibility() != visibility_visible);
-	}
-
-	inline position& litehtml::element::get_position()
-	{
-		return m_pos;
-	}
-
-	inline std::shared_ptr<document> element::get_document() const
-	{
-		return m_doc.lock();
-	}
-}
+#ifndef LH_ELEMENT_H
+#define LH_ELEMENT_H
+
+#include <memory>
+#include "stylesheet.h"
+#include "css_offsets.h"
+
+namespace litehtml
+{
+	class box;
+
+	class element : public std::enable_shared_from_this<element>
+	{
+		friend class block_box;
+		friend class line_box;
+		friend class html_tag;
+		friend class el_table;
+		friend class document;
+	public:
+		typedef std::shared_ptr<litehtml::element>		ptr;
+		typedef std::weak_ptr<litehtml::element>		weak_ptr;
+	protected:
+		std::weak_ptr<element>		m_parent;
+		std::weak_ptr<litehtml::document>	m_doc;
+		litehtml::box*				m_box;
+		elements_vector				m_children;
+		position					m_pos;
+		margins						m_margins;
+		margins						m_padding;
+		margins						m_borders;
+		bool						m_skip;
+		
+		virtual void select_all(const css_selector& selector, elements_vector& res);
+	public:
+		element(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~element();
+
+		// returns refer to m_pos member;
+		position&					get_position();
+
+		int							left()						const;
+		int							right()						const;
+		int							top()						const;
+		int							bottom()					const;
+		int							height()					const;
+		int							width()						const;
+
+		int							content_margins_top()		const;
+		int							content_margins_bottom()	const;
+		int							content_margins_left()		const;
+		int							content_margins_right()		const;
+		int							content_margins_width()		const;
+		int							content_margins_height()	const;
+
+		int							margin_top()				const;
+		int							margin_bottom()				const;
+		int							margin_left()				const;
+		int							margin_right()				const;
+		margins						get_margins()				const;
+
+		int							padding_top()				const;
+		int							padding_bottom()			const;
+		int							padding_left()				const;
+		int							padding_right()				const;
+		margins						get_paddings()				const;
+
+		int							border_top()				const;
+		int							border_bottom()				const;
+		int							border_left()				const;
+		int							border_right()				const;
+		margins						get_borders()				const;
+
+		bool						in_normal_flow()			const;
+		litehtml::web_color			get_color(const tchar_t* prop_name, bool inherited, const litehtml::web_color& def_color = litehtml::web_color());
+		bool						is_inline_box()				const;
+		position					get_placement()				const;
+		bool						collapse_top_margin()		const;
+		bool						collapse_bottom_margin()	const;
+		bool						is_positioned()				const;
+
+		bool						skip();
+		void						skip(bool val);
+		bool						have_parent() const;
+		element::ptr				parent() const;
+		void						parent(element::ptr par);
+		bool						is_visible() const;
+		int							calc_width(int defVal) const;
+		int							get_inline_shift_left();
+		int							get_inline_shift_right();
+		void						apply_relative_shift(int parent_width);
+
+		std::shared_ptr<document>	get_document() const;
+
+		virtual elements_vector		select_all(const tstring& selector);
+		virtual elements_vector		select_all(const css_selector& selector);
+
+		virtual element::ptr		select_one(const tstring& selector);
+		virtual element::ptr		select_one(const css_selector& selector);
+
+		virtual int					render(int x, int y, int max_width, bool second_pass = false);
+		virtual int					render_inline(const ptr &container, int max_width);
+		virtual int					place_element(const ptr &el, int max_width);
+		virtual void				calc_outlines( int parent_width );
+		virtual void				calc_auto_margins(int parent_width);
+		virtual void				apply_vertical_align();
+		virtual bool				fetch_positioned();
+		virtual void				render_positioned(render_type rt = render_all);
+
+		virtual bool				appendChild(const ptr &el);
+		virtual bool				removeChild(const ptr &el);
+		virtual void				clearRecursive();
+
+		virtual const tchar_t*		get_tagName() const;
+		virtual void				set_tagName(const tchar_t* tag);
+		virtual void				set_data(const tchar_t* data);
+		virtual element_float		get_float() const;
+		virtual vertical_align		get_vertical_align() const;
+		virtual element_clear		get_clear() const;
+		virtual size_t				get_children_count() const;
+		virtual element::ptr		get_child(int idx) const;
+		virtual overflow			get_overflow() const;
+
+		virtual css_length			get_css_left() const;
+		virtual css_length			get_css_right() const;
+		virtual css_length			get_css_top() const;
+		virtual css_length			get_css_bottom() const;
+		virtual css_offsets			get_css_offsets() const;
+		virtual css_length			get_css_width() const;
+		virtual void				set_css_width(css_length& w);
+		virtual css_length			get_css_height() const;
+
+		virtual void				set_attr(const tchar_t* name, const tchar_t* val);
+		virtual const tchar_t*		get_attr(const tchar_t* name, const tchar_t* def = 0);
+		virtual void				apply_stylesheet(const litehtml::css& stylesheet);
+		virtual void				refresh_styles();
+		virtual bool				is_white_space() const;
+		virtual bool				is_body() const;
+		virtual bool				is_break() const;
+		virtual int					get_base_line();
+		virtual bool				on_mouse_over();
+		virtual bool				on_mouse_leave();
+		virtual bool				on_lbutton_down();
+		virtual bool				on_lbutton_up();
+		virtual void				on_click();
+		virtual bool				find_styles_changes(position::vector& redraw_boxes, int x, int y);
+		virtual const tchar_t*		get_cursor();
+		virtual void				init_font();
+		virtual bool				is_point_inside(int x, int y);
+		virtual bool				set_pseudo_class(const tchar_t* pclass, bool add);
+		virtual bool				set_class(const tchar_t* pclass, bool add);
+		virtual bool				is_replaced() const;
+		virtual int					line_height() const;
+		virtual white_space			get_white_space() const;
+		virtual style_display		get_display() const;
+		virtual visibility			get_visibility() const;
+		virtual element_position	get_element_position(css_offsets* offsets = 0) const;
+		virtual void				get_inline_boxes(position::vector& boxes);
+		virtual void				parse_styles(bool is_reparse = false);
+		virtual void				draw(uint_ptr hdc, int x, int y, const position* clip);
+		virtual void				draw_background( uint_ptr hdc, int x, int y, const position* clip );
+		virtual const tchar_t*		get_style_property(const tchar_t* name, bool inherited, const tchar_t* def = 0);
+		virtual uint_ptr			get_font(font_metrics* fm = 0);
+		virtual int					get_font_size() const;
+		virtual void				get_text(tstring& text);
+		virtual void				parse_attributes();
+		virtual int					select(const css_selector& selector, bool apply_pseudo = true);
+		virtual int					select(const css_element_selector& selector, bool apply_pseudo = true);
+		virtual element::ptr		find_ancestor(const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0);
+		virtual bool				is_ancestor(const ptr &el) const;
+		virtual element::ptr		find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0);
+		virtual element::ptr		find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0);
+		virtual bool				is_first_child_inline(const element::ptr& el) const;
+		virtual bool				is_last_child_inline(const element::ptr& el);
+		virtual bool				have_inline_child() const;
+		virtual void				get_content_size(size& sz, int max_width);
+		virtual void				init();
+		virtual bool				is_floats_holder() const;
+		virtual int					get_floats_height(element_float el_float = float_none) const;
+		virtual int					get_left_floats_height() const;
+		virtual int					get_right_floats_height() const;
+		virtual int					get_line_left(int y);
+		virtual int					get_line_right(int y, int def_right);
+		virtual void				get_line_left_right(int y, int def_right, int& ln_left, int& ln_right);
+		virtual void				add_float(const ptr &el, int x, int y);
+		virtual void				update_floats(int dy, const ptr &parent);
+		virtual void				add_positioned(const ptr &el);
+		virtual int					find_next_line_top(int top, int width, int def_right);
+		virtual int					get_zindex() const;
+		virtual void				draw_stacking_context(uint_ptr hdc, int x, int y, const position* clip, bool with_positioned);
+		virtual void				draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex );
+		virtual bool				is_nth_child(const element::ptr& el, int num, int off, bool of_type) const;
+		virtual bool				is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const;
+		virtual bool				is_only_child(const element::ptr& el, bool of_type) const;
+		virtual bool				get_predefined_height(int& p_height) const;
+		virtual void				calc_document_size(litehtml::size& sz, int x = 0, int y = 0);
+		virtual void				get_redraw_box(litehtml::position& pos, int x = 0, int y = 0);
+		virtual void				add_style(const litehtml::style& st);
+		virtual element::ptr		get_element_by_point(int x, int y, int client_x, int client_y);
+		virtual element::ptr		get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex);
+		virtual const background*	get_background(bool own_only = false);
+	};
+
+	//////////////////////////////////////////////////////////////////////////
+	//							INLINE FUNCTIONS							//
+	//////////////////////////////////////////////////////////////////////////
+
+	inline int litehtml::element::right() const
+	{
+		return left() + width();
+	}
+
+	inline int litehtml::element::left() const
+	{
+		return m_pos.left() - margin_left() - m_padding.left - m_borders.left;
+	}
+
+	inline int litehtml::element::top() const
+	{
+		return m_pos.top() - margin_top() - m_padding.top - m_borders.top;
+	}
+
+	inline int litehtml::element::bottom() const
+	{
+		return top() + height();
+	}
+
+	inline int litehtml::element::height() const
+	{
+		return m_pos.height + margin_top() + margin_bottom() + m_padding.height() + m_borders.height();
+	}
+
+	inline int litehtml::element::width() const
+	{
+		return m_pos.width + margin_left() + margin_right() + m_padding.width() + m_borders.width();
+	}
+
+	inline int litehtml::element::content_margins_top() const
+	{
+		return margin_top() + m_padding.top + m_borders.top;
+	}
+
+	inline int litehtml::element::content_margins_bottom() const
+	{
+		return margin_bottom() + m_padding.bottom + m_borders.bottom;
+	}
+
+	inline int litehtml::element::content_margins_left() const
+	{
+		return margin_left() + m_padding.left + m_borders.left;
+	}
+
+	inline int litehtml::element::content_margins_right() const
+	{
+		return margin_right() + m_padding.right + m_borders.right;
+	}
+
+	inline int litehtml::element::content_margins_width() const
+	{
+		return content_margins_left() + content_margins_right();
+	}
+
+	inline int litehtml::element::content_margins_height() const
+	{
+		return content_margins_top() + content_margins_bottom();
+	}
+
+	inline litehtml::margins litehtml::element::get_paddings()	const
+	{
+		return m_padding;
+	}
+
+	inline litehtml::margins litehtml::element::get_borders()	const
+	{
+		return m_borders;
+	}
+
+	inline int litehtml::element::padding_top() const
+	{
+		return m_padding.top;
+	}
+
+	inline int litehtml::element::padding_bottom() const
+	{
+		return m_padding.bottom;
+	}
+
+	inline int litehtml::element::padding_left() const
+	{
+		return m_padding.left;
+	}
+
+	inline int litehtml::element::padding_right() const
+	{
+		return m_padding.right;
+	}
+
+	inline bool litehtml::element::in_normal_flow() const
+	{
+		if(get_element_position() != element_position_absolute && get_display() != display_none)
+		{
+			return true;
+		}
+		return false;
+	}
+
+	inline int litehtml::element::border_top() const
+	{
+		return m_borders.top;
+	}
+
+	inline int litehtml::element::border_bottom() const
+	{
+		return m_borders.bottom;
+	}
+
+	inline int litehtml::element::border_left() const
+	{
+		return m_borders.left;
+	}
+
+	inline int litehtml::element::border_right() const
+	{
+		return m_borders.right;
+	}
+
+	inline bool litehtml::element::skip()
+	{
+		return m_skip;
+	}
+
+	inline void litehtml::element::skip(bool val)
+	{
+		m_skip = val;
+	}
+
+	inline bool litehtml::element::have_parent() const
+	{
+		return !m_parent.expired();
+	}
+
+	inline element::ptr litehtml::element::parent() const
+	{
+		return m_parent.lock();
+	}
+
+	inline void litehtml::element::parent(element::ptr par)
+	{
+		m_parent = par;
+	}
+
+	inline int litehtml::element::margin_top() const
+	{
+		return m_margins.top;
+	}
+
+	inline int litehtml::element::margin_bottom() const
+	{
+		return m_margins.bottom;
+	}
+
+	inline int litehtml::element::margin_left() const
+	{
+		return m_margins.left;
+	}
+
+	inline int litehtml::element::margin_right() const
+	{
+		return m_margins.right;
+	}
+
+	inline litehtml::margins litehtml::element::get_margins() const
+	{
+		margins ret;
+		ret.left	= margin_left();
+		ret.right	= margin_right();
+		ret.top		= margin_top();
+		ret.bottom	= margin_bottom();
+
+		return ret;
+	}
+
+	inline bool litehtml::element::is_positioned()	const
+	{
+		return (get_element_position() > element_position_static);
+	}
+
+	inline bool litehtml::element::is_visible() const
+	{
+		return !(m_skip || get_display() == display_none || get_visibility() != visibility_visible);
+	}
+
+	inline position& litehtml::element::get_position()
+	{
+		return m_pos;
+	}
+
+	inline std::shared_ptr<document> element::get_document() const
+	{
+		return m_doc.lock();
+	}
+}
+
+#endif  // LH_ELEMENT_H
diff --git a/src/plugins/litehtml_viewer/litehtml/html.cpp b/src/plugins/litehtml_viewer/litehtml/html.cpp
index a11e2e4..a27daca 100644
--- a/src/plugins/litehtml_viewer/litehtml/html.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/html.cpp
@@ -1,169 +1,169 @@
-#include "html.h"
-#include "types.h"
-#include "html_tag.h"
-
-void litehtml::trim(tstring &s) 
-{
-	tstring::size_type pos = s.find_first_not_of(_t(" \n\r\t"));
-	if(pos != tstring::npos)
-	{
-		s.erase(s.begin(), s.begin() + pos);
-	}
-	pos = s.find_last_not_of(_t(" \n\r\t"));
-	if(pos != tstring::npos)
-	{
-		s.erase(s.begin() + pos + 1, s.end());
-	}
-}
-
-void litehtml::lcase(tstring &s) 
-{
-	for(tstring::iterator i = s.begin(); i != s.end(); i++)
-	{
-		(*i) = t_tolower(*i);
-	}
-}
-
-litehtml::tstring::size_type litehtml::find_close_bracket(const tstring &s, tstring::size_type off, tchar_t open_b, tchar_t close_b)
-{
-	int cnt = 0;
-	for(tstring::size_type i = off; i < s.length(); i++)
-	{
-		if(s[i] == open_b)
-		{
-			cnt++;
-		} else if(s[i] == close_b)
-		{
-			cnt--;
-			if(!cnt)
-			{
-				return i;
-			}
-		}
-	}
-	return tstring::npos;
-}
-
-int litehtml::value_index( const tstring& val, const tstring& strings, int defValue, tchar_t delim )
-{
-	if(val.empty() || strings.empty() || !delim)
-	{
-		return defValue;
-	}
-
-	int idx = 0;
-	tstring::size_type delim_start	= 0;
-	tstring::size_type delim_end	= strings.find(delim, delim_start);
-	tstring::size_type item_len		= 0;
-	while(true)
-	{
-		if(delim_end == tstring::npos)
-		{
-			item_len = strings.length() - delim_start;
-		} else
-		{
-			item_len = delim_end - delim_start;
-		}
-		if(item_len == val.length())
-		{
-			if(val == strings.substr(delim_start, item_len))
-			{
-				return idx;
-			}
-		}
-		idx++;
-		delim_start = delim_end;
-		if(delim_start == tstring::npos) break;
-		delim_start++;
-		if(delim_start == strings.length()) break;
-		delim_end = strings.find(delim, delim_start);
-	}
-	return defValue;
-}
-
-bool litehtml::value_in_list( const tstring& val, const tstring& strings, tchar_t delim )
-{
-	int idx = value_index(val, strings, -1, delim);
-	if(idx >= 0)
-	{
-		return true;
-	}
-	return false;
-}
-
-void litehtml::split_string(const tstring& str, string_vector& tokens, const tstring& delims, const tstring& delims_preserve, const tstring& quote)
-{
-	if(str.empty() || (delims.empty() && delims_preserve.empty()))
-	{
-		return;
-	}
-
-	tstring all_delims = delims + delims_preserve + quote;
-
-	tstring::size_type token_start	= 0;
-	tstring::size_type token_end	= str.find_first_of(all_delims, token_start);
-	tstring::size_type token_len	= 0;
-	tstring token;
-	while(true)
-	{
-		while( token_end != tstring::npos && quote.find_first_of(str[token_end]) != tstring::npos )
-		{
-			if(str[token_end] == _t('('))
-			{
-				token_end = find_close_bracket(str, token_end, _t('('), _t(')'));
-			} else if(str[token_end] == _t('['))
-			{
-				token_end = find_close_bracket(str, token_end, _t('['), _t(']'));
-			} else if(str[token_end] == _t('{'))
-			{
-				token_end = find_close_bracket(str, token_end, _t('{'), _t('}'));
-			} else
-			{
-				token_end = str.find_first_of(str[token_end], token_end + 1);
-			}
-			if(token_end != tstring::npos)
-			{
-				token_end = str.find_first_of(all_delims, token_end + 1);
-			}
-		}
-
-		if(token_end == tstring::npos)
-		{
-			token_len = tstring::npos;
-		} else
-		{
-			token_len = token_end - token_start;
-		}
-
-		token = str.substr(token_start, token_len);
-		if(!token.empty())
-		{
-			tokens.push_back( token );
-		}
-		if(token_end != tstring::npos && !delims_preserve.empty() && delims_preserve.find_first_of(str[token_end]) != tstring::npos)
-		{
-			tokens.push_back( str.substr(token_end, 1) );
-		}
-
-		token_start = token_end;
-		if(token_start == tstring::npos) break;
-		token_start++;
-		if(token_start == str.length()) break;
-		token_end = str.find_first_of(all_delims, token_start);
-	}
-}
-
-void litehtml::join_string(tstring& str, const string_vector& tokens, const tstring& delims)
-{
-	tstringstream ss;
-	for(size_t i=0; i<tokens.size(); ++i)
-	{
-		if(i != 0)
-		{
-			ss << delims;
-		}
-		ss << tokens[i];
-	}
-
-	str = ss.str();
-}
+#include "html.h"
+#include "types.h"
+#include "html_tag.h"
+
+void litehtml::trim(tstring &s) 
+{
+	tstring::size_type pos = s.find_first_not_of(_t(" \n\r\t"));
+	if(pos != tstring::npos)
+	{
+	    s.erase(s.begin(), s.begin() + pos);
+	}
+	pos = s.find_last_not_of(_t(" \n\r\t"));
+	if(pos != tstring::npos)
+	{
+	    s.erase(s.begin() + pos + 1, s.end());
+	}
+}
+
+void litehtml::lcase(tstring &s) 
+{
+	for(tstring::iterator i = s.begin(); i != s.end(); i++)
+	{
+		(*i) = t_tolower(*i);
+	}
+}
+
+litehtml::tstring::size_type litehtml::find_close_bracket(const tstring &s, tstring::size_type off, tchar_t open_b, tchar_t close_b)
+{
+	int cnt = 0;
+	for(tstring::size_type i = off; i < s.length(); i++)
+	{
+		if(s[i] == open_b)
+		{
+			cnt++;
+		} else if(s[i] == close_b)
+		{
+			cnt--;
+			if(!cnt)
+			{
+				return i;
+			}
+		}
+	}
+	return tstring::npos;
+}
+
+int litehtml::value_index( const tstring& val, const tstring& strings, int defValue, tchar_t delim )
+{
+	if(val.empty() || strings.empty() || !delim)
+	{
+		return defValue;
+	}
+
+	int idx = 0;
+	tstring::size_type delim_start	= 0;
+	tstring::size_type delim_end	= strings.find(delim, delim_start);
+	tstring::size_type item_len		= 0;
+	while(true)
+	{
+		if(delim_end == tstring::npos)
+		{
+			item_len = strings.length() - delim_start;
+		} else
+		{
+			item_len = delim_end - delim_start;
+		}
+		if(item_len == val.length())
+		{
+			if(val == strings.substr(delim_start, item_len))
+			{
+				return idx;
+			}
+		}
+		idx++;
+		delim_start = delim_end;
+		if(delim_start == tstring::npos) break;
+		delim_start++;
+		if(delim_start == strings.length()) break;
+		delim_end = strings.find(delim, delim_start);
+	}
+	return defValue;
+}
+
+bool litehtml::value_in_list( const tstring& val, const tstring& strings, tchar_t delim )
+{
+	int idx = value_index(val, strings, -1, delim);
+	if(idx >= 0)
+	{
+		return true;
+	}
+	return false;
+}
+
+void litehtml::split_string(const tstring& str, string_vector& tokens, const tstring& delims, const tstring& delims_preserve, const tstring& quote)
+{
+	if(str.empty() || (delims.empty() && delims_preserve.empty()))
+	{
+		return;
+	}
+
+	tstring all_delims = delims + delims_preserve + quote;
+
+	tstring::size_type token_start	= 0;
+	tstring::size_type token_end	= str.find_first_of(all_delims, token_start);
+	tstring::size_type token_len	= 0;
+	tstring token;
+	while(true)
+	{
+		while( token_end != tstring::npos && quote.find_first_of(str[token_end]) != tstring::npos )
+		{
+			if(str[token_end] == _t('('))
+			{
+				token_end = find_close_bracket(str, token_end, _t('('), _t(')'));
+			} else if(str[token_end] == _t('['))
+			{
+				token_end = find_close_bracket(str, token_end, _t('['), _t(']'));
+			} else if(str[token_end] == _t('{'))
+			{
+				token_end = find_close_bracket(str, token_end, _t('{'), _t('}'));
+			} else
+			{
+				token_end = str.find_first_of(str[token_end], token_end + 1);
+			}
+			if(token_end != tstring::npos)
+			{
+				token_end = str.find_first_of(all_delims, token_end + 1);
+			}
+		}
+
+		if(token_end == tstring::npos)
+		{
+			token_len = tstring::npos;
+		} else
+		{
+			token_len = token_end - token_start;
+		}
+
+		token = str.substr(token_start, token_len);
+		if(!token.empty())
+		{
+			tokens.push_back( token );
+		}
+		if(token_end != tstring::npos && !delims_preserve.empty() && delims_preserve.find_first_of(str[token_end]) != tstring::npos)
+		{
+			tokens.push_back( str.substr(token_end, 1) );
+		}
+
+		token_start = token_end;
+		if(token_start == tstring::npos) break;
+		token_start++;
+		if(token_start == str.length()) break;
+		token_end = str.find_first_of(all_delims, token_start);
+	}
+}
+
+void litehtml::join_string(tstring& str, const string_vector& tokens, const tstring& delims)
+{
+	tstringstream ss;
+	for(size_t i=0; i<tokens.size(); ++i)
+	{
+		if(i != 0)
+		{
+			ss << delims;
+		}
+		ss << tokens[i];
+	}
+
+	str = ss.str();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/html.h b/src/plugins/litehtml_viewer/litehtml/html.h
index 31852c3..2c5c556 100644
--- a/src/plugins/litehtml_viewer/litehtml/html.h
+++ b/src/plugins/litehtml_viewer/litehtml/html.h
@@ -1,92 +1,96 @@
-#pragma once
-
-#include <stdlib.h>
-#include <string>
-#include <ctype.h>
-#include <vector>
-#include <map>
-#include <cstring>
-#include <algorithm>
-#include <sstream>
-#include "os_types.h"
-#include "types.h"
-#include "background.h"
-#include "borders.h"
-#include "html_tag.h"
-#include "web_color.h"
-#include "media_query.h"
-
-namespace litehtml
-{
-	struct list_marker
-	{
-		tstring			image;
-		const tchar_t*	baseurl;
-		list_style_type	marker_type;
-		web_color		color;
-		position		pos;
-	};
-
-	// call back interface to draw text, images and other elements
-	class document_container
-	{
-	public:
-		virtual litehtml::uint_ptr	create_font(const litehtml::tchar_t* faceName, int size, int weight, litehtml::font_style italic, unsigned int decoration, litehtml::font_metrics* fm) = 0;
-		virtual void				delete_font(litehtml::uint_ptr hFont) = 0;
-		virtual int					text_width(const litehtml::tchar_t* text, litehtml::uint_ptr hFont) = 0;
-		virtual void				draw_text(litehtml::uint_ptr hdc, const litehtml::tchar_t* text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos) = 0;
-		virtual int					pt_to_px(int pt) = 0;
-		virtual int					get_default_font_size() const = 0;
-		virtual const litehtml::tchar_t*	get_default_font_name() const = 0;
-		virtual void				draw_list_marker(litehtml::uint_ptr hdc, const litehtml::list_marker& marker) = 0;
-		virtual void				load_image(const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, bool redraw_on_ready) = 0;
-		virtual void				get_image_size(const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, litehtml::size& sz) = 0;
-		virtual void				draw_background(litehtml::uint_ptr hdc, const litehtml::background_paint& bg) = 0;
-		virtual void				draw_borders(litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root) = 0;
-
-		virtual	void				set_caption(const litehtml::tchar_t* caption) = 0;
-		virtual	void				set_base_url(const litehtml::tchar_t* base_url) = 0;
-		virtual void				link(const std::shared_ptr<litehtml::document>& doc, const litehtml::element::ptr& el) = 0;
-		virtual void				on_anchor_click(const litehtml::tchar_t* url, const litehtml::element::ptr& el) = 0;
-		virtual	void				set_cursor(const litehtml::tchar_t* cursor) = 0;
-		virtual	void				transform_text(litehtml::tstring& text, litehtml::text_transform tt) = 0;
-		virtual void				import_css(litehtml::tstring& text, const litehtml::tstring& url, litehtml::tstring& baseurl) = 0;
-		virtual void				set_clip(const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius, bool valid_x, bool valid_y) = 0;
-		virtual void				del_clip() = 0;
-		virtual void				get_client_rect(litehtml::position& client) const = 0;
-		virtual std::shared_ptr<litehtml::element>	create_element(const litehtml::tchar_t *tag_name,
-																	 const litehtml::string_map &attributes,
-																	 const std::shared_ptr<litehtml::document> &doc) = 0;
-
-		virtual void				get_media_features(litehtml::media_features& media) const = 0;
-		virtual void				get_language(litehtml::tstring& language, litehtml::tstring & culture) const = 0;
-	};
-
-	void trim(tstring &s);
-	void lcase(tstring &s);
-	int	 value_index(const tstring& val, const tstring& strings, int defValue = -1, tchar_t delim = _t(';'));
-	bool value_in_list(const tstring& val, const tstring& strings, tchar_t delim = _t(';'));
-	tstring::size_type find_close_bracket(const tstring &s, tstring::size_type off, tchar_t open_b = _t('('), tchar_t close_b = _t(')'));
-	void split_string(const tstring& str, string_vector& tokens, const tstring& delims, const tstring& delims_preserve = _t(""), const tstring& quote = _t("\""));
-	void join_string(tstring& str, const string_vector& tokens, const tstring& delims);
-
-	inline int round_f(float val)
-	{
-		int int_val = (int) val;
-		if(val - int_val >= 0.5)
-		{
-			int_val++;
-		}
-		return int_val;
-	}
-
-	inline int round_d(double val)
-	{
-		int int_val = (int) val;
-		if(val - int_val >= 0.5)
-		{
-			int_val++;
-		}
-		return int_val;
-	}
-}
+#ifndef LH_HTML_H
+#define LH_HTML_H
+
+#include <stdlib.h>
+#include <string>
+#include <ctype.h>
+#include <vector>
+#include <map>
+#include <cstring>
+#include <algorithm>
+#include <sstream>
+#include "os_types.h"
+#include "types.h"
+#include "background.h"
+#include "borders.h"
+#include "html_tag.h"
+#include "web_color.h"
+#include "media_query.h"
+
+namespace litehtml
+{
+	struct list_marker
+	{
+		tstring			image;
+		const tchar_t*	baseurl;
+		list_style_type	marker_type;
+		web_color		color;
+		position		pos;
+	};
+
+	// call back interface to draw text, images and other elements
+	class document_container
+	{
+	public:
+		virtual litehtml::uint_ptr	create_font(const litehtml::tchar_t* faceName, int size, int weight, litehtml::font_style italic, unsigned int decoration, litehtml::font_metrics* fm) = 0;
+		virtual void				delete_font(litehtml::uint_ptr hFont) = 0;
+		virtual int					text_width(const litehtml::tchar_t* text, litehtml::uint_ptr hFont) = 0;
+		virtual void				draw_text(litehtml::uint_ptr hdc, const litehtml::tchar_t* text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos) = 0;
+		virtual int					pt_to_px(int pt) = 0;
+		virtual int					get_default_font_size() const = 0;
+		virtual const litehtml::tchar_t*	get_default_font_name() const = 0;
+		virtual void				draw_list_marker(litehtml::uint_ptr hdc, const litehtml::list_marker& marker) = 0;
+		virtual void				load_image(const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, bool redraw_on_ready) = 0;
+		virtual void				get_image_size(const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, litehtml::size& sz) = 0;
+		virtual void				draw_background(litehtml::uint_ptr hdc, const litehtml::background_paint& bg) = 0;
+		virtual void				draw_borders(litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root) = 0;
+
+		virtual	void				set_caption(const litehtml::tchar_t* caption) = 0;
+		virtual	void				set_base_url(const litehtml::tchar_t* base_url) = 0;
+		virtual void				link(const std::shared_ptr<litehtml::document>& doc, const litehtml::element::ptr& el) = 0;
+		virtual void				on_anchor_click(const litehtml::tchar_t* url, const litehtml::element::ptr& el) = 0;
+		virtual	void				set_cursor(const litehtml::tchar_t* cursor) = 0;
+		virtual	void				transform_text(litehtml::tstring& text, litehtml::text_transform tt) = 0;
+		virtual void				import_css(litehtml::tstring& text, const litehtml::tstring& url, litehtml::tstring& baseurl) = 0;
+		virtual void				set_clip(const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius, bool valid_x, bool valid_y) = 0;
+		virtual void				del_clip() = 0;
+		virtual void				get_client_rect(litehtml::position& client) const = 0;
+		virtual std::shared_ptr<litehtml::element>	create_element(const litehtml::tchar_t *tag_name,
+																	 const litehtml::string_map &attributes,
+																	 const std::shared_ptr<litehtml::document> &doc) = 0;
+
+		virtual void				get_media_features(litehtml::media_features& media) const = 0;
+		virtual void				get_language(litehtml::tstring& language, litehtml::tstring & culture) const = 0;
+		virtual litehtml::tstring	resolve_color(const litehtml::tstring& color) const  { return litehtml::tstring(); }
+	};
+
+	void trim(tstring &s);
+	void lcase(tstring &s);
+	int	 value_index(const tstring& val, const tstring& strings, int defValue = -1, tchar_t delim = _t(';'));
+	bool value_in_list(const tstring& val, const tstring& strings, tchar_t delim = _t(';'));
+	tstring::size_type find_close_bracket(const tstring &s, tstring::size_type off, tchar_t open_b = _t('('), tchar_t close_b = _t(')'));
+	void split_string(const tstring& str, string_vector& tokens, const tstring& delims, const tstring& delims_preserve = _t(""), const tstring& quote = _t("\""));
+	void join_string(tstring& str, const string_vector& tokens, const tstring& delims);
+
+	inline int round_f(float val)
+	{
+		int int_val = (int) val;
+		if(val - int_val >= 0.5)
+		{
+			int_val++;
+		}
+		return int_val;
+	}
+
+	inline int round_d(double val)
+	{
+		int int_val = (int) val;
+		if(val - int_val >= 0.5)
+		{
+			int_val++;
+		}
+		return int_val;
+	}
+}
+
+#endif  // LH_HTML_H
diff --git a/src/plugins/litehtml_viewer/litehtml/html_tag.cpp b/src/plugins/litehtml_viewer/litehtml/html_tag.cpp
index 40a76de..f856b1e 100644
--- a/src/plugins/litehtml_viewer/litehtml/html_tag.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/html_tag.cpp
@@ -1,4663 +1,4663 @@
-#include "html.h"
-#include "html_tag.h"
-#include "document.h"
-#include "iterators.h"
-#include "stylesheet.h"
-#include "table.h"
-#include <algorithm>
-#include <locale>
-#include "el_before_after.h"
-
-litehtml::html_tag::html_tag(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
-{
-	m_box_sizing			= box_sizing_content_box;
-	m_z_index				= 0;
-	m_overflow				= overflow_visible;
-	m_box					= 0;
-	m_text_align			= text_align_left;
-	m_el_position			= element_position_static;
-	m_display				= display_inline;
-	m_vertical_align		= va_baseline;
-	m_list_style_type		= list_style_type_none;
-	m_list_style_position	= list_style_position_outside;
-	m_float					= float_none;
-	m_clear					= clear_none;
-	m_font					= 0;
-	m_font_size				= 0;
-	m_white_space			= white_space_normal;
-	m_lh_predefined			= false;
-	m_line_height			= 0;
-	m_visibility			= visibility_visible;
-	m_border_spacing_x		= 0;
-	m_border_spacing_y		= 0;
-	m_border_collapse		= border_collapse_separate;
-}
-
-litehtml::html_tag::~html_tag()
-{
-
-}
-
-bool litehtml::html_tag::appendChild(const element::ptr &el)
-{
-	if(el)
-	{
-		el->parent(shared_from_this());
-		m_children.push_back(el);
-		return true;
-	}
-	return false;
-}
-
-bool litehtml::html_tag::removeChild(const element::ptr &el)
-{
-	if(el && el->parent() == shared_from_this())
-	{
-		el->parent(nullptr);
-		m_children.erase(std::remove(m_children.begin(), m_children.end(), el), m_children.end());
-		return true;
-	}
-	return false;
-}
-
-void litehtml::html_tag::clearRecursive()
-{
-	for(auto& el : m_children)
-	{
-		el->clearRecursive();
-		el->parent(nullptr);
-	}
-	m_children.clear();
-}
-
-
-const litehtml::tchar_t* litehtml::html_tag::get_tagName() const
-{
-	return m_tag.c_str();
-}
-
-void litehtml::html_tag::set_attr( const tchar_t* name, const tchar_t* val )
-{
-	if(name && val)
-	{
-		tstring s_val = name;
-		std::locale lc = std::locale::global(std::locale::classic());
-		for(size_t i = 0; i < s_val.length(); i++)
-		{
-			s_val[i] = std::tolower(s_val[i], lc);
-		}
-		m_attrs[s_val] = val;
-
-		if( t_strcasecmp( name, _t("class") ) == 0 )
-		{
-			m_class_values.resize( 0 );
-			split_string( val, m_class_values, _t(" ") );
-		}
-	}
-}
-
-const litehtml::tchar_t* litehtml::html_tag::get_attr( const tchar_t* name, const tchar_t* def )
-{
-	string_map::const_iterator attr = m_attrs.find(name);
-	if(attr != m_attrs.end())
-	{
-		return attr->second.c_str();
-	}
-	return def;
-}
-
-litehtml::elements_vector litehtml::html_tag::select_all( const tstring& selector )
-{
-	css_selector sel(media_query_list::ptr(0));
-	sel.parse(selector);
-	
-	return select_all(sel);
-}
-
-litehtml::elements_vector litehtml::html_tag::select_all( const css_selector& selector )
-{
-	litehtml::elements_vector res;
-	select_all(selector, res);
-	return res;
-}
-
-void litehtml::html_tag::select_all(const css_selector& selector, elements_vector& res)
-{
-	if(select(selector))
-	{
-		res.push_back(shared_from_this());
-	}
-	
-	for(auto& el : m_children)
-	{
-		el->select_all(selector, res);
-	}
-}
-
-
-litehtml::element::ptr litehtml::html_tag::select_one( const tstring& selector )
-{
-	css_selector sel(media_query_list::ptr(0));
-	sel.parse(selector);
-
-	return select_one(sel);
-}
-
-litehtml::element::ptr litehtml::html_tag::select_one( const css_selector& selector )
-{
-	if(select(selector))
-	{
-		return shared_from_this();
-	}
-
-	for(auto& el : m_children)
-	{
-		element::ptr res = el->select_one(selector);
-		if(res)
-		{
-			return res;
-		}
-	}
-	return 0;
-}
-
-void litehtml::html_tag::apply_stylesheet( const litehtml::css& stylesheet )
-{
-	remove_before_after();
-
-	for(const auto& sel : stylesheet.selectors())
-	{
-		int apply = select(*sel, false);
-
-		if(apply != select_no_match)
-		{
-			used_selector::ptr us = std::unique_ptr<used_selector>(new used_selector(sel, false));
-
-			if(sel->is_media_valid())
-			{
-				if(apply & select_match_pseudo_class)
-				{
-					if(select(*sel, true))
-					{
-						if(apply & select_match_with_after)
-						{
-							element::ptr el = get_element_after();
-							if(el)
-							{
-								el->add_style(*sel->m_style);
-							}
-						} else if(apply & select_match_with_before)
-						{
-							element::ptr el = get_element_before();
-							if(el)
-							{
-								el->add_style(*sel->m_style);
-							}
-						}
-						else
-						{
-							add_style(*sel->m_style);
-							us->m_used = true;
-						}
-					}
-				} else if(apply & select_match_with_after)
-				{
-					element::ptr el = get_element_after();
-					if(el)
-					{
-						el->add_style(*sel->m_style);
-					}
-				} else if(apply & select_match_with_before)
-				{
-					element::ptr el = get_element_before();
-					if(el)
-					{
-						el->add_style(*sel->m_style);
-					}
-				} else
-				{
-					add_style(*sel->m_style);
-					us->m_used = true;
-				}
-			}
-			m_used_styles.push_back(std::move(us));
-		}
-	}
-
-	for(auto& el : m_children)
-	{
-		if(el->get_display() != display_inline_text)
-		{
-			el->apply_stylesheet(stylesheet);
-		}
-	}
-}
-
-void litehtml::html_tag::get_content_size( size& sz, int max_width )
-{
-	sz.height	= 0;
-	if(m_display == display_block)
-	{
-		sz.width	= max_width;
-	} else
-	{
-		sz.width	= 0;
-	}
-}
-
-void litehtml::html_tag::draw( uint_ptr hdc, int x, int y, const position* clip )
-{
-	position pos = m_pos;
-	pos.x	+= x;
-	pos.y	+= y;
-
-	draw_background(hdc, x, y, clip);
-
-	if(m_display == display_list_item && m_list_style_type != list_style_type_none)
-	{
-		if(m_overflow > overflow_visible)
-		{
-			position border_box = pos;
-			border_box += m_padding;
-			border_box += m_borders;
-
-			border_radiuses bdr_radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
-
-			bdr_radius -= m_borders;
-			bdr_radius -= m_padding;
-
-			get_document()->container()->set_clip(pos, bdr_radius, true, true);
-		}
-
-		draw_list_marker(hdc, pos);
-
-		if(m_overflow > overflow_visible)
-		{
-			get_document()->container()->del_clip();
-		}
-	}
-}
-
-litehtml::uint_ptr litehtml::html_tag::get_font(font_metrics* fm)
-{
-	if(fm)
-	{
-		*fm = m_font_metrics;
-	}
-	return m_font;
-}
-
-const litehtml::tchar_t* litehtml::html_tag::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ )
-{
-	const tchar_t* ret = m_style.get_property(name);
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		if ( ( ret && !t_strcasecmp(ret, _t("inherit")) ) || (!ret && inherited) )
-		{
-			ret = el_parent->get_style_property(name, inherited, def);
-		}
-	}
-
-	if(!ret)
-	{
-		ret = def;
-	}
-
-	return ret;
-}
-
-void litehtml::html_tag::parse_styles(bool is_reparse)
-{
-	const tchar_t* style = get_attr(_t("style"));
-
-	if(style)
-	{
-		m_style.add(style, NULL);
-	}
-
-	init_font();
-	document::ptr doc = get_document();
-
-	m_el_position	= (element_position)	value_index(get_style_property(_t("position"),		false,	_t("static")),		element_position_strings,	element_position_fixed);
-	m_text_align	= (text_align)			value_index(get_style_property(_t("text-align"),		true,	_t("left")),		text_align_strings,			text_align_left);
-	m_overflow		= (overflow)			value_index(get_style_property(_t("overflow"),		false,	_t("visible")),		overflow_strings,			overflow_visible);
-	m_white_space	= (white_space)			value_index(get_style_property(_t("white-space"),	true,	_t("normal")),		white_space_strings,		white_space_normal);
-	m_display		= (style_display)		value_index(get_style_property(_t("display"),		false,	_t("inline")),		style_display_strings,		display_inline);
-	m_visibility	= (visibility)			value_index(get_style_property(_t("visibility"),	true,	_t("visible")),		visibility_strings,			visibility_visible);
-	m_box_sizing	= (box_sizing)			value_index(get_style_property(_t("box-sizing"),		false,	_t("content-box")),	box_sizing_strings,			box_sizing_content_box);
-
-	if(m_el_position != element_position_static)
-	{
-		const tchar_t* val = get_style_property(_t("z-index"), false, 0);
-		if(val)
-		{
-			m_z_index = t_atoi(val);
-		}
-	}
-
-	const tchar_t* va	= get_style_property(_t("vertical-align"), true,	_t("baseline"));
-	m_vertical_align = (vertical_align) value_index(va, vertical_align_strings, va_baseline);
-
-	const tchar_t* fl	= get_style_property(_t("float"), false,	_t("none"));
-	m_float = (element_float) value_index(fl, element_float_strings, float_none);
-
-	m_clear = (element_clear) value_index(get_style_property(_t("clear"), false, _t("none")), element_clear_strings, clear_none);
-
-	if (m_float != float_none)
-	{
-		// reset display in to block for floating elements
-		if (m_display != display_none)
-		{
-			m_display = display_block;
-		}
-	}
-	else if (m_display == display_table ||
-		m_display == display_table_caption ||
-		m_display == display_table_cell ||
-		m_display == display_table_column ||
-		m_display == display_table_column_group ||
-		m_display == display_table_footer_group ||
-		m_display == display_table_header_group ||
-		m_display == display_table_row ||
-		m_display == display_table_row_group)
-	{
-		doc->add_tabular(shared_from_this());
-	}
-	// fix inline boxes with absolute/fixed positions
-	else if (m_display != display_none && is_inline_box())
-	{
-		if (m_el_position == element_position_absolute || m_el_position == element_position_fixed)
-		{
-			m_display = display_block;
-		}
-	}
-
-	m_css_text_indent.fromString(	get_style_property(_t("text-indent"),	true,	_t("0")),	_t("0"));
-
-	m_css_width.fromString(			get_style_property(_t("width"),			false,	_t("auto")), _t("auto"));
-	m_css_height.fromString(		get_style_property(_t("height"),		false,	_t("auto")), _t("auto"));
-
-	doc->cvt_units(m_css_width, m_font_size);
-	doc->cvt_units(m_css_height, m_font_size);
-
-	m_css_min_width.fromString(		get_style_property(_t("min-width"),		false,	_t("0")));
-	m_css_min_height.fromString(	get_style_property(_t("min-height"),		false,	_t("0")));
-
-	m_css_max_width.fromString(		get_style_property(_t("max-width"),		false,	_t("none")),	_t("none"));
-	m_css_max_height.fromString(	get_style_property(_t("max-height"),		false,	_t("none")),	_t("none"));
-	
-	doc->cvt_units(m_css_min_width, m_font_size);
-	doc->cvt_units(m_css_min_height, m_font_size);
-
-	m_css_offsets.left.fromString(		get_style_property(_t("left"),				false,	_t("auto")), _t("auto"));
-	m_css_offsets.right.fromString(		get_style_property(_t("right"),				false,	_t("auto")), _t("auto"));
-	m_css_offsets.top.fromString(		get_style_property(_t("top"),				false,	_t("auto")), _t("auto"));
-	m_css_offsets.bottom.fromString(	get_style_property(_t("bottom"),			false,	_t("auto")), _t("auto"));
-
-	doc->cvt_units(m_css_offsets.left, m_font_size);
-	doc->cvt_units(m_css_offsets.right, m_font_size);
-	doc->cvt_units(m_css_offsets.top,		m_font_size);
-	doc->cvt_units(m_css_offsets.bottom,	m_font_size);
-
-	m_css_margins.left.fromString(		get_style_property(_t("margin-left"),		false,	_t("0")), _t("auto"));
-	m_css_margins.right.fromString(		get_style_property(_t("margin-right"),		false,	_t("0")), _t("auto"));
-	m_css_margins.top.fromString(		get_style_property(_t("margin-top"),			false,	_t("0")), _t("auto"));
-	m_css_margins.bottom.fromString(	get_style_property(_t("margin-bottom"),		false,	_t("0")), _t("auto"));
-
-	m_css_padding.left.fromString(		get_style_property(_t("padding-left"),		false,	_t("0")), _t(""));
-	m_css_padding.right.fromString(		get_style_property(_t("padding-right"),		false,	_t("0")), _t(""));
-	m_css_padding.top.fromString(		get_style_property(_t("padding-top"),		false,	_t("0")), _t(""));
-	m_css_padding.bottom.fromString(	get_style_property(_t("padding-bottom"),		false,	_t("0")), _t(""));
-
-	m_css_borders.left.width.fromString(	get_style_property(_t("border-left-width"),		false,	_t("medium")), border_width_strings);
-	m_css_borders.right.width.fromString(	get_style_property(_t("border-right-width"),		false,	_t("medium")), border_width_strings);
-	m_css_borders.top.width.fromString(		get_style_property(_t("border-top-width"),		false,	_t("medium")), border_width_strings);
-	m_css_borders.bottom.width.fromString(	get_style_property(_t("border-bottom-width"),	false,	_t("medium")), border_width_strings);
-
-	m_css_borders.left.color = web_color::from_string(get_style_property(_t("border-left-color"),	false,	_t("")));
-	m_css_borders.left.style = (border_style) value_index(get_style_property(_t("border-left-style"), false, _t("none")), border_style_strings, border_style_none);
-
-	m_css_borders.right.color = web_color::from_string(get_style_property(_t("border-right-color"),	false,	_t("")));
-	m_css_borders.right.style = (border_style) value_index(get_style_property(_t("border-right-style"), false, _t("none")), border_style_strings, border_style_none);
-
-	m_css_borders.top.color = web_color::from_string(get_style_property(_t("border-top-color"),	false,	_t("")));
-	m_css_borders.top.style = (border_style) value_index(get_style_property(_t("border-top-style"), false, _t("none")), border_style_strings, border_style_none);
-
-	m_css_borders.bottom.color = web_color::from_string(get_style_property(_t("border-bottom-color"),	false,	_t("")));
-	m_css_borders.bottom.style = (border_style) value_index(get_style_property(_t("border-bottom-style"), false, _t("none")), border_style_strings, border_style_none);
-
-	m_css_borders.radius.top_left_x.fromString(get_style_property(_t("border-top-left-radius-x"), false, _t("0")));
-	m_css_borders.radius.top_left_y.fromString(get_style_property(_t("border-top-left-radius-y"), false, _t("0")));
-
-	m_css_borders.radius.top_right_x.fromString(get_style_property(_t("border-top-right-radius-x"), false, _t("0")));
-	m_css_borders.radius.top_right_y.fromString(get_style_property(_t("border-top-right-radius-y"), false, _t("0")));
-
-	m_css_borders.radius.bottom_right_x.fromString(get_style_property(_t("border-bottom-right-radius-x"), false, _t("0")));
-	m_css_borders.radius.bottom_right_y.fromString(get_style_property(_t("border-bottom-right-radius-y"), false, _t("0")));
-
-	m_css_borders.radius.bottom_left_x.fromString(get_style_property(_t("border-bottom-left-radius-x"), false, _t("0")));
-	m_css_borders.radius.bottom_left_y.fromString(get_style_property(_t("border-bottom-left-radius-y"), false, _t("0")));
-
-	doc->cvt_units(m_css_borders.radius.bottom_left_x,			m_font_size);
-	doc->cvt_units(m_css_borders.radius.bottom_left_y,			m_font_size);
-	doc->cvt_units(m_css_borders.radius.bottom_right_x,			m_font_size);
-	doc->cvt_units(m_css_borders.radius.bottom_right_y,			m_font_size);
-	doc->cvt_units(m_css_borders.radius.top_left_x,				m_font_size);
-	doc->cvt_units(m_css_borders.radius.top_left_y,				m_font_size);
-	doc->cvt_units(m_css_borders.radius.top_right_x,				m_font_size);
-	doc->cvt_units(m_css_borders.radius.top_right_y,				m_font_size);
-
-	doc->cvt_units(m_css_text_indent,								m_font_size);
-
-	m_margins.left		= doc->cvt_units(m_css_margins.left,		m_font_size);
-	m_margins.right		= doc->cvt_units(m_css_margins.right,		m_font_size);
-	m_margins.top		= doc->cvt_units(m_css_margins.top,		m_font_size);
-	m_margins.bottom	= doc->cvt_units(m_css_margins.bottom,	m_font_size);
-
-	m_padding.left		= doc->cvt_units(m_css_padding.left,		m_font_size);
-	m_padding.right		= doc->cvt_units(m_css_padding.right,		m_font_size);
-	m_padding.top		= doc->cvt_units(m_css_padding.top,		m_font_size);
-	m_padding.bottom	= doc->cvt_units(m_css_padding.bottom,	m_font_size);
-
-	m_borders.left		= doc->cvt_units(m_css_borders.left.width,	m_font_size);
-	m_borders.right		= doc->cvt_units(m_css_borders.right.width,	m_font_size);
-	m_borders.top		= doc->cvt_units(m_css_borders.top.width,		m_font_size);
-	m_borders.bottom	= doc->cvt_units(m_css_borders.bottom.width,	m_font_size);
-
-	css_length line_height;
-	line_height.fromString(get_style_property(_t("line-height"),	true,	_t("normal")), _t("normal"));
-	if(line_height.is_predefined())
-	{
-		m_line_height = m_font_metrics.height;
-		m_lh_predefined = true;
-	} else if(line_height.units() == css_units_none)
-	{
-		m_line_height = (int) (line_height.val() * m_font_size);
-		m_lh_predefined = false;
-	} else
-	{
-		m_line_height =  doc->cvt_units(line_height,	m_font_size, m_font_size);
-		m_lh_predefined = false;
-	}
-
-
-	if(m_display == display_list_item)
-	{
-		const tchar_t* list_type = get_style_property(_t("list-style-type"), true, _t("disc"));
-		m_list_style_type = (list_style_type) value_index(list_type, list_style_type_strings, list_style_type_disc);
-
-		const tchar_t* list_pos = get_style_property(_t("list-style-position"), true, _t("outside"));
-		m_list_style_position = (list_style_position) value_index(list_pos, list_style_position_strings, list_style_position_outside);
-
-		const tchar_t* list_image = get_style_property(_t("list-style-image"), true, 0);
-		if(list_image && list_image[0])
-		{
-			tstring url;
-			css::parse_css_url(list_image, url);
-
-			const tchar_t* list_image_baseurl = get_style_property(_t("list-style-image-baseurl"), true, 0);
-			doc->container()->load_image(url.c_str(), list_image_baseurl, true);
-		}
-
-	}
-
-	parse_background();
-
-	if(!is_reparse)
-	{
-		for(auto& el : m_children)
-		{
-			el->parse_styles();
-		}
-	}
-}
-
-int litehtml::html_tag::render( int x, int y, int max_width, bool second_pass )
-{
-	if (m_display == display_table || m_display == display_inline_table)
-	{
-		return render_table(x, y, max_width, second_pass);
-	}
-
-	return render_box(x, y, max_width, second_pass);
-}
-
-bool litehtml::html_tag::is_white_space() const
-{
-	return false;
-}
-
-int litehtml::html_tag::get_font_size() const
-{
-	return m_font_size;
-}
-
-int litehtml::html_tag::get_base_line()
-{
-	if(is_replaced())
-	{
-		return 0;
-	}
-	int bl = 0;
-	if(!m_boxes.empty())
-	{
-		bl = m_boxes.back()->baseline() + content_margins_bottom();
-	}
-	return bl;
-}
-
-void litehtml::html_tag::init()
-{
-	if (m_display == display_table || m_display == display_inline_table)
-	{
-		if (m_grid)
-		{
-			m_grid->clear();
-		}
-		else
-		{
-			m_grid = std::unique_ptr<table_grid>(new table_grid());
-		}
-
-		go_inside_table 		table_selector;
-		table_rows_selector		row_selector;
-		table_cells_selector	cell_selector;
-
-		elements_iterator row_iter(shared_from_this(), &table_selector, &row_selector);
-
-		element::ptr row = row_iter.next(false);
-		while (row)
-		{
-			m_grid->begin_row(row);
-
-			elements_iterator cell_iter(row, &table_selector, &cell_selector);
-			element::ptr cell = cell_iter.next();
-			while (cell)
-			{
-				m_grid->add_cell(cell);
-
-				cell = cell_iter.next(false);
-			}
-			row = row_iter.next(false);
-		}
-
-		m_grid->finish();
-	}
-
-	for (auto& el : m_children)
-	{
-		el->init();
-	}
-}
-
-int litehtml::html_tag::select(const css_selector& selector, bool apply_pseudo)
-{
-	int right_res = select(selector.m_right, apply_pseudo);
-	if(right_res == select_no_match)
-	{
-		return select_no_match;
-	}
-	element::ptr el_parent = parent();
-	if(selector.m_left)
-	{
-		if (!el_parent)
-		{
-			return select_no_match;
-		}
-		switch(selector.m_combinator)
-		{
-		case combinator_descendant:
-			{
-				bool is_pseudo = false;
-				element::ptr res = find_ancestor(*selector.m_left, apply_pseudo, &is_pseudo);
-				if(!res)
-				{
-					return select_no_match;
-				} else
-				{
-					if(is_pseudo)
-					{
-						right_res |= select_match_pseudo_class;
-					}
-				}
-			}
-			break;
-		case combinator_child:
-			{
-				int res = el_parent->select(*selector.m_left, apply_pseudo);
-				if(res == select_no_match)
-				{
-					return select_no_match;
-				} else
-				{
-					if(right_res != select_match_pseudo_class)
-					{
-						right_res |= res;
-					}
-				}
-			}
-			break;
-		case combinator_adjacent_sibling:
-			{
-				bool is_pseudo = false;
-				element::ptr res = el_parent->find_adjacent_sibling(shared_from_this(), *selector.m_left, apply_pseudo, &is_pseudo);
-				if(!res)
-				{
-					return select_no_match;
-				} else
-				{
-					if(is_pseudo)
-					{
-						right_res |= select_match_pseudo_class;
-					}
-				}
-			}
-			break;
-		case combinator_general_sibling:
-			{
-				bool is_pseudo = false;
-				element::ptr res =  el_parent->find_sibling(shared_from_this(), *selector.m_left, apply_pseudo, &is_pseudo);
-				if(!res)
-				{
-					return select_no_match;
-				} else
-				{
-					if(is_pseudo)
-					{
-						right_res |= select_match_pseudo_class;
-					}
-				}
-			}
-			break;
-		default:
-			right_res = select_no_match;
-		}
-	}
-	return right_res;
-}
-
-int litehtml::html_tag::select(const css_element_selector& selector, bool apply_pseudo)
-{
-	if(!selector.m_tag.empty() && selector.m_tag != _t("*"))
-	{
-		if(selector.m_tag != m_tag)
-		{
-			return select_no_match;
-		}
-	}
-
-	int res = select_match;
-	element::ptr el_parent = parent();
-
-	for(css_attribute_selector::vector::const_iterator i = selector.m_attrs.begin(); i != selector.m_attrs.end(); i++)
-	{
-		const tchar_t* attr_value = get_attr(i->attribute.c_str());
-		switch(i->condition)
-		{
-		case select_exists:
-			if(!attr_value)
-			{
-				return select_no_match;
-			}
-			break;
-		case select_equal:
-			if(!attr_value)
-			{
-				return select_no_match;
-			} else 
-			{
-				if(i->attribute == _t("class"))
-				{
-					const string_vector & tokens1 = m_class_values;
-					const string_vector & tokens2 = i->class_val;
-					bool found = true;
-					for(string_vector::const_iterator str1 = tokens2.begin(); str1 != tokens2.end() && found; str1++)
-					{
-						bool f = false;
-						for(string_vector::const_iterator str2 = tokens1.begin(); str2 != tokens1.end() && !f; str2++)
-						{
-							if( !t_strcasecmp(str1->c_str(), str2->c_str()) )
-							{
-								f = true;
-							}
-						}
-						if(!f)
-						{
-							found = false;
-						}
-					}
-					if(!found)
-					{
-						return select_no_match;
-					}
-				} else
-				{
-					if( t_strcasecmp(i->val.c_str(), attr_value) )
-					{
-						return select_no_match;
-					}
-				}
-			}
-			break;
-		case select_contain_str:
-			if(!attr_value)
-			{
-				return select_no_match;
-			} else if(!t_strstr(attr_value, i->val.c_str()))
-			{
-				return select_no_match;
-			}
-			break;
-		case select_start_str:
-			if(!attr_value)
-			{
-				return select_no_match;
-			} else if(t_strncmp(attr_value, i->val.c_str(), i->val.length()))
-			{
-				return select_no_match;
-			}
-			break;
-		case select_end_str:
-			if(!attr_value)
-			{
-				return select_no_match;
-			} else if(t_strncmp(attr_value, i->val.c_str(), i->val.length()))
-			{
-				const tchar_t* s = attr_value + t_strlen(attr_value) - i->val.length() - 1;
-				if(s < attr_value)
-				{
-					return select_no_match;
-				}
-				if(i->val != s)
-				{
-					return select_no_match;
-				}
-			}
-			break;
-		case select_pseudo_element:
-			if(i->val == _t("after"))
-			{
-				res |= select_match_with_after;
-			} else if(i->val == _t("before"))
-			{
-				res |= select_match_with_before;
-			} else
-			{
-				return select_no_match;
-			}
-			break;
-		case select_pseudo_class:
-			if(apply_pseudo)
-			{
-				if (!el_parent) return select_no_match;
-
-				tstring selector_param;
-				tstring	selector_name;
-
-				tstring::size_type begin	= i->val.find_first_of(_t('('));
-				tstring::size_type end		= (begin == tstring::npos) ? tstring::npos : find_close_bracket(i->val, begin);
-				if(begin != tstring::npos && end != tstring::npos)
-				{
-					selector_param = i->val.substr(begin + 1, end - begin - 1);
-				}
-				if(begin != tstring::npos)
-				{
-					selector_name = i->val.substr(0, begin);
-					litehtml::trim(selector_name);
-				} else
-				{
-					selector_name = i->val;
-				}
-
-				int selector = value_index(selector_name.c_str(), pseudo_class_strings);
-				
-				switch(selector)
-				{
-				case pseudo_class_only_child:
-					if (!el_parent->is_only_child(shared_from_this(), false))
-					{
-						return select_no_match;
-					}
-					break;
-				case pseudo_class_only_of_type:
-					if (!el_parent->is_only_child(shared_from_this(), true))
-					{
-						return select_no_match;
-					}
-					break;
-				case pseudo_class_first_child:
-					if (!el_parent->is_nth_child(shared_from_this(), 0, 1, false))
-					{
-						return select_no_match;
-					}
-					break;
-				case pseudo_class_first_of_type:
-					if (!el_parent->is_nth_child(shared_from_this(), 0, 1, true))
-					{
-						return select_no_match;
-					}
-					break;
-				case pseudo_class_last_child:
-					if (!el_parent->is_nth_last_child(shared_from_this(), 0, 1, false))
-					{
-						return select_no_match;
-					}
-					break;
-				case pseudo_class_last_of_type:
-					if (!el_parent->is_nth_last_child(shared_from_this(), 0, 1, true))
-					{
-						return select_no_match;
-					}
-					break;
-				case pseudo_class_nth_child:
-				case pseudo_class_nth_of_type:
-				case pseudo_class_nth_last_child:
-				case pseudo_class_nth_last_of_type:
-					{
-						if(selector_param.empty()) return select_no_match;
-
-						int num = 0;
-						int off = 0;
-
-						parse_nth_child_params(selector_param, num, off);
-						if(!num && !off) return select_no_match;
-						switch(selector)
-						{
-						case pseudo_class_nth_child:
-							if (!el_parent->is_nth_child(shared_from_this(), num, off, false))
-							{
-								return select_no_match;
-							}
-							break;
-						case pseudo_class_nth_of_type:
-							if (!el_parent->is_nth_child(shared_from_this(), num, off, true))
-							{
-								return select_no_match;
-							}
-							break;
-						case pseudo_class_nth_last_child:
-							if (!el_parent->is_nth_last_child(shared_from_this(), num, off, false))
-							{
-								return select_no_match;
-							}
-							break;
-						case pseudo_class_nth_last_of_type:
-							if (!el_parent->is_nth_last_child(shared_from_this(), num, off, true))
-							{
-								return select_no_match;
-							}
-							break;
-						}
-
-					}
-					break;
-				case pseudo_class_not:
-					{
-						css_element_selector sel;
-						sel.parse(selector_param);
-						if(select(sel, apply_pseudo))
-						{
-							return select_no_match;
-						}
-					}
-					break;
-				case pseudo_class_lang:
-					{
-						trim( selector_param );
-
-						if( !get_document()->match_lang( selector_param ) )
-						{
-							return select_no_match;
-						}
-					}
-					break;
-				default:
-					if(std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), i->val) == m_pseudo_classes.end())
-					{
-						return select_no_match;
-					}
-					break;
-				}
-			} else
-			{
-				res |= select_match_pseudo_class;
-			}
-			break;
-		}
-	}
-	return res;
-}
-
-litehtml::element::ptr litehtml::html_tag::find_ancestor(const css_selector& selector, bool apply_pseudo, bool* is_pseudo)
-{
-	element::ptr el_parent = parent();
-	if (!el_parent)
-	{
-		return nullptr;
-	}
-	int res = el_parent->select(selector, apply_pseudo);
-	if(res != select_no_match)
-	{
-		if(is_pseudo)
-		{
-			if(res & select_match_pseudo_class)
-			{
-				*is_pseudo = true;
-			} else
-			{
-				*is_pseudo = false;
-			}
-		}
-		return el_parent;
-	}
-	return el_parent->find_ancestor(selector, apply_pseudo, is_pseudo);
-}
-
-int litehtml::html_tag::get_floats_height(element_float el_float) const
-{
-	if(is_floats_holder())
-	{
-		int h = 0;
-
-		bool process = false;
-
-		for(const auto& fb : m_floats_left)
-		{
-			process = false;
-			switch(el_float)
-			{
-			case float_none:
-				process = true;
-				break;
-			case float_left:
-				if (fb.clear_floats == clear_left || fb.clear_floats == clear_both)
-				{
-					process = true;
-				}
-				break;
-			case float_right:
-				if (fb.clear_floats == clear_right || fb.clear_floats == clear_both)
-				{
-					process = true;
-				}
-				break;
-			}
-			if(process)
-			{
-				if(el_float == float_none)
-				{
-					h = std::max(h, fb.pos.bottom());
-				} else
-				{
-					h = std::max(h, fb.pos.top());
-				}
-			}
-		}
-
-
-		for(const auto fb : m_floats_right)
-		{
-			process = false;
-			switch(el_float)
-			{
-			case float_none:
-				process = true;
-				break;
-			case float_left:
-				if (fb.clear_floats == clear_left || fb.clear_floats == clear_both)
-				{
-					process = true;
-				}
-				break;
-			case float_right:
-				if (fb.clear_floats == clear_right || fb.clear_floats == clear_both)
-				{
-					process = true;
-				}
-				break;
-			}
-			if(process)
-			{
-				if(el_float == float_none)
-				{
-					h = std::max(h, fb.pos.bottom());
-				} else
-				{
-					h = std::max(h, fb.pos.top());
-				}
-			}
-		}
-
-		return h;
-	}
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		int h = el_parent->get_floats_height(el_float);
-		return h - m_pos.y;
-	}
-	return 0;
-}
-
-int litehtml::html_tag::get_left_floats_height() const
-{
-	if(is_floats_holder())
-	{
-		int h = 0;
-		if(!m_floats_left.empty())
-		{
-			for (const auto& fb : m_floats_left)
-			{
-				h = std::max(h, fb.pos.bottom());
-			}
-		}
-		return h;
-	}
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		int h = el_parent->get_left_floats_height();
-		return h - m_pos.y;
-	}
-	return 0;
-}
-
-int litehtml::html_tag::get_right_floats_height() const
-{
-	if(is_floats_holder())
-	{
-		int h = 0;
-		if(!m_floats_right.empty())
-		{
-			for(const auto& fb : m_floats_right)
-			{
-				h = std::max(h, fb.pos.bottom());
-			}
-		}
-		return h;
-	}
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		int h = el_parent->get_right_floats_height();
-		return h - m_pos.y;
-	}
-	return 0;
-}
-
-int litehtml::html_tag::get_line_left( int y )
-{
-	if(is_floats_holder())
-	{
-		if(m_cahe_line_left.is_valid && m_cahe_line_left.hash == y)
-		{
-			return m_cahe_line_left.val;
-		}
-
-		int w = 0;
-		for(const auto& fb : m_floats_left)
-		{
-			if (y >= fb.pos.top() && y < fb.pos.bottom())
-			{
-				w = std::max(w, fb.pos.right());
-				if (w < fb.pos.right())
-				{
-					break;
-				}
-			}
-		}
-		m_cahe_line_left.set_value(y, w);
-		return w;
-	}
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		int w = el_parent->get_line_left(y + m_pos.y);
-		if (w < 0)
-		{
-			w = 0;
-		}
-		return w - (w ? m_pos.x : 0);
-	}
-	return 0;
-}
-
-int litehtml::html_tag::get_line_right( int y, int def_right )
-{
-	if(is_floats_holder())
-	{
-		if(m_cahe_line_right.is_valid && m_cahe_line_right.hash == y)
-		{
-			if(m_cahe_line_right.is_default)
-			{
-				return def_right;
-			} else
-			{
-				return std::min(m_cahe_line_right.val, def_right);
-			}
-		}
-
-		int w = def_right;
-		m_cahe_line_right.is_default = true;
-		for(const auto& fb : m_floats_right)
-		{
-			if(y >= fb.pos.top() && y < fb.pos.bottom())
-			{
-				w = std::min(w, fb.pos.left());
-				m_cahe_line_right.is_default = false;
-				if(w > fb.pos.left())
-				{
-					break;
-				}
-			}
-		}
-		m_cahe_line_right.set_value(y, w);
-		return w;
-	}
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		int w = el_parent->get_line_right(y + m_pos.y, def_right + m_pos.x);
-		return w - m_pos.x;
-	}
-	return 0;
-}
-
-
-void litehtml::html_tag::get_line_left_right( int y, int def_right, int& ln_left, int& ln_right )
-{
-	if(is_floats_holder())
-	{
-		ln_left		= get_line_left(y);
-		ln_right	= get_line_right(y, def_right);
-	} else
-	{
-		element::ptr el_parent = parent();
-		if (el_parent)
-		{
-			el_parent->get_line_left_right(y + m_pos.y, def_right + m_pos.x, ln_left, ln_right);
-		}
-		ln_right -= m_pos.x;
-		ln_left -= m_pos.x;
-
-		if(ln_left < 0)
-		{
-			ln_left = 0;
-		}
-	}
-}
-
-int litehtml::html_tag::fix_line_width( int max_width, element_float flt )
-{
-	int ret_width = 0;
-	if(!m_boxes.empty())
-	{
-		elements_vector els;
-		m_boxes.back()->get_elements(els);
-		bool was_cleared = false;
-		if(!els.empty() && els.front()->get_clear() != clear_none)
-		{
-			if(els.front()->get_clear() == clear_both)
-			{
-				was_cleared = true;
-			} else
-			{
-				if(	(flt == float_left	&& els.front()->get_clear() == clear_left) ||
-					(flt == float_right	&& els.front()->get_clear() == clear_right) )
-				{
-					was_cleared = true;
-				}
-			}
-		}
-
-		if(!was_cleared)
-		{
-			m_boxes.pop_back();
-
-			for(elements_vector::iterator i = els.begin(); i != els.end(); i++)
-			{
-				int rw = place_element((*i), max_width);
-				if(rw > ret_width)
-				{
-					ret_width = rw;
-				}
-			}
-		} else
-		{
-			int line_top = 0;
-			if(m_boxes.back()->get_type() == box_line)
-			{
-				line_top = m_boxes.back()->top();
-			} else
-			{
-				line_top = m_boxes.back()->bottom();
-			}
-
-			int line_left	= 0;
-			int line_right	= max_width;
-			get_line_left_right(line_top, max_width, line_left, line_right);
-
-			if(m_boxes.back()->get_type() == box_line)
-			{
-				if(m_boxes.size() == 1 && m_list_style_type != list_style_type_none && m_list_style_position == list_style_position_inside)
-				{
-					int sz_font = get_font_size();
-					line_left += sz_font;
-				}
-
-				if(m_css_text_indent.val() != 0)
-				{
-					bool line_box_found = false;
-					for(box::vector::iterator iter = m_boxes.begin(); iter < m_boxes.end(); iter++)
-					{
-						if((*iter)->get_type() == box_line)
-						{
-							line_box_found = true;
-							break;
-						}
-					}
-					if(!line_box_found)
-					{
-						line_left += m_css_text_indent.calc_percent(max_width);
-					}
-				}
-
-			}
-
-			elements_vector els;
-			m_boxes.back()->new_width(line_left, line_right, els);
-			for(auto& el : els)
-			{
-				int rw = place_element(el, max_width);
-				if(rw > ret_width)
-				{
-					ret_width = rw;
-				}
-			}
-		}
-	}
-
-	return ret_width;
-}
-
-void litehtml::html_tag::add_float(const element::ptr &el, int x, int y)
-{
-	if(is_floats_holder())
-	{
-		floated_box fb;
-		fb.pos.x		= el->left() + x;
-		fb.pos.y		= el->top()  + y;
-		fb.pos.width	= el->width();
-		fb.pos.height	= el->height();
-		fb.float_side	= el->get_float();
-		fb.clear_floats	= el->get_clear();
-		fb.el			= el;
-
-		if(fb.float_side == float_left)
-		{
-			if(m_floats_left.empty())
-			{
-				m_floats_left.push_back(fb);
-			} else
-			{
-				bool inserted = false;
-				for(floated_box::vector::iterator i = m_floats_left.begin(); i != m_floats_left.end(); i++)
-				{
-					if(fb.pos.right() > i->pos.right())
-					{
-						m_floats_left.insert(i, std::move(fb));
-						inserted = true;
-						break;
-					}
-				}
-				if(!inserted)
-				{
-					m_floats_left.push_back(std::move(fb));
-				}
-			}
-			m_cahe_line_left.invalidate();
-		} else if(fb.float_side == float_right)
-		{
-			if(m_floats_right.empty())
-			{
-				m_floats_right.push_back(std::move(fb));
-			} else
-			{
-				bool inserted = false;
-				for(floated_box::vector::iterator i = m_floats_right.begin(); i != m_floats_right.end(); i++)
-				{
-					if(fb.pos.left() < i->pos.left())
-					{
-						m_floats_right.insert(i, std::move(fb));
-						inserted = true;
-						break;
-					}
-				}
-				if(!inserted)
-				{
-					m_floats_right.push_back(fb);
-				}
-			}
-			m_cahe_line_right.invalidate();
-		}
-	} else
-	{
-		element::ptr el_parent = parent();
-		if (el_parent)
-		{
-			el_parent->add_float(el, x + m_pos.x, y + m_pos.y);
-		}
-	}
-}
-
-int litehtml::html_tag::find_next_line_top( int top, int width, int def_right )
-{
-	if(is_floats_holder())
-	{
-		int new_top = top;
-		int_vector points;
-
-		for(const auto& fb : m_floats_left)
-		{
-			if(fb.pos.top() >= top)
-			{
-				if(find(points.begin(), points.end(), fb.pos.top()) == points.end())
-				{
-					points.push_back(fb.pos.top());
-				}
-			}
-			if (fb.pos.bottom() >= top)
-			{
-				if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end())
-				{
-					points.push_back(fb.pos.bottom());
-				}
-			}
-		}
-
-		for (const auto& fb : m_floats_right)
-		{
-			if (fb.pos.top() >= top)
-			{
-				if (find(points.begin(), points.end(), fb.pos.top()) == points.end())
-				{
-					points.push_back(fb.pos.top());
-				}
-			}
-			if (fb.pos.bottom() >= top)
-			{
-				if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end())
-				{
-					points.push_back(fb.pos.bottom());
-				}
-			}
-		}
-
-		if(!points.empty())
-		{
-			sort(points.begin(), points.end(), std::less<int>( ));
-			new_top = points.back();
-
-			for(auto pt : points)
-			{
-				int pos_left	= 0;
-				int pos_right	= def_right;
-				get_line_left_right(pt, def_right, pos_left, pos_right);
-
-				if(pos_right - pos_left >= width)
-				{
-					new_top = pt;
-					break;
-				}
-			}
-		}
-		return new_top;
-	}
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		int new_top = el_parent->find_next_line_top(top + m_pos.y, width, def_right + m_pos.x);
-		return new_top - m_pos.y;
-	}
-	return 0;
-}
-
-void litehtml::html_tag::parse_background()
-{
-	// parse background-color
-	m_bg.m_color		= get_color(_t("background-color"), false, web_color(0, 0, 0, 0));
-
-	// parse background-position
-	const tchar_t* str = get_style_property(_t("background-position"), false, _t("0% 0%"));
-	if(str)
-	{
-		string_vector res;
-		split_string(str, res, _t(" \t"));
-		if(res.size() > 0)
-		{
-			if(res.size() == 1)
-			{
-				if( value_in_list(res[0].c_str(), _t("left;right;center")) )
-				{
-					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
-					m_bg.m_position.y.set_value(50, css_units_percentage);
-				} else if( value_in_list(res[0].c_str(), _t("top;bottom;center")) )
-				{
-					m_bg.m_position.y.fromString(res[0], _t("top;bottom;center"));
-					m_bg.m_position.x.set_value(50, css_units_percentage);
-				} else
-				{
-					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
-					m_bg.m_position.y.set_value(50, css_units_percentage);
-				}
-			} else
-			{
-				if(value_in_list(res[0].c_str(), _t("left;right")))
-				{
-					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
-					m_bg.m_position.y.fromString(res[1], _t("top;bottom;center"));
-				} else if(value_in_list(res[0].c_str(), _t("top;bottom")))
-				{
-					m_bg.m_position.x.fromString(res[1], _t("left;right;center"));
-					m_bg.m_position.y.fromString(res[0], _t("top;bottom;center"));
-				} else if(value_in_list(res[1].c_str(), _t("left;right")))
-				{
-					m_bg.m_position.x.fromString(res[1], _t("left;right;center"));
-					m_bg.m_position.y.fromString(res[0], _t("top;bottom;center"));
-				}else if(value_in_list(res[1].c_str(), _t("top;bottom")))
-				{
-					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
-					m_bg.m_position.y.fromString(res[1], _t("top;bottom;center"));
-				} else
-				{
-					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
-					m_bg.m_position.y.fromString(res[1], _t("top;bottom;center"));
-				}
-			}
-
-			if(m_bg.m_position.x.is_predefined())
-			{
-				switch(m_bg.m_position.x.predef())
-				{
-				case 0:
-					m_bg.m_position.x.set_value(0, css_units_percentage);
-					break;
-				case 1:
-					m_bg.m_position.x.set_value(100, css_units_percentage);
-					break;
-				case 2:
-					m_bg.m_position.x.set_value(50, css_units_percentage);
-					break;
-				}
-			}
-			if(m_bg.m_position.y.is_predefined())
-			{
-				switch(m_bg.m_position.y.predef())
-				{
-				case 0:
-					m_bg.m_position.y.set_value(0, css_units_percentage);
-					break;
-				case 1:
-					m_bg.m_position.y.set_value(100, css_units_percentage);
-					break;
-				case 2:
-					m_bg.m_position.y.set_value(50, css_units_percentage);
-					break;
-				}
-			}
-		} else
-		{
-			m_bg.m_position.x.set_value(0, css_units_percentage);
-			m_bg.m_position.y.set_value(0, css_units_percentage);
-		}
-	} else
-	{
-		m_bg.m_position.y.set_value(0, css_units_percentage);
-		m_bg.m_position.x.set_value(0, css_units_percentage);
-	}
-
-	str = get_style_property(_t("background-size"), false, _t("auto"));
-	if(str)
-	{
-		string_vector res;
-		split_string(str, res, _t(" \t"));
-		if(!res.empty())
-		{
-			m_bg.m_position.width.fromString(res[0], background_size_strings);
-			if(res.size() > 1)
-			{
-				m_bg.m_position.height.fromString(res[1], background_size_strings);
-			} else
-			{
-				m_bg.m_position.height.predef(background_size_auto);
-			}
-		} else
-		{
-			m_bg.m_position.width.predef(background_size_auto);
-			m_bg.m_position.height.predef(background_size_auto);
-		}
-	}
-
-	document::ptr doc = get_document();
-
-	doc->cvt_units(m_bg.m_position.x,		m_font_size);
-	doc->cvt_units(m_bg.m_position.y,		m_font_size);
-	doc->cvt_units(m_bg.m_position.width,	m_font_size);
-	doc->cvt_units(m_bg.m_position.height,	m_font_size);
-
-	// parse background_attachment
-	m_bg.m_attachment = (background_attachment) value_index(
-		get_style_property(_t("background-attachment"), false, _t("scroll")), 
-		background_attachment_strings, 
-		background_attachment_scroll);
-
-	// parse background_attachment
-	m_bg.m_repeat = (background_repeat) value_index(
-		get_style_property(_t("background-repeat"), false, _t("repeat")), 
-		background_repeat_strings, 
-		background_repeat_repeat);
-
-	// parse background_clip
-	m_bg.m_clip = (background_box) value_index(
-		get_style_property(_t("background-clip"), false, _t("border-box")), 
-		background_box_strings, 
-		background_box_border);
-
-	// parse background_origin
-	m_bg.m_origin = (background_box) value_index(
-		get_style_property(_t("background-origin"), false, _t("padding-box")), 
-		background_box_strings, 
-		background_box_content);
-
-	// parse background-image
-	css::parse_css_url(get_style_property(_t("background-image"), false, _t("")), m_bg.m_image);
-	m_bg.m_baseurl = get_style_property(_t("background-image-baseurl"), false, _t(""));
-
-	if(!m_bg.m_image.empty())
-	{
-		doc->container()->load_image(m_bg.m_image.c_str(), m_bg.m_baseurl.empty() ? 0 : m_bg.m_baseurl.c_str(), true);
-	}
-}
-
-void litehtml::html_tag::add_positioned(const element::ptr &el)
-{
-	if (m_el_position != element_position_static || (!have_parent()))
-	{
-		m_positioned.push_back(el);
-	} else
-	{
-		element::ptr el_parent = parent();
-		if (el_parent)
-		{
-			el_parent->add_positioned(el);
-		}
-	}
-}
-
-void litehtml::html_tag::calc_outlines( int parent_width )
-{
-	m_padding.left	= m_css_padding.left.calc_percent(parent_width);
-	m_padding.right	= m_css_padding.right.calc_percent(parent_width);
-
-	m_borders.left	= m_css_borders.left.width.calc_percent(parent_width);
-	m_borders.right	= m_css_borders.right.width.calc_percent(parent_width);
-
-	m_margins.left	= m_css_margins.left.calc_percent(parent_width);
-	m_margins.right	= m_css_margins.right.calc_percent(parent_width);
-
-	m_margins.top		= m_css_margins.top.calc_percent(parent_width);
-	m_margins.bottom	= m_css_margins.bottom.calc_percent(parent_width);
-
-	m_padding.top		= m_css_padding.top.calc_percent(parent_width);
-	m_padding.bottom	= m_css_padding.bottom.calc_percent(parent_width);
-}
-
-void litehtml::html_tag::calc_auto_margins(int parent_width)
-{
-	if (get_element_position() != element_position_absolute && (m_display == display_block || m_display == display_table))
-	{
-		if (m_css_margins.left.is_predefined() && m_css_margins.right.is_predefined())
-		{
-			int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right;
-			if (el_width <= parent_width)
-			{
-				m_margins.left = (parent_width - el_width) / 2;
-				m_margins.right = (parent_width - el_width) - m_margins.left;
-			}
-			else
-			{
-				m_margins.left = 0;
-				m_margins.right = 0;
-			}
-		}
-		else if (m_css_margins.left.is_predefined() && !m_css_margins.right.is_predefined())
-		{
-			int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right + m_margins.right;
-			m_margins.left = parent_width - el_width;
-			if (m_margins.left < 0) m_margins.left = 0;
-		}
-		else if (!m_css_margins.left.is_predefined() && m_css_margins.right.is_predefined())
-		{
-			int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right + m_margins.left;
-			m_margins.right = parent_width - el_width;
-			if (m_margins.right < 0) m_margins.right = 0;
-		}
-	}
-}
-
-void litehtml::html_tag::parse_attributes()
-{
-	for(auto& el : m_children)
-	{
-		el->parse_attributes();
-	}
-}
-
-void litehtml::html_tag::get_text( tstring& text )
-{
-	for (auto& el : m_children)
-	{
-		el->get_text(text);
-	}
-}
-
-bool litehtml::html_tag::is_body()  const
-{
-	return false;
-}
-
-void litehtml::html_tag::set_data( const tchar_t* data )
-{
-
-}
-
-void litehtml::html_tag::get_inline_boxes( position::vector& boxes )
-{
-	litehtml::box* old_box = 0;
-	position pos;
-	for(auto& el : m_children)
-	{
-		if(!el->skip())
-		{
-			if(el->m_box)
-			{
-				if(el->m_box != old_box)
-				{
-					if(old_box)
-					{
-						if(boxes.empty())
-						{
-							pos.x		-= m_padding.left + m_borders.left;
-							pos.width	+= m_padding.left + m_borders.left;
-						}
-						boxes.push_back(pos);
-					}
-					old_box		= el->m_box;
-					pos.x		= el->left() + el->margin_left();
-					pos.y		= el->top() - m_padding.top - m_borders.top;
-					pos.width	= 0;
-					pos.height	= 0;
-				}
-				pos.width	= el->right() - pos.x - el->margin_right() - el->margin_left();
-				pos.height	= std::max(pos.height, el->height() + m_padding.top + m_padding.bottom + m_borders.top + m_borders.bottom);
-			} else if(el->get_display() == display_inline)
-			{
-				position::vector sub_boxes;
-				el->get_inline_boxes(sub_boxes);
-				if(!sub_boxes.empty())
-				{
-					sub_boxes.rbegin()->width += el->margin_right();
-					if(boxes.empty())
-					{
-						if(m_padding.left + m_borders.left > 0)
-						{
-							position padding_box = (*sub_boxes.begin());
-							padding_box.x		-= m_padding.left + m_borders.left + el->margin_left();
-							padding_box.width	= m_padding.left + m_borders.left + el->margin_left();
-							boxes.push_back(padding_box);
-						}
-					}
-
-					sub_boxes.rbegin()->width += el->margin_right();
-
-					boxes.insert(boxes.end(), sub_boxes.begin(), sub_boxes.end());
-				}
-			}
-		}
-	}
-	if(pos.width || pos.height)
-	{
-		if(boxes.empty())
-		{
-			pos.x		-= m_padding.left + m_borders.left;
-			pos.width	+= m_padding.left + m_borders.left;
-		}
-		boxes.push_back(pos);
-	}
-	if(!boxes.empty())
-	{
-		if(m_padding.right + m_borders.right > 0)
-		{
-			boxes.back().width += m_padding.right + m_borders.right;
-		}
-	}
-}
-
-bool litehtml::html_tag::on_mouse_over()
-{
-	bool ret = false;
-
-	element::ptr el = shared_from_this();
-	while(el)
-	{
-		if(el->set_pseudo_class(_t("hover"), true))
-		{
-			ret = true;
-		}
-		el = el->parent();
-	}
-
-	return ret;
-}
-
-bool litehtml::html_tag::find_styles_changes( position::vector& redraw_boxes, int x, int y )
-{
-	if(m_display == display_inline_text)
-	{
-		return false;
-	}
-
-	bool ret = false;
-	bool apply = false;
-	for (used_selector::vector::iterator iter = m_used_styles.begin(); iter != m_used_styles.end() && !apply; iter++)
-	{
-		if((*iter)->m_selector->is_media_valid())
-		{
-			int res = select(*((*iter)->m_selector), true);
-			if( (res == select_no_match && (*iter)->m_used) || (res == select_match && !(*iter)->m_used) )
-			{
-				apply = true;
-			}
-		}
-	}
-
-	if(apply)
-	{
-		if(m_display == display_inline ||  m_display == display_table_row)
-		{
-			position::vector boxes;
-			get_inline_boxes(boxes);
-			for(position::vector::iterator pos = boxes.begin(); pos != boxes.end(); pos++)
-			{
-				pos->x	+= x;
-				pos->y	+= y;
-				redraw_boxes.push_back(*pos);
-			}
-		} else
-		{
-			position pos = m_pos;
-			if(m_el_position != element_position_fixed)
-			{
-				pos.x += x;
-				pos.y += y;
-			}
-			pos += m_padding;
-			pos += m_borders;
-			redraw_boxes.push_back(pos);
-		}
-
-		ret = true;
-		refresh_styles();
-		parse_styles();
-	}
-	for (auto& el : m_children)
-	{
-		if(!el->skip())
-		{
-			if(m_el_position != element_position_fixed)
-			{
-				if(el->find_styles_changes(redraw_boxes, x + m_pos.x, y + m_pos.y))
-				{
-					ret = true;
-				}
-			} else
-			{
-				if(el->find_styles_changes(redraw_boxes, m_pos.x, m_pos.y))
-				{
-					ret = true;
-				}
-			}
-		}
-	}
-	return ret;
-}
-
-bool litehtml::html_tag::on_mouse_leave()
-{
-	bool ret = false;
-
-	element::ptr el = shared_from_this();
-	while(el)
-	{
-		if(el->set_pseudo_class(_t("hover"), false))
-		{
-			ret = true;
-		}
-		if(el->set_pseudo_class(_t("active"), false))
-		{
-			ret = true;
-		}
-		el = el->parent();
-	}
-
-	return ret;
-}
-
-bool litehtml::html_tag::on_lbutton_down()
-{
-    bool ret = false;
-
-	element::ptr el = shared_from_this();
-    while (el)
-    {
-        if (el->set_pseudo_class(_t("active"), true))
-        {
-            ret = true;
-        }
-        el = el->parent();
-    }
-
-    return ret;
-}
-
-bool litehtml::html_tag::on_lbutton_up()
-{
-	bool ret = false;
-
-	element::ptr el = shared_from_this();
-    while (el)
-    {
-        if (el->set_pseudo_class(_t("active"), false))
-        {
-            ret = true;
-        }
-        el = el->parent();
-    }
-
-    on_click();
-
-	return ret;
-}
-
-void litehtml::html_tag::on_click()
-{
-	if (have_parent())
-	{
-		element::ptr el_parent = parent();
-		if (el_parent)
-		{
-			el_parent->on_click();
-		}
-	}
-}
-
-const litehtml::tchar_t* litehtml::html_tag::get_cursor()
-{
-	return get_style_property(_t("cursor"), true, 0);
-}
-
-static const int font_size_table[8][7] =
-{
-	{ 9,    9,     9,     9,    11,    14,    18},
-	{ 9,    9,     9,    10,    12,    15,    20},
-	{ 9,    9,     9,    11,    13,    17,    22},
-	{ 9,    9,    10,    12,    14,    18,    24},
-	{ 9,    9,    10,    13,    16,    20,    26},
-	{ 9,    9,    11,    14,    17,    21,    28},
-	{ 9,   10,    12,    15,    17,    23,    30},
-	{ 9,   10,    13,    16,    18,    24,    32}
-};
-
-
-void litehtml::html_tag::init_font()
-{
-	// initialize font size
-	const tchar_t* str = get_style_property(_t("font-size"), false, 0);
-
-	int parent_sz = 0;
-	int doc_font_size = get_document()->container()->get_default_font_size();
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		parent_sz = el_parent->get_font_size();
-	} else
-	{
-		parent_sz = doc_font_size;
-	}
-
-
-	if(!str)
-	{
-		m_font_size = parent_sz;
-	} else
-	{
-		m_font_size = parent_sz;
-
-		css_length sz;
-		sz.fromString(str, font_size_strings);
-		if(sz.is_predefined())
-		{
-			int idx_in_table = doc_font_size - 9;
-			if(idx_in_table >= 0 && idx_in_table <= 7)
-			{
-				if(sz.predef() >= fontSize_xx_small && sz.predef() <= fontSize_xx_large)
-				{
-					m_font_size = font_size_table[idx_in_table][sz.predef()];
-				} else
-				{
-					m_font_size = doc_font_size;
-				}
-			} else			
-			{
-				switch(sz.predef())
-				{
-				case fontSize_xx_small:
-					m_font_size = doc_font_size * 3 / 5;
-					break;
-				case fontSize_x_small:
-					m_font_size = doc_font_size * 3 / 4;
-					break;
-				case fontSize_small:
-					m_font_size = doc_font_size * 8 / 9;
-					break;
-				case fontSize_large:
-					m_font_size = doc_font_size * 6 / 5;
-					break;
-				case fontSize_x_large:
-					m_font_size = doc_font_size * 3 / 2;
-					break;
-				case fontSize_xx_large:
-					m_font_size = doc_font_size * 2;
-					break;
-				default:
-					m_font_size = doc_font_size;
-					break;
-				}
-			}
-		} else
-		{
-			if(sz.units() == css_units_percentage)
-			{
-				m_font_size = sz.calc_percent(parent_sz);
-			} else if(sz.units() == css_units_none)
-			{
-				m_font_size = parent_sz;
-			} else
-			{
-				m_font_size = get_document()->cvt_units(sz, parent_sz);
-			}
-		}
-	}
-
-	// initialize font
-	const tchar_t* name			= get_style_property(_t("font-family"),		true,	_t("inherit"));
-	const tchar_t* weight		= get_style_property(_t("font-weight"),		true,	_t("normal"));
-	const tchar_t* style		= get_style_property(_t("font-style"),		true,	_t("normal"));
-	const tchar_t* decoration	= get_style_property(_t("text-decoration"),	true,	_t("none"));
-
-	m_font = get_document()->get_font(name, m_font_size, weight, style, decoration, &m_font_metrics);
-}
-
-bool litehtml::html_tag::is_break() const
-{
-	return false;
-}
-
-void litehtml::html_tag::set_tagName( const tchar_t* tag )
-{
-	tstring s_val = tag;
-	std::locale lc = std::locale::global(std::locale::classic());
-	for(size_t i = 0; i < s_val.length(); i++)
-	{
-		s_val[i] = std::tolower(s_val[i], lc);
-	}
-	m_tag = s_val;
-}
-
-void litehtml::html_tag::draw_background( uint_ptr hdc, int x, int y, const position* clip )
-{
-	position pos = m_pos;
-	pos.x	+= x;
-	pos.y	+= y;
-
-	position el_pos = pos;
-	el_pos += m_padding;
-	el_pos += m_borders;
-
-	if(m_display != display_inline && m_display != display_table_row)
-	{
-		if(el_pos.does_intersect(clip))
-		{
-			const background* bg = get_background();
-			if(bg)
-			{
-				background_paint bg_paint;
-				init_background_paint(pos, bg_paint, bg);
-
-				get_document()->container()->draw_background(hdc, bg_paint);
-			}
-			position border_box = pos;
-			border_box += m_padding;
-			border_box += m_borders;
-
-			borders bdr = m_css_borders;
-			bdr.radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
-
-			get_document()->container()->draw_borders(hdc, bdr, border_box, have_parent() ? false : true);
-		}
-	} else
-	{
-		const background* bg = get_background();
-
-		position::vector boxes;
-		get_inline_boxes(boxes);
-
-		background_paint bg_paint;
-		position content_box;
-
-		for(position::vector::iterator box = boxes.begin(); box != boxes.end(); box++)
-		{
-			box->x	+= x;
-			box->y	+= y;
-
-			if(box->does_intersect(clip))
-			{
-				content_box = *box;
-				content_box -= m_borders;
-				content_box -= m_padding;
-
-				if(bg)
-				{
-					init_background_paint(content_box, bg_paint, bg);
-				}
-
-				css_borders bdr;
-
-				// set left borders radius for the first box
-				if(box == boxes.begin())
-				{
-					bdr.radius.bottom_left_x	= m_css_borders.radius.bottom_left_x;
-					bdr.radius.bottom_left_y	= m_css_borders.radius.bottom_left_y;
-					bdr.radius.top_left_x		= m_css_borders.radius.top_left_x;
-					bdr.radius.top_left_y		= m_css_borders.radius.top_left_y;
-				}
-
-				// set right borders radius for the last box
-				if(box == boxes.end() - 1)
-				{
-					bdr.radius.bottom_right_x	= m_css_borders.radius.bottom_right_x;
-					bdr.radius.bottom_right_y	= m_css_borders.radius.bottom_right_y;
-					bdr.radius.top_right_x		= m_css_borders.radius.top_right_x;
-					bdr.radius.top_right_y		= m_css_borders.radius.top_right_y;
-				}
-
-				
-				bdr.top		= m_css_borders.top;
-				bdr.bottom	= m_css_borders.bottom;
-				if(box == boxes.begin())
-				{
-					bdr.left	= m_css_borders.left;
-				}
-				if(box == boxes.end() - 1)
-				{
-					bdr.right	= m_css_borders.right;
-				}
-
-
-				if(bg)
-				{
-					bg_paint.border_radius = bdr.radius.calc_percents(bg_paint.border_box.width, bg_paint.border_box.width);
-					get_document()->container()->draw_background(hdc, bg_paint);
-				}
-				borders b = bdr;
-				b.radius = bdr.radius.calc_percents(box->width, box->height);
-				get_document()->container()->draw_borders(hdc, b, *box, false);
-			}
-		}
-	}
-}
-
-int litehtml::html_tag::render_inline(const element::ptr &container, int max_width)
-{
-	int ret_width = 0;
-	int rw = 0;
-
-	white_space ws = get_white_space();
-	bool skip_spaces = false;
-	if (ws == white_space_normal ||
-		ws == white_space_nowrap ||
-		ws == white_space_pre_line)
-	{
-		skip_spaces = true;
-	}
-	bool was_space = false;
-
-	for (auto& el : m_children)
-	{
-		// skip spaces to make rendering a bit faster
-		if (skip_spaces)
-		{
-			if (el->is_white_space())
-			{
-				if (was_space)
-				{
-					el->skip(true);
-					continue;
-				}
-				else
-				{
-					was_space = true;
-				}
-			}
-			else
-			{
-				was_space = false;
-			}
-		}
-
-		rw = container->place_element( el, max_width );
-		if(rw > ret_width)
-		{
-			ret_width = rw;
-		}
-	}
-	return ret_width;
-}
-
-int litehtml::html_tag::place_element(const element::ptr &el, int max_width)
-{
-	if(el->get_display() == display_none) return 0;
-
-	if(el->get_display() == display_inline)
-	{
-		return el->render_inline(shared_from_this(), max_width);
-	}
-
-	element_position el_position = el->get_element_position();
-
-	if(el_position == element_position_absolute || el_position == element_position_fixed)
-	{
-		int line_top = 0;
-		if(!m_boxes.empty())
-		{
-			if(m_boxes.back()->get_type() == box_line)
-			{
-				line_top = m_boxes.back()->top();
-				if(!m_boxes.back()->is_empty())
-				{
-					line_top += line_height();
-				}
-			} else
-			{
-				line_top = m_boxes.back()->bottom();
-			}
-		}
-
-		el->render(0, line_top, max_width);
-		el->m_pos.x	+= el->content_margins_left();
-		el->m_pos.y	+= el->content_margins_top();
-
-		return 0;
-	}
-
-	int ret_width = 0;
-
-	switch(el->get_float())
-	{
-	case float_left:
-		{
-			int line_top = 0;
-			if(!m_boxes.empty())
-			{
-				if(m_boxes.back()->get_type() == box_line)
-				{
-					line_top = m_boxes.back()->top();
-				} else
-				{
-					line_top = m_boxes.back()->bottom();
-				}
-			}
-			line_top		= get_cleared_top(el, line_top);
-			int line_left	= 0;
-			int line_right	= max_width;
-			get_line_left_right(line_top, max_width, line_left, line_right);
-
-			el->render(line_left, line_top, line_right);
-			if(el->right() > line_right)
-			{
-				int new_top = find_next_line_top(el->top(), el->width(), max_width);
-				el->m_pos.x = get_line_left(new_top) + el->content_margins_left();
-				el->m_pos.y = new_top + el->content_margins_top();
-			}
-			add_float(el, 0, 0);
-			ret_width = fix_line_width(max_width, float_left);
-			if(!ret_width)
-			{
-				ret_width = el->right();
-			}
-		}
-		break;
-	case float_right:
-		{
-			int line_top = 0;
-			if(!m_boxes.empty())
-			{
-				if(m_boxes.back()->get_type() == box_line)
-				{
-					line_top = m_boxes.back()->top();
-				} else
-				{
-					line_top = m_boxes.back()->bottom();
-				}
-			}
-			line_top		= get_cleared_top(el, line_top);
-			int line_left	= 0;
-			int line_right	= max_width;
-			get_line_left_right(line_top, max_width, line_left, line_right);
-
-			el->render(0, line_top, line_right);
-
-			if(line_left + el->width() > line_right)
-			{
-				int new_top = find_next_line_top(el->top(), el->width(), max_width);
-				el->m_pos.x = get_line_right(new_top, max_width) - el->width() + el->content_margins_left();
-				el->m_pos.y = new_top + el->content_margins_top();
-			} else
-			{
-				el->m_pos.x = line_right - el->width() + el->content_margins_left();
-			}
-			add_float(el, 0, 0);
-			ret_width = fix_line_width(max_width, float_right);
-
-			if(!ret_width)
-			{
-				line_left	= 0;
-				line_right	= max_width;
-				get_line_left_right(line_top, max_width, line_left, line_right);
-
-				ret_width = ret_width + (max_width - line_right);
-			}
-		}
-		break;
-	default:
-		{
-			line_context line_ctx;
-			line_ctx.top = 0;
-			if (!m_boxes.empty())
-			{
-				line_ctx.top = m_boxes.back()->top();
-			}
-			line_ctx.left = 0;
-			line_ctx.right = max_width;
-			line_ctx.fix_top();
-			get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
-
-			switch(el->get_display())
-			{
-			case display_inline_block:
-				ret_width = el->render(line_ctx.left, line_ctx.top, line_ctx.right);
-				break;
-			case display_block:		
-				if(el->is_replaced() || el->is_floats_holder())
-				{
-					element::ptr el_parent = el->parent();
-					el->m_pos.width = el->get_css_width().calc_percent(line_ctx.right - line_ctx.left);
-					el->m_pos.height = el->get_css_height().calc_percent(el_parent ? el_parent->m_pos.height : 0);
-				}
-				el->calc_outlines(line_ctx.right - line_ctx.left);
-				break;
-			case display_inline_text:
-				{
-					litehtml::size sz;
-					el->get_content_size(sz, line_ctx.right);
-					el->m_pos = sz;
-				}
-				break;
-			default:
-				ret_width = 0;
-				break;
-			}
-
-			bool add_box = true;
-			if(!m_boxes.empty())
-			{
-				if(m_boxes.back()->can_hold(el, m_white_space))
-				{
-					add_box = false;
-				}
-			}
-			if(add_box)
-			{
-				new_box(el, max_width, line_ctx);
-			} else if(!m_boxes.empty())
-			{
-				line_ctx.top = m_boxes.back()->top();
-			}
-
-			if (line_ctx.top != line_ctx.calculatedTop)
-			{
-				line_ctx.left = 0;
-				line_ctx.right = max_width;
-				line_ctx.fix_top();
-				get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
-			}
-
-			if(!el->is_inline_box())
-			{
-				if(m_boxes.size() == 1)
-				{
-					if(collapse_top_margin())
-					{
-						int shift = el->margin_top();
-						if(shift >= 0)
-						{
-							line_ctx.top -= shift;
-							m_boxes.back()->y_shift(-shift);
-						}
-					}
-				} else
-				{
-					int shift = 0;
-					int prev_margin = m_boxes[m_boxes.size() - 2]->bottom_margin();
-
-					if(prev_margin > el->margin_top())
-					{
-						shift = el->margin_top();
-					} else
-					{
-						shift = prev_margin;
-					}
-					if(shift >= 0)
-					{
-						line_ctx.top -= shift;
-						m_boxes.back()->y_shift(-shift);
-					}
-				}
-			}
-
-			switch(el->get_display())
-			{
-			case display_table:
-			case display_list_item:
-				ret_width = el->render(line_ctx.left, line_ctx.top, line_ctx.width());
-				break;
-			case display_block:
-			case display_table_cell:
-			case display_table_caption:
-			case display_table_row:
-				if(el->is_replaced() || el->is_floats_holder())
-				{
-					ret_width = el->render(line_ctx.left, line_ctx.top, line_ctx.width()) + line_ctx.left + (max_width - line_ctx.right);
-				} else
-				{
-					ret_width = el->render(0, line_ctx.top, max_width);
-				}
-				break;
-			default:
-				ret_width = 0;
-				break;
-			}
-
-			m_boxes.back()->add_element(el);
-
-			if(el->is_inline_box() && !el->skip())
-			{
-				ret_width = el->right() + (max_width - line_ctx.right);
-			}
-		}
-		break;
-	}
-
-	return ret_width;
-}
-
-bool litehtml::html_tag::set_pseudo_class( const tchar_t* pclass, bool add )
-{
-	bool ret = false;
-	if(add)
-	{
-		if(std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), pclass) == m_pseudo_classes.end())
-		{
-			m_pseudo_classes.push_back(pclass);
-			ret = true;
-		}
-	} else
-	{
-		string_vector::iterator pi = std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), pclass);
-		if(pi != m_pseudo_classes.end())
-		{
-			m_pseudo_classes.erase(pi);
-			ret = true;
-		}
-	}
-	return ret;
-}
-
-bool litehtml::html_tag::set_class( const tchar_t* pclass, bool add )
-{
-	string_vector classes;
-	bool changed = false;
-
-	split_string( pclass, classes, _t(" ") );
-
-	if(add)
-	{
-		for( auto & _class : classes  )
-		{
-			if(std::find(m_class_values.begin(), m_class_values.end(), _class) == m_class_values.end())
-			{
-				m_class_values.push_back( std::move( _class ) );
-				changed = true;
-			}
-		}
-	} else
-	{
-		for( const auto & _class : classes )
-		{
-			auto end = std::remove(m_class_values.begin(), m_class_values.end(), _class);
-
-			if(end != m_class_values.end())
-			{
-				m_class_values.erase(end, m_class_values.end());
-				changed = true;
-			}
-		}
-	}
-
-	if( changed )
-	{
-		tstring class_string;
-		join_string(class_string, m_class_values, _t(" "));
-		set_attr(_t("class"), class_string.c_str());
-
-		return true;
-	}
-	else
-	{
-		return false;
-	}
-
-}
-
-int litehtml::html_tag::line_height() const
-{
-	return m_line_height;
-}
-
-bool litehtml::html_tag::is_replaced() const
-{
-	return false;
-}
-
-int litehtml::html_tag::finish_last_box(bool end_of_render)
-{
-	int line_top = 0;
-
-	if(!m_boxes.empty())
-	{
-		m_boxes.back()->finish(end_of_render);
-
-		if(m_boxes.back()->is_empty())
-		{
-			line_top = m_boxes.back()->top();
-			m_boxes.pop_back();
-		}
-
-		if(!m_boxes.empty())
-		{
-			line_top = m_boxes.back()->bottom();
-		}
-	}
-	return line_top;
-}
-
-int litehtml::html_tag::new_box(const element::ptr &el, int max_width, line_context& line_ctx)
-{
-	line_ctx.top = get_cleared_top(el, finish_last_box());
-
-	line_ctx.left = 0;
-	line_ctx.right = max_width;
-	line_ctx.fix_top();
-	get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
-
-	if(el->is_inline_box() || el->is_floats_holder())
-	{
-		if (el->width() > line_ctx.right - line_ctx.left)
-		{
-			line_ctx.top = find_next_line_top(line_ctx.top, el->width(), max_width);
-			line_ctx.left = 0;
-			line_ctx.right = max_width;
-			line_ctx.fix_top();
-			get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
-		}
-	}
-
-	int first_line_margin = 0;
-	if(m_boxes.empty() && m_list_style_type != list_style_type_none && m_list_style_position == list_style_position_inside)
-	{
-		int sz_font = get_font_size();
-		first_line_margin = sz_font;
-	}
-
-	if(el->is_inline_box())
-	{
-		int text_indent = 0;
-		if(m_css_text_indent.val() != 0)
-		{
-			bool line_box_found = false;
-			for(box::vector::iterator iter = m_boxes.begin(); iter != m_boxes.end(); iter++)
-			{
-				if((*iter)->get_type() == box_line)
-				{
-					line_box_found = true;
-					break;
-				}
-			}
-			if(!line_box_found)
-			{
-				text_indent = m_css_text_indent.calc_percent(max_width);
-			}
-		}
-
-		font_metrics fm;
-		get_font(&fm);
-		m_boxes.emplace_back(std::unique_ptr<line_box>(new line_box(line_ctx.top, line_ctx.left + first_line_margin + text_indent, line_ctx.right, line_height(), fm, m_text_align)));
-	} else
-	{
-		m_boxes.emplace_back(std::unique_ptr<block_box>(new block_box(line_ctx.top, line_ctx.left, line_ctx.right)));
-	}
-
-	return line_ctx.top;
-}
-
-int litehtml::html_tag::get_cleared_top(const element::ptr &el, int line_top) const
-{
-	switch(el->get_clear())
-	{
-	case clear_left:
-		{
-			int fh = get_left_floats_height();
-			if(fh && fh > line_top)
-			{
-				line_top = fh;
-			}
-		}
-		break;
-	case clear_right:
-		{
-			int fh = get_right_floats_height();
-			if(fh && fh > line_top)
-			{
-				line_top = fh;
-			}
-		}
-		break;
-	case clear_both:
-		{
-			int fh = get_floats_height();
-			if(fh && fh > line_top)
-			{
-				line_top = fh;
-			}
-		}
-		break;
-	default:
-		if(el->get_float() != float_none)
-		{
-			int fh = get_floats_height(el->get_float());
-			if(fh && fh > line_top)
-			{
-				line_top = fh;
-			}
-		}
-		break;
-	}
-	return line_top;
-}
-
-litehtml::style_display litehtml::html_tag::get_display() const
-{
-	return m_display;
-}
-
-litehtml::element_float litehtml::html_tag::get_float() const
-{
-	return m_float;
-}
-
-bool litehtml::html_tag::is_floats_holder() const
-{
-	if(	m_display == display_inline_block || 
-		m_display == display_table_cell || 
-		!have_parent() ||
-		is_body() || 
-		m_float != float_none ||
-		m_el_position == element_position_absolute ||
-		m_el_position == element_position_fixed ||
-		m_overflow > overflow_visible)
-	{
-		return true;
-	}
-	return false;
-}
-
-bool litehtml::html_tag::is_first_child_inline(const element::ptr& el) const
-{
-	if(!m_children.empty())
-	{
-		for (const auto& this_el : m_children)
-		{
-			if (!this_el->is_white_space())
-			{
-				if (el == this_el)
-				{
-					return true;
-				}
-				if (this_el->get_display() == display_inline)
-				{
-					if (this_el->have_inline_child())
-					{
-						return false;
-					}
-				} else
-				{
-					return false;
-				}
-			}
-		}
-	}
-	return false;
-}
-
-bool litehtml::html_tag::is_last_child_inline(const element::ptr& el)
-{
-	if(!m_children.empty())
-	{
-		for (auto this_el = m_children.rbegin(); this_el < m_children.rend(); ++this_el)
-		{
-			if (!(*this_el)->is_white_space())
-			{
-				if (el == (*this_el))
-				{
-					return true;
-				}
-				if ((*this_el)->get_display() == display_inline)
-				{
-					if ((*this_el)->have_inline_child())
-					{
-						return false;
-					}
-				} else
-				{
-					return false;
-				}
-			}
-		}
-	}
-	return false;
-}
-
-litehtml::white_space litehtml::html_tag::get_white_space() const
-{
-	return m_white_space;
-}
-
-litehtml::vertical_align litehtml::html_tag::get_vertical_align() const
-{
-	return m_vertical_align;
-}
-
-litehtml::css_length litehtml::html_tag::get_css_left() const
-{
-	return m_css_offsets.left;
-}
-
-litehtml::css_length litehtml::html_tag::get_css_right() const
-{
-	return m_css_offsets.right;
-}
-
-litehtml::css_length litehtml::html_tag::get_css_top() const
-{
-	return m_css_offsets.top;
-}
-
-litehtml::css_length litehtml::html_tag::get_css_bottom() const
-{
-	return m_css_offsets.bottom;
-}
-
-
-litehtml::css_offsets litehtml::html_tag::get_css_offsets() const
-{
-	return m_css_offsets;
-}
-
-litehtml::element_clear litehtml::html_tag::get_clear() const
-{
-	return m_clear;
-}
-
-litehtml::css_length litehtml::html_tag::get_css_width() const
-{
-	return m_css_width;
-}
-
-litehtml::css_length litehtml::html_tag::get_css_height() const
-{
-	return m_css_height;
-}
-
-size_t litehtml::html_tag::get_children_count() const
-{
-	return m_children.size();
-}
-
-litehtml::element::ptr litehtml::html_tag::get_child( int idx ) const
-{
-	return m_children[idx];
-}
-
-void litehtml::html_tag::set_css_width( css_length& w )
-{
-	m_css_width = w;
-}
-
-void litehtml::html_tag::apply_vertical_align()
-{
-	if(!m_boxes.empty())
-	{
-		int add = 0;
-		int content_height	= m_boxes.back()->bottom();
-
-		if(m_pos.height > content_height)
-		{
-			switch(m_vertical_align)
-			{
-			case va_middle:
-				add = (m_pos.height - content_height) / 2;
-				break;
-			case va_bottom:
-				add = m_pos.height - content_height;
-				break;
-			default:
-				add = 0;
-				break;
-			}
-		}
-
-		if(add)
-		{
-			for(size_t i = 0; i < m_boxes.size(); i++)
-			{
-				m_boxes[i]->y_shift(add);
-			}
-		}
-	}
-}
-
-litehtml::element_position litehtml::html_tag::get_element_position(css_offsets* offsets) const
-{
-	if(offsets && m_el_position != element_position_static)
-	{
-		*offsets = m_css_offsets;
-	}
-	return m_el_position;
-}
-
-void litehtml::html_tag::init_background_paint(position pos, background_paint &bg_paint, const background* bg)
-{
-	if(!bg) return;
-
-	bg_paint = *bg;
-	position content_box	= pos;
-	position padding_box	= pos;
-	padding_box += m_padding;
-	position border_box		= padding_box;
-	border_box += m_borders;
-
-	switch(bg->m_clip)
-	{
-	case litehtml::background_box_padding:
-		bg_paint.clip_box = padding_box;
-		break;
-	case litehtml::background_box_content:
-		bg_paint.clip_box = content_box;
-		break;
-	default:
-		bg_paint.clip_box = border_box;
-		break;
-	}
-
-	switch(bg->m_origin)
-	{
-	case litehtml::background_box_border:
-		bg_paint.origin_box = border_box;
-		break;
-	case litehtml::background_box_content:
-		bg_paint.origin_box = content_box;
-		break;
-	default:
-		bg_paint.origin_box = padding_box;
-		break;
-	}
-
-	if(!bg_paint.image.empty())
-	{
-		get_document()->container()->get_image_size(bg_paint.image.c_str(), bg_paint.baseurl.c_str(), bg_paint.image_size);
-		if(bg_paint.image_size.width && bg_paint.image_size.height)
-		{
-			litehtml::size img_new_sz = bg_paint.image_size;
-			double img_ar_width		= (double) bg_paint.image_size.width / (double) bg_paint.image_size.height;
-			double img_ar_height	= (double) bg_paint.image_size.height / (double) bg_paint.image_size.width;
-
-
-			if(bg->m_position.width.is_predefined())
-			{
-				switch(bg->m_position.width.predef())
-				{
-				case litehtml::background_size_contain:
-					if( (int) ((double) bg_paint.origin_box.width * img_ar_height) <= bg_paint.origin_box.height )
-					{
-						img_new_sz.width = bg_paint.origin_box.width;
-						img_new_sz.height	= (int) ((double) bg_paint.origin_box.width * img_ar_height);
-					} else
-					{
-						img_new_sz.height = bg_paint.origin_box.height;
-						img_new_sz.width	= (int) ((double) bg_paint.origin_box.height * img_ar_width);
-					}
-					break;
-				case litehtml::background_size_cover:
-					if( (int) ((double) bg_paint.origin_box.width * img_ar_height) >= bg_paint.origin_box.height )
-					{
-						img_new_sz.width = bg_paint.origin_box.width;
-						img_new_sz.height	= (int) ((double) bg_paint.origin_box.width * img_ar_height);
-					} else
-					{
-						img_new_sz.height = bg_paint.origin_box.height;
-						img_new_sz.width	= (int) ((double) bg_paint.origin_box.height * img_ar_width);
-					}
-					break;
-					break;
-				case litehtml::background_size_auto:
-					if(!bg->m_position.height.is_predefined())
-					{
-						img_new_sz.height	= bg->m_position.height.calc_percent(bg_paint.origin_box.height);
-						img_new_sz.width	= (int) ((double) img_new_sz.height * img_ar_width);
-					}
-					break;
-				}
-			} else
-			{
-				img_new_sz.width = bg->m_position.width.calc_percent(bg_paint.origin_box.width);
-				if(bg->m_position.height.is_predefined())
-				{
-					img_new_sz.height = (int) ((double) img_new_sz.width * img_ar_height);
-				} else
-				{
-					img_new_sz.height = bg->m_position.height.calc_percent(bg_paint.origin_box.height);
-				}
-			}
-
-			bg_paint.image_size = img_new_sz;
-			bg_paint.position_x = bg_paint.origin_box.x + (int) bg->m_position.x.calc_percent(bg_paint.origin_box.width - bg_paint.image_size.width);
-			bg_paint.position_y = bg_paint.origin_box.y + (int) bg->m_position.y.calc_percent(bg_paint.origin_box.height - bg_paint.image_size.height);
-		}
-
-	}
-	bg_paint.border_radius	= m_css_borders.radius.calc_percents(border_box.width, border_box.height);;
-	bg_paint.border_box		= border_box;
-	bg_paint.is_root		= have_parent() ? false : true;
-}
-
-litehtml::visibility litehtml::html_tag::get_visibility() const
-{
-	return m_visibility;
-}
-
-void litehtml::html_tag::draw_list_marker( uint_ptr hdc, const position &pos )
-{
-	list_marker lm;
-
-	const tchar_t* list_image = get_style_property(_t("list-style-image"), true, 0);
-	size img_size;
-	if(list_image)
-	{
-		css::parse_css_url(list_image, lm.image);
-		lm.baseurl = get_style_property(_t("list-style-image-baseurl"), true, 0);
-		get_document()->container()->get_image_size(lm.image.c_str(), lm.baseurl, img_size);
-	} else
-	{
-		lm.baseurl = 0;
-	}
-
-
-	int ln_height	= line_height();
-	int sz_font		= get_font_size();
-	lm.pos.x		= pos.x;
-	lm.pos.width	= sz_font	- sz_font * 2 / 3;
-	lm.pos.height	= sz_font	- sz_font * 2 / 3;
-	lm.pos.y		= pos.y		+ ln_height / 2 - lm.pos.height / 2;
-
-	if(img_size.width && img_size.height)
-	{
-		if(lm.pos.y + img_size.height > pos.y + pos.height)
-		{
-			lm.pos.y = pos.y + pos.height - img_size.height;
-		}
-		if(img_size.width > lm.pos.width)
-		{
-			lm.pos.x -= img_size.width - lm.pos.width;
-		}
-
-		lm.pos.width	= img_size.width;
-		lm.pos.height	= img_size.height;
-	}
-	if(m_list_style_position == list_style_position_outside)
-	{
-		lm.pos.x -= sz_font;
-	}
-
-	lm.color = get_color(_t("color"), true, web_color(0, 0, 0));
-	lm.marker_type = m_list_style_type;
-	get_document()->container()->draw_list_marker(hdc, lm);
-}
-
-void litehtml::html_tag::draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex )
-{
-	if (m_display == display_table || m_display == display_inline_table)
-	{
-		draw_children_table(hdc, x, y, clip, flag, zindex);
-	}
-	else
-	{
-		draw_children_box(hdc, x, y, clip, flag, zindex);
-	}
-}
-
-bool litehtml::html_tag::fetch_positioned()
-{
-	bool ret = false;
-
-	m_positioned.clear();
-
-	litehtml::element_position el_pos;
-
-	for(auto& el : m_children)
-	{
-		el_pos = el->get_element_position();
-		if (el_pos != element_position_static)
-		{
-			add_positioned(el);
-		}
-		if (!ret && (el_pos == element_position_absolute || el_pos == element_position_fixed))
-		{
-			ret = true;
-		}
-		if(el->fetch_positioned())
-		{
-			ret = true;
-		}
-	}
-	return ret;
-}
-
-int litehtml::html_tag::get_zindex() const
-{
-	return m_z_index;
-}
-
-void litehtml::html_tag::render_positioned(render_type rt)
-{
-	position wnd_position;
-	get_document()->container()->get_client_rect(wnd_position);
-
-	element_position el_position;
-	bool process;
-	for (auto& el : m_positioned)
-	{
-		el_position = el->get_element_position();
-
-		process = false;
-		if(el->get_display() != display_none)
-		{
-			if(el_position == element_position_absolute)
-			{
-				if(rt != render_fixed_only)
-				{
-					process = true;
-				}
-			} else if(el_position == element_position_fixed)
-			{
-				if(rt != render_no_fixed)
-				{
-					process = true;
-				}
-			}
-		}
-
-		if(process)
-		{
-			int parent_height	= 0;
-			int parent_width	= 0;
-			int client_x		= 0;
-			int client_y		= 0;
-			if(el_position == element_position_fixed)
-			{
-				parent_height	= wnd_position.height;
-				parent_width	= wnd_position.width;
-				client_x		= wnd_position.left();
-				client_y		= wnd_position.top();
-			} else
-			{
-				element::ptr el_parent = el->parent();
-				if(el_parent)
-				{
-					parent_height	= el_parent->height();
-					parent_width	= el_parent->width();
-				}
-			}
-
-			css_length	css_left	= el->get_css_left();
-			css_length	css_right	= el->get_css_right();
-			css_length	css_top		= el->get_css_top();
-			css_length	css_bottom	= el->get_css_bottom();
-
-			bool need_render = false;
-
-			css_length el_w = el->get_css_width();
-			css_length el_h = el->get_css_height();
-
-            int new_width = -1;
-            int new_height = -1;
-			if(el_w.units() == css_units_percentage && parent_width)
-			{
-                new_width = el_w.calc_percent(parent_width);
-                if(el->m_pos.width != new_width)
-				{
-					need_render = true;
-                    el->m_pos.width = new_width;
-				}
-			}
-
-			if(el_h.units() == css_units_percentage && parent_height)
-			{
-                new_height = el_h.calc_percent(parent_height);
-                if(el->m_pos.height != new_height)
-				{
-					need_render = true;
-                    el->m_pos.height = new_height;
-				}
-			}
-
-			bool cvt_x = false;
-			bool cvt_y = false;
-
-			if(el_position == element_position_fixed)
-			{
-				if(!css_left.is_predefined() || !css_right.is_predefined())
-				{
-					if(!css_left.is_predefined() && css_right.is_predefined())
-					{
-						el->m_pos.x = css_left.calc_percent(parent_width) + el->content_margins_left();
-					} else if(css_left.is_predefined() && !css_right.is_predefined())
-					{
-						el->m_pos.x = parent_width - css_right.calc_percent(parent_width) - el->m_pos.width - el->content_margins_right();
-					} else
-					{
-						el->m_pos.x		= css_left.calc_percent(parent_width) + el->content_margins_left();
-						el->m_pos.width	= parent_width - css_left.calc_percent(parent_width) - css_right.calc_percent(parent_width) - (el->content_margins_left() + el->content_margins_right());
-						need_render = true;
-					}
-				}
-
-				if(!css_top.is_predefined() || !css_bottom.is_predefined())
-				{
-					if(!css_top.is_predefined() && css_bottom.is_predefined())
-					{
-						el->m_pos.y = css_top.calc_percent(parent_height) + el->content_margins_top();
-					} else if(css_top.is_predefined() && !css_bottom.is_predefined())
-					{
-						el->m_pos.y = parent_height - css_bottom.calc_percent(parent_height) - el->m_pos.height - el->content_margins_bottom();
-					} else
-					{
-						el->m_pos.y			= css_top.calc_percent(parent_height) + el->content_margins_top();
-						el->m_pos.height	= parent_height - css_top.calc_percent(parent_height) - css_bottom.calc_percent(parent_height) - (el->content_margins_top() + el->content_margins_bottom());
-						need_render = true;
-					}
-				}
-			} else 
-			{
-				if(!css_left.is_predefined() || !css_right.is_predefined())
-				{
-					if(!css_left.is_predefined() && css_right.is_predefined())
-					{
-						el->m_pos.x = css_left.calc_percent(parent_width) + el->content_margins_left() - m_padding.left;
-					} else if(css_left.is_predefined() && !css_right.is_predefined())
-					{
-						el->m_pos.x = m_pos.width + m_padding.right - css_right.calc_percent(parent_width) - el->m_pos.width - el->content_margins_right();
-					} else
-					{
-						el->m_pos.x		= css_left.calc_percent(parent_width) + el->content_margins_left() - m_padding.left;
-						el->m_pos.width	= m_pos.width + m_padding.left + m_padding.right - css_left.calc_percent(parent_width) - css_right.calc_percent(parent_width) - (el->content_margins_left() + el->content_margins_right());
-                        if (new_width != -1)
-                        {
-                            el->m_pos.x += (el->m_pos.width - new_width) / 2;
-                            el->m_pos.width = new_width;
-                        }
-                        need_render = true;
-					}
-					cvt_x = true;
-				}
-
-				if(!css_top.is_predefined() || !css_bottom.is_predefined())
-				{
-					if(!css_top.is_predefined() && css_bottom.is_predefined())
-					{
-						el->m_pos.y = css_top.calc_percent(parent_height) + el->content_margins_top() - m_padding.top;
-					} else if(css_top.is_predefined() && !css_bottom.is_predefined())
-					{
-						el->m_pos.y = m_pos.height + m_padding.bottom - css_bottom.calc_percent(parent_height) - el->m_pos.height - el->content_margins_bottom();
-					} else
-					{
-						el->m_pos.y			= css_top.calc_percent(parent_height) + el->content_margins_top() - m_padding.top;
-						el->m_pos.height	= m_pos.height + m_padding.top + m_padding.bottom - css_top.calc_percent(parent_height) - css_bottom.calc_percent(parent_height) - (el->content_margins_top() + el->content_margins_bottom());
-                        if (new_height != -1)
-                        {
-                            el->m_pos.y += (el->m_pos.height - new_height) / 2;
-                            el->m_pos.height = new_height;
-                        }
-                        need_render = true;
-					}
-					cvt_y = true;
-				}
-			}
-
-			if(cvt_x || cvt_y)
-			{
-				int offset_x = 0;
-				int offset_y = 0;
-				element::ptr cur_el = el->parent();
-				element::ptr this_el = shared_from_this();
-				while(cur_el && cur_el != this_el)
-				{
-					offset_x += cur_el->m_pos.x;
-					offset_y += cur_el->m_pos.y;
-					cur_el = cur_el->parent();
-				}
-				if(cvt_x)	el->m_pos.x -= offset_x;
-				if(cvt_y)	el->m_pos.y -= offset_y;
-			}
-
-			if(need_render)
-			{
-				position pos = el->m_pos;
-				el->render(el->left(), el->top(), el->width(), true);
-				el->m_pos = pos;
-			}
-
-			if(el_position == element_position_fixed)
-			{
-				position fixed_pos;
-				el->get_redraw_box(fixed_pos);
-				get_document()->add_fixed_box(fixed_pos);
-			}
-		}
-
-		el->render_positioned();
-	}
-
-	if(!m_positioned.empty())
-	{
-		std::stable_sort(m_positioned.begin(), m_positioned.end(), [](const litehtml::element::ptr& _Left, const litehtml::element::ptr& _Right)
-		{
-			return (_Left->get_zindex() < _Right->get_zindex());
-		});
-	}
-}
-
-void litehtml::html_tag::draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned )
-{
-	if(!is_visible()) return;
-
-	std::map<int, bool> zindexes;
-	if(with_positioned)
-	{
-		for(elements_vector::iterator i = m_positioned.begin(); i != m_positioned.end(); i++)
-		{
-			zindexes[(*i)->get_zindex()];
-		}
-
-		for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end(); idx++)
-		{
-			if(idx->first < 0)
-			{
-				draw_children(hdc, x, y, clip, draw_positioned, idx->first);
-			}
-		}
-	}
-	draw_children(hdc, x, y, clip, draw_block, 0);
-	draw_children(hdc, x, y, clip, draw_floats, 0);
-	draw_children(hdc, x, y, clip, draw_inlines, 0);
-	if(with_positioned)
-	{
-		for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end(); idx++)
-		{
-			if(idx->first == 0)
-			{
-				draw_children(hdc, x, y, clip, draw_positioned, idx->first);
-			}
-		}
-
-		for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end(); idx++)
-		{
-			if(idx->first > 0)
-			{
-				draw_children(hdc, x, y, clip, draw_positioned, idx->first);
-			}
-		}
-	}
-}
-
-litehtml::overflow litehtml::html_tag::get_overflow() const
-{
-	return m_overflow;
-}
-
-bool litehtml::html_tag::is_nth_child(const element::ptr& el, int num, int off, bool of_type) const
-{
-	int idx = 1;
-	for(const auto& child : m_children)
-	{
-		if(child->get_display() != display_inline_text)
-		{
-			if( (!of_type) || (of_type && !t_strcmp(el->get_tagName(), child->get_tagName())) )
-			{
-				if(el == child)
-				{
-					if(num != 0)
-					{
-						if((idx - off) >= 0 && (idx - off) % num == 0)
-						{
-							return true;
-						}
-
-					} else if(idx == off)
-					{
-						return true;
-					}
-					return false;
-				}
-				idx++;
-			}
-			if(el == child) break;
-		}
-	}
-	return false;
-}
-
-bool litehtml::html_tag::is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const
-{
-	int idx = 1;
-	for(elements_vector::const_reverse_iterator child = m_children.rbegin(); child != m_children.rend(); child++)
-	{
-		if((*child)->get_display() != display_inline_text)
-		{
-			if( !of_type || (of_type && !t_strcmp(el->get_tagName(), (*child)->get_tagName())) )
-			{
-				if(el == (*child))
-				{
-					if(num != 0)
-					{
-						if((idx - off) >= 0 && (idx - off) % num == 0)
-						{
-							return true;
-						}
-
-					} else if(idx == off)
-					{
-						return true;
-					}
-					return false;
-				}
-				idx++;
-			}
-			if(el == (*child)) break;
-		}
-	}
-	return false;
-}
-
-void litehtml::html_tag::parse_nth_child_params( tstring param, int &num, int &off )
-{
-	if(param == _t("odd"))
-	{
-		num = 2;
-		off = 1;
-	} else if(param == _t("even"))
-	{
-		num = 2;
-		off = 0;
-	} else
-	{
-		string_vector tokens;
-		split_string(param, tokens, _t(" n"), _t("n"));
-
-		tstring s_num;
-		tstring s_off;
-
-		tstring s_int;
-		for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
-		{
-			if((*tok) == _t("n"))
-			{
-				s_num = s_int;
-				s_int.clear();
-			} else
-			{
-				s_int += (*tok);
-			}
-		}
-		s_off = s_int;
-
-		num = t_atoi(s_num.c_str());
-		off = t_atoi(s_off.c_str());
-	}
-}
-
-void litehtml::html_tag::calc_document_size( litehtml::size& sz, int x /*= 0*/, int y /*= 0*/ )
-{
-	if(is_visible() && m_el_position != element_position_fixed)
-	{
-		element::calc_document_size(sz, x, y);
-
-		if(m_overflow == overflow_visible)
-		{
-			for(auto& el : m_children)
-			{
-				el->calc_document_size(sz, x + m_pos.x, y + m_pos.y);
-			}
-		}
-
-		// root element (<html>) must to cover entire window
-		if(!have_parent())
-		{
-			position client_pos;
-			get_document()->container()->get_client_rect(client_pos);
-			m_pos.height = std::max(sz.height, client_pos.height) - content_margins_top() - content_margins_bottom();
-			m_pos.width	 = std::max(sz.width, client_pos.width) - content_margins_left() - content_margins_right();
-		}
-	}
-}
-
-
-void litehtml::html_tag::get_redraw_box(litehtml::position& pos, int x /*= 0*/, int y /*= 0*/)
-{
-	if(is_visible())
-	{
-		element::get_redraw_box(pos, x, y);
-
-		if(m_overflow == overflow_visible)
-		{
-			for(auto& el : m_children)
-			{
-				if(el->get_element_position() != element_position_fixed)
-				{
-					el->get_redraw_box(pos, x + m_pos.x, y + m_pos.y);
-				}
-			}
-		}
-	}
-}
-
-litehtml::element::ptr litehtml::html_tag::find_adjacent_sibling( const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/ )
-{
-	element::ptr ret;
-	for(auto& e : m_children)
-	{
-		if(e->get_display() != display_inline_text)
-		{
-			if(e == el)
-			{
-				if(ret)
-				{
-					int res = ret->select(selector, apply_pseudo);
-					if(res != select_no_match)
-					{
-						if(is_pseudo)
-						{
-							if(res & select_match_pseudo_class)
-							{
-								*is_pseudo = true;
-							} else
-							{
-								*is_pseudo = false;
-							}
-						}
-						return ret;
-					}
-				}
-				return 0;
-			} else
-			{
-				ret = e;
-			}
-		}
-	}
-	return 0;
-}
-
-litehtml::element::ptr litehtml::html_tag::find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/)
-{
-	element::ptr ret = 0;
-	for(auto& e : m_children)
-	{
-		if(e->get_display() != display_inline_text)
-		{
-			if(e == el)
-			{
-				return ret;
-			} else if(!ret)
-			{
-				int res = e->select(selector, apply_pseudo);
-				if(res != select_no_match)
-				{
-					if(is_pseudo)
-					{
-						if(res & select_match_pseudo_class)
-						{
-							*is_pseudo = true;
-						} else
-						{
-							*is_pseudo = false;
-						}
-					}
-					ret = e;
-				}
-			}
-		}
-	}
-	return 0;
-}
-
-bool litehtml::html_tag::is_only_child(const element::ptr& el, bool of_type) const
-{
-	int child_count = 0;
-	for(const auto& child : m_children)
-	{
-		if(child->get_display() != display_inline_text)
-		{
-			if( !of_type || (of_type && !t_strcmp(el->get_tagName(), child->get_tagName())) )
-			{
-				child_count++;
-			}
-			if(child_count > 1) break;
-		}
-	}
-	if(child_count > 1)
-	{
-		return false;
-	}
-	return true;
-}
-
-void litehtml::html_tag::update_floats(int dy, const element::ptr &parent)
-{
-	if(is_floats_holder())
-	{
-		bool reset_cache = false;
-		for(floated_box::vector::reverse_iterator fb = m_floats_left.rbegin(); fb != m_floats_left.rend(); fb++)
-		{
-			if(fb->el->is_ancestor(parent))
-			{
-				reset_cache	= true;
-				fb->pos.y	+= dy;
-			}
-		}
-		if(reset_cache)
-		{
-			m_cahe_line_left.invalidate();
-		}
-		reset_cache = false;
-		for(floated_box::vector::reverse_iterator fb = m_floats_right.rbegin(); fb != m_floats_right.rend(); fb++)
-		{
-			if(fb->el->is_ancestor(parent))
-			{
-				reset_cache	= true;
-				fb->pos.y	+= dy;
-			}
-		}
-		if(reset_cache)
-		{
-			m_cahe_line_right.invalidate();
-		}
-	} else
-	{
-		element::ptr el_parent = this->parent();
-		if (el_parent)
-		{
-			el_parent->update_floats(dy, parent);
-		}
-	}
-}
-
-void litehtml::html_tag::remove_before_after()
-{
-	if(!m_children.empty())
-	{
-		if( !t_strcmp(m_children.front()->get_tagName(), _t("::before")) )
-		{
-			m_children.erase(m_children.begin());
-		}
-	}
-	if(!m_children.empty())
-	{
-		if( !t_strcmp(m_children.back()->get_tagName(), _t("::after")) )
-		{
-			m_children.erase(m_children.end() - 1);
-		}
-	}
-}
-
-litehtml::element::ptr litehtml::html_tag::get_element_before()
-{
-	if(!m_children.empty())
-	{
-		if( !t_strcmp(m_children.front()->get_tagName(), _t("::before")) )
-		{
-			return m_children.front();
-		}
-	}
-	element::ptr el = std::make_shared<el_before>(get_document());
-	el->parent(shared_from_this());
-	m_children.insert(m_children.begin(), el);
-	return el;
-}
-
-litehtml::element::ptr litehtml::html_tag::get_element_after()
-{
-	if(!m_children.empty())
-	{
-		if( !t_strcmp(m_children.back()->get_tagName(), _t("::after")) )
-		{
-			return m_children.back();
-		}
-	}
-	element::ptr el = std::make_shared<el_after>(get_document());
-	appendChild(el);
-	return el;
-}
-
-void litehtml::html_tag::add_style( const litehtml::style& st )
-{
-	m_style.combine(st);
-}
-
-bool litehtml::html_tag::have_inline_child() const
-{
-	if(!m_children.empty())
-	{
-		for(const auto& el : m_children)
-		{
-			if(!el->is_white_space())
-			{
-				return true;
-			}
-		}
-	}
-	return false;
-}
-
-void litehtml::html_tag::refresh_styles()
-{
-	remove_before_after();
-
-	for (auto& el : m_children)
-	{
-		if(el->get_display() != display_inline_text)
-		{
-			el->refresh_styles();
-		}
-	}
-
-	m_style.clear();
-
-	for (auto& usel : m_used_styles)
-	{
-		usel->m_used = false;
-
-		if(usel->m_selector->is_media_valid())
-		{
-			int apply = select(*usel->m_selector, false);
-
-			if(apply != select_no_match)
-			{
-				if(apply & select_match_pseudo_class)
-				{
-					if(select(*usel->m_selector, true))
-					{
-						if(apply & select_match_with_after)
-						{
-							element::ptr el = get_element_after();
-							if(el)
-							{
-								el->add_style(*usel->m_selector->m_style);
-							}
-						} else if(apply & select_match_with_before)
-						{
-							element::ptr el = get_element_before();
-							if(el)
-							{
-								el->add_style(*usel->m_selector->m_style);
-							}
-						}
-						else
-						{
-							add_style(*usel->m_selector->m_style);
-							usel->m_used = true;
-						}
-					}
-				} else if(apply & select_match_with_after)
-				{
-					element::ptr el = get_element_after();
-					if(el)
-					{
-						el->add_style(*usel->m_selector->m_style);
-					}
-				} else if(apply & select_match_with_before)
-				{
-					element::ptr el = get_element_before();
-					if(el)
-					{
-						el->add_style(*usel->m_selector->m_style);
-					}
-				} else
-				{
-					add_style(*usel->m_selector->m_style);
-					usel->m_used = true;
-				}
-			}
-		}
-	}
-}
-
-litehtml::element::ptr litehtml::html_tag::get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex)
-{
-	element::ptr ret = 0;
-
-	if(m_overflow > overflow_visible)
-	{
-		if(!m_pos.is_point_inside(x, y))
-		{
-			return ret;
-		}
-	}
-
-	position pos = m_pos;
-	pos.x	= x - pos.x;
-	pos.y	= y - pos.y;
-
-	for(elements_vector::reverse_iterator i = m_children.rbegin(); i != m_children.rend() && !ret; i++)
-	{
-		element::ptr el = (*i);
-
-		if(el->is_visible() && el->get_display() != display_inline_text)
-		{
-			switch(flag)
-			{
-			case draw_positioned:
-				if(el->is_positioned() && el->get_zindex() == zindex)
-				{
-					if(el->get_element_position() == element_position_fixed)
-					{
-						ret = el->get_element_by_point(client_x, client_y, client_x, client_y);
-						if(!ret && (*i)->is_point_inside(client_x, client_y))
-						{
-							ret = (*i);
-						}
-					} else
-					{
-						ret = el->get_element_by_point(pos.x, pos.y, client_x, client_y);
-						if(!ret && (*i)->is_point_inside(pos.x, pos.y))
-						{
-							ret = (*i);
-						}
-					}
-					el = 0;
-				}
-				break;
-			case draw_block:
-				if(!el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
-				{
-					if(el->is_point_inside(pos.x, pos.y))
-					{
-						ret = el;
-					}
-				}
-				break;
-			case draw_floats:
-				if(el->get_float() != float_none && !el->is_positioned())
-				{
-					ret = el->get_element_by_point(pos.x, pos.y, client_x, client_y);
-
-					if(!ret && (*i)->is_point_inside(pos.x, pos.y))
-					{
-						ret = (*i);
-					}
-					el = 0;
-				}
-				break;
-			case draw_inlines:
-				if(el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
-				{
-					if(el->get_display() == display_inline_block)
-					{
-						ret = el->get_element_by_point(pos.x, pos.y, client_x, client_y);
-						el = 0;
-					}
-					if(!ret && (*i)->is_point_inside(pos.x, pos.y))
-					{
-						ret = (*i);
-					}
-				}
-				break;
-			default:
-				break;
-			}
-
-			if(el && !el->is_positioned())
-			{
-				if(flag == draw_positioned)
-				{
-					element::ptr child = el->get_child_by_point(pos.x, pos.y, client_x, client_y, flag, zindex);
-					if(child)
-					{
-						ret = child;
-					}
-				} else
-				{
-					if(	el->get_float() == float_none &&
-						el->get_display() != display_inline_block)
-					{
-						element::ptr child = el->get_child_by_point(pos.x, pos.y, client_x, client_y, flag, zindex);
-						if(child)
-						{
-							ret = child;
-						}
-					}
-				}
-			}
-		}
-	}
-
-	return ret;
-}
-
-litehtml::element::ptr litehtml::html_tag::get_element_by_point(int x, int y, int client_x, int client_y)
-{
-	if(!is_visible()) return 0;
-
-	element::ptr ret;
-
-	std::map<int, bool> zindexes;
-
-	for(elements_vector::iterator i = m_positioned.begin(); i != m_positioned.end(); i++)
-	{
-		zindexes[(*i)->get_zindex()];
-	}
-
-	for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end() && !ret; idx++)
-	{
-		if(idx->first > 0)
-		{
-			ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, idx->first);
-		}
-	}
-	if(ret) return ret;
-
-	for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end() && !ret; idx++)
-	{
-		if(idx->first == 0)
-		{
-			ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, idx->first);
-		}
-	}
-	if(ret) return ret;
-
-	ret = get_child_by_point(x, y, client_x, client_y, draw_inlines, 0);
-	if(ret) return ret;
-
-	ret = get_child_by_point(x, y, client_x, client_y, draw_floats, 0);
-	if(ret) return ret;
-
-	ret = get_child_by_point(x, y, client_x, client_y, draw_block, 0);
-	if(ret) return ret;
-
-
-	for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end() && !ret; idx++)
-	{
-		if(idx->first < 0)
-		{
-			ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, idx->first);
-		}
-	}
-	if(ret) return ret;
-
-	if(m_el_position == element_position_fixed)
-	{
-		if(is_point_inside(client_x, client_y))
-		{
-			ret = shared_from_this();
-		}
-	} else
-	{
-		if(is_point_inside(x, y))
-		{
-			ret = shared_from_this();
-		}
-	}
-
-	return ret;
-}
-
-const litehtml::background* litehtml::html_tag::get_background(bool own_only)
-{
-	if(own_only)
-	{
-		// return own background with check for empty one
-		if(m_bg.m_image.empty() && !m_bg.m_color.alpha)
-		{
-			return 0;
-		}
-		return &m_bg;
-	}
-
-	if(m_bg.m_image.empty() && !m_bg.m_color.alpha)
-	{
-		// if this is root element (<html>) try to get background from body
-		if (!have_parent())
-		{
-			for (const auto& el : m_children)
-			{
-				if( el->is_body() )
-				{
-					// return own body background
-					return el->get_background(true);
-				}
-			}
-		}
-		return 0;
-	}
-	
-	if(is_body())
-	{
-		element::ptr el_parent = parent();
-		if (el_parent)
-		{
-			if (!el_parent->get_background(true))
-			{
-				// parent of body will draw background for body
-				return 0;
-			}
-		}
-	}
-
-	return &m_bg;
-}
-
-int litehtml::html_tag::render_box(int x, int y, int max_width, bool second_pass /*= false*/)
-{
-	int parent_width = max_width;
-
-	calc_outlines(parent_width);
-
-	m_pos.clear();
-	m_pos.move_to(x, y);
-
-	m_pos.x += content_margins_left();
-	m_pos.y += content_margins_top();
-
-	int ret_width = 0;
-
-	def_value<int>	block_width(0);
-
-	if (m_display != display_table_cell && !m_css_width.is_predefined())
-	{
-		int w = calc_width(parent_width);
-		
-		if (m_box_sizing == box_sizing_border_box)
-		{
-			w -= m_padding.width() + m_borders.width();
-		}
-		ret_width = max_width = block_width = w;
-	}
-	else
-	{
-		if (max_width)
-		{
-			max_width -= content_margins_left() + content_margins_right();
-		}
-	}
-
-	// check for max-width (on the first pass only)
-	if (!m_css_max_width.is_predefined() && !second_pass)
-	{
-		int mw = get_document()->cvt_units(m_css_max_width, m_font_size, parent_width);
-		if (m_box_sizing == box_sizing_border_box)
-		{
-			mw -= m_padding.left + m_borders.left + m_padding.right + m_borders.right;
-		}
-		if (max_width > mw)
-		{
-			max_width = mw;
-		}
-	}
-
-	m_floats_left.clear();
-	m_floats_right.clear();
-	m_boxes.clear();
-	m_cahe_line_left.invalidate();
-	m_cahe_line_right.invalidate();
-
-	element_position el_position;
-
-	int block_height = 0;
-
-	m_pos.height = 0;
-
-	if (get_predefined_height(block_height))
-	{
-		m_pos.height = block_height;
-	}
-
-	white_space ws = get_white_space();
-	bool skip_spaces = false;
-	if (ws == white_space_normal ||
-		ws == white_space_nowrap ||
-		ws == white_space_pre_line)
-	{
-		skip_spaces = true;
-	}
-
-	bool was_space = false;
-
-	for (auto el : m_children)
-	{
-		// we don't need process absolute and fixed positioned element on the second pass
-		if (second_pass)
-		{
-			el_position = el->get_element_position();
-			if ((el_position == element_position_absolute || el_position == element_position_fixed)) continue;
-		}
-
-		// skip spaces to make rendering a bit faster
-		if (skip_spaces)
-		{
-			if (el->is_white_space())
-			{
-				if (was_space)
-				{
-					el->skip(true);
-					continue;
-				}
-				else
-				{
-					was_space = true;
-				}
-			}
-			else
-			{
-				was_space = false;
-			}
-		}
-
-		// place element into rendering flow
-		int rw = place_element(el, max_width);
-		if (rw > ret_width)
-		{
-			ret_width = rw;
-		}
-	}
-
-	finish_last_box(true);
-
-	if (block_width.is_default() && is_inline_box())
-	{
-		m_pos.width = ret_width;
-	}
-	else
-	{
-		m_pos.width = max_width;
-	}
-	calc_auto_margins(parent_width);
-
-	if (!m_boxes.empty())
-	{
-		if (collapse_top_margin())
-		{
-			int old_top = m_margins.top;
-			m_margins.top = std::max(m_boxes.front()->top_margin(), m_margins.top);
-			if (m_margins.top != old_top)
-			{
-				update_floats(m_margins.top - old_top, shared_from_this());
-			}
-		}
-		if (collapse_bottom_margin())
-		{
-			m_margins.bottom = std::max(m_boxes.back()->bottom_margin(), m_margins.bottom);
-			m_pos.height = m_boxes.back()->bottom() - m_boxes.back()->bottom_margin();
-		}
-		else
-		{
-			m_pos.height = m_boxes.back()->bottom();
-		}
-	}
-
-	// add the floats height to the block height
-	if (is_floats_holder())
-	{
-		int floats_height = get_floats_height();
-		if (floats_height > m_pos.height)
-		{
-			m_pos.height = floats_height;
-		}
-	}
-
-	// calculate the final position
-
-	m_pos.move_to(x, y);
-	m_pos.x += content_margins_left();
-	m_pos.y += content_margins_top();
-
-	if (get_predefined_height(block_height))
-	{
-		m_pos.height = block_height;
-	}
-
-	int min_height = 0;
-	if (!m_css_min_height.is_predefined() && m_css_min_height.units() == css_units_percentage)
-	{
-		element::ptr el_parent = parent();
-		if (el_parent)
-		{
-			if (el_parent->get_predefined_height(block_height))
-			{
-				min_height = m_css_min_height.calc_percent(block_height);
-			}
-		}
-	}
-	else
-	{
-		min_height = (int)m_css_min_height.val();
-	}
-	if (min_height != 0 && m_box_sizing == box_sizing_border_box)
-	{
-		min_height -= m_padding.top + m_borders.top + m_padding.bottom + m_borders.bottom;
-		if (min_height < 0) min_height = 0;
-	}
-
-	if (m_display == display_list_item)
-	{
-		const tchar_t* list_image = get_style_property(_t("list-style-image"), true, 0);
-		if (list_image)
-		{
-			tstring url;
-			css::parse_css_url(list_image, url);
-
-			size sz;
-			const tchar_t* list_image_baseurl = get_style_property(_t("list-style-image-baseurl"), true, 0);
-			get_document()->container()->get_image_size(url.c_str(), list_image_baseurl, sz);
-			if (min_height < sz.height)
-			{
-				min_height = sz.height;
-			}
-		}
-
-	}
-
-	if (min_height > m_pos.height)
-	{
-		m_pos.height = min_height;
-	}
-
-	int min_width = m_css_min_width.calc_percent(parent_width);
-
-	if (min_width != 0 && m_box_sizing == box_sizing_border_box)
-	{
-		min_width -= m_padding.left + m_borders.left + m_padding.right + m_borders.right;
-		if (min_width < 0) min_width = 0;
-	}
-
-	if (min_width != 0)
-	{
-		if (min_width > m_pos.width)
-		{
-			m_pos.width = min_width;
-		}
-		if (min_width > ret_width)
-		{
-			ret_width = min_width;
-		}
-	}
-
-	ret_width += content_margins_left() + content_margins_right();
-
-	// re-render with new width
-	if (ret_width < max_width && !second_pass && have_parent())
-	{
-		if (m_display == display_inline_block ||
-			m_css_width.is_predefined() &&
-			(m_float != float_none ||
-			m_display == display_table ||
-			m_el_position == element_position_absolute ||
-			m_el_position == element_position_fixed
-			)
-			)
-		{
-			render(x, y, ret_width, true);
-			m_pos.width = ret_width - (content_margins_left() + content_margins_right());
-		}
-	}
-
-	if (is_floats_holder() && !second_pass)
-	{
-		for (const auto& fb : m_floats_left)
-		{
-			fb.el->apply_relative_shift(fb.el->parent()->calc_width(m_pos.width));
-		}
-	}
-
-
-	return ret_width;
-}
-
-int litehtml::html_tag::render_table(int x, int y, int max_width, bool second_pass /*= false*/)
-{
-	if (!m_grid) return 0;
-
-	int parent_width = max_width;
-
-	calc_outlines(parent_width);
-
-	m_pos.clear();
-	m_pos.move_to(x, y);
-
-	m_pos.x += content_margins_left();
-	m_pos.y += content_margins_top();
-
-	def_value<int>	block_width(0);
-
-	if (!m_css_width.is_predefined())
-	{
-		max_width = block_width = calc_width(parent_width) - m_padding.width() - m_borders.width();
-	}
-	else
-	{
-		if (max_width)
-		{
-			max_width -= content_margins_left() + content_margins_right();
-		}
-	}
-
-	// Calculate table spacing
-	int table_width_spacing = 0;
-	if (m_border_collapse == border_collapse_separate)
-	{
-		table_width_spacing = m_border_spacing_x * (m_grid->cols_count() + 1);
-	}
-	else
-	{
-		table_width_spacing = 0;
-
-		if (m_grid->cols_count())
-		{
-			table_width_spacing -= std::min(border_left(), m_grid->column(0).border_left);
-			table_width_spacing -= std::min(border_right(), m_grid->column(m_grid->cols_count() - 1).border_right);
-		}
-
-		for (int col = 1; col < m_grid->cols_count(); col++)
-		{
-			table_width_spacing -= std::min(m_grid->column(col).border_left, m_grid->column(col - 1).border_right);
-		}
-	}
-
-
-	// Calculate the minimum content width (MCW) of each cell: the formatted content may span any number of lines but may not overflow the cell box. 
-	// If the specified 'width' (W) of the cell is greater than MCW, W is the minimum cell width. A value of 'auto' means that MCW is the minimum 
-	// cell width.
-	// 
-	// Also, calculate the "maximum" cell width of each cell: formatting the content without breaking lines other than where explicit line breaks occur.
-
-	if (m_grid->cols_count() == 1 && !block_width.is_default())
-	{
-		for (int row = 0; row < m_grid->rows_count(); row++)
-		{
-			table_cell* cell = m_grid->cell(0, row);
-			if (cell && cell->el)
-			{
-				cell->min_width = cell->max_width = cell->el->render(0, 0, max_width - table_width_spacing);
-				cell->el->m_pos.width = cell->min_width - cell->el->content_margins_left() - cell->el->content_margins_right();
-			}
-		}
-	}
-	else
-	{
-		for (int row = 0; row < m_grid->rows_count(); row++)
-		{
-			for (int col = 0; col < m_grid->cols_count(); col++)
-			{
-				table_cell* cell = m_grid->cell(col, row);
-				if (cell && cell->el)
-				{
-					if (!m_grid->column(col).css_width.is_predefined() && m_grid->column(col).css_width.units() != css_units_percentage)
-					{
-						int css_w = m_grid->column(col).css_width.calc_percent(block_width);
-						int el_w = cell->el->render(0, 0, css_w);
-						cell->min_width = cell->max_width = std::max(css_w, el_w);
-						cell->el->m_pos.width = cell->min_width - cell->el->content_margins_left() - cell->el->content_margins_right();
-					}
-					else
-					{
-						// calculate minimum content width
-						cell->min_width = cell->el->render(0, 0, 1);
-						// calculate maximum content width
-						cell->max_width = cell->el->render(0, 0, max_width - table_width_spacing);
-					}
-				}
-			}
-		}
-	}
-
-	// For each column, determine a maximum and minimum column width from the cells that span only that column. 
-	// The minimum is that required by the cell with the largest minimum cell width (or the column 'width', whichever is larger). 
-	// The maximum is that required by the cell with the largest maximum cell width (or the column 'width', whichever is larger).
-
-	for (int col = 0; col < m_grid->cols_count(); col++)
-	{
-		m_grid->column(col).max_width = 0;
-		m_grid->column(col).min_width = 0;
-		for (int row = 0; row < m_grid->rows_count(); row++)
-		{
-			if (m_grid->cell(col, row)->colspan <= 1)
-			{
-				m_grid->column(col).max_width = std::max(m_grid->column(col).max_width, m_grid->cell(col, row)->max_width);
-				m_grid->column(col).min_width = std::max(m_grid->column(col).min_width, m_grid->cell(col, row)->min_width);
-			}
-		}
-	}
-
-	// For each cell that spans more than one column, increase the minimum widths of the columns it spans so that together, 
-	// they are at least as wide as the cell. Do the same for the maximum widths. 
-	// If possible, widen all spanned columns by approximately the same amount.
-
-	for (int col = 0; col < m_grid->cols_count(); col++)
-	{
-		for (int row = 0; row < m_grid->rows_count(); row++)
-		{
-			if (m_grid->cell(col, row)->colspan > 1)
-			{
-				int max_total_width = m_grid->column(col).max_width;
-				int min_total_width = m_grid->column(col).min_width;
-				for (int col2 = col + 1; col2 < col + m_grid->cell(col, row)->colspan; col2++)
-				{
-					max_total_width += m_grid->column(col2).max_width;
-					min_total_width += m_grid->column(col2).min_width;
-				}
-				if (min_total_width < m_grid->cell(col, row)->min_width)
-				{
-					m_grid->distribute_min_width(m_grid->cell(col, row)->min_width - min_total_width, col, col + m_grid->cell(col, row)->colspan - 1);
-				}
-				if (max_total_width < m_grid->cell(col, row)->max_width)
-				{
-					m_grid->distribute_max_width(m_grid->cell(col, row)->max_width - max_total_width, col, col + m_grid->cell(col, row)->colspan - 1);
-				}
-			}
-		}
-	}
-
-	// If the 'table' or 'inline-table' element's 'width' property has a computed value (W) other than 'auto', the used width is the 
-	// greater of W, CAPMIN, and the minimum width required by all the columns plus cell spacing or borders (MIN). 
-	// If the used width is greater than MIN, the extra width should be distributed over the columns.
-	//
-	// If the 'table' or 'inline-table' element has 'width: auto', the used width is the greater of the table's containing block width, 
-	// CAPMIN, and MIN. However, if either CAPMIN or the maximum width required by the columns plus cell spacing or borders (MAX) is 
-	// less than that of the containing block, use max(MAX, CAPMIN).
-
-
-	int table_width = 0;
-	int min_table_width = 0;
-	int max_table_width = 0;
-
-	if (!block_width.is_default())
-	{
-		table_width = m_grid->calc_table_width(block_width - table_width_spacing, false, min_table_width, max_table_width);
-	}
-	else
-	{
-		table_width = m_grid->calc_table_width(max_width - table_width_spacing, true, min_table_width, max_table_width);
-	}
-
-	min_table_width += table_width_spacing;
-	max_table_width += table_width_spacing;
-	table_width += table_width_spacing;
-	m_grid->calc_horizontal_positions(m_borders, m_border_collapse, m_border_spacing_x);
-
-	bool row_span_found = false;
-
-	// render cells with computed width
-	for (int row = 0; row < m_grid->rows_count(); row++)
-	{
-		m_grid->row(row).height = 0;
-		for (int col = 0; col < m_grid->cols_count(); col++)
-		{
-			table_cell* cell = m_grid->cell(col, row);
-			if (cell->el)
-			{
-				int span_col = col + cell->colspan - 1;
-				if (span_col >= m_grid->cols_count())
-				{
-					span_col = m_grid->cols_count() - 1;
-				}
-				int cell_width = m_grid->column(span_col).right - m_grid->column(col).left;
-
-				if (cell->el->m_pos.width != cell_width - cell->el->content_margins_left() - cell->el->content_margins_right())
-				{
-					cell->el->render(m_grid->column(col).left, 0, cell_width);
-					cell->el->m_pos.width = cell_width - cell->el->content_margins_left() - cell->el->content_margins_right();
-				}
-				else
-				{
-					cell->el->m_pos.x = m_grid->column(col).left + cell->el->content_margins_left();
-				}
-
-				if (cell->rowspan <= 1)
-				{
-					m_grid->row(row).height = std::max(m_grid->row(row).height, cell->el->height());
-				}
-				else
-				{
-					row_span_found = true;
-				}
-
-			}
-		}
-	}
-
-	if (row_span_found)
-	{
-		for (int col = 0; col < m_grid->cols_count(); col++)
-		{
-			for (int row = 0; row < m_grid->rows_count(); row++)
-			{
-				table_cell* cell = m_grid->cell(col, row);
-				if (cell->el)
-				{
-					int span_row = row + cell->rowspan - 1;
-					if (span_row >= m_grid->rows_count())
-					{
-						span_row = m_grid->rows_count() - 1;
-					}
-					if (span_row != row)
-					{
-						int h = 0;
-						for (int i = row; i <= span_row; i++)
-						{
-							h += m_grid->row(i).height;
-						}
-						if (h < cell->el->height())
-						{
-							m_grid->row(span_row).height += cell->el->height() - h;
-						}
-					}
-				}
-			}
-		}
-	}
-
-	// Calculate vertical table spacing
-	int table_height_spacing = 0;
-	if (m_border_collapse == border_collapse_separate)
-	{
-		table_height_spacing = m_border_spacing_y * (m_grid->rows_count() + 1);
-	}
-	else
-	{
-		table_height_spacing = 0;
-
-		if (m_grid->rows_count())
-		{
-			table_height_spacing -= std::min(border_top(), m_grid->row(0).border_top);
-			table_height_spacing -= std::min(border_bottom(), m_grid->row(m_grid->rows_count() - 1).border_bottom);
-		}
-
-		for (int row = 1; row < m_grid->rows_count(); row++)
-		{
-			table_height_spacing -= std::min(m_grid->row(row).border_top, m_grid->row(row - 1).border_bottom);
-		}
-	}
-
-
-	// calculate block height
-	int block_height = 0;
-	if (get_predefined_height(block_height))
-	{
-		block_height -= m_padding.height() + m_borders.height();
-	}
-
-	// calculate minimum height from m_css_min_height
-	int min_height = 0;
-	if (!m_css_min_height.is_predefined() && m_css_min_height.units() == css_units_percentage)
-	{
-		element::ptr el_parent = parent();
-		if (el_parent)
-		{
-			int parent_height = 0;
-			if (el_parent->get_predefined_height(parent_height))
-			{
-				min_height = m_css_min_height.calc_percent(parent_height);
-			}
-		}
-	}
-	else
-	{
-		min_height = (int)m_css_min_height.val();
-	}
-
-	int extra_row_height = 0;
-	int minimum_table_height = std::max(block_height, min_height);
-
-	m_grid->calc_rows_height(minimum_table_height - table_height_spacing, m_border_spacing_y);
-	m_grid->calc_vertical_positions(m_borders, m_border_collapse, m_border_spacing_y);
-
-	int table_height = 0;
-
-	// place cells vertically
-	for (int col = 0; col < m_grid->cols_count(); col++)
-	{
-		for (int row = 0; row < m_grid->rows_count(); row++)
-		{
-			table_cell* cell = m_grid->cell(col, row);
-			if (cell->el)
-			{
-				int span_row = row + cell->rowspan - 1;
-				if (span_row >= m_grid->rows_count())
-				{
-					span_row = m_grid->rows_count() - 1;
-				}
-				cell->el->m_pos.y = m_grid->row(row).top + cell->el->content_margins_top();
-				cell->el->m_pos.height = m_grid->row(span_row).bottom - m_grid->row(row).top - cell->el->content_margins_top() - cell->el->content_margins_bottom();
-				table_height = std::max(table_height, m_grid->row(span_row).bottom);
-				cell->el->apply_vertical_align();
-			}
-		}
-	}
-
-	if (m_border_collapse == border_collapse_collapse)
-	{
-		if (m_grid->rows_count())
-		{
-			table_height -= std::min(border_bottom(), m_grid->row(m_grid->rows_count() - 1).border_bottom);
-		}
-	}
-	else
-	{
-		table_height += m_border_spacing_y;
-	}
-
-	m_pos.width = table_width;
-
-	calc_auto_margins(parent_width);
-
-	m_pos.move_to(x, y);
-	m_pos.x += content_margins_left();
-	m_pos.y += content_margins_top();
-	m_pos.width = table_width;
-	m_pos.height = table_height;
-
-	return max_table_width;
-}
-
-void litehtml::html_tag::draw_children_box(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex)
-{
-	position pos = m_pos;
-	pos.x += x;
-	pos.y += y;
-
-	document::ptr doc = get_document();
-
-	if (m_overflow > overflow_visible)
-	{
-		position border_box = pos;
-		border_box += m_padding;
-		border_box += m_borders;
-
-		border_radiuses bdr_radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
-
-		bdr_radius -= m_borders;
-		bdr_radius -= m_padding;
-
-		doc->container()->set_clip(pos, bdr_radius, true, true);
-	}
-
-	position browser_wnd;
-	doc->container()->get_client_rect(browser_wnd);
-
-	element::ptr el;
-	for (auto& item : m_children)
-	{
-		el = item;
-		if (el->is_visible())
-		{
-			switch (flag)
-			{
-			case draw_positioned:
-				if (el->is_positioned() && el->get_zindex() == zindex)
-				{
-					if (el->get_element_position() == element_position_fixed)
-					{
-						el->draw(hdc, browser_wnd.x, browser_wnd.y, clip);
-						el->draw_stacking_context(hdc, browser_wnd.x, browser_wnd.y, clip, true);
-					}
-					else
-					{
-						el->draw(hdc, pos.x, pos.y, clip);
-						el->draw_stacking_context(hdc, pos.x, pos.y, clip, true);
-					}
-					el = 0;
-				}
-				break;
-			case draw_block:
-				if (!el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
-				{
-					el->draw(hdc, pos.x, pos.y, clip);
-				}
-				break;
-			case draw_floats:
-				if (el->get_float() != float_none && !el->is_positioned())
-				{
-					el->draw(hdc, pos.x, pos.y, clip);
-					el->draw_stacking_context(hdc, pos.x, pos.y, clip, false);
-					el = 0;
-				}
-				break;
-			case draw_inlines:
-				if (el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
-				{
-					el->draw(hdc, pos.x, pos.y, clip);
-					if (el->get_display() == display_inline_block)
-					{
-						el->draw_stacking_context(hdc, pos.x, pos.y, clip, false);
-						el = 0;
-					}
-				}
-				break;
-			default:
-				break;
-			}
-
-			if (el)
-			{
-				if (flag == draw_positioned)
-				{
-					if (!el->is_positioned())
-					{
-						el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
-					}
-				}
-				else
-				{
-					if (el->get_float() == float_none &&
-						el->get_display() != display_inline_block &&
-						!el->is_positioned())
-					{
-						el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
-					}
-				}
-			}
-		}
-	}
-
-	if (m_overflow > overflow_visible)
-	{
-		doc->container()->del_clip();
-	}
-}
-
-void litehtml::html_tag::draw_children_table(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex)
-{
-	if (!m_grid) return;
-
-	position pos = m_pos;
-	pos.x += x;
-	pos.y += y;
-	for (int row = 0; row < m_grid->rows_count(); row++)
-	{
-		if (flag == draw_block)
-		{
-			m_grid->row(row).el_row->draw_background(hdc, pos.x, pos.y, clip);
-		}
-		for (int col = 0; col < m_grid->cols_count(); col++)
-		{
-			table_cell* cell = m_grid->cell(col, row);
-			if (cell->el)
-			{
-				if (flag == draw_block)
-				{
-					cell->el->draw(hdc, pos.x, pos.y, clip);
-				}
-				cell->el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
-			}
-		}
-	}
-}
+#include "html.h"
+#include "html_tag.h"
+#include "document.h"
+#include "iterators.h"
+#include "stylesheet.h"
+#include "table.h"
+#include <algorithm>
+#include <locale>
+#include "el_before_after.h"
+
+litehtml::html_tag::html_tag(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
+{
+	m_box_sizing			= box_sizing_content_box;
+	m_z_index				= 0;
+	m_overflow				= overflow_visible;
+	m_box					= 0;
+	m_text_align			= text_align_left;
+	m_el_position			= element_position_static;
+	m_display				= display_inline;
+	m_vertical_align		= va_baseline;
+	m_list_style_type		= list_style_type_none;
+	m_list_style_position	= list_style_position_outside;
+	m_float					= float_none;
+	m_clear					= clear_none;
+	m_font					= 0;
+	m_font_size				= 0;
+	m_white_space			= white_space_normal;
+	m_lh_predefined			= false;
+	m_line_height			= 0;
+	m_visibility			= visibility_visible;
+	m_border_spacing_x		= 0;
+	m_border_spacing_y		= 0;
+	m_border_collapse		= border_collapse_separate;
+}
+
+litehtml::html_tag::~html_tag()
+{
+
+}
+
+bool litehtml::html_tag::appendChild(const element::ptr &el)
+{
+	if(el)
+	{
+		el->parent(shared_from_this());
+		m_children.push_back(el);
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::html_tag::removeChild(const element::ptr &el)
+{
+	if(el && el->parent() == shared_from_this())
+	{
+		el->parent(nullptr);
+		m_children.erase(std::remove(m_children.begin(), m_children.end(), el), m_children.end());
+		return true;
+	}
+	return false;
+}
+
+void litehtml::html_tag::clearRecursive()
+{
+	for(auto& el : m_children)
+	{
+		el->clearRecursive();
+		el->parent(nullptr);
+	}
+	m_children.clear();
+}
+
+
+const litehtml::tchar_t* litehtml::html_tag::get_tagName() const
+{
+	return m_tag.c_str();
+}
+
+void litehtml::html_tag::set_attr( const tchar_t* name, const tchar_t* val )
+{
+	if(name && val)
+	{
+		tstring s_val = name;
+		std::locale lc = std::locale::global(std::locale::classic());
+		for(size_t i = 0; i < s_val.length(); i++)
+		{
+			s_val[i] = std::tolower(s_val[i], lc);
+		}
+		m_attrs[s_val] = val;
+
+		if( t_strcasecmp( name, _t("class") ) == 0 )
+		{
+			m_class_values.resize( 0 );
+			split_string( val, m_class_values, _t(" ") );
+		}
+	}
+}
+
+const litehtml::tchar_t* litehtml::html_tag::get_attr( const tchar_t* name, const tchar_t* def )
+{
+	string_map::const_iterator attr = m_attrs.find(name);
+	if(attr != m_attrs.end())
+	{
+		return attr->second.c_str();
+	}
+	return def;
+}
+
+litehtml::elements_vector litehtml::html_tag::select_all( const tstring& selector )
+{
+	css_selector sel(media_query_list::ptr(0));
+	sel.parse(selector);
+	
+	return select_all(sel);
+}
+
+litehtml::elements_vector litehtml::html_tag::select_all( const css_selector& selector )
+{
+	litehtml::elements_vector res;
+	select_all(selector, res);
+	return res;
+}
+
+void litehtml::html_tag::select_all(const css_selector& selector, elements_vector& res)
+{
+	if(select(selector))
+	{
+		res.push_back(shared_from_this());
+	}
+	
+	for(auto& el : m_children)
+	{
+		el->select_all(selector, res);
+	}
+}
+
+
+litehtml::element::ptr litehtml::html_tag::select_one( const tstring& selector )
+{
+	css_selector sel(media_query_list::ptr(0));
+	sel.parse(selector);
+
+	return select_one(sel);
+}
+
+litehtml::element::ptr litehtml::html_tag::select_one( const css_selector& selector )
+{
+	if(select(selector))
+	{
+		return shared_from_this();
+	}
+
+	for(auto& el : m_children)
+	{
+		element::ptr res = el->select_one(selector);
+		if(res)
+		{
+			return res;
+		}
+	}
+	return 0;
+}
+
+void litehtml::html_tag::apply_stylesheet( const litehtml::css& stylesheet )
+{
+	remove_before_after();
+
+	for(const auto& sel : stylesheet.selectors())
+	{
+		int apply = select(*sel, false);
+
+		if(apply != select_no_match)
+		{
+			used_selector::ptr us = std::unique_ptr<used_selector>(new used_selector(sel, false));
+
+			if(sel->is_media_valid())
+			{
+				if(apply & select_match_pseudo_class)
+				{
+					if(select(*sel, true))
+					{
+						if(apply & select_match_with_after)
+						{
+							element::ptr el = get_element_after();
+							if(el)
+							{
+								el->add_style(*sel->m_style);
+							}
+						} else if(apply & select_match_with_before)
+						{
+							element::ptr el = get_element_before();
+							if(el)
+							{
+								el->add_style(*sel->m_style);
+							}
+						}
+						else
+						{
+							add_style(*sel->m_style);
+							us->m_used = true;
+						}
+					}
+				} else if(apply & select_match_with_after)
+				{
+					element::ptr el = get_element_after();
+					if(el)
+					{
+						el->add_style(*sel->m_style);
+					}
+				} else if(apply & select_match_with_before)
+				{
+					element::ptr el = get_element_before();
+					if(el)
+					{
+						el->add_style(*sel->m_style);
+					}
+				} else
+				{
+					add_style(*sel->m_style);
+					us->m_used = true;
+				}
+			}
+			m_used_styles.push_back(std::move(us));
+		}
+	}
+
+	for(auto& el : m_children)
+	{
+		if(el->get_display() != display_inline_text)
+		{
+			el->apply_stylesheet(stylesheet);
+		}
+	}
+}
+
+void litehtml::html_tag::get_content_size( size& sz, int max_width )
+{
+	sz.height	= 0;
+	if(m_display == display_block)
+	{
+		sz.width	= max_width;
+	} else
+	{
+		sz.width	= 0;
+	}
+}
+
+void litehtml::html_tag::draw( uint_ptr hdc, int x, int y, const position* clip )
+{
+	position pos = m_pos;
+	pos.x	+= x;
+	pos.y	+= y;
+
+	draw_background(hdc, x, y, clip);
+
+	if(m_display == display_list_item && m_list_style_type != list_style_type_none)
+	{
+		if(m_overflow > overflow_visible)
+		{
+			position border_box = pos;
+			border_box += m_padding;
+			border_box += m_borders;
+
+			border_radiuses bdr_radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
+
+			bdr_radius -= m_borders;
+			bdr_radius -= m_padding;
+
+			get_document()->container()->set_clip(pos, bdr_radius, true, true);
+		}
+
+		draw_list_marker(hdc, pos);
+
+		if(m_overflow > overflow_visible)
+		{
+			get_document()->container()->del_clip();
+		}
+	}
+}
+
+litehtml::uint_ptr litehtml::html_tag::get_font(font_metrics* fm)
+{
+	if(fm)
+	{
+		*fm = m_font_metrics;
+	}
+	return m_font;
+}
+
+const litehtml::tchar_t* litehtml::html_tag::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ )
+{
+	const tchar_t* ret = m_style.get_property(name);
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		if ( ( ret && !t_strcasecmp(ret, _t("inherit")) ) || (!ret && inherited) )
+		{
+			ret = el_parent->get_style_property(name, inherited, def);
+		}
+	}
+
+	if(!ret)
+	{
+		ret = def;
+	}
+
+	return ret;
+}
+
+void litehtml::html_tag::parse_styles(bool is_reparse)
+{
+	const tchar_t* style = get_attr(_t("style"));
+
+	if(style)
+	{
+		m_style.add(style, NULL);
+	}
+
+	init_font();
+	document::ptr doc = get_document();
+
+	m_el_position	= (element_position)	value_index(get_style_property(_t("position"),		false,	_t("static")),		element_position_strings,	element_position_fixed);
+	m_text_align	= (text_align)			value_index(get_style_property(_t("text-align"),		true,	_t("left")),		text_align_strings,			text_align_left);
+	m_overflow		= (overflow)			value_index(get_style_property(_t("overflow"),		false,	_t("visible")),		overflow_strings,			overflow_visible);
+	m_white_space	= (white_space)			value_index(get_style_property(_t("white-space"),	true,	_t("normal")),		white_space_strings,		white_space_normal);
+	m_display		= (style_display)		value_index(get_style_property(_t("display"),		false,	_t("inline")),		style_display_strings,		display_inline);
+	m_visibility	= (visibility)			value_index(get_style_property(_t("visibility"),	true,	_t("visible")),		visibility_strings,			visibility_visible);
+	m_box_sizing	= (box_sizing)			value_index(get_style_property(_t("box-sizing"),		false,	_t("content-box")),	box_sizing_strings,			box_sizing_content_box);
+
+	if(m_el_position != element_position_static)
+	{
+		const tchar_t* val = get_style_property(_t("z-index"), false, 0);
+		if(val)
+		{
+			m_z_index = t_atoi(val);
+		}
+	}
+
+	const tchar_t* va	= get_style_property(_t("vertical-align"), true,	_t("baseline"));
+	m_vertical_align = (vertical_align) value_index(va, vertical_align_strings, va_baseline);
+
+	const tchar_t* fl	= get_style_property(_t("float"), false,	_t("none"));
+	m_float = (element_float) value_index(fl, element_float_strings, float_none);
+
+	m_clear = (element_clear) value_index(get_style_property(_t("clear"), false, _t("none")), element_clear_strings, clear_none);
+
+	if (m_float != float_none)
+	{
+		// reset display in to block for floating elements
+		if (m_display != display_none)
+		{
+			m_display = display_block;
+		}
+	}
+	else if (m_display == display_table ||
+		m_display == display_table_caption ||
+		m_display == display_table_cell ||
+		m_display == display_table_column ||
+		m_display == display_table_column_group ||
+		m_display == display_table_footer_group ||
+		m_display == display_table_header_group ||
+		m_display == display_table_row ||
+		m_display == display_table_row_group)
+	{
+		doc->add_tabular(shared_from_this());
+	}
+	// fix inline boxes with absolute/fixed positions
+	else if (m_display != display_none && is_inline_box())
+	{
+		if (m_el_position == element_position_absolute || m_el_position == element_position_fixed)
+		{
+			m_display = display_block;
+		}
+	}
+
+	m_css_text_indent.fromString(	get_style_property(_t("text-indent"),	true,	_t("0")),	_t("0"));
+
+	m_css_width.fromString(			get_style_property(_t("width"),			false,	_t("auto")), _t("auto"));
+	m_css_height.fromString(		get_style_property(_t("height"),		false,	_t("auto")), _t("auto"));
+
+	doc->cvt_units(m_css_width, m_font_size);
+	doc->cvt_units(m_css_height, m_font_size);
+
+	m_css_min_width.fromString(		get_style_property(_t("min-width"),		false,	_t("0")));
+	m_css_min_height.fromString(	get_style_property(_t("min-height"),		false,	_t("0")));
+
+	m_css_max_width.fromString(		get_style_property(_t("max-width"),		false,	_t("none")),	_t("none"));
+	m_css_max_height.fromString(	get_style_property(_t("max-height"),		false,	_t("none")),	_t("none"));
+	
+	doc->cvt_units(m_css_min_width, m_font_size);
+	doc->cvt_units(m_css_min_height, m_font_size);
+
+	m_css_offsets.left.fromString(		get_style_property(_t("left"),				false,	_t("auto")), _t("auto"));
+	m_css_offsets.right.fromString(		get_style_property(_t("right"),				false,	_t("auto")), _t("auto"));
+	m_css_offsets.top.fromString(		get_style_property(_t("top"),				false,	_t("auto")), _t("auto"));
+	m_css_offsets.bottom.fromString(	get_style_property(_t("bottom"),			false,	_t("auto")), _t("auto"));
+
+	doc->cvt_units(m_css_offsets.left, m_font_size);
+	doc->cvt_units(m_css_offsets.right, m_font_size);
+	doc->cvt_units(m_css_offsets.top,		m_font_size);
+	doc->cvt_units(m_css_offsets.bottom,	m_font_size);
+
+	m_css_margins.left.fromString(		get_style_property(_t("margin-left"),		false,	_t("0")), _t("auto"));
+	m_css_margins.right.fromString(		get_style_property(_t("margin-right"),		false,	_t("0")), _t("auto"));
+	m_css_margins.top.fromString(		get_style_property(_t("margin-top"),			false,	_t("0")), _t("auto"));
+	m_css_margins.bottom.fromString(	get_style_property(_t("margin-bottom"),		false,	_t("0")), _t("auto"));
+
+	m_css_padding.left.fromString(		get_style_property(_t("padding-left"),		false,	_t("0")), _t(""));
+	m_css_padding.right.fromString(		get_style_property(_t("padding-right"),		false,	_t("0")), _t(""));
+	m_css_padding.top.fromString(		get_style_property(_t("padding-top"),		false,	_t("0")), _t(""));
+	m_css_padding.bottom.fromString(	get_style_property(_t("padding-bottom"),		false,	_t("0")), _t(""));
+
+	m_css_borders.left.width.fromString(	get_style_property(_t("border-left-width"),		false,	_t("medium")), border_width_strings);
+	m_css_borders.right.width.fromString(	get_style_property(_t("border-right-width"),		false,	_t("medium")), border_width_strings);
+	m_css_borders.top.width.fromString(		get_style_property(_t("border-top-width"),		false,	_t("medium")), border_width_strings);
+	m_css_borders.bottom.width.fromString(	get_style_property(_t("border-bottom-width"),	false,	_t("medium")), border_width_strings);
+
+	m_css_borders.left.color = web_color::from_string(get_style_property(_t("border-left-color"),	false,	_t("")), doc->container());
+	m_css_borders.left.style = (border_style) value_index(get_style_property(_t("border-left-style"), false, _t("none")), border_style_strings, border_style_none);
+
+    m_css_borders.right.color = web_color::from_string(get_style_property(_t("border-right-color"), false, _t("")), doc->container());
+	m_css_borders.right.style = (border_style) value_index(get_style_property(_t("border-right-style"), false, _t("none")), border_style_strings, border_style_none);
+
+    m_css_borders.top.color = web_color::from_string(get_style_property(_t("border-top-color"), false, _t("")), doc->container());
+	m_css_borders.top.style = (border_style) value_index(get_style_property(_t("border-top-style"), false, _t("none")), border_style_strings, border_style_none);
+
+    m_css_borders.bottom.color = web_color::from_string(get_style_property(_t("border-bottom-color"), false, _t("")), doc->container());
+	m_css_borders.bottom.style = (border_style) value_index(get_style_property(_t("border-bottom-style"), false, _t("none")), border_style_strings, border_style_none);
+
+	m_css_borders.radius.top_left_x.fromString(get_style_property(_t("border-top-left-radius-x"), false, _t("0")));
+	m_css_borders.radius.top_left_y.fromString(get_style_property(_t("border-top-left-radius-y"), false, _t("0")));
+
+	m_css_borders.radius.top_right_x.fromString(get_style_property(_t("border-top-right-radius-x"), false, _t("0")));
+	m_css_borders.radius.top_right_y.fromString(get_style_property(_t("border-top-right-radius-y"), false, _t("0")));
+
+	m_css_borders.radius.bottom_right_x.fromString(get_style_property(_t("border-bottom-right-radius-x"), false, _t("0")));
+	m_css_borders.radius.bottom_right_y.fromString(get_style_property(_t("border-bottom-right-radius-y"), false, _t("0")));
+
+	m_css_borders.radius.bottom_left_x.fromString(get_style_property(_t("border-bottom-left-radius-x"), false, _t("0")));
+	m_css_borders.radius.bottom_left_y.fromString(get_style_property(_t("border-bottom-left-radius-y"), false, _t("0")));
+
+	doc->cvt_units(m_css_borders.radius.bottom_left_x,			m_font_size);
+	doc->cvt_units(m_css_borders.radius.bottom_left_y,			m_font_size);
+	doc->cvt_units(m_css_borders.radius.bottom_right_x,			m_font_size);
+	doc->cvt_units(m_css_borders.radius.bottom_right_y,			m_font_size);
+	doc->cvt_units(m_css_borders.radius.top_left_x,				m_font_size);
+	doc->cvt_units(m_css_borders.radius.top_left_y,				m_font_size);
+	doc->cvt_units(m_css_borders.radius.top_right_x,				m_font_size);
+	doc->cvt_units(m_css_borders.radius.top_right_y,				m_font_size);
+
+	doc->cvt_units(m_css_text_indent,								m_font_size);
+
+	m_margins.left		= doc->cvt_units(m_css_margins.left,		m_font_size);
+	m_margins.right		= doc->cvt_units(m_css_margins.right,		m_font_size);
+	m_margins.top		= doc->cvt_units(m_css_margins.top,		m_font_size);
+	m_margins.bottom	= doc->cvt_units(m_css_margins.bottom,	m_font_size);
+
+	m_padding.left		= doc->cvt_units(m_css_padding.left,		m_font_size);
+	m_padding.right		= doc->cvt_units(m_css_padding.right,		m_font_size);
+	m_padding.top		= doc->cvt_units(m_css_padding.top,		m_font_size);
+	m_padding.bottom	= doc->cvt_units(m_css_padding.bottom,	m_font_size);
+
+	m_borders.left		= doc->cvt_units(m_css_borders.left.width,	m_font_size);
+	m_borders.right		= doc->cvt_units(m_css_borders.right.width,	m_font_size);
+	m_borders.top		= doc->cvt_units(m_css_borders.top.width,		m_font_size);
+	m_borders.bottom	= doc->cvt_units(m_css_borders.bottom.width,	m_font_size);
+
+	css_length line_height;
+	line_height.fromString(get_style_property(_t("line-height"),	true,	_t("normal")), _t("normal"));
+	if(line_height.is_predefined())
+	{
+		m_line_height = m_font_metrics.height;
+		m_lh_predefined = true;
+	} else if(line_height.units() == css_units_none)
+	{
+		m_line_height = (int) (line_height.val() * m_font_size);
+		m_lh_predefined = false;
+	} else
+	{
+		m_line_height =  doc->cvt_units(line_height,	m_font_size, m_font_size);
+		m_lh_predefined = false;
+	}
+
+
+	if(m_display == display_list_item)
+	{
+		const tchar_t* list_type = get_style_property(_t("list-style-type"), true, _t("disc"));
+		m_list_style_type = (list_style_type) value_index(list_type, list_style_type_strings, list_style_type_disc);
+
+		const tchar_t* list_pos = get_style_property(_t("list-style-position"), true, _t("outside"));
+		m_list_style_position = (list_style_position) value_index(list_pos, list_style_position_strings, list_style_position_outside);
+
+		const tchar_t* list_image = get_style_property(_t("list-style-image"), true, 0);
+		if(list_image && list_image[0])
+		{
+			tstring url;
+			css::parse_css_url(list_image, url);
+
+			const tchar_t* list_image_baseurl = get_style_property(_t("list-style-image-baseurl"), true, 0);
+			doc->container()->load_image(url.c_str(), list_image_baseurl, true);
+		}
+
+	}
+
+	parse_background();
+
+	if(!is_reparse)
+	{
+		for(auto& el : m_children)
+		{
+			el->parse_styles();
+		}
+	}
+}
+
+int litehtml::html_tag::render( int x, int y, int max_width, bool second_pass )
+{
+	if (m_display == display_table || m_display == display_inline_table)
+	{
+		return render_table(x, y, max_width, second_pass);
+	}
+
+	return render_box(x, y, max_width, second_pass);
+}
+
+bool litehtml::html_tag::is_white_space() const
+{
+	return false;
+}
+
+int litehtml::html_tag::get_font_size() const
+{
+	return m_font_size;
+}
+
+int litehtml::html_tag::get_base_line()
+{
+	if(is_replaced())
+	{
+		return 0;
+	}
+	int bl = 0;
+	if(!m_boxes.empty())
+	{
+		bl = m_boxes.back()->baseline() + content_margins_bottom();
+	}
+	return bl;
+}
+
+void litehtml::html_tag::init()
+{
+	if (m_display == display_table || m_display == display_inline_table)
+	{
+		if (m_grid)
+		{
+			m_grid->clear();
+		}
+		else
+		{
+			m_grid = std::unique_ptr<table_grid>(new table_grid());
+		}
+
+		go_inside_table 		table_selector;
+		table_rows_selector		row_selector;
+		table_cells_selector	cell_selector;
+
+		elements_iterator row_iter(shared_from_this(), &table_selector, &row_selector);
+
+		element::ptr row = row_iter.next(false);
+		while (row)
+		{
+			m_grid->begin_row(row);
+
+			elements_iterator cell_iter(row, &table_selector, &cell_selector);
+			element::ptr cell = cell_iter.next();
+			while (cell)
+			{
+				m_grid->add_cell(cell);
+
+				cell = cell_iter.next(false);
+			}
+			row = row_iter.next(false);
+		}
+
+		m_grid->finish();
+	}
+
+	for (auto& el : m_children)
+	{
+		el->init();
+	}
+}
+
+int litehtml::html_tag::select(const css_selector& selector, bool apply_pseudo)
+{
+	int right_res = select(selector.m_right, apply_pseudo);
+	if(right_res == select_no_match)
+	{
+		return select_no_match;
+	}
+	element::ptr el_parent = parent();
+	if(selector.m_left)
+	{
+		if (!el_parent)
+		{
+			return select_no_match;
+		}
+		switch(selector.m_combinator)
+		{
+		case combinator_descendant:
+			{
+				bool is_pseudo = false;
+				element::ptr res = find_ancestor(*selector.m_left, apply_pseudo, &is_pseudo);
+				if(!res)
+				{
+					return select_no_match;
+				} else
+				{
+					if(is_pseudo)
+					{
+						right_res |= select_match_pseudo_class;
+					}
+				}
+			}
+			break;
+		case combinator_child:
+			{
+				int res = el_parent->select(*selector.m_left, apply_pseudo);
+				if(res == select_no_match)
+				{
+					return select_no_match;
+				} else
+				{
+					if(right_res != select_match_pseudo_class)
+					{
+						right_res |= res;
+					}
+				}
+			}
+			break;
+		case combinator_adjacent_sibling:
+			{
+				bool is_pseudo = false;
+				element::ptr res = el_parent->find_adjacent_sibling(shared_from_this(), *selector.m_left, apply_pseudo, &is_pseudo);
+				if(!res)
+				{
+					return select_no_match;
+				} else
+				{
+					if(is_pseudo)
+					{
+						right_res |= select_match_pseudo_class;
+					}
+				}
+			}
+			break;
+		case combinator_general_sibling:
+			{
+				bool is_pseudo = false;
+				element::ptr res =  el_parent->find_sibling(shared_from_this(), *selector.m_left, apply_pseudo, &is_pseudo);
+				if(!res)
+				{
+					return select_no_match;
+				} else
+				{
+					if(is_pseudo)
+					{
+						right_res |= select_match_pseudo_class;
+					}
+				}
+			}
+			break;
+		default:
+			right_res = select_no_match;
+		}
+	}
+	return right_res;
+}
+
+int litehtml::html_tag::select(const css_element_selector& selector, bool apply_pseudo)
+{
+	if(!selector.m_tag.empty() && selector.m_tag != _t("*"))
+	{
+		if(selector.m_tag != m_tag)
+		{
+			return select_no_match;
+		}
+	}
+
+	int res = select_match;
+	element::ptr el_parent = parent();
+
+	for(css_attribute_selector::vector::const_iterator i = selector.m_attrs.begin(); i != selector.m_attrs.end(); i++)
+	{
+		const tchar_t* attr_value = get_attr(i->attribute.c_str());
+		switch(i->condition)
+		{
+		case select_exists:
+			if(!attr_value)
+			{
+				return select_no_match;
+			}
+			break;
+		case select_equal:
+			if(!attr_value)
+			{
+				return select_no_match;
+			} else 
+			{
+				if(i->attribute == _t("class"))
+				{
+					const string_vector & tokens1 = m_class_values;
+					const string_vector & tokens2 = i->class_val;
+					bool found = true;
+					for(string_vector::const_iterator str1 = tokens2.begin(); str1 != tokens2.end() && found; str1++)
+					{
+						bool f = false;
+						for(string_vector::const_iterator str2 = tokens1.begin(); str2 != tokens1.end() && !f; str2++)
+						{
+							if( !t_strcasecmp(str1->c_str(), str2->c_str()) )
+							{
+								f = true;
+							}
+						}
+						if(!f)
+						{
+							found = false;
+						}
+					}
+					if(!found)
+					{
+						return select_no_match;
+					}
+				} else
+				{
+					if( t_strcasecmp(i->val.c_str(), attr_value) )
+					{
+						return select_no_match;
+					}
+				}
+			}
+			break;
+		case select_contain_str:
+			if(!attr_value)
+			{
+				return select_no_match;
+			} else if(!t_strstr(attr_value, i->val.c_str()))
+			{
+				return select_no_match;
+			}
+			break;
+		case select_start_str:
+			if(!attr_value)
+			{
+				return select_no_match;
+			} else if(t_strncmp(attr_value, i->val.c_str(), i->val.length()))
+			{
+				return select_no_match;
+			}
+			break;
+		case select_end_str:
+			if(!attr_value)
+			{
+				return select_no_match;
+			} else if(t_strncmp(attr_value, i->val.c_str(), i->val.length()))
+			{
+				const tchar_t* s = attr_value + t_strlen(attr_value) - i->val.length() - 1;
+				if(s < attr_value)
+				{
+					return select_no_match;
+				}
+				if(i->val != s)
+				{
+					return select_no_match;
+				}
+			}
+			break;
+		case select_pseudo_element:
+			if(i->val == _t("after"))
+			{
+				res |= select_match_with_after;
+			} else if(i->val == _t("before"))
+			{
+				res |= select_match_with_before;
+			} else
+			{
+				return select_no_match;
+			}
+			break;
+		case select_pseudo_class:
+			if(apply_pseudo)
+			{
+				if (!el_parent) return select_no_match;
+
+				tstring selector_param;
+				tstring	selector_name;
+
+				tstring::size_type begin	= i->val.find_first_of(_t('('));
+				tstring::size_type end		= (begin == tstring::npos) ? tstring::npos : find_close_bracket(i->val, begin);
+				if(begin != tstring::npos && end != tstring::npos)
+				{
+					selector_param = i->val.substr(begin + 1, end - begin - 1);
+				}
+				if(begin != tstring::npos)
+				{
+					selector_name = i->val.substr(0, begin);
+					litehtml::trim(selector_name);
+				} else
+				{
+					selector_name = i->val;
+				}
+
+				int selector = value_index(selector_name.c_str(), pseudo_class_strings);
+				
+				switch(selector)
+				{
+				case pseudo_class_only_child:
+					if (!el_parent->is_only_child(shared_from_this(), false))
+					{
+						return select_no_match;
+					}
+					break;
+				case pseudo_class_only_of_type:
+					if (!el_parent->is_only_child(shared_from_this(), true))
+					{
+						return select_no_match;
+					}
+					break;
+				case pseudo_class_first_child:
+					if (!el_parent->is_nth_child(shared_from_this(), 0, 1, false))
+					{
+						return select_no_match;
+					}
+					break;
+				case pseudo_class_first_of_type:
+					if (!el_parent->is_nth_child(shared_from_this(), 0, 1, true))
+					{
+						return select_no_match;
+					}
+					break;
+				case pseudo_class_last_child:
+					if (!el_parent->is_nth_last_child(shared_from_this(), 0, 1, false))
+					{
+						return select_no_match;
+					}
+					break;
+				case pseudo_class_last_of_type:
+					if (!el_parent->is_nth_last_child(shared_from_this(), 0, 1, true))
+					{
+						return select_no_match;
+					}
+					break;
+				case pseudo_class_nth_child:
+				case pseudo_class_nth_of_type:
+				case pseudo_class_nth_last_child:
+				case pseudo_class_nth_last_of_type:
+					{
+						if(selector_param.empty()) return select_no_match;
+
+						int num = 0;
+						int off = 0;
+
+						parse_nth_child_params(selector_param, num, off);
+						if(!num && !off) return select_no_match;
+						switch(selector)
+						{
+						case pseudo_class_nth_child:
+							if (!el_parent->is_nth_child(shared_from_this(), num, off, false))
+							{
+								return select_no_match;
+							}
+							break;
+						case pseudo_class_nth_of_type:
+							if (!el_parent->is_nth_child(shared_from_this(), num, off, true))
+							{
+								return select_no_match;
+							}
+							break;
+						case pseudo_class_nth_last_child:
+							if (!el_parent->is_nth_last_child(shared_from_this(), num, off, false))
+							{
+								return select_no_match;
+							}
+							break;
+						case pseudo_class_nth_last_of_type:
+							if (!el_parent->is_nth_last_child(shared_from_this(), num, off, true))
+							{
+								return select_no_match;
+							}
+							break;
+						}
+
+					}
+					break;
+				case pseudo_class_not:
+					{
+						css_element_selector sel;
+						sel.parse(selector_param);
+						if(select(sel, apply_pseudo))
+						{
+							return select_no_match;
+						}
+					}
+					break;
+				case pseudo_class_lang:
+					{
+						trim( selector_param );
+
+						if( !get_document()->match_lang( selector_param ) )
+						{
+							return select_no_match;
+						}
+					}
+					break;
+				default:
+					if(std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), i->val) == m_pseudo_classes.end())
+					{
+						return select_no_match;
+					}
+					break;
+				}
+			} else
+			{
+				res |= select_match_pseudo_class;
+			}
+			break;
+		}
+	}
+	return res;
+}
+
+litehtml::element::ptr litehtml::html_tag::find_ancestor(const css_selector& selector, bool apply_pseudo, bool* is_pseudo)
+{
+	element::ptr el_parent = parent();
+	if (!el_parent)
+	{
+		return nullptr;
+	}
+	int res = el_parent->select(selector, apply_pseudo);
+	if(res != select_no_match)
+	{
+		if(is_pseudo)
+		{
+			if(res & select_match_pseudo_class)
+			{
+				*is_pseudo = true;
+			} else
+			{
+				*is_pseudo = false;
+			}
+		}
+		return el_parent;
+	}
+	return el_parent->find_ancestor(selector, apply_pseudo, is_pseudo);
+}
+
+int litehtml::html_tag::get_floats_height(element_float el_float) const
+{
+	if(is_floats_holder())
+	{
+		int h = 0;
+
+		bool process = false;
+
+		for(const auto& fb : m_floats_left)
+		{
+			process = false;
+			switch(el_float)
+			{
+			case float_none:
+				process = true;
+				break;
+			case float_left:
+				if (fb.clear_floats == clear_left || fb.clear_floats == clear_both)
+				{
+					process = true;
+				}
+				break;
+			case float_right:
+				if (fb.clear_floats == clear_right || fb.clear_floats == clear_both)
+				{
+					process = true;
+				}
+				break;
+			}
+			if(process)
+			{
+				if(el_float == float_none)
+				{
+					h = std::max(h, fb.pos.bottom());
+				} else
+				{
+					h = std::max(h, fb.pos.top());
+				}
+			}
+		}
+
+
+		for(const auto fb : m_floats_right)
+		{
+			process = false;
+			switch(el_float)
+			{
+			case float_none:
+				process = true;
+				break;
+			case float_left:
+				if (fb.clear_floats == clear_left || fb.clear_floats == clear_both)
+				{
+					process = true;
+				}
+				break;
+			case float_right:
+				if (fb.clear_floats == clear_right || fb.clear_floats == clear_both)
+				{
+					process = true;
+				}
+				break;
+			}
+			if(process)
+			{
+				if(el_float == float_none)
+				{
+					h = std::max(h, fb.pos.bottom());
+				} else
+				{
+					h = std::max(h, fb.pos.top());
+				}
+			}
+		}
+
+		return h;
+	}
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		int h = el_parent->get_floats_height(el_float);
+		return h - m_pos.y;
+	}
+	return 0;
+}
+
+int litehtml::html_tag::get_left_floats_height() const
+{
+	if(is_floats_holder())
+	{
+		int h = 0;
+		if(!m_floats_left.empty())
+		{
+			for (const auto& fb : m_floats_left)
+			{
+				h = std::max(h, fb.pos.bottom());
+			}
+		}
+		return h;
+	}
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		int h = el_parent->get_left_floats_height();
+		return h - m_pos.y;
+	}
+	return 0;
+}
+
+int litehtml::html_tag::get_right_floats_height() const
+{
+	if(is_floats_holder())
+	{
+		int h = 0;
+		if(!m_floats_right.empty())
+		{
+			for(const auto& fb : m_floats_right)
+			{
+				h = std::max(h, fb.pos.bottom());
+			}
+		}
+		return h;
+	}
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		int h = el_parent->get_right_floats_height();
+		return h - m_pos.y;
+	}
+	return 0;
+}
+
+int litehtml::html_tag::get_line_left( int y )
+{
+	if(is_floats_holder())
+	{
+		if(m_cahe_line_left.is_valid && m_cahe_line_left.hash == y)
+		{
+			return m_cahe_line_left.val;
+		}
+
+		int w = 0;
+		for(const auto& fb : m_floats_left)
+		{
+			if (y >= fb.pos.top() && y < fb.pos.bottom())
+			{
+				w = std::max(w, fb.pos.right());
+				if (w < fb.pos.right())
+				{
+					break;
+				}
+			}
+		}
+		m_cahe_line_left.set_value(y, w);
+		return w;
+	}
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		int w = el_parent->get_line_left(y + m_pos.y);
+		if (w < 0)
+		{
+			w = 0;
+		}
+		return w - (w ? m_pos.x : 0);
+	}
+	return 0;
+}
+
+int litehtml::html_tag::get_line_right( int y, int def_right )
+{
+	if(is_floats_holder())
+	{
+		if(m_cahe_line_right.is_valid && m_cahe_line_right.hash == y)
+		{
+			if(m_cahe_line_right.is_default)
+			{
+				return def_right;
+			} else
+			{
+				return std::min(m_cahe_line_right.val, def_right);
+			}
+		}
+
+		int w = def_right;
+		m_cahe_line_right.is_default = true;
+		for(const auto& fb : m_floats_right)
+		{
+			if(y >= fb.pos.top() && y < fb.pos.bottom())
+			{
+				w = std::min(w, fb.pos.left());
+				m_cahe_line_right.is_default = false;
+				if(w > fb.pos.left())
+				{
+					break;
+				}
+			}
+		}
+		m_cahe_line_right.set_value(y, w);
+		return w;
+	}
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		int w = el_parent->get_line_right(y + m_pos.y, def_right + m_pos.x);
+		return w - m_pos.x;
+	}
+	return 0;
+}
+
+
+void litehtml::html_tag::get_line_left_right( int y, int def_right, int& ln_left, int& ln_right )
+{
+	if(is_floats_holder())
+	{
+		ln_left		= get_line_left(y);
+		ln_right	= get_line_right(y, def_right);
+	} else
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			el_parent->get_line_left_right(y + m_pos.y, def_right + m_pos.x, ln_left, ln_right);
+		}
+		ln_right -= m_pos.x;
+		ln_left -= m_pos.x;
+
+		if(ln_left < 0)
+		{
+			ln_left = 0;
+		}
+	}
+}
+
+int litehtml::html_tag::fix_line_width( int max_width, element_float flt )
+{
+	int ret_width = 0;
+	if(!m_boxes.empty())
+	{
+		elements_vector els;
+		m_boxes.back()->get_elements(els);
+		bool was_cleared = false;
+		if(!els.empty() && els.front()->get_clear() != clear_none)
+		{
+			if(els.front()->get_clear() == clear_both)
+			{
+				was_cleared = true;
+			} else
+			{
+				if(	(flt == float_left	&& els.front()->get_clear() == clear_left) ||
+					(flt == float_right	&& els.front()->get_clear() == clear_right) )
+				{
+					was_cleared = true;
+				}
+			}
+		}
+
+		if(!was_cleared)
+		{
+			m_boxes.pop_back();
+
+			for(elements_vector::iterator i = els.begin(); i != els.end(); i++)
+			{
+				int rw = place_element((*i), max_width);
+				if(rw > ret_width)
+				{
+					ret_width = rw;
+				}
+			}
+		} else
+		{
+			int line_top = 0;
+			if(m_boxes.back()->get_type() == box_line)
+			{
+				line_top = m_boxes.back()->top();
+			} else
+			{
+				line_top = m_boxes.back()->bottom();
+			}
+
+			int line_left	= 0;
+			int line_right	= max_width;
+			get_line_left_right(line_top, max_width, line_left, line_right);
+
+			if(m_boxes.back()->get_type() == box_line)
+			{
+				if(m_boxes.size() == 1 && m_list_style_type != list_style_type_none && m_list_style_position == list_style_position_inside)
+				{
+					int sz_font = get_font_size();
+					line_left += sz_font;
+				}
+
+				if(m_css_text_indent.val() != 0)
+				{
+					bool line_box_found = false;
+					for(box::vector::iterator iter = m_boxes.begin(); iter < m_boxes.end(); iter++)
+					{
+						if((*iter)->get_type() == box_line)
+						{
+							line_box_found = true;
+							break;
+						}
+					}
+					if(!line_box_found)
+					{
+						line_left += m_css_text_indent.calc_percent(max_width);
+					}
+				}
+
+			}
+
+			elements_vector els;
+			m_boxes.back()->new_width(line_left, line_right, els);
+			for(auto& el : els)
+			{
+				int rw = place_element(el, max_width);
+				if(rw > ret_width)
+				{
+					ret_width = rw;
+				}
+			}
+		}
+	}
+
+	return ret_width;
+}
+
+void litehtml::html_tag::add_float(const element::ptr &el, int x, int y)
+{
+	if(is_floats_holder())
+	{
+		floated_box fb;
+		fb.pos.x		= el->left() + x;
+		fb.pos.y		= el->top()  + y;
+		fb.pos.width	= el->width();
+		fb.pos.height	= el->height();
+		fb.float_side	= el->get_float();
+		fb.clear_floats	= el->get_clear();
+		fb.el			= el;
+
+		if(fb.float_side == float_left)
+		{
+			if(m_floats_left.empty())
+			{
+				m_floats_left.push_back(fb);
+			} else
+			{
+				bool inserted = false;
+				for(floated_box::vector::iterator i = m_floats_left.begin(); i != m_floats_left.end(); i++)
+				{
+					if(fb.pos.right() > i->pos.right())
+					{
+						m_floats_left.insert(i, std::move(fb));
+						inserted = true;
+						break;
+					}
+				}
+				if(!inserted)
+				{
+					m_floats_left.push_back(std::move(fb));
+				}
+			}
+			m_cahe_line_left.invalidate();
+		} else if(fb.float_side == float_right)
+		{
+			if(m_floats_right.empty())
+			{
+				m_floats_right.push_back(std::move(fb));
+			} else
+			{
+				bool inserted = false;
+				for(floated_box::vector::iterator i = m_floats_right.begin(); i != m_floats_right.end(); i++)
+				{
+					if(fb.pos.left() < i->pos.left())
+					{
+						m_floats_right.insert(i, std::move(fb));
+						inserted = true;
+						break;
+					}
+				}
+				if(!inserted)
+				{
+					m_floats_right.push_back(fb);
+				}
+			}
+			m_cahe_line_right.invalidate();
+		}
+	} else
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			el_parent->add_float(el, x + m_pos.x, y + m_pos.y);
+		}
+	}
+}
+
+int litehtml::html_tag::find_next_line_top( int top, int width, int def_right )
+{
+	if(is_floats_holder())
+	{
+		int new_top = top;
+		int_vector points;
+
+		for(const auto& fb : m_floats_left)
+		{
+			if(fb.pos.top() >= top)
+			{
+				if(find(points.begin(), points.end(), fb.pos.top()) == points.end())
+				{
+					points.push_back(fb.pos.top());
+				}
+			}
+			if (fb.pos.bottom() >= top)
+			{
+				if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end())
+				{
+					points.push_back(fb.pos.bottom());
+				}
+			}
+		}
+
+		for (const auto& fb : m_floats_right)
+		{
+			if (fb.pos.top() >= top)
+			{
+				if (find(points.begin(), points.end(), fb.pos.top()) == points.end())
+				{
+					points.push_back(fb.pos.top());
+				}
+			}
+			if (fb.pos.bottom() >= top)
+			{
+				if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end())
+				{
+					points.push_back(fb.pos.bottom());
+				}
+			}
+		}
+
+		if(!points.empty())
+		{
+			sort(points.begin(), points.end(), std::less<int>( ));
+			new_top = points.back();
+
+			for(auto pt : points)
+			{
+				int pos_left	= 0;
+				int pos_right	= def_right;
+				get_line_left_right(pt, def_right, pos_left, pos_right);
+
+				if(pos_right - pos_left >= width)
+				{
+					new_top = pt;
+					break;
+				}
+			}
+		}
+		return new_top;
+	}
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		int new_top = el_parent->find_next_line_top(top + m_pos.y, width, def_right + m_pos.x);
+		return new_top - m_pos.y;
+	}
+	return 0;
+}
+
+void litehtml::html_tag::parse_background()
+{
+	// parse background-color
+	m_bg.m_color		= get_color(_t("background-color"), false, web_color(0, 0, 0, 0));
+
+	// parse background-position
+	const tchar_t* str = get_style_property(_t("background-position"), false, _t("0% 0%"));
+	if(str)
+	{
+		string_vector res;
+		split_string(str, res, _t(" \t"));
+		if(res.size() > 0)
+		{
+			if(res.size() == 1)
+			{
+				if( value_in_list(res[0].c_str(), _t("left;right;center")) )
+				{
+					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
+					m_bg.m_position.y.set_value(50, css_units_percentage);
+				} else if( value_in_list(res[0].c_str(), _t("top;bottom;center")) )
+				{
+					m_bg.m_position.y.fromString(res[0], _t("top;bottom;center"));
+					m_bg.m_position.x.set_value(50, css_units_percentage);
+				} else
+				{
+					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
+					m_bg.m_position.y.set_value(50, css_units_percentage);
+				}
+			} else
+			{
+				if(value_in_list(res[0].c_str(), _t("left;right")))
+				{
+					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
+					m_bg.m_position.y.fromString(res[1], _t("top;bottom;center"));
+				} else if(value_in_list(res[0].c_str(), _t("top;bottom")))
+				{
+					m_bg.m_position.x.fromString(res[1], _t("left;right;center"));
+					m_bg.m_position.y.fromString(res[0], _t("top;bottom;center"));
+				} else if(value_in_list(res[1].c_str(), _t("left;right")))
+				{
+					m_bg.m_position.x.fromString(res[1], _t("left;right;center"));
+					m_bg.m_position.y.fromString(res[0], _t("top;bottom;center"));
+				}else if(value_in_list(res[1].c_str(), _t("top;bottom")))
+				{
+					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
+					m_bg.m_position.y.fromString(res[1], _t("top;bottom;center"));
+				} else
+				{
+					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
+					m_bg.m_position.y.fromString(res[1], _t("top;bottom;center"));
+				}
+			}
+
+			if(m_bg.m_position.x.is_predefined())
+			{
+				switch(m_bg.m_position.x.predef())
+				{
+				case 0:
+					m_bg.m_position.x.set_value(0, css_units_percentage);
+					break;
+				case 1:
+					m_bg.m_position.x.set_value(100, css_units_percentage);
+					break;
+				case 2:
+					m_bg.m_position.x.set_value(50, css_units_percentage);
+					break;
+				}
+			}
+			if(m_bg.m_position.y.is_predefined())
+			{
+				switch(m_bg.m_position.y.predef())
+				{
+				case 0:
+					m_bg.m_position.y.set_value(0, css_units_percentage);
+					break;
+				case 1:
+					m_bg.m_position.y.set_value(100, css_units_percentage);
+					break;
+				case 2:
+					m_bg.m_position.y.set_value(50, css_units_percentage);
+					break;
+				}
+			}
+		} else
+		{
+			m_bg.m_position.x.set_value(0, css_units_percentage);
+			m_bg.m_position.y.set_value(0, css_units_percentage);
+		}
+	} else
+	{
+		m_bg.m_position.y.set_value(0, css_units_percentage);
+		m_bg.m_position.x.set_value(0, css_units_percentage);
+	}
+
+	str = get_style_property(_t("background-size"), false, _t("auto"));
+	if(str)
+	{
+		string_vector res;
+		split_string(str, res, _t(" \t"));
+		if(!res.empty())
+		{
+			m_bg.m_position.width.fromString(res[0], background_size_strings);
+			if(res.size() > 1)
+			{
+				m_bg.m_position.height.fromString(res[1], background_size_strings);
+			} else
+			{
+				m_bg.m_position.height.predef(background_size_auto);
+			}
+		} else
+		{
+			m_bg.m_position.width.predef(background_size_auto);
+			m_bg.m_position.height.predef(background_size_auto);
+		}
+	}
+
+	document::ptr doc = get_document();
+
+	doc->cvt_units(m_bg.m_position.x,		m_font_size);
+	doc->cvt_units(m_bg.m_position.y,		m_font_size);
+	doc->cvt_units(m_bg.m_position.width,	m_font_size);
+	doc->cvt_units(m_bg.m_position.height,	m_font_size);
+
+	// parse background_attachment
+	m_bg.m_attachment = (background_attachment) value_index(
+		get_style_property(_t("background-attachment"), false, _t("scroll")), 
+		background_attachment_strings, 
+		background_attachment_scroll);
+
+	// parse background_attachment
+	m_bg.m_repeat = (background_repeat) value_index(
+		get_style_property(_t("background-repeat"), false, _t("repeat")), 
+		background_repeat_strings, 
+		background_repeat_repeat);
+
+	// parse background_clip
+	m_bg.m_clip = (background_box) value_index(
+		get_style_property(_t("background-clip"), false, _t("border-box")), 
+		background_box_strings, 
+		background_box_border);
+
+	// parse background_origin
+	m_bg.m_origin = (background_box) value_index(
+		get_style_property(_t("background-origin"), false, _t("padding-box")), 
+		background_box_strings, 
+		background_box_content);
+
+	// parse background-image
+	css::parse_css_url(get_style_property(_t("background-image"), false, _t("")), m_bg.m_image);
+	m_bg.m_baseurl = get_style_property(_t("background-image-baseurl"), false, _t(""));
+
+	if(!m_bg.m_image.empty())
+	{
+		doc->container()->load_image(m_bg.m_image.c_str(), m_bg.m_baseurl.empty() ? 0 : m_bg.m_baseurl.c_str(), true);
+	}
+}
+
+void litehtml::html_tag::add_positioned(const element::ptr &el)
+{
+	if (m_el_position != element_position_static || (!have_parent()))
+	{
+		m_positioned.push_back(el);
+	} else
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			el_parent->add_positioned(el);
+		}
+	}
+}
+
+void litehtml::html_tag::calc_outlines( int parent_width )
+{
+	m_padding.left	= m_css_padding.left.calc_percent(parent_width);
+	m_padding.right	= m_css_padding.right.calc_percent(parent_width);
+
+	m_borders.left	= m_css_borders.left.width.calc_percent(parent_width);
+	m_borders.right	= m_css_borders.right.width.calc_percent(parent_width);
+
+	m_margins.left	= m_css_margins.left.calc_percent(parent_width);
+	m_margins.right	= m_css_margins.right.calc_percent(parent_width);
+
+	m_margins.top		= m_css_margins.top.calc_percent(parent_width);
+	m_margins.bottom	= m_css_margins.bottom.calc_percent(parent_width);
+
+	m_padding.top		= m_css_padding.top.calc_percent(parent_width);
+	m_padding.bottom	= m_css_padding.bottom.calc_percent(parent_width);
+}
+
+void litehtml::html_tag::calc_auto_margins(int parent_width)
+{
+	if (get_element_position() != element_position_absolute && (m_display == display_block || m_display == display_table))
+	{
+		if (m_css_margins.left.is_predefined() && m_css_margins.right.is_predefined())
+		{
+			int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right;
+			if (el_width <= parent_width)
+			{
+				m_margins.left = (parent_width - el_width) / 2;
+				m_margins.right = (parent_width - el_width) - m_margins.left;
+			}
+			else
+			{
+				m_margins.left = 0;
+				m_margins.right = 0;
+			}
+		}
+		else if (m_css_margins.left.is_predefined() && !m_css_margins.right.is_predefined())
+		{
+			int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right + m_margins.right;
+			m_margins.left = parent_width - el_width;
+			if (m_margins.left < 0) m_margins.left = 0;
+		}
+		else if (!m_css_margins.left.is_predefined() && m_css_margins.right.is_predefined())
+		{
+			int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right + m_margins.left;
+			m_margins.right = parent_width - el_width;
+			if (m_margins.right < 0) m_margins.right = 0;
+		}
+	}
+}
+
+void litehtml::html_tag::parse_attributes()
+{
+	for(auto& el : m_children)
+	{
+		el->parse_attributes();
+	}
+}
+
+void litehtml::html_tag::get_text( tstring& text )
+{
+	for (auto& el : m_children)
+	{
+		el->get_text(text);
+	}
+}
+
+bool litehtml::html_tag::is_body()  const
+{
+	return false;
+}
+
+void litehtml::html_tag::set_data( const tchar_t* data )
+{
+
+}
+
+void litehtml::html_tag::get_inline_boxes( position::vector& boxes )
+{
+	litehtml::box* old_box = 0;
+	position pos;
+	for(auto& el : m_children)
+	{
+		if(!el->skip())
+		{
+			if(el->m_box)
+			{
+				if(el->m_box != old_box)
+				{
+					if(old_box)
+					{
+						if(boxes.empty())
+						{
+							pos.x		-= m_padding.left + m_borders.left;
+							pos.width	+= m_padding.left + m_borders.left;
+						}
+						boxes.push_back(pos);
+					}
+					old_box		= el->m_box;
+					pos.x		= el->left() + el->margin_left();
+					pos.y		= el->top() - m_padding.top - m_borders.top;
+					pos.width	= 0;
+					pos.height	= 0;
+				}
+				pos.width	= el->right() - pos.x - el->margin_right() - el->margin_left();
+				pos.height	= std::max(pos.height, el->height() + m_padding.top + m_padding.bottom + m_borders.top + m_borders.bottom);
+			} else if(el->get_display() == display_inline)
+			{
+				position::vector sub_boxes;
+				el->get_inline_boxes(sub_boxes);
+				if(!sub_boxes.empty())
+				{
+					sub_boxes.rbegin()->width += el->margin_right();
+					if(boxes.empty())
+					{
+						if(m_padding.left + m_borders.left > 0)
+						{
+							position padding_box = (*sub_boxes.begin());
+							padding_box.x		-= m_padding.left + m_borders.left + el->margin_left();
+							padding_box.width	= m_padding.left + m_borders.left + el->margin_left();
+							boxes.push_back(padding_box);
+						}
+					}
+
+					sub_boxes.rbegin()->width += el->margin_right();
+
+					boxes.insert(boxes.end(), sub_boxes.begin(), sub_boxes.end());
+				}
+			}
+		}
+	}
+	if(pos.width || pos.height)
+	{
+		if(boxes.empty())
+		{
+			pos.x		-= m_padding.left + m_borders.left;
+			pos.width	+= m_padding.left + m_borders.left;
+		}
+		boxes.push_back(pos);
+	}
+	if(!boxes.empty())
+	{
+		if(m_padding.right + m_borders.right > 0)
+		{
+			boxes.back().width += m_padding.right + m_borders.right;
+		}
+	}
+}
+
+bool litehtml::html_tag::on_mouse_over()
+{
+	bool ret = false;
+
+	element::ptr el = shared_from_this();
+	while(el)
+	{
+		if(el->set_pseudo_class(_t("hover"), true))
+		{
+			ret = true;
+		}
+		el = el->parent();
+	}
+
+	return ret;
+}
+
+bool litehtml::html_tag::find_styles_changes( position::vector& redraw_boxes, int x, int y )
+{
+	if(m_display == display_inline_text)
+	{
+		return false;
+	}
+
+	bool ret = false;
+	bool apply = false;
+	for (used_selector::vector::iterator iter = m_used_styles.begin(); iter != m_used_styles.end() && !apply; iter++)
+	{
+		if((*iter)->m_selector->is_media_valid())
+		{
+			int res = select(*((*iter)->m_selector), true);
+			if( (res == select_no_match && (*iter)->m_used) || (res == select_match && !(*iter)->m_used) )
+			{
+				apply = true;
+			}
+		}
+	}
+
+	if(apply)
+	{
+		if(m_display == display_inline ||  m_display == display_table_row)
+		{
+			position::vector boxes;
+			get_inline_boxes(boxes);
+			for(position::vector::iterator pos = boxes.begin(); pos != boxes.end(); pos++)
+			{
+				pos->x	+= x;
+				pos->y	+= y;
+				redraw_boxes.push_back(*pos);
+			}
+		} else
+		{
+			position pos = m_pos;
+			if(m_el_position != element_position_fixed)
+			{
+				pos.x += x;
+				pos.y += y;
+			}
+			pos += m_padding;
+			pos += m_borders;
+			redraw_boxes.push_back(pos);
+		}
+
+		ret = true;
+		refresh_styles();
+		parse_styles();
+	}
+	for (auto& el : m_children)
+	{
+		if(!el->skip())
+		{
+			if(m_el_position != element_position_fixed)
+			{
+				if(el->find_styles_changes(redraw_boxes, x + m_pos.x, y + m_pos.y))
+				{
+					ret = true;
+				}
+			} else
+			{
+				if(el->find_styles_changes(redraw_boxes, m_pos.x, m_pos.y))
+				{
+					ret = true;
+				}
+			}
+		}
+	}
+	return ret;
+}
+
+bool litehtml::html_tag::on_mouse_leave()
+{
+	bool ret = false;
+
+	element::ptr el = shared_from_this();
+	while(el)
+	{
+		if(el->set_pseudo_class(_t("hover"), false))
+		{
+			ret = true;
+		}
+		if(el->set_pseudo_class(_t("active"), false))
+		{
+			ret = true;
+		}
+		el = el->parent();
+	}
+
+	return ret;
+}
+
+bool litehtml::html_tag::on_lbutton_down()
+{
+    bool ret = false;
+
+	element::ptr el = shared_from_this();
+    while (el)
+    {
+        if (el->set_pseudo_class(_t("active"), true))
+        {
+            ret = true;
+        }
+        el = el->parent();
+    }
+
+    return ret;
+}
+
+bool litehtml::html_tag::on_lbutton_up()
+{
+	bool ret = false;
+
+	element::ptr el = shared_from_this();
+    while (el)
+    {
+        if (el->set_pseudo_class(_t("active"), false))
+        {
+            ret = true;
+        }
+        el = el->parent();
+    }
+
+    on_click();
+
+	return ret;
+}
+
+void litehtml::html_tag::on_click()
+{
+	if (have_parent())
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			el_parent->on_click();
+		}
+	}
+}
+
+const litehtml::tchar_t* litehtml::html_tag::get_cursor()
+{
+	return get_style_property(_t("cursor"), true, 0);
+}
+
+static const int font_size_table[8][7] =
+{
+	{ 9,    9,     9,     9,    11,    14,    18},
+	{ 9,    9,     9,    10,    12,    15,    20},
+	{ 9,    9,     9,    11,    13,    17,    22},
+	{ 9,    9,    10,    12,    14,    18,    24},
+	{ 9,    9,    10,    13,    16,    20,    26},
+	{ 9,    9,    11,    14,    17,    21,    28},
+	{ 9,   10,    12,    15,    17,    23,    30},
+	{ 9,   10,    13,    16,    18,    24,    32}
+};
+
+
+void litehtml::html_tag::init_font()
+{
+	// initialize font size
+	const tchar_t* str = get_style_property(_t("font-size"), false, 0);
+
+	int parent_sz = 0;
+	int doc_font_size = get_document()->container()->get_default_font_size();
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		parent_sz = el_parent->get_font_size();
+	} else
+	{
+		parent_sz = doc_font_size;
+	}
+
+
+	if(!str)
+	{
+		m_font_size = parent_sz;
+	} else
+	{
+		m_font_size = parent_sz;
+
+		css_length sz;
+		sz.fromString(str, font_size_strings);
+		if(sz.is_predefined())
+		{
+			int idx_in_table = doc_font_size - 9;
+			if(idx_in_table >= 0 && idx_in_table <= 7)
+			{
+				if(sz.predef() >= fontSize_xx_small && sz.predef() <= fontSize_xx_large)
+				{
+					m_font_size = font_size_table[idx_in_table][sz.predef()];
+				} else
+				{
+					m_font_size = doc_font_size;
+				}
+			} else			
+			{
+				switch(sz.predef())
+				{
+				case fontSize_xx_small:
+					m_font_size = doc_font_size * 3 / 5;
+					break;
+				case fontSize_x_small:
+					m_font_size = doc_font_size * 3 / 4;
+					break;
+				case fontSize_small:
+					m_font_size = doc_font_size * 8 / 9;
+					break;
+				case fontSize_large:
+					m_font_size = doc_font_size * 6 / 5;
+					break;
+				case fontSize_x_large:
+					m_font_size = doc_font_size * 3 / 2;
+					break;
+				case fontSize_xx_large:
+					m_font_size = doc_font_size * 2;
+					break;
+				default:
+					m_font_size = doc_font_size;
+					break;
+				}
+			}
+		} else
+		{
+			if(sz.units() == css_units_percentage)
+			{
+				m_font_size = sz.calc_percent(parent_sz);
+			} else if(sz.units() == css_units_none)
+			{
+				m_font_size = parent_sz;
+			} else
+			{
+				m_font_size = get_document()->cvt_units(sz, parent_sz);
+			}
+		}
+	}
+
+	// initialize font
+	const tchar_t* name			= get_style_property(_t("font-family"),		true,	_t("inherit"));
+	const tchar_t* weight		= get_style_property(_t("font-weight"),		true,	_t("normal"));
+	const tchar_t* style		= get_style_property(_t("font-style"),		true,	_t("normal"));
+	const tchar_t* decoration	= get_style_property(_t("text-decoration"),	true,	_t("none"));
+
+	m_font = get_document()->get_font(name, m_font_size, weight, style, decoration, &m_font_metrics);
+}
+
+bool litehtml::html_tag::is_break() const
+{
+	return false;
+}
+
+void litehtml::html_tag::set_tagName( const tchar_t* tag )
+{
+	tstring s_val = tag;
+	std::locale lc = std::locale::global(std::locale::classic());
+	for(size_t i = 0; i < s_val.length(); i++)
+	{
+		s_val[i] = std::tolower(s_val[i], lc);
+	}
+	m_tag = s_val;
+}
+
+void litehtml::html_tag::draw_background( uint_ptr hdc, int x, int y, const position* clip )
+{
+	position pos = m_pos;
+	pos.x	+= x;
+	pos.y	+= y;
+
+	position el_pos = pos;
+	el_pos += m_padding;
+	el_pos += m_borders;
+
+	if(m_display != display_inline && m_display != display_table_row)
+	{
+		if(el_pos.does_intersect(clip))
+		{
+			const background* bg = get_background();
+			if(bg)
+			{
+				background_paint bg_paint;
+				init_background_paint(pos, bg_paint, bg);
+
+				get_document()->container()->draw_background(hdc, bg_paint);
+			}
+			position border_box = pos;
+			border_box += m_padding;
+			border_box += m_borders;
+
+			borders bdr = m_css_borders;
+			bdr.radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
+
+			get_document()->container()->draw_borders(hdc, bdr, border_box, have_parent() ? false : true);
+		}
+	} else
+	{
+		const background* bg = get_background();
+
+		position::vector boxes;
+		get_inline_boxes(boxes);
+
+		background_paint bg_paint;
+		position content_box;
+
+		for(position::vector::iterator box = boxes.begin(); box != boxes.end(); box++)
+		{
+			box->x	+= x;
+			box->y	+= y;
+
+			if(box->does_intersect(clip))
+			{
+				content_box = *box;
+				content_box -= m_borders;
+				content_box -= m_padding;
+
+				if(bg)
+				{
+					init_background_paint(content_box, bg_paint, bg);
+				}
+
+				css_borders bdr;
+
+				// set left borders radius for the first box
+				if(box == boxes.begin())
+				{
+					bdr.radius.bottom_left_x	= m_css_borders.radius.bottom_left_x;
+					bdr.radius.bottom_left_y	= m_css_borders.radius.bottom_left_y;
+					bdr.radius.top_left_x		= m_css_borders.radius.top_left_x;
+					bdr.radius.top_left_y		= m_css_borders.radius.top_left_y;
+				}
+
+				// set right borders radius for the last box
+				if(box == boxes.end() - 1)
+				{
+					bdr.radius.bottom_right_x	= m_css_borders.radius.bottom_right_x;
+					bdr.radius.bottom_right_y	= m_css_borders.radius.bottom_right_y;
+					bdr.radius.top_right_x		= m_css_borders.radius.top_right_x;
+					bdr.radius.top_right_y		= m_css_borders.radius.top_right_y;
+				}
+
+				
+				bdr.top		= m_css_borders.top;
+				bdr.bottom	= m_css_borders.bottom;
+				if(box == boxes.begin())
+				{
+					bdr.left	= m_css_borders.left;
+				}
+				if(box == boxes.end() - 1)
+				{
+					bdr.right	= m_css_borders.right;
+				}
+
+
+				if(bg)
+				{
+					bg_paint.border_radius = bdr.radius.calc_percents(bg_paint.border_box.width, bg_paint.border_box.width);
+					get_document()->container()->draw_background(hdc, bg_paint);
+				}
+				borders b = bdr;
+				b.radius = bdr.radius.calc_percents(box->width, box->height);
+				get_document()->container()->draw_borders(hdc, b, *box, false);
+			}
+		}
+	}
+}
+
+int litehtml::html_tag::render_inline(const element::ptr &container, int max_width)
+{
+	int ret_width = 0;
+	int rw = 0;
+
+	white_space ws = get_white_space();
+	bool skip_spaces = false;
+	if (ws == white_space_normal ||
+		ws == white_space_nowrap ||
+		ws == white_space_pre_line)
+	{
+		skip_spaces = true;
+	}
+	bool was_space = false;
+
+	for (auto& el : m_children)
+	{
+		// skip spaces to make rendering a bit faster
+		if (skip_spaces)
+		{
+			if (el->is_white_space())
+			{
+				if (was_space)
+				{
+					el->skip(true);
+					continue;
+				}
+				else
+				{
+					was_space = true;
+				}
+			}
+			else
+			{
+				was_space = false;
+			}
+		}
+
+		rw = container->place_element( el, max_width );
+		if(rw > ret_width)
+		{
+			ret_width = rw;
+		}
+	}
+	return ret_width;
+}
+
+int litehtml::html_tag::place_element(const element::ptr &el, int max_width)
+{
+	if(el->get_display() == display_none) return 0;
+
+	if(el->get_display() == display_inline)
+	{
+		return el->render_inline(shared_from_this(), max_width);
+	}
+
+	element_position el_position = el->get_element_position();
+
+	if(el_position == element_position_absolute || el_position == element_position_fixed)
+	{
+		int line_top = 0;
+		if(!m_boxes.empty())
+		{
+			if(m_boxes.back()->get_type() == box_line)
+			{
+				line_top = m_boxes.back()->top();
+				if(!m_boxes.back()->is_empty())
+				{
+					line_top += line_height();
+				}
+			} else
+			{
+				line_top = m_boxes.back()->bottom();
+			}
+		}
+
+		el->render(0, line_top, max_width);
+		el->m_pos.x	+= el->content_margins_left();
+		el->m_pos.y	+= el->content_margins_top();
+
+		return 0;
+	}
+
+	int ret_width = 0;
+
+	switch(el->get_float())
+	{
+	case float_left:
+		{
+			int line_top = 0;
+			if(!m_boxes.empty())
+			{
+				if(m_boxes.back()->get_type() == box_line)
+				{
+					line_top = m_boxes.back()->top();
+				} else
+				{
+					line_top = m_boxes.back()->bottom();
+				}
+			}
+			line_top		= get_cleared_top(el, line_top);
+			int line_left	= 0;
+			int line_right	= max_width;
+			get_line_left_right(line_top, max_width, line_left, line_right);
+
+			el->render(line_left, line_top, line_right);
+			if(el->right() > line_right)
+			{
+				int new_top = find_next_line_top(el->top(), el->width(), max_width);
+				el->m_pos.x = get_line_left(new_top) + el->content_margins_left();
+				el->m_pos.y = new_top + el->content_margins_top();
+			}
+			add_float(el, 0, 0);
+			ret_width = fix_line_width(max_width, float_left);
+			if(!ret_width)
+			{
+				ret_width = el->right();
+			}
+		}
+		break;
+	case float_right:
+		{
+			int line_top = 0;
+			if(!m_boxes.empty())
+			{
+				if(m_boxes.back()->get_type() == box_line)
+				{
+					line_top = m_boxes.back()->top();
+				} else
+				{
+					line_top = m_boxes.back()->bottom();
+				}
+			}
+			line_top		= get_cleared_top(el, line_top);
+			int line_left	= 0;
+			int line_right	= max_width;
+			get_line_left_right(line_top, max_width, line_left, line_right);
+
+			el->render(0, line_top, line_right);
+
+			if(line_left + el->width() > line_right)
+			{
+				int new_top = find_next_line_top(el->top(), el->width(), max_width);
+				el->m_pos.x = get_line_right(new_top, max_width) - el->width() + el->content_margins_left();
+				el->m_pos.y = new_top + el->content_margins_top();
+			} else
+			{
+				el->m_pos.x = line_right - el->width() + el->content_margins_left();
+			}
+			add_float(el, 0, 0);
+			ret_width = fix_line_width(max_width, float_right);
+
+			if(!ret_width)
+			{
+				line_left	= 0;
+				line_right	= max_width;
+				get_line_left_right(line_top, max_width, line_left, line_right);
+
+				ret_width = ret_width + (max_width - line_right);
+			}
+		}
+		break;
+	default:
+		{
+			line_context line_ctx;
+			line_ctx.top = 0;
+			if (!m_boxes.empty())
+			{
+				line_ctx.top = m_boxes.back()->top();
+			}
+			line_ctx.left = 0;
+			line_ctx.right = max_width;
+			line_ctx.fix_top();
+			get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
+
+			switch(el->get_display())
+			{
+			case display_inline_block:
+				ret_width = el->render(line_ctx.left, line_ctx.top, line_ctx.right);
+				break;
+			case display_block:		
+				if(el->is_replaced() || el->is_floats_holder())
+				{
+					element::ptr el_parent = el->parent();
+					el->m_pos.width = el->get_css_width().calc_percent(line_ctx.right - line_ctx.left);
+					el->m_pos.height = el->get_css_height().calc_percent(el_parent ? el_parent->m_pos.height : 0);
+				}
+				el->calc_outlines(line_ctx.right - line_ctx.left);
+				break;
+			case display_inline_text:
+				{
+					litehtml::size sz;
+					el->get_content_size(sz, line_ctx.right);
+					el->m_pos = sz;
+				}
+				break;
+			default:
+				ret_width = 0;
+				break;
+			}
+
+			bool add_box = true;
+			if(!m_boxes.empty())
+			{
+				if(m_boxes.back()->can_hold(el, m_white_space))
+				{
+					add_box = false;
+				}
+			}
+			if(add_box)
+			{
+				new_box(el, max_width, line_ctx);
+			} else if(!m_boxes.empty())
+			{
+				line_ctx.top = m_boxes.back()->top();
+			}
+
+			if (line_ctx.top != line_ctx.calculatedTop)
+			{
+				line_ctx.left = 0;
+				line_ctx.right = max_width;
+				line_ctx.fix_top();
+				get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
+			}
+
+			if(!el->is_inline_box())
+			{
+				if(m_boxes.size() == 1)
+				{
+					if(collapse_top_margin())
+					{
+						int shift = el->margin_top();
+						if(shift >= 0)
+						{
+							line_ctx.top -= shift;
+							m_boxes.back()->y_shift(-shift);
+						}
+					}
+				} else
+				{
+					int shift = 0;
+					int prev_margin = m_boxes[m_boxes.size() - 2]->bottom_margin();
+
+					if(prev_margin > el->margin_top())
+					{
+						shift = el->margin_top();
+					} else
+					{
+						shift = prev_margin;
+					}
+					if(shift >= 0)
+					{
+						line_ctx.top -= shift;
+						m_boxes.back()->y_shift(-shift);
+					}
+				}
+			}
+
+			switch(el->get_display())
+			{
+			case display_table:
+			case display_list_item:
+				ret_width = el->render(line_ctx.left, line_ctx.top, line_ctx.width());
+				break;
+			case display_block:
+			case display_table_cell:
+			case display_table_caption:
+			case display_table_row:
+				if(el->is_replaced() || el->is_floats_holder())
+				{
+					ret_width = el->render(line_ctx.left, line_ctx.top, line_ctx.width()) + line_ctx.left + (max_width - line_ctx.right);
+				} else
+				{
+					ret_width = el->render(0, line_ctx.top, max_width);
+				}
+				break;
+			default:
+				ret_width = 0;
+				break;
+			}
+
+			m_boxes.back()->add_element(el);
+
+			if(el->is_inline_box() && !el->skip())
+			{
+				ret_width = el->right() + (max_width - line_ctx.right);
+			}
+		}
+		break;
+	}
+
+	return ret_width;
+}
+
+bool litehtml::html_tag::set_pseudo_class( const tchar_t* pclass, bool add )
+{
+	bool ret = false;
+	if(add)
+	{
+		if(std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), pclass) == m_pseudo_classes.end())
+		{
+			m_pseudo_classes.push_back(pclass);
+			ret = true;
+		}
+	} else
+	{
+		string_vector::iterator pi = std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), pclass);
+		if(pi != m_pseudo_classes.end())
+		{
+			m_pseudo_classes.erase(pi);
+			ret = true;
+		}
+	}
+	return ret;
+}
+
+bool litehtml::html_tag::set_class( const tchar_t* pclass, bool add )
+{
+	string_vector classes;
+	bool changed = false;
+
+	split_string( pclass, classes, _t(" ") );
+
+	if(add)
+	{
+		for( auto & _class : classes  )
+		{
+			if(std::find(m_class_values.begin(), m_class_values.end(), _class) == m_class_values.end())
+			{
+				m_class_values.push_back( std::move( _class ) );
+				changed = true;
+			}
+		}
+	} else
+	{
+		for( const auto & _class : classes )
+		{
+			auto end = std::remove(m_class_values.begin(), m_class_values.end(), _class);
+
+			if(end != m_class_values.end())
+			{
+				m_class_values.erase(end, m_class_values.end());
+				changed = true;
+			}
+		}
+	}
+
+	if( changed )
+	{
+		tstring class_string;
+		join_string(class_string, m_class_values, _t(" "));
+		set_attr(_t("class"), class_string.c_str());
+
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+
+}
+
+int litehtml::html_tag::line_height() const
+{
+	return m_line_height;
+}
+
+bool litehtml::html_tag::is_replaced() const
+{
+	return false;
+}
+
+int litehtml::html_tag::finish_last_box(bool end_of_render)
+{
+	int line_top = 0;
+
+	if(!m_boxes.empty())
+	{
+		m_boxes.back()->finish(end_of_render);
+
+		if(m_boxes.back()->is_empty())
+		{
+			line_top = m_boxes.back()->top();
+			m_boxes.pop_back();
+		}
+
+		if(!m_boxes.empty())
+		{
+			line_top = m_boxes.back()->bottom();
+		}
+	}
+	return line_top;
+}
+
+int litehtml::html_tag::new_box(const element::ptr &el, int max_width, line_context& line_ctx)
+{
+	line_ctx.top = get_cleared_top(el, finish_last_box());
+
+	line_ctx.left = 0;
+	line_ctx.right = max_width;
+	line_ctx.fix_top();
+	get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
+
+	if(el->is_inline_box() || el->is_floats_holder())
+	{
+		if (el->width() > line_ctx.right - line_ctx.left)
+		{
+			line_ctx.top = find_next_line_top(line_ctx.top, el->width(), max_width);
+			line_ctx.left = 0;
+			line_ctx.right = max_width;
+			line_ctx.fix_top();
+			get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
+		}
+	}
+
+	int first_line_margin = 0;
+	if(m_boxes.empty() && m_list_style_type != list_style_type_none && m_list_style_position == list_style_position_inside)
+	{
+		int sz_font = get_font_size();
+		first_line_margin = sz_font;
+	}
+
+	if(el->is_inline_box())
+	{
+		int text_indent = 0;
+		if(m_css_text_indent.val() != 0)
+		{
+			bool line_box_found = false;
+			for(box::vector::iterator iter = m_boxes.begin(); iter != m_boxes.end(); iter++)
+			{
+				if((*iter)->get_type() == box_line)
+				{
+					line_box_found = true;
+					break;
+				}
+			}
+			if(!line_box_found)
+			{
+				text_indent = m_css_text_indent.calc_percent(max_width);
+			}
+		}
+
+		font_metrics fm;
+		get_font(&fm);
+		m_boxes.emplace_back(std::unique_ptr<line_box>(new line_box(line_ctx.top, line_ctx.left + first_line_margin + text_indent, line_ctx.right, line_height(), fm, m_text_align)));
+	} else
+	{
+		m_boxes.emplace_back(std::unique_ptr<block_box>(new block_box(line_ctx.top, line_ctx.left, line_ctx.right)));
+	}
+
+	return line_ctx.top;
+}
+
+int litehtml::html_tag::get_cleared_top(const element::ptr &el, int line_top) const
+{
+	switch(el->get_clear())
+	{
+	case clear_left:
+		{
+			int fh = get_left_floats_height();
+			if(fh && fh > line_top)
+			{
+				line_top = fh;
+			}
+		}
+		break;
+	case clear_right:
+		{
+			int fh = get_right_floats_height();
+			if(fh && fh > line_top)
+			{
+				line_top = fh;
+			}
+		}
+		break;
+	case clear_both:
+		{
+			int fh = get_floats_height();
+			if(fh && fh > line_top)
+			{
+				line_top = fh;
+			}
+		}
+		break;
+	default:
+		if(el->get_float() != float_none)
+		{
+			int fh = get_floats_height(el->get_float());
+			if(fh && fh > line_top)
+			{
+				line_top = fh;
+			}
+		}
+		break;
+	}
+	return line_top;
+}
+
+litehtml::style_display litehtml::html_tag::get_display() const
+{
+	return m_display;
+}
+
+litehtml::element_float litehtml::html_tag::get_float() const
+{
+	return m_float;
+}
+
+bool litehtml::html_tag::is_floats_holder() const
+{
+	if(	m_display == display_inline_block || 
+		m_display == display_table_cell || 
+		!have_parent() ||
+		is_body() || 
+		m_float != float_none ||
+		m_el_position == element_position_absolute ||
+		m_el_position == element_position_fixed ||
+		m_overflow > overflow_visible)
+	{
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::html_tag::is_first_child_inline(const element::ptr& el) const
+{
+	if(!m_children.empty())
+	{
+		for (const auto& this_el : m_children)
+		{
+			if (!this_el->is_white_space())
+			{
+				if (el == this_el)
+				{
+					return true;
+				}
+				if (this_el->get_display() == display_inline)
+				{
+					if (this_el->have_inline_child())
+					{
+						return false;
+					}
+				} else
+				{
+					return false;
+				}
+			}
+		}
+	}
+	return false;
+}
+
+bool litehtml::html_tag::is_last_child_inline(const element::ptr& el)
+{
+	if(!m_children.empty())
+	{
+		for (auto this_el = m_children.rbegin(); this_el < m_children.rend(); ++this_el)
+		{
+			if (!(*this_el)->is_white_space())
+			{
+				if (el == (*this_el))
+				{
+					return true;
+				}
+				if ((*this_el)->get_display() == display_inline)
+				{
+					if ((*this_el)->have_inline_child())
+					{
+						return false;
+					}
+				} else
+				{
+					return false;
+				}
+			}
+		}
+	}
+	return false;
+}
+
+litehtml::white_space litehtml::html_tag::get_white_space() const
+{
+	return m_white_space;
+}
+
+litehtml::vertical_align litehtml::html_tag::get_vertical_align() const
+{
+	return m_vertical_align;
+}
+
+litehtml::css_length litehtml::html_tag::get_css_left() const
+{
+	return m_css_offsets.left;
+}
+
+litehtml::css_length litehtml::html_tag::get_css_right() const
+{
+	return m_css_offsets.right;
+}
+
+litehtml::css_length litehtml::html_tag::get_css_top() const
+{
+	return m_css_offsets.top;
+}
+
+litehtml::css_length litehtml::html_tag::get_css_bottom() const
+{
+	return m_css_offsets.bottom;
+}
+
+
+litehtml::css_offsets litehtml::html_tag::get_css_offsets() const
+{
+	return m_css_offsets;
+}
+
+litehtml::element_clear litehtml::html_tag::get_clear() const
+{
+	return m_clear;
+}
+
+litehtml::css_length litehtml::html_tag::get_css_width() const
+{
+	return m_css_width;
+}
+
+litehtml::css_length litehtml::html_tag::get_css_height() const
+{
+	return m_css_height;
+}
+
+size_t litehtml::html_tag::get_children_count() const
+{
+	return m_children.size();
+}
+
+litehtml::element::ptr litehtml::html_tag::get_child( int idx ) const
+{
+	return m_children[idx];
+}
+
+void litehtml::html_tag::set_css_width( css_length& w )
+{
+	m_css_width = w;
+}
+
+void litehtml::html_tag::apply_vertical_align()
+{
+	if(!m_boxes.empty())
+	{
+		int add = 0;
+		int content_height	= m_boxes.back()->bottom();
+
+		if(m_pos.height > content_height)
+		{
+			switch(m_vertical_align)
+			{
+			case va_middle:
+				add = (m_pos.height - content_height) / 2;
+				break;
+			case va_bottom:
+				add = m_pos.height - content_height;
+				break;
+			default:
+				add = 0;
+				break;
+			}
+		}
+
+		if(add)
+		{
+			for(size_t i = 0; i < m_boxes.size(); i++)
+			{
+				m_boxes[i]->y_shift(add);
+			}
+		}
+	}
+}
+
+litehtml::element_position litehtml::html_tag::get_element_position(css_offsets* offsets) const
+{
+	if(offsets && m_el_position != element_position_static)
+	{
+		*offsets = m_css_offsets;
+	}
+	return m_el_position;
+}
+
+void litehtml::html_tag::init_background_paint(position pos, background_paint &bg_paint, const background* bg)
+{
+	if(!bg) return;
+
+	bg_paint = *bg;
+	position content_box	= pos;
+	position padding_box	= pos;
+	padding_box += m_padding;
+	position border_box		= padding_box;
+	border_box += m_borders;
+
+	switch(bg->m_clip)
+	{
+	case litehtml::background_box_padding:
+		bg_paint.clip_box = padding_box;
+		break;
+	case litehtml::background_box_content:
+		bg_paint.clip_box = content_box;
+		break;
+	default:
+		bg_paint.clip_box = border_box;
+		break;
+	}
+
+	switch(bg->m_origin)
+	{
+	case litehtml::background_box_border:
+		bg_paint.origin_box = border_box;
+		break;
+	case litehtml::background_box_content:
+		bg_paint.origin_box = content_box;
+		break;
+	default:
+		bg_paint.origin_box = padding_box;
+		break;
+	}
+
+	if(!bg_paint.image.empty())
+	{
+		get_document()->container()->get_image_size(bg_paint.image.c_str(), bg_paint.baseurl.c_str(), bg_paint.image_size);
+		if(bg_paint.image_size.width && bg_paint.image_size.height)
+		{
+			litehtml::size img_new_sz = bg_paint.image_size;
+			double img_ar_width		= (double) bg_paint.image_size.width / (double) bg_paint.image_size.height;
+			double img_ar_height	= (double) bg_paint.image_size.height / (double) bg_paint.image_size.width;
+
+
+			if(bg->m_position.width.is_predefined())
+			{
+				switch(bg->m_position.width.predef())
+				{
+				case litehtml::background_size_contain:
+					if( (int) ((double) bg_paint.origin_box.width * img_ar_height) <= bg_paint.origin_box.height )
+					{
+						img_new_sz.width = bg_paint.origin_box.width;
+						img_new_sz.height	= (int) ((double) bg_paint.origin_box.width * img_ar_height);
+					} else
+					{
+						img_new_sz.height = bg_paint.origin_box.height;
+						img_new_sz.width	= (int) ((double) bg_paint.origin_box.height * img_ar_width);
+					}
+					break;
+				case litehtml::background_size_cover:
+					if( (int) ((double) bg_paint.origin_box.width * img_ar_height) >= bg_paint.origin_box.height )
+					{
+						img_new_sz.width = bg_paint.origin_box.width;
+						img_new_sz.height	= (int) ((double) bg_paint.origin_box.width * img_ar_height);
+					} else
+					{
+						img_new_sz.height = bg_paint.origin_box.height;
+						img_new_sz.width	= (int) ((double) bg_paint.origin_box.height * img_ar_width);
+					}
+					break;
+					break;
+				case litehtml::background_size_auto:
+					if(!bg->m_position.height.is_predefined())
+					{
+						img_new_sz.height	= bg->m_position.height.calc_percent(bg_paint.origin_box.height);
+						img_new_sz.width	= (int) ((double) img_new_sz.height * img_ar_width);
+					}
+					break;
+				}
+			} else
+			{
+				img_new_sz.width = bg->m_position.width.calc_percent(bg_paint.origin_box.width);
+				if(bg->m_position.height.is_predefined())
+				{
+					img_new_sz.height = (int) ((double) img_new_sz.width * img_ar_height);
+				} else
+				{
+					img_new_sz.height = bg->m_position.height.calc_percent(bg_paint.origin_box.height);
+				}
+			}
+
+			bg_paint.image_size = img_new_sz;
+			bg_paint.position_x = bg_paint.origin_box.x + (int) bg->m_position.x.calc_percent(bg_paint.origin_box.width - bg_paint.image_size.width);
+			bg_paint.position_y = bg_paint.origin_box.y + (int) bg->m_position.y.calc_percent(bg_paint.origin_box.height - bg_paint.image_size.height);
+		}
+
+	}
+	bg_paint.border_radius	= m_css_borders.radius.calc_percents(border_box.width, border_box.height);;
+	bg_paint.border_box		= border_box;
+	bg_paint.is_root		= have_parent() ? false : true;
+}
+
+litehtml::visibility litehtml::html_tag::get_visibility() const
+{
+	return m_visibility;
+}
+
+void litehtml::html_tag::draw_list_marker( uint_ptr hdc, const position &pos )
+{
+	list_marker lm;
+
+	const tchar_t* list_image = get_style_property(_t("list-style-image"), true, 0);
+	size img_size;
+	if(list_image)
+	{
+		css::parse_css_url(list_image, lm.image);
+		lm.baseurl = get_style_property(_t("list-style-image-baseurl"), true, 0);
+		get_document()->container()->get_image_size(lm.image.c_str(), lm.baseurl, img_size);
+	} else
+	{
+		lm.baseurl = 0;
+	}
+
+
+	int ln_height	= line_height();
+	int sz_font		= get_font_size();
+	lm.pos.x		= pos.x;
+	lm.pos.width	= sz_font	- sz_font * 2 / 3;
+	lm.pos.height	= sz_font	- sz_font * 2 / 3;
+	lm.pos.y		= pos.y		+ ln_height / 2 - lm.pos.height / 2;
+
+	if(img_size.width && img_size.height)
+	{
+		if(lm.pos.y + img_size.height > pos.y + pos.height)
+		{
+			lm.pos.y = pos.y + pos.height - img_size.height;
+		}
+		if(img_size.width > lm.pos.width)
+		{
+			lm.pos.x -= img_size.width - lm.pos.width;
+		}
+
+		lm.pos.width	= img_size.width;
+		lm.pos.height	= img_size.height;
+	}
+	if(m_list_style_position == list_style_position_outside)
+	{
+		lm.pos.x -= sz_font;
+	}
+
+	lm.color = get_color(_t("color"), true, web_color(0, 0, 0));
+	lm.marker_type = m_list_style_type;
+	get_document()->container()->draw_list_marker(hdc, lm);
+}
+
+void litehtml::html_tag::draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex )
+{
+	if (m_display == display_table || m_display == display_inline_table)
+	{
+		draw_children_table(hdc, x, y, clip, flag, zindex);
+	}
+	else
+	{
+		draw_children_box(hdc, x, y, clip, flag, zindex);
+	}
+}
+
+bool litehtml::html_tag::fetch_positioned()
+{
+	bool ret = false;
+
+	m_positioned.clear();
+
+	litehtml::element_position el_pos;
+
+	for(auto& el : m_children)
+	{
+		el_pos = el->get_element_position();
+		if (el_pos != element_position_static)
+		{
+			add_positioned(el);
+		}
+		if (!ret && (el_pos == element_position_absolute || el_pos == element_position_fixed))
+		{
+			ret = true;
+		}
+		if(el->fetch_positioned())
+		{
+			ret = true;
+		}
+	}
+	return ret;
+}
+
+int litehtml::html_tag::get_zindex() const
+{
+	return m_z_index;
+}
+
+void litehtml::html_tag::render_positioned(render_type rt)
+{
+	position wnd_position;
+	get_document()->container()->get_client_rect(wnd_position);
+
+	element_position el_position;
+	bool process;
+	for (auto& el : m_positioned)
+	{
+		el_position = el->get_element_position();
+
+		process = false;
+		if(el->get_display() != display_none)
+		{
+			if(el_position == element_position_absolute)
+			{
+				if(rt != render_fixed_only)
+				{
+					process = true;
+				}
+			} else if(el_position == element_position_fixed)
+			{
+				if(rt != render_no_fixed)
+				{
+					process = true;
+				}
+			}
+		}
+
+		if(process)
+		{
+			int parent_height	= 0;
+			int parent_width	= 0;
+			int client_x		= 0;
+			int client_y		= 0;
+			if(el_position == element_position_fixed)
+			{
+				parent_height	= wnd_position.height;
+				parent_width	= wnd_position.width;
+				client_x		= wnd_position.left();
+				client_y		= wnd_position.top();
+			} else
+			{
+				element::ptr el_parent = el->parent();
+				if(el_parent)
+				{
+					parent_height	= el_parent->height();
+					parent_width	= el_parent->width();
+				}
+			}
+
+			css_length	css_left	= el->get_css_left();
+			css_length	css_right	= el->get_css_right();
+			css_length	css_top		= el->get_css_top();
+			css_length	css_bottom	= el->get_css_bottom();
+
+			bool need_render = false;
+
+			css_length el_w = el->get_css_width();
+			css_length el_h = el->get_css_height();
+
+            int new_width = -1;
+            int new_height = -1;
+			if(el_w.units() == css_units_percentage && parent_width)
+			{
+                new_width = el_w.calc_percent(parent_width);
+                if(el->m_pos.width != new_width)
+				{
+					need_render = true;
+                    el->m_pos.width = new_width;
+				}
+			}
+
+			if(el_h.units() == css_units_percentage && parent_height)
+			{
+                new_height = el_h.calc_percent(parent_height);
+                if(el->m_pos.height != new_height)
+				{
+					need_render = true;
+                    el->m_pos.height = new_height;
+				}
+			}
+
+			bool cvt_x = false;
+			bool cvt_y = false;
+
+			if(el_position == element_position_fixed)
+			{
+				if(!css_left.is_predefined() || !css_right.is_predefined())
+				{
+					if(!css_left.is_predefined() && css_right.is_predefined())
+					{
+						el->m_pos.x = css_left.calc_percent(parent_width) + el->content_margins_left();
+					} else if(css_left.is_predefined() && !css_right.is_predefined())
+					{
+						el->m_pos.x = parent_width - css_right.calc_percent(parent_width) - el->m_pos.width - el->content_margins_right();
+					} else
+					{
+						el->m_pos.x		= css_left.calc_percent(parent_width) + el->content_margins_left();
+						el->m_pos.width	= parent_width - css_left.calc_percent(parent_width) - css_right.calc_percent(parent_width) - (el->content_margins_left() + el->content_margins_right());
+						need_render = true;
+					}
+				}
+
+				if(!css_top.is_predefined() || !css_bottom.is_predefined())
+				{
+					if(!css_top.is_predefined() && css_bottom.is_predefined())
+					{
+						el->m_pos.y = css_top.calc_percent(parent_height) + el->content_margins_top();
+					} else if(css_top.is_predefined() && !css_bottom.is_predefined())
+					{
+						el->m_pos.y = parent_height - css_bottom.calc_percent(parent_height) - el->m_pos.height - el->content_margins_bottom();
+					} else
+					{
+						el->m_pos.y			= css_top.calc_percent(parent_height) + el->content_margins_top();
+						el->m_pos.height	= parent_height - css_top.calc_percent(parent_height) - css_bottom.calc_percent(parent_height) - (el->content_margins_top() + el->content_margins_bottom());
+						need_render = true;
+					}
+				}
+			} else 
+			{
+				if(!css_left.is_predefined() || !css_right.is_predefined())
+				{
+					if(!css_left.is_predefined() && css_right.is_predefined())
+					{
+						el->m_pos.x = css_left.calc_percent(parent_width) + el->content_margins_left() - m_padding.left;
+					} else if(css_left.is_predefined() && !css_right.is_predefined())
+					{
+						el->m_pos.x = m_pos.width + m_padding.right - css_right.calc_percent(parent_width) - el->m_pos.width - el->content_margins_right();
+					} else
+					{
+						el->m_pos.x		= css_left.calc_percent(parent_width) + el->content_margins_left() - m_padding.left;
+						el->m_pos.width	= m_pos.width + m_padding.left + m_padding.right - css_left.calc_percent(parent_width) - css_right.calc_percent(parent_width) - (el->content_margins_left() + el->content_margins_right());
+                        if (new_width != -1)
+                        {
+                            el->m_pos.x += (el->m_pos.width - new_width) / 2;
+                            el->m_pos.width = new_width;
+                        }
+                        need_render = true;
+					}
+					cvt_x = true;
+				}
+
+				if(!css_top.is_predefined() || !css_bottom.is_predefined())
+				{
+					if(!css_top.is_predefined() && css_bottom.is_predefined())
+					{
+						el->m_pos.y = css_top.calc_percent(parent_height) + el->content_margins_top() - m_padding.top;
+					} else if(css_top.is_predefined() && !css_bottom.is_predefined())
+					{
+						el->m_pos.y = m_pos.height + m_padding.bottom - css_bottom.calc_percent(parent_height) - el->m_pos.height - el->content_margins_bottom();
+					} else
+					{
+						el->m_pos.y			= css_top.calc_percent(parent_height) + el->content_margins_top() - m_padding.top;
+						el->m_pos.height	= m_pos.height + m_padding.top + m_padding.bottom - css_top.calc_percent(parent_height) - css_bottom.calc_percent(parent_height) - (el->content_margins_top() + el->content_margins_bottom());
+                        if (new_height != -1)
+                        {
+                            el->m_pos.y += (el->m_pos.height - new_height) / 2;
+                            el->m_pos.height = new_height;
+                        }
+                        need_render = true;
+					}
+					cvt_y = true;
+				}
+			}
+
+			if(cvt_x || cvt_y)
+			{
+				int offset_x = 0;
+				int offset_y = 0;
+				element::ptr cur_el = el->parent();
+				element::ptr this_el = shared_from_this();
+				while(cur_el && cur_el != this_el)
+				{
+					offset_x += cur_el->m_pos.x;
+					offset_y += cur_el->m_pos.y;
+					cur_el = cur_el->parent();
+				}
+				if(cvt_x)	el->m_pos.x -= offset_x;
+				if(cvt_y)	el->m_pos.y -= offset_y;
+			}
+
+			if(need_render)
+			{
+				position pos = el->m_pos;
+				el->render(el->left(), el->top(), el->width(), true);
+				el->m_pos = pos;
+			}
+
+			if(el_position == element_position_fixed)
+			{
+				position fixed_pos;
+				el->get_redraw_box(fixed_pos);
+				get_document()->add_fixed_box(fixed_pos);
+			}
+		}
+
+		el->render_positioned();
+	}
+
+	if(!m_positioned.empty())
+	{
+		std::stable_sort(m_positioned.begin(), m_positioned.end(), [](const litehtml::element::ptr& _Left, const litehtml::element::ptr& _Right)
+		{
+			return (_Left->get_zindex() < _Right->get_zindex());
+		});
+	}
+}
+
+void litehtml::html_tag::draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned )
+{
+	if(!is_visible()) return;
+
+	std::map<int, bool> zindexes;
+	if(with_positioned)
+	{
+		for(elements_vector::iterator i = m_positioned.begin(); i != m_positioned.end(); i++)
+		{
+			zindexes[(*i)->get_zindex()];
+		}
+
+		for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end(); idx++)
+		{
+			if(idx->first < 0)
+			{
+				draw_children(hdc, x, y, clip, draw_positioned, idx->first);
+			}
+		}
+	}
+	draw_children(hdc, x, y, clip, draw_block, 0);
+	draw_children(hdc, x, y, clip, draw_floats, 0);
+	draw_children(hdc, x, y, clip, draw_inlines, 0);
+	if(with_positioned)
+	{
+		for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end(); idx++)
+		{
+			if(idx->first == 0)
+			{
+				draw_children(hdc, x, y, clip, draw_positioned, idx->first);
+			}
+		}
+
+		for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end(); idx++)
+		{
+			if(idx->first > 0)
+			{
+				draw_children(hdc, x, y, clip, draw_positioned, idx->first);
+			}
+		}
+	}
+}
+
+litehtml::overflow litehtml::html_tag::get_overflow() const
+{
+	return m_overflow;
+}
+
+bool litehtml::html_tag::is_nth_child(const element::ptr& el, int num, int off, bool of_type) const
+{
+	int idx = 1;
+	for(const auto& child : m_children)
+	{
+		if(child->get_display() != display_inline_text)
+		{
+			if( (!of_type) || (of_type && !t_strcmp(el->get_tagName(), child->get_tagName())) )
+			{
+				if(el == child)
+				{
+					if(num != 0)
+					{
+						if((idx - off) >= 0 && (idx - off) % num == 0)
+						{
+							return true;
+						}
+
+					} else if(idx == off)
+					{
+						return true;
+					}
+					return false;
+				}
+				idx++;
+			}
+			if(el == child) break;
+		}
+	}
+	return false;
+}
+
+bool litehtml::html_tag::is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const
+{
+	int idx = 1;
+	for(elements_vector::const_reverse_iterator child = m_children.rbegin(); child != m_children.rend(); child++)
+	{
+		if((*child)->get_display() != display_inline_text)
+		{
+			if( !of_type || (of_type && !t_strcmp(el->get_tagName(), (*child)->get_tagName())) )
+			{
+				if(el == (*child))
+				{
+					if(num != 0)
+					{
+						if((idx - off) >= 0 && (idx - off) % num == 0)
+						{
+							return true;
+						}
+
+					} else if(idx == off)
+					{
+						return true;
+					}
+					return false;
+				}
+				idx++;
+			}
+			if(el == (*child)) break;
+		}
+	}
+	return false;
+}
+
+void litehtml::html_tag::parse_nth_child_params( tstring param, int &num, int &off )
+{
+	if(param == _t("odd"))
+	{
+		num = 2;
+		off = 1;
+	} else if(param == _t("even"))
+	{
+		num = 2;
+		off = 0;
+	} else
+	{
+		string_vector tokens;
+		split_string(param, tokens, _t(" n"), _t("n"));
+
+		tstring s_num;
+		tstring s_off;
+
+		tstring s_int;
+		for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+		{
+			if((*tok) == _t("n"))
+			{
+				s_num = s_int;
+				s_int.clear();
+			} else
+			{
+				s_int += (*tok);
+			}
+		}
+		s_off = s_int;
+
+		num = t_atoi(s_num.c_str());
+		off = t_atoi(s_off.c_str());
+	}
+}
+
+void litehtml::html_tag::calc_document_size( litehtml::size& sz, int x /*= 0*/, int y /*= 0*/ )
+{
+	if(is_visible() && m_el_position != element_position_fixed)
+	{
+		element::calc_document_size(sz, x, y);
+
+		if(m_overflow == overflow_visible)
+		{
+			for(auto& el : m_children)
+			{
+				el->calc_document_size(sz, x + m_pos.x, y + m_pos.y);
+			}
+		}
+
+		// root element (<html>) must to cover entire window
+		if(!have_parent())
+		{
+			position client_pos;
+			get_document()->container()->get_client_rect(client_pos);
+			m_pos.height = std::max(sz.height, client_pos.height) - content_margins_top() - content_margins_bottom();
+			m_pos.width	 = std::max(sz.width, client_pos.width) - content_margins_left() - content_margins_right();
+		}
+	}
+}
+
+
+void litehtml::html_tag::get_redraw_box(litehtml::position& pos, int x /*= 0*/, int y /*= 0*/)
+{
+	if(is_visible())
+	{
+		element::get_redraw_box(pos, x, y);
+
+		if(m_overflow == overflow_visible)
+		{
+			for(auto& el : m_children)
+			{
+				if(el->get_element_position() != element_position_fixed)
+				{
+					el->get_redraw_box(pos, x + m_pos.x, y + m_pos.y);
+				}
+			}
+		}
+	}
+}
+
+litehtml::element::ptr litehtml::html_tag::find_adjacent_sibling( const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/ )
+{
+	element::ptr ret;
+	for(auto& e : m_children)
+	{
+		if(e->get_display() != display_inline_text)
+		{
+			if(e == el)
+			{
+				if(ret)
+				{
+					int res = ret->select(selector, apply_pseudo);
+					if(res != select_no_match)
+					{
+						if(is_pseudo)
+						{
+							if(res & select_match_pseudo_class)
+							{
+								*is_pseudo = true;
+							} else
+							{
+								*is_pseudo = false;
+							}
+						}
+						return ret;
+					}
+				}
+				return 0;
+			} else
+			{
+				ret = e;
+			}
+		}
+	}
+	return 0;
+}
+
+litehtml::element::ptr litehtml::html_tag::find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/)
+{
+	element::ptr ret = 0;
+	for(auto& e : m_children)
+	{
+		if(e->get_display() != display_inline_text)
+		{
+			if(e == el)
+			{
+				return ret;
+			} else if(!ret)
+			{
+				int res = e->select(selector, apply_pseudo);
+				if(res != select_no_match)
+				{
+					if(is_pseudo)
+					{
+						if(res & select_match_pseudo_class)
+						{
+							*is_pseudo = true;
+						} else
+						{
+							*is_pseudo = false;
+						}
+					}
+					ret = e;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+bool litehtml::html_tag::is_only_child(const element::ptr& el, bool of_type) const
+{
+	int child_count = 0;
+	for(const auto& child : m_children)
+	{
+		if(child->get_display() != display_inline_text)
+		{
+			if( !of_type || (of_type && !t_strcmp(el->get_tagName(), child->get_tagName())) )
+			{
+				child_count++;
+			}
+			if(child_count > 1) break;
+		}
+	}
+	if(child_count > 1)
+	{
+		return false;
+	}
+	return true;
+}
+
+void litehtml::html_tag::update_floats(int dy, const element::ptr &parent)
+{
+	if(is_floats_holder())
+	{
+		bool reset_cache = false;
+		for(floated_box::vector::reverse_iterator fb = m_floats_left.rbegin(); fb != m_floats_left.rend(); fb++)
+		{
+			if(fb->el->is_ancestor(parent))
+			{
+				reset_cache	= true;
+				fb->pos.y	+= dy;
+			}
+		}
+		if(reset_cache)
+		{
+			m_cahe_line_left.invalidate();
+		}
+		reset_cache = false;
+		for(floated_box::vector::reverse_iterator fb = m_floats_right.rbegin(); fb != m_floats_right.rend(); fb++)
+		{
+			if(fb->el->is_ancestor(parent))
+			{
+				reset_cache	= true;
+				fb->pos.y	+= dy;
+			}
+		}
+		if(reset_cache)
+		{
+			m_cahe_line_right.invalidate();
+		}
+	} else
+	{
+		element::ptr el_parent = this->parent();
+		if (el_parent)
+		{
+			el_parent->update_floats(dy, parent);
+		}
+	}
+}
+
+void litehtml::html_tag::remove_before_after()
+{
+	if(!m_children.empty())
+	{
+		if( !t_strcmp(m_children.front()->get_tagName(), _t("::before")) )
+		{
+			m_children.erase(m_children.begin());
+		}
+	}
+	if(!m_children.empty())
+	{
+		if( !t_strcmp(m_children.back()->get_tagName(), _t("::after")) )
+		{
+			m_children.erase(m_children.end() - 1);
+		}
+	}
+}
+
+litehtml::element::ptr litehtml::html_tag::get_element_before()
+{
+	if(!m_children.empty())
+	{
+		if( !t_strcmp(m_children.front()->get_tagName(), _t("::before")) )
+		{
+			return m_children.front();
+		}
+	}
+	element::ptr el = std::make_shared<el_before>(get_document());
+	el->parent(shared_from_this());
+	m_children.insert(m_children.begin(), el);
+	return el;
+}
+
+litehtml::element::ptr litehtml::html_tag::get_element_after()
+{
+	if(!m_children.empty())
+	{
+		if( !t_strcmp(m_children.back()->get_tagName(), _t("::after")) )
+		{
+			return m_children.back();
+		}
+	}
+	element::ptr el = std::make_shared<el_after>(get_document());
+	appendChild(el);
+	return el;
+}
+
+void litehtml::html_tag::add_style( const litehtml::style& st )
+{
+	m_style.combine(st);
+}
+
+bool litehtml::html_tag::have_inline_child() const
+{
+	if(!m_children.empty())
+	{
+		for(const auto& el : m_children)
+		{
+			if(!el->is_white_space())
+			{
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+void litehtml::html_tag::refresh_styles()
+{
+	remove_before_after();
+
+	for (auto& el : m_children)
+	{
+		if(el->get_display() != display_inline_text)
+		{
+			el->refresh_styles();
+		}
+	}
+
+	m_style.clear();
+
+	for (auto& usel : m_used_styles)
+	{
+		usel->m_used = false;
+
+		if(usel->m_selector->is_media_valid())
+		{
+			int apply = select(*usel->m_selector, false);
+
+			if(apply != select_no_match)
+			{
+				if(apply & select_match_pseudo_class)
+				{
+					if(select(*usel->m_selector, true))
+					{
+						if(apply & select_match_with_after)
+						{
+							element::ptr el = get_element_after();
+							if(el)
+							{
+								el->add_style(*usel->m_selector->m_style);
+							}
+						} else if(apply & select_match_with_before)
+						{
+							element::ptr el = get_element_before();
+							if(el)
+							{
+								el->add_style(*usel->m_selector->m_style);
+							}
+						}
+						else
+						{
+							add_style(*usel->m_selector->m_style);
+							usel->m_used = true;
+						}
+					}
+				} else if(apply & select_match_with_after)
+				{
+					element::ptr el = get_element_after();
+					if(el)
+					{
+						el->add_style(*usel->m_selector->m_style);
+					}
+				} else if(apply & select_match_with_before)
+				{
+					element::ptr el = get_element_before();
+					if(el)
+					{
+						el->add_style(*usel->m_selector->m_style);
+					}
+				} else
+				{
+					add_style(*usel->m_selector->m_style);
+					usel->m_used = true;
+				}
+			}
+		}
+	}
+}
+
+litehtml::element::ptr litehtml::html_tag::get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex)
+{
+	element::ptr ret = 0;
+
+	if(m_overflow > overflow_visible)
+	{
+		if(!m_pos.is_point_inside(x, y))
+		{
+			return ret;
+		}
+	}
+
+	position pos = m_pos;
+	pos.x	= x - pos.x;
+	pos.y	= y - pos.y;
+
+	for(elements_vector::reverse_iterator i = m_children.rbegin(); i != m_children.rend() && !ret; i++)
+	{
+		element::ptr el = (*i);
+
+		if(el->is_visible() && el->get_display() != display_inline_text)
+		{
+			switch(flag)
+			{
+			case draw_positioned:
+				if(el->is_positioned() && el->get_zindex() == zindex)
+				{
+					if(el->get_element_position() == element_position_fixed)
+					{
+						ret = el->get_element_by_point(client_x, client_y, client_x, client_y);
+						if(!ret && (*i)->is_point_inside(client_x, client_y))
+						{
+							ret = (*i);
+						}
+					} else
+					{
+						ret = el->get_element_by_point(pos.x, pos.y, client_x, client_y);
+						if(!ret && (*i)->is_point_inside(pos.x, pos.y))
+						{
+							ret = (*i);
+						}
+					}
+					el = 0;
+				}
+				break;
+			case draw_block:
+				if(!el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
+				{
+					if(el->is_point_inside(pos.x, pos.y))
+					{
+						ret = el;
+					}
+				}
+				break;
+			case draw_floats:
+				if(el->get_float() != float_none && !el->is_positioned())
+				{
+					ret = el->get_element_by_point(pos.x, pos.y, client_x, client_y);
+
+					if(!ret && (*i)->is_point_inside(pos.x, pos.y))
+					{
+						ret = (*i);
+					}
+					el = 0;
+				}
+				break;
+			case draw_inlines:
+				if(el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
+				{
+					if(el->get_display() == display_inline_block)
+					{
+						ret = el->get_element_by_point(pos.x, pos.y, client_x, client_y);
+						el = 0;
+					}
+					if(!ret && (*i)->is_point_inside(pos.x, pos.y))
+					{
+						ret = (*i);
+					}
+				}
+				break;
+			default:
+				break;
+			}
+
+			if(el && !el->is_positioned())
+			{
+				if(flag == draw_positioned)
+				{
+					element::ptr child = el->get_child_by_point(pos.x, pos.y, client_x, client_y, flag, zindex);
+					if(child)
+					{
+						ret = child;
+					}
+				} else
+				{
+					if(	el->get_float() == float_none &&
+						el->get_display() != display_inline_block)
+					{
+						element::ptr child = el->get_child_by_point(pos.x, pos.y, client_x, client_y, flag, zindex);
+						if(child)
+						{
+							ret = child;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	return ret;
+}
+
+litehtml::element::ptr litehtml::html_tag::get_element_by_point(int x, int y, int client_x, int client_y)
+{
+	if(!is_visible()) return 0;
+
+	element::ptr ret;
+
+	std::map<int, bool> zindexes;
+
+	for(elements_vector::iterator i = m_positioned.begin(); i != m_positioned.end(); i++)
+	{
+		zindexes[(*i)->get_zindex()];
+	}
+
+	for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end() && !ret; idx++)
+	{
+		if(idx->first > 0)
+		{
+			ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, idx->first);
+		}
+	}
+	if(ret) return ret;
+
+	for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end() && !ret; idx++)
+	{
+		if(idx->first == 0)
+		{
+			ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, idx->first);
+		}
+	}
+	if(ret) return ret;
+
+	ret = get_child_by_point(x, y, client_x, client_y, draw_inlines, 0);
+	if(ret) return ret;
+
+	ret = get_child_by_point(x, y, client_x, client_y, draw_floats, 0);
+	if(ret) return ret;
+
+	ret = get_child_by_point(x, y, client_x, client_y, draw_block, 0);
+	if(ret) return ret;
+
+
+	for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end() && !ret; idx++)
+	{
+		if(idx->first < 0)
+		{
+			ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, idx->first);
+		}
+	}
+	if(ret) return ret;
+
+	if(m_el_position == element_position_fixed)
+	{
+		if(is_point_inside(client_x, client_y))
+		{
+			ret = shared_from_this();
+		}
+	} else
+	{
+		if(is_point_inside(x, y))
+		{
+			ret = shared_from_this();
+		}
+	}
+
+	return ret;
+}
+
+const litehtml::background* litehtml::html_tag::get_background(bool own_only)
+{
+	if(own_only)
+	{
+		// return own background with check for empty one
+		if(m_bg.m_image.empty() && !m_bg.m_color.alpha)
+		{
+			return 0;
+		}
+		return &m_bg;
+	}
+
+	if(m_bg.m_image.empty() && !m_bg.m_color.alpha)
+	{
+		// if this is root element (<html>) try to get background from body
+		if (!have_parent())
+		{
+			for (const auto& el : m_children)
+			{
+				if( el->is_body() )
+				{
+					// return own body background
+					return el->get_background(true);
+				}
+			}
+		}
+		return 0;
+	}
+	
+	if(is_body())
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			if (!el_parent->get_background(true))
+			{
+				// parent of body will draw background for body
+				return 0;
+			}
+		}
+	}
+
+	return &m_bg;
+}
+
+int litehtml::html_tag::render_box(int x, int y, int max_width, bool second_pass /*= false*/)
+{
+	int parent_width = max_width;
+
+	calc_outlines(parent_width);
+
+	m_pos.clear();
+	m_pos.move_to(x, y);
+
+	m_pos.x += content_margins_left();
+	m_pos.y += content_margins_top();
+
+	int ret_width = 0;
+
+	def_value<int>	block_width(0);
+
+	if (m_display != display_table_cell && !m_css_width.is_predefined())
+	{
+		int w = calc_width(parent_width);
+		
+		if (m_box_sizing == box_sizing_border_box)
+		{
+			w -= m_padding.width() + m_borders.width();
+		}
+		ret_width = max_width = block_width = w;
+	}
+	else
+	{
+		if (max_width)
+		{
+			max_width -= content_margins_left() + content_margins_right();
+		}
+	}
+
+	// check for max-width (on the first pass only)
+	if (!m_css_max_width.is_predefined() && !second_pass)
+	{
+		int mw = get_document()->cvt_units(m_css_max_width, m_font_size, parent_width);
+		if (m_box_sizing == box_sizing_border_box)
+		{
+			mw -= m_padding.left + m_borders.left + m_padding.right + m_borders.right;
+		}
+		if (max_width > mw)
+		{
+			max_width = mw;
+		}
+	}
+
+	m_floats_left.clear();
+	m_floats_right.clear();
+	m_boxes.clear();
+	m_cahe_line_left.invalidate();
+	m_cahe_line_right.invalidate();
+
+	element_position el_position;
+
+	int block_height = 0;
+
+	m_pos.height = 0;
+
+	if (get_predefined_height(block_height))
+	{
+		m_pos.height = block_height;
+	}
+
+	white_space ws = get_white_space();
+	bool skip_spaces = false;
+	if (ws == white_space_normal ||
+		ws == white_space_nowrap ||
+		ws == white_space_pre_line)
+	{
+		skip_spaces = true;
+	}
+
+	bool was_space = false;
+
+	for (auto el : m_children)
+	{
+		// we don't need process absolute and fixed positioned element on the second pass
+		if (second_pass)
+		{
+			el_position = el->get_element_position();
+			if ((el_position == element_position_absolute || el_position == element_position_fixed)) continue;
+		}
+
+		// skip spaces to make rendering a bit faster
+		if (skip_spaces)
+		{
+			if (el->is_white_space())
+			{
+				if (was_space)
+				{
+					el->skip(true);
+					continue;
+				}
+				else
+				{
+					was_space = true;
+				}
+			}
+			else
+			{
+				was_space = false;
+			}
+		}
+
+		// place element into rendering flow
+		int rw = place_element(el, max_width);
+		if (rw > ret_width)
+		{
+			ret_width = rw;
+		}
+	}
+
+	finish_last_box(true);
+
+	if (block_width.is_default() && is_inline_box())
+	{
+		m_pos.width = ret_width;
+	}
+	else
+	{
+		m_pos.width = max_width;
+	}
+	calc_auto_margins(parent_width);
+
+	if (!m_boxes.empty())
+	{
+		if (collapse_top_margin())
+		{
+			int old_top = m_margins.top;
+			m_margins.top = std::max(m_boxes.front()->top_margin(), m_margins.top);
+			if (m_margins.top != old_top)
+			{
+				update_floats(m_margins.top - old_top, shared_from_this());
+			}
+		}
+		if (collapse_bottom_margin())
+		{
+			m_margins.bottom = std::max(m_boxes.back()->bottom_margin(), m_margins.bottom);
+			m_pos.height = m_boxes.back()->bottom() - m_boxes.back()->bottom_margin();
+		}
+		else
+		{
+			m_pos.height = m_boxes.back()->bottom();
+		}
+	}
+
+	// add the floats height to the block height
+	if (is_floats_holder())
+	{
+		int floats_height = get_floats_height();
+		if (floats_height > m_pos.height)
+		{
+			m_pos.height = floats_height;
+		}
+	}
+
+	// calculate the final position
+
+	m_pos.move_to(x, y);
+	m_pos.x += content_margins_left();
+	m_pos.y += content_margins_top();
+
+	if (get_predefined_height(block_height))
+	{
+		m_pos.height = block_height;
+	}
+
+	int min_height = 0;
+	if (!m_css_min_height.is_predefined() && m_css_min_height.units() == css_units_percentage)
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			if (el_parent->get_predefined_height(block_height))
+			{
+				min_height = m_css_min_height.calc_percent(block_height);
+			}
+		}
+	}
+	else
+	{
+		min_height = (int)m_css_min_height.val();
+	}
+	if (min_height != 0 && m_box_sizing == box_sizing_border_box)
+	{
+		min_height -= m_padding.top + m_borders.top + m_padding.bottom + m_borders.bottom;
+		if (min_height < 0) min_height = 0;
+	}
+
+	if (m_display == display_list_item)
+	{
+		const tchar_t* list_image = get_style_property(_t("list-style-image"), true, 0);
+		if (list_image)
+		{
+			tstring url;
+			css::parse_css_url(list_image, url);
+
+			size sz;
+			const tchar_t* list_image_baseurl = get_style_property(_t("list-style-image-baseurl"), true, 0);
+			get_document()->container()->get_image_size(url.c_str(), list_image_baseurl, sz);
+			if (min_height < sz.height)
+			{
+				min_height = sz.height;
+			}
+		}
+
+	}
+
+	if (min_height > m_pos.height)
+	{
+		m_pos.height = min_height;
+	}
+
+	int min_width = m_css_min_width.calc_percent(parent_width);
+
+	if (min_width != 0 && m_box_sizing == box_sizing_border_box)
+	{
+		min_width -= m_padding.left + m_borders.left + m_padding.right + m_borders.right;
+		if (min_width < 0) min_width = 0;
+	}
+
+	if (min_width != 0)
+	{
+		if (min_width > m_pos.width)
+		{
+			m_pos.width = min_width;
+		}
+		if (min_width > ret_width)
+		{
+			ret_width = min_width;
+		}
+	}
+
+	ret_width += content_margins_left() + content_margins_right();
+
+	// re-render with new width
+	if (ret_width < max_width && !second_pass && have_parent())
+	{
+		if (m_display == display_inline_block ||
+			m_css_width.is_predefined() &&
+			(m_float != float_none ||
+			m_display == display_table ||
+			m_el_position == element_position_absolute ||
+			m_el_position == element_position_fixed
+			)
+			)
+		{
+			render(x, y, ret_width, true);
+			m_pos.width = ret_width - (content_margins_left() + content_margins_right());
+		}
+	}
+
+	if (is_floats_holder() && !second_pass)
+	{
+		for (const auto& fb : m_floats_left)
+		{
+			fb.el->apply_relative_shift(fb.el->parent()->calc_width(m_pos.width));
+		}
+	}
+
+
+	return ret_width;
+}
+
+int litehtml::html_tag::render_table(int x, int y, int max_width, bool second_pass /*= false*/)
+{
+	if (!m_grid) return 0;
+
+	int parent_width = max_width;
+
+	calc_outlines(parent_width);
+
+	m_pos.clear();
+	m_pos.move_to(x, y);
+
+	m_pos.x += content_margins_left();
+	m_pos.y += content_margins_top();
+
+	def_value<int>	block_width(0);
+
+	if (!m_css_width.is_predefined())
+	{
+		max_width = block_width = calc_width(parent_width) - m_padding.width() - m_borders.width();
+	}
+	else
+	{
+		if (max_width)
+		{
+			max_width -= content_margins_left() + content_margins_right();
+		}
+	}
+
+	// Calculate table spacing
+	int table_width_spacing = 0;
+	if (m_border_collapse == border_collapse_separate)
+	{
+		table_width_spacing = m_border_spacing_x * (m_grid->cols_count() + 1);
+	}
+	else
+	{
+		table_width_spacing = 0;
+
+		if (m_grid->cols_count())
+		{
+			table_width_spacing -= std::min(border_left(), m_grid->column(0).border_left);
+			table_width_spacing -= std::min(border_right(), m_grid->column(m_grid->cols_count() - 1).border_right);
+		}
+
+		for (int col = 1; col < m_grid->cols_count(); col++)
+		{
+			table_width_spacing -= std::min(m_grid->column(col).border_left, m_grid->column(col - 1).border_right);
+		}
+	}
+
+
+	// Calculate the minimum content width (MCW) of each cell: the formatted content may span any number of lines but may not overflow the cell box. 
+	// If the specified 'width' (W) of the cell is greater than MCW, W is the minimum cell width. A value of 'auto' means that MCW is the minimum 
+	// cell width.
+	// 
+	// Also, calculate the "maximum" cell width of each cell: formatting the content without breaking lines other than where explicit line breaks occur.
+
+	if (m_grid->cols_count() == 1 && !block_width.is_default())
+	{
+		for (int row = 0; row < m_grid->rows_count(); row++)
+		{
+			table_cell* cell = m_grid->cell(0, row);
+			if (cell && cell->el)
+			{
+				cell->min_width = cell->max_width = cell->el->render(0, 0, max_width - table_width_spacing);
+				cell->el->m_pos.width = cell->min_width - cell->el->content_margins_left() - cell->el->content_margins_right();
+			}
+		}
+	}
+	else
+	{
+		for (int row = 0; row < m_grid->rows_count(); row++)
+		{
+			for (int col = 0; col < m_grid->cols_count(); col++)
+			{
+				table_cell* cell = m_grid->cell(col, row);
+				if (cell && cell->el)
+				{
+					if (!m_grid->column(col).css_width.is_predefined() && m_grid->column(col).css_width.units() != css_units_percentage)
+					{
+						int css_w = m_grid->column(col).css_width.calc_percent(block_width);
+						int el_w = cell->el->render(0, 0, css_w);
+						cell->min_width = cell->max_width = std::max(css_w, el_w);
+						cell->el->m_pos.width = cell->min_width - cell->el->content_margins_left() - cell->el->content_margins_right();
+					}
+					else
+					{
+						// calculate minimum content width
+						cell->min_width = cell->el->render(0, 0, 1);
+						// calculate maximum content width
+						cell->max_width = cell->el->render(0, 0, max_width - table_width_spacing);
+					}
+				}
+			}
+		}
+	}
+
+	// For each column, determine a maximum and minimum column width from the cells that span only that column. 
+	// The minimum is that required by the cell with the largest minimum cell width (or the column 'width', whichever is larger). 
+	// The maximum is that required by the cell with the largest maximum cell width (or the column 'width', whichever is larger).
+
+	for (int col = 0; col < m_grid->cols_count(); col++)
+	{
+		m_grid->column(col).max_width = 0;
+		m_grid->column(col).min_width = 0;
+		for (int row = 0; row < m_grid->rows_count(); row++)
+		{
+			if (m_grid->cell(col, row)->colspan <= 1)
+			{
+				m_grid->column(col).max_width = std::max(m_grid->column(col).max_width, m_grid->cell(col, row)->max_width);
+				m_grid->column(col).min_width = std::max(m_grid->column(col).min_width, m_grid->cell(col, row)->min_width);
+			}
+		}
+	}
+
+	// For each cell that spans more than one column, increase the minimum widths of the columns it spans so that together, 
+	// they are at least as wide as the cell. Do the same for the maximum widths. 
+	// If possible, widen all spanned columns by approximately the same amount.
+
+	for (int col = 0; col < m_grid->cols_count(); col++)
+	{
+		for (int row = 0; row < m_grid->rows_count(); row++)
+		{
+			if (m_grid->cell(col, row)->colspan > 1)
+			{
+				int max_total_width = m_grid->column(col).max_width;
+				int min_total_width = m_grid->column(col).min_width;
+				for (int col2 = col + 1; col2 < col + m_grid->cell(col, row)->colspan; col2++)
+				{
+					max_total_width += m_grid->column(col2).max_width;
+					min_total_width += m_grid->column(col2).min_width;
+				}
+				if (min_total_width < m_grid->cell(col, row)->min_width)
+				{
+					m_grid->distribute_min_width(m_grid->cell(col, row)->min_width - min_total_width, col, col + m_grid->cell(col, row)->colspan - 1);
+				}
+				if (max_total_width < m_grid->cell(col, row)->max_width)
+				{
+					m_grid->distribute_max_width(m_grid->cell(col, row)->max_width - max_total_width, col, col + m_grid->cell(col, row)->colspan - 1);
+				}
+			}
+		}
+	}
+
+	// If the 'table' or 'inline-table' element's 'width' property has a computed value (W) other than 'auto', the used width is the 
+	// greater of W, CAPMIN, and the minimum width required by all the columns plus cell spacing or borders (MIN). 
+	// If the used width is greater than MIN, the extra width should be distributed over the columns.
+	//
+	// If the 'table' or 'inline-table' element has 'width: auto', the used width is the greater of the table's containing block width, 
+	// CAPMIN, and MIN. However, if either CAPMIN or the maximum width required by the columns plus cell spacing or borders (MAX) is 
+	// less than that of the containing block, use max(MAX, CAPMIN).
+
+
+	int table_width = 0;
+	int min_table_width = 0;
+	int max_table_width = 0;
+
+	if (!block_width.is_default())
+	{
+		table_width = m_grid->calc_table_width(block_width - table_width_spacing, false, min_table_width, max_table_width);
+	}
+	else
+	{
+		table_width = m_grid->calc_table_width(max_width - table_width_spacing, true, min_table_width, max_table_width);
+	}
+
+	min_table_width += table_width_spacing;
+	max_table_width += table_width_spacing;
+	table_width += table_width_spacing;
+	m_grid->calc_horizontal_positions(m_borders, m_border_collapse, m_border_spacing_x);
+
+	bool row_span_found = false;
+
+	// render cells with computed width
+	for (int row = 0; row < m_grid->rows_count(); row++)
+	{
+		m_grid->row(row).height = 0;
+		for (int col = 0; col < m_grid->cols_count(); col++)
+		{
+			table_cell* cell = m_grid->cell(col, row);
+			if (cell->el)
+			{
+				int span_col = col + cell->colspan - 1;
+				if (span_col >= m_grid->cols_count())
+				{
+					span_col = m_grid->cols_count() - 1;
+				}
+				int cell_width = m_grid->column(span_col).right - m_grid->column(col).left;
+
+				if (cell->el->m_pos.width != cell_width - cell->el->content_margins_left() - cell->el->content_margins_right())
+				{
+					cell->el->render(m_grid->column(col).left, 0, cell_width);
+					cell->el->m_pos.width = cell_width - cell->el->content_margins_left() - cell->el->content_margins_right();
+				}
+				else
+				{
+					cell->el->m_pos.x = m_grid->column(col).left + cell->el->content_margins_left();
+				}
+
+				if (cell->rowspan <= 1)
+				{
+					m_grid->row(row).height = std::max(m_grid->row(row).height, cell->el->height());
+				}
+				else
+				{
+					row_span_found = true;
+				}
+
+			}
+		}
+	}
+
+	if (row_span_found)
+	{
+		for (int col = 0; col < m_grid->cols_count(); col++)
+		{
+			for (int row = 0; row < m_grid->rows_count(); row++)
+			{
+				table_cell* cell = m_grid->cell(col, row);
+				if (cell->el)
+				{
+					int span_row = row + cell->rowspan - 1;
+					if (span_row >= m_grid->rows_count())
+					{
+						span_row = m_grid->rows_count() - 1;
+					}
+					if (span_row != row)
+					{
+						int h = 0;
+						for (int i = row; i <= span_row; i++)
+						{
+							h += m_grid->row(i).height;
+						}
+						if (h < cell->el->height())
+						{
+							m_grid->row(span_row).height += cell->el->height() - h;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	// Calculate vertical table spacing
+	int table_height_spacing = 0;
+	if (m_border_collapse == border_collapse_separate)
+	{
+		table_height_spacing = m_border_spacing_y * (m_grid->rows_count() + 1);
+	}
+	else
+	{
+		table_height_spacing = 0;
+
+		if (m_grid->rows_count())
+		{
+			table_height_spacing -= std::min(border_top(), m_grid->row(0).border_top);
+			table_height_spacing -= std::min(border_bottom(), m_grid->row(m_grid->rows_count() - 1).border_bottom);
+		}
+
+		for (int row = 1; row < m_grid->rows_count(); row++)
+		{
+			table_height_spacing -= std::min(m_grid->row(row).border_top, m_grid->row(row - 1).border_bottom);
+		}
+	}
+
+
+	// calculate block height
+	int block_height = 0;
+	if (get_predefined_height(block_height))
+	{
+		block_height -= m_padding.height() + m_borders.height();
+	}
+
+	// calculate minimum height from m_css_min_height
+	int min_height = 0;
+	if (!m_css_min_height.is_predefined() && m_css_min_height.units() == css_units_percentage)
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			int parent_height = 0;
+			if (el_parent->get_predefined_height(parent_height))
+			{
+				min_height = m_css_min_height.calc_percent(parent_height);
+			}
+		}
+	}
+	else
+	{
+		min_height = (int)m_css_min_height.val();
+	}
+
+	int extra_row_height = 0;
+	int minimum_table_height = std::max(block_height, min_height);
+
+	m_grid->calc_rows_height(minimum_table_height - table_height_spacing, m_border_spacing_y);
+	m_grid->calc_vertical_positions(m_borders, m_border_collapse, m_border_spacing_y);
+
+	int table_height = 0;
+
+	// place cells vertically
+	for (int col = 0; col < m_grid->cols_count(); col++)
+	{
+		for (int row = 0; row < m_grid->rows_count(); row++)
+		{
+			table_cell* cell = m_grid->cell(col, row);
+			if (cell->el)
+			{
+				int span_row = row + cell->rowspan - 1;
+				if (span_row >= m_grid->rows_count())
+				{
+					span_row = m_grid->rows_count() - 1;
+				}
+				cell->el->m_pos.y = m_grid->row(row).top + cell->el->content_margins_top();
+				cell->el->m_pos.height = m_grid->row(span_row).bottom - m_grid->row(row).top - cell->el->content_margins_top() - cell->el->content_margins_bottom();
+				table_height = std::max(table_height, m_grid->row(span_row).bottom);
+				cell->el->apply_vertical_align();
+			}
+		}
+	}
+
+	if (m_border_collapse == border_collapse_collapse)
+	{
+		if (m_grid->rows_count())
+		{
+			table_height -= std::min(border_bottom(), m_grid->row(m_grid->rows_count() - 1).border_bottom);
+		}
+	}
+	else
+	{
+		table_height += m_border_spacing_y;
+	}
+
+	m_pos.width = table_width;
+
+	calc_auto_margins(parent_width);
+
+	m_pos.move_to(x, y);
+	m_pos.x += content_margins_left();
+	m_pos.y += content_margins_top();
+	m_pos.width = table_width;
+	m_pos.height = table_height;
+
+	return max_table_width;
+}
+
+void litehtml::html_tag::draw_children_box(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex)
+{
+	position pos = m_pos;
+	pos.x += x;
+	pos.y += y;
+
+	document::ptr doc = get_document();
+
+	if (m_overflow > overflow_visible)
+	{
+		position border_box = pos;
+		border_box += m_padding;
+		border_box += m_borders;
+
+		border_radiuses bdr_radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
+
+		bdr_radius -= m_borders;
+		bdr_radius -= m_padding;
+
+		doc->container()->set_clip(pos, bdr_radius, true, true);
+	}
+
+	position browser_wnd;
+	doc->container()->get_client_rect(browser_wnd);
+
+	element::ptr el;
+	for (auto& item : m_children)
+	{
+		el = item;
+		if (el->is_visible())
+		{
+			switch (flag)
+			{
+			case draw_positioned:
+				if (el->is_positioned() && el->get_zindex() == zindex)
+				{
+					if (el->get_element_position() == element_position_fixed)
+					{
+						el->draw(hdc, browser_wnd.x, browser_wnd.y, clip);
+						el->draw_stacking_context(hdc, browser_wnd.x, browser_wnd.y, clip, true);
+					}
+					else
+					{
+						el->draw(hdc, pos.x, pos.y, clip);
+						el->draw_stacking_context(hdc, pos.x, pos.y, clip, true);
+					}
+					el = 0;
+				}
+				break;
+			case draw_block:
+				if (!el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
+				{
+					el->draw(hdc, pos.x, pos.y, clip);
+				}
+				break;
+			case draw_floats:
+				if (el->get_float() != float_none && !el->is_positioned())
+				{
+					el->draw(hdc, pos.x, pos.y, clip);
+					el->draw_stacking_context(hdc, pos.x, pos.y, clip, false);
+					el = 0;
+				}
+				break;
+			case draw_inlines:
+				if (el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
+				{
+					el->draw(hdc, pos.x, pos.y, clip);
+					if (el->get_display() == display_inline_block)
+					{
+						el->draw_stacking_context(hdc, pos.x, pos.y, clip, false);
+						el = 0;
+					}
+				}
+				break;
+			default:
+				break;
+			}
+
+			if (el)
+			{
+				if (flag == draw_positioned)
+				{
+					if (!el->is_positioned())
+					{
+						el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
+					}
+				}
+				else
+				{
+					if (el->get_float() == float_none &&
+						el->get_display() != display_inline_block &&
+						!el->is_positioned())
+					{
+						el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
+					}
+				}
+			}
+		}
+	}
+
+	if (m_overflow > overflow_visible)
+	{
+		doc->container()->del_clip();
+	}
+}
+
+void litehtml::html_tag::draw_children_table(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex)
+{
+	if (!m_grid) return;
+
+	position pos = m_pos;
+	pos.x += x;
+	pos.y += y;
+	for (int row = 0; row < m_grid->rows_count(); row++)
+	{
+		if (flag == draw_block)
+		{
+			m_grid->row(row).el_row->draw_background(hdc, pos.x, pos.y, clip);
+		}
+		for (int col = 0; col < m_grid->cols_count(); col++)
+		{
+			table_cell* cell = m_grid->cell(col, row);
+			if (cell->el)
+			{
+				if (flag == draw_block)
+				{
+					cell->el->draw(hdc, pos.x, pos.y, clip);
+				}
+				cell->el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
+			}
+		}
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/html_tag.h b/src/plugins/litehtml_viewer/litehtml/html_tag.h
index f03bb62..460eb07 100644
--- a/src/plugins/litehtml_viewer/litehtml/html_tag.h
+++ b/src/plugins/litehtml_viewer/litehtml/html_tag.h
@@ -1,246 +1,248 @@
-#pragma once
-
-#include "element.h"
-#include "style.h"
-#include "background.h"
-#include "css_margins.h"
-#include "borders.h"
-#include "css_selector.h"
-#include "stylesheet.h"
-#include "box.h"
-#include "table.h"
-
-namespace litehtml
-{
-	struct line_context
-	{
-		int calculatedTop;
-		int top;
-		int left;
-		int right;
-
-		int width()
-		{
-			return right - left;
-		}
-		void fix_top()
-		{
-			calculatedTop = top;
-		}
-	};
-
-	class html_tag : public element
-	{
-		friend class elements_iterator;
-		friend class el_table;
-		friend class table_grid;
-		friend class block_box;
-		friend class line_box;
-	public:
-		typedef std::shared_ptr<litehtml::html_tag>	ptr;
-	protected:
-		box::vector				m_boxes;
-		string_vector			m_class_values;
-		tstring					m_tag;
-		litehtml::style			m_style;
-		string_map				m_attrs;
-		vertical_align			m_vertical_align;
-		text_align				m_text_align;
-		style_display			m_display;
-		list_style_type			m_list_style_type;
-		list_style_position		m_list_style_position;
-		white_space				m_white_space;
-		element_float			m_float;
-		element_clear			m_clear;
-		floated_box::vector		m_floats_left;
-		floated_box::vector		m_floats_right;
-		elements_vector			m_positioned;
-		background				m_bg;
-		element_position		m_el_position;
-		int						m_line_height;
-		bool					m_lh_predefined;
-		string_vector			m_pseudo_classes;
-		used_selector::vector	m_used_styles;		
-		
-		uint_ptr				m_font;
-		int						m_font_size;
-		font_metrics			m_font_metrics;
-
-		css_margins				m_css_margins;
-		css_margins				m_css_padding;
-		css_borders				m_css_borders;
-		css_length				m_css_width;
-		css_length				m_css_height;
-		css_length				m_css_min_width;
-		css_length				m_css_min_height;
-		css_length				m_css_max_width;
-		css_length				m_css_max_height;
-		css_offsets				m_css_offsets;
-		css_length				m_css_text_indent;
-
-		overflow				m_overflow;
-		visibility				m_visibility;
-		int						m_z_index;
-		box_sizing				m_box_sizing;
-
-		int_int_cache			m_cahe_line_left;
-		int_int_cache			m_cahe_line_right;
-
-		// data for table rendering
-		std::unique_ptr<table_grid>	m_grid;
-		css_length				m_css_border_spacing_x;
-		css_length				m_css_border_spacing_y;
-		int						m_border_spacing_x;
-		int						m_border_spacing_y;
-		border_collapse			m_border_collapse;
-
-		virtual void			select_all(const css_selector& selector, elements_vector& res);
-
-	public:
-		html_tag(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~html_tag();
-
-		/* render functions */
-
-		virtual int					render(int x, int y, int max_width, bool second_pass = false) override;
-
-		virtual int					render_inline(const element::ptr &container, int max_width) override;
-		virtual int					place_element(const element::ptr &el, int max_width) override;
-		virtual bool				fetch_positioned() override;
-		virtual void				render_positioned(render_type rt = render_all) override;
-
-		int							new_box(const element::ptr &el, int max_width, line_context& line_ctx);
-
-		int							get_cleared_top(const element::ptr &el, int line_top) const;
-		int							finish_last_box(bool end_of_render = false);
-
-		virtual bool				appendChild(const element::ptr &el) override;
-		virtual bool				removeChild(const element::ptr &el) override;
-		virtual void				clearRecursive() override;
-		virtual const tchar_t*		get_tagName() const override;
-		virtual void				set_tagName(const tchar_t* tag) override;
-		virtual void				set_data(const tchar_t* data) override;
-		virtual element_float		get_float() const override;
-		virtual vertical_align		get_vertical_align() const override;
-		virtual css_length			get_css_left() const override;
-		virtual css_length			get_css_right() const override;
-		virtual css_length			get_css_top() const override;
-		virtual css_length			get_css_bottom() const override;
-		virtual css_length			get_css_width() const override;
-		virtual css_offsets			get_css_offsets() const override;
-		virtual void				set_css_width(css_length& w) override;
-		virtual css_length			get_css_height() const override;
-		virtual element_clear		get_clear() const override;
-		virtual size_t				get_children_count() const override;
-		virtual element::ptr		get_child(int idx) const override;
-		virtual element_position	get_element_position(css_offsets* offsets = 0) const override;
-		virtual overflow			get_overflow() const override;
-
-		virtual void				set_attr(const tchar_t* name, const tchar_t* val) override;
-		virtual const tchar_t*		get_attr(const tchar_t* name, const tchar_t* def = 0) override;
-		virtual void				apply_stylesheet(const litehtml::css& stylesheet) override;
-		virtual void				refresh_styles() override;
-
-		virtual bool				is_white_space() const override;
-		virtual bool				is_body() const override;
-		virtual bool				is_break() const override;
-		virtual int					get_base_line() override;
-		virtual bool				on_mouse_over() override;
-		virtual bool				on_mouse_leave() override;
-		virtual bool				on_lbutton_down() override;
-		virtual bool				on_lbutton_up() override;
-		virtual void				on_click() override;
-		virtual bool				find_styles_changes(position::vector& redraw_boxes, int x, int y) override;
-		virtual const tchar_t*		get_cursor() override;
-		virtual void				init_font() override;
-		virtual bool				set_pseudo_class(const tchar_t* pclass, bool add) override;
-		virtual bool				set_class(const tchar_t* pclass, bool add) override;
-		virtual bool				is_replaced() const override;
-		virtual int					line_height() const override;
-		virtual white_space			get_white_space() const override;
-		virtual style_display		get_display() const override;
-		virtual visibility			get_visibility() const override;
-		virtual void				parse_styles(bool is_reparse = false) override;
-		virtual void				draw(uint_ptr hdc, int x, int y, const position* clip) override;
-		virtual void				draw_background(uint_ptr hdc, int x, int y, const position* clip) override;
-
-		virtual const tchar_t*		get_style_property(const tchar_t* name, bool inherited, const tchar_t* def = 0) override;
-		virtual uint_ptr			get_font(font_metrics* fm = 0) override;
-		virtual int					get_font_size() const override;
-
-		elements_vector&			children();
-		virtual void				calc_outlines(int parent_width) override;
-		virtual void				calc_auto_margins(int parent_width) override;
-
-		virtual int					select(const css_selector& selector, bool apply_pseudo = true) override;
-		virtual int					select(const css_element_selector& selector, bool apply_pseudo = true) override;
-
-		virtual elements_vector		select_all(const tstring& selector) override;
-		virtual elements_vector		select_all(const css_selector& selector) override;
-
-		virtual element::ptr		select_one(const tstring& selector) override;
-		virtual element::ptr		select_one(const css_selector& selector) override;
-
-		virtual element::ptr		find_ancestor(const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0) override;
-		virtual element::ptr		find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0) override;
-		virtual element::ptr		find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0) override;
-		virtual void				get_text(tstring& text) override;
-		virtual void				parse_attributes() override;
-
-		virtual bool				is_first_child_inline(const element::ptr& el) const override;
-		virtual bool				is_last_child_inline(const element::ptr& el) override;
-		virtual bool				have_inline_child() const override;
-		virtual void				get_content_size(size& sz, int max_width) override;
-		virtual void				init() override;
-		virtual void				get_inline_boxes(position::vector& boxes) override;
-		virtual bool				is_floats_holder() const override;
-		virtual int					get_floats_height(element_float el_float = float_none) const override;
-		virtual int					get_left_floats_height() const override;
-		virtual int					get_right_floats_height() const override;
-		virtual int					get_line_left(int y) override;
-		virtual int					get_line_right(int y, int def_right) override;
-		virtual void				get_line_left_right(int y, int def_right, int& ln_left, int& ln_right) override;
-		virtual void				add_float(const element::ptr &el, int x, int y) override;
-		virtual void				update_floats(int dy, const element::ptr &parent) override;
-		virtual void				add_positioned(const element::ptr &el) override;
-		virtual int					find_next_line_top(int top, int width, int def_right) override;
-		virtual void				apply_vertical_align() override;
-		virtual void				draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override;
-		virtual int					get_zindex() const override;
-		virtual void				draw_stacking_context(uint_ptr hdc, int x, int y, const position* clip, bool with_positioned) override;
-		virtual void				calc_document_size(litehtml::size& sz, int x = 0, int y = 0) override;
-		virtual void				get_redraw_box(litehtml::position& pos, int x = 0, int y = 0) override;
-		virtual void				add_style(const litehtml::style& st) override;
-		virtual element::ptr		get_element_by_point(int x, int y, int client_x, int client_y) override;
-		virtual element::ptr		get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex) override;
-
-		virtual bool				is_nth_child(const element::ptr& el, int num, int off, bool of_type) const override;
-		virtual bool				is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const override;
-		virtual bool				is_only_child(const element::ptr& el, bool of_type) const override;
-		virtual const background*	get_background(bool own_only = false) override;
-
-	protected:
-		void						draw_children_box(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex);
-		void						draw_children_table(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex);
-		int							render_box(int x, int y, int max_width, bool second_pass = false);
-		int							render_table(int x, int y, int max_width, bool second_pass = false);
-		int							fix_line_width(int max_width, element_float flt);
-		void						parse_background();
-		void						init_background_paint( position pos, background_paint &bg_paint, const background* bg );
-		void						draw_list_marker( uint_ptr hdc, const position &pos );
-		void						parse_nth_child_params( tstring param, int &num, int &off );
-		void						remove_before_after();
-		litehtml::element::ptr		get_element_before();
-		litehtml::element::ptr		get_element_after();
-	};
-
-	/************************************************************************/
-	/*                        Inline Functions                              */
-	/************************************************************************/
-
-	inline elements_vector& litehtml::html_tag::children()
-	{
-		return m_children;
-	}
-}
-
+#ifndef LH_HTML_TAG_H
+#define LH_HTML_TAG_H
+
+#include "element.h"
+#include "style.h"
+#include "background.h"
+#include "css_margins.h"
+#include "borders.h"
+#include "css_selector.h"
+#include "stylesheet.h"
+#include "box.h"
+#include "table.h"
+
+namespace litehtml
+{
+	struct line_context
+	{
+		int calculatedTop;
+		int top;
+		int left;
+		int right;
+
+		int width()
+		{
+			return right - left;
+		}
+		void fix_top()
+		{
+			calculatedTop = top;
+		}
+	};
+
+	class html_tag : public element
+	{
+		friend class elements_iterator;
+		friend class el_table;
+		friend class table_grid;
+		friend class block_box;
+		friend class line_box;
+	public:
+		typedef std::shared_ptr<litehtml::html_tag>	ptr;
+	protected:
+		box::vector				m_boxes;
+		string_vector			m_class_values;
+		tstring					m_tag;
+		litehtml::style			m_style;
+		string_map				m_attrs;
+		vertical_align			m_vertical_align;
+		text_align				m_text_align;
+		style_display			m_display;
+		list_style_type			m_list_style_type;
+		list_style_position		m_list_style_position;
+		white_space				m_white_space;
+		element_float			m_float;
+		element_clear			m_clear;
+		floated_box::vector		m_floats_left;
+		floated_box::vector		m_floats_right;
+		elements_vector			m_positioned;
+		background				m_bg;
+		element_position		m_el_position;
+		int						m_line_height;
+		bool					m_lh_predefined;
+		string_vector			m_pseudo_classes;
+		used_selector::vector	m_used_styles;		
+		
+		uint_ptr				m_font;
+		int						m_font_size;
+		font_metrics			m_font_metrics;
+
+		css_margins				m_css_margins;
+		css_margins				m_css_padding;
+		css_borders				m_css_borders;
+		css_length				m_css_width;
+		css_length				m_css_height;
+		css_length				m_css_min_width;
+		css_length				m_css_min_height;
+		css_length				m_css_max_width;
+		css_length				m_css_max_height;
+		css_offsets				m_css_offsets;
+		css_length				m_css_text_indent;
+
+		overflow				m_overflow;
+		visibility				m_visibility;
+		int						m_z_index;
+		box_sizing				m_box_sizing;
+
+		int_int_cache			m_cahe_line_left;
+		int_int_cache			m_cahe_line_right;
+
+		// data for table rendering
+		std::unique_ptr<table_grid>	m_grid;
+		css_length				m_css_border_spacing_x;
+		css_length				m_css_border_spacing_y;
+		int						m_border_spacing_x;
+		int						m_border_spacing_y;
+		border_collapse			m_border_collapse;
+
+		virtual void			select_all(const css_selector& selector, elements_vector& res) override;
+
+	public:
+		html_tag(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~html_tag();
+
+		/* render functions */
+
+		virtual int					render(int x, int y, int max_width, bool second_pass = false) override;
+
+		virtual int					render_inline(const element::ptr &container, int max_width) override;
+		virtual int					place_element(const element::ptr &el, int max_width) override;
+		virtual bool				fetch_positioned() override;
+		virtual void				render_positioned(render_type rt = render_all) override;
+
+		int							new_box(const element::ptr &el, int max_width, line_context& line_ctx);
+
+		int							get_cleared_top(const element::ptr &el, int line_top) const;
+		int							finish_last_box(bool end_of_render = false);
+
+		virtual bool				appendChild(const element::ptr &el) override;
+		virtual bool				removeChild(const element::ptr &el) override;
+		virtual void				clearRecursive() override;
+		virtual const tchar_t*		get_tagName() const override;
+		virtual void				set_tagName(const tchar_t* tag) override;
+		virtual void				set_data(const tchar_t* data) override;
+		virtual element_float		get_float() const override;
+		virtual vertical_align		get_vertical_align() const override;
+		virtual css_length			get_css_left() const override;
+		virtual css_length			get_css_right() const override;
+		virtual css_length			get_css_top() const override;
+		virtual css_length			get_css_bottom() const override;
+		virtual css_length			get_css_width() const override;
+		virtual css_offsets			get_css_offsets() const override;
+		virtual void				set_css_width(css_length& w) override;
+		virtual css_length			get_css_height() const override;
+		virtual element_clear		get_clear() const override;
+		virtual size_t				get_children_count() const override;
+		virtual element::ptr		get_child(int idx) const override;
+		virtual element_position	get_element_position(css_offsets* offsets = 0) const override;
+		virtual overflow			get_overflow() const override;
+
+		virtual void				set_attr(const tchar_t* name, const tchar_t* val) override;
+		virtual const tchar_t*		get_attr(const tchar_t* name, const tchar_t* def = 0) override;
+		virtual void				apply_stylesheet(const litehtml::css& stylesheet) override;
+		virtual void				refresh_styles() override;
+
+		virtual bool				is_white_space() const override;
+		virtual bool				is_body() const override;
+		virtual bool				is_break() const override;
+		virtual int					get_base_line() override;
+		virtual bool				on_mouse_over() override;
+		virtual bool				on_mouse_leave() override;
+		virtual bool				on_lbutton_down() override;
+		virtual bool				on_lbutton_up() override;
+		virtual void				on_click() override;
+		virtual bool				find_styles_changes(position::vector& redraw_boxes, int x, int y) override;
+		virtual const tchar_t*		get_cursor() override;
+		virtual void				init_font() override;
+		virtual bool				set_pseudo_class(const tchar_t* pclass, bool add) override;
+		virtual bool				set_class(const tchar_t* pclass, bool add) override;
+		virtual bool				is_replaced() const override;
+		virtual int					line_height() const override;
+		virtual white_space			get_white_space() const override;
+		virtual style_display		get_display() const override;
+		virtual visibility			get_visibility() const override;
+		virtual void				parse_styles(bool is_reparse = false) override;
+		virtual void				draw(uint_ptr hdc, int x, int y, const position* clip) override;
+		virtual void				draw_background(uint_ptr hdc, int x, int y, const position* clip) override;
+
+		virtual const tchar_t*		get_style_property(const tchar_t* name, bool inherited, const tchar_t* def = 0) override;
+		virtual uint_ptr			get_font(font_metrics* fm = 0) override;
+		virtual int					get_font_size() const override;
+
+		elements_vector&			children();
+		virtual void				calc_outlines(int parent_width) override;
+		virtual void				calc_auto_margins(int parent_width) override;
+
+		virtual int					select(const css_selector& selector, bool apply_pseudo = true) override;
+		virtual int					select(const css_element_selector& selector, bool apply_pseudo = true) override;
+
+		virtual elements_vector		select_all(const tstring& selector) override;
+		virtual elements_vector		select_all(const css_selector& selector) override;
+
+		virtual element::ptr		select_one(const tstring& selector) override;
+		virtual element::ptr		select_one(const css_selector& selector) override;
+
+		virtual element::ptr		find_ancestor(const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0) override;
+		virtual element::ptr		find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0) override;
+		virtual element::ptr		find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0) override;
+		virtual void				get_text(tstring& text) override;
+		virtual void				parse_attributes() override;
+
+		virtual bool				is_first_child_inline(const element::ptr& el) const override;
+		virtual bool				is_last_child_inline(const element::ptr& el) override;
+		virtual bool				have_inline_child() const override;
+		virtual void				get_content_size(size& sz, int max_width) override;
+		virtual void				init() override;
+		virtual void				get_inline_boxes(position::vector& boxes) override;
+		virtual bool				is_floats_holder() const override;
+		virtual int					get_floats_height(element_float el_float = float_none) const override;
+		virtual int					get_left_floats_height() const override;
+		virtual int					get_right_floats_height() const override;
+		virtual int					get_line_left(int y) override;
+		virtual int					get_line_right(int y, int def_right) override;
+		virtual void				get_line_left_right(int y, int def_right, int& ln_left, int& ln_right) override;
+		virtual void				add_float(const element::ptr &el, int x, int y) override;
+		virtual void				update_floats(int dy, const element::ptr &parent) override;
+		virtual void				add_positioned(const element::ptr &el) override;
+		virtual int					find_next_line_top(int top, int width, int def_right) override;
+		virtual void				apply_vertical_align() override;
+		virtual void				draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override;
+		virtual int					get_zindex() const override;
+		virtual void				draw_stacking_context(uint_ptr hdc, int x, int y, const position* clip, bool with_positioned) override;
+		virtual void				calc_document_size(litehtml::size& sz, int x = 0, int y = 0) override;
+		virtual void				get_redraw_box(litehtml::position& pos, int x = 0, int y = 0) override;
+		virtual void				add_style(const litehtml::style& st) override;
+		virtual element::ptr		get_element_by_point(int x, int y, int client_x, int client_y) override;
+		virtual element::ptr		get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex) override;
+
+		virtual bool				is_nth_child(const element::ptr& el, int num, int off, bool of_type) const override;
+		virtual bool				is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const override;
+		virtual bool				is_only_child(const element::ptr& el, bool of_type) const override;
+		virtual const background*	get_background(bool own_only = false) override;
+
+	protected:
+		void						draw_children_box(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex);
+		void						draw_children_table(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex);
+		int							render_box(int x, int y, int max_width, bool second_pass = false);
+		int							render_table(int x, int y, int max_width, bool second_pass = false);
+		int							fix_line_width(int max_width, element_float flt);
+		void						parse_background();
+		void						init_background_paint( position pos, background_paint &bg_paint, const background* bg );
+		void						draw_list_marker( uint_ptr hdc, const position &pos );
+		void						parse_nth_child_params( tstring param, int &num, int &off );
+		void						remove_before_after();
+		litehtml::element::ptr		get_element_before();
+		litehtml::element::ptr		get_element_after();
+	};
+
+	/************************************************************************/
+	/*                        Inline Functions                              */
+	/************************************************************************/
+
+	inline elements_vector& litehtml::html_tag::children()
+	{
+		return m_children;
+	}
+}
+
+#endif  // LH_HTML_TAG_H
diff --git a/src/plugins/litehtml_viewer/litehtml/iterators.cpp b/src/plugins/litehtml_viewer/litehtml/iterators.cpp
index 3459f5c..9d6a623 100644
--- a/src/plugins/litehtml_viewer/litehtml/iterators.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/iterators.cpp
@@ -1,94 +1,94 @@
-#include "html.h"
-#include "iterators.h"
-#include "html_tag.h"
-
-litehtml::element::ptr litehtml::elements_iterator::next(bool ret_parent)
-{
-	next_idx();
-
-	while(m_idx < (int) m_el->get_children_count())
-	{
-		element::ptr el = m_el->get_child(m_idx);
-		if(	el->get_children_count() && m_go_inside && m_go_inside->select(el) )
-		{
-			stack_item si;
-			si.idx		= m_idx;
-			si.el		= m_el;
-			m_stack.push_back(si);
-			m_el		= el;
-			m_idx		= -1;
-			if(ret_parent)
-			{
-				return el;
-			}
-			next_idx();
-		} else
-		{
-			if( !m_select || (m_select && m_select->select(m_el->get_child(m_idx))) )
-			{
-				return m_el->get_child(m_idx);
-			} else
-			{
-				next_idx();
-			}
-		}
-	}
-
-	return 0;
-}
-
-void litehtml::elements_iterator::next_idx()
-{
-	m_idx++;
-	while(m_idx >= (int) m_el->get_children_count() && m_stack.size())
-	{
-		stack_item si = m_stack.back();
-		m_stack.pop_back();
-		m_idx	= si.idx;
-		m_el	= si.el;
-		m_idx++;
-		continue;
-	}
-}
-
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-
-
-bool litehtml::go_inside_inline::select(const element::ptr& el)
-{
-	if(el->get_display() == display_inline || el->get_display() == display_inline_text)
-	{
-		return true;
-	}
-	return false;
-}
-
-bool litehtml::go_inside_table::select(const element::ptr& el)
-{
-	if(	el->get_display() == display_table_row_group ||
-		el->get_display() == display_table_header_group ||
-		el->get_display() == display_table_footer_group)
-	{
-		return true;
-	}
-	return false;
-}
-
-bool litehtml::table_rows_selector::select(const element::ptr& el)
-{
-	if(	el->get_display() == display_table_row)
-	{
-		return true;
-	}
-	return false;
-}
-
-bool litehtml::table_cells_selector::select(const element::ptr& el)
-{
-	if(	el->get_display() == display_table_cell)
-	{
-		return true;
-	}
-	return false;
-}
+#include "html.h"
+#include "iterators.h"
+#include "html_tag.h"
+
+litehtml::element::ptr litehtml::elements_iterator::next(bool ret_parent)
+{
+	next_idx();
+
+	while(m_idx < (int) m_el->get_children_count())
+	{
+		element::ptr el = m_el->get_child(m_idx);
+		if(	el->get_children_count() && m_go_inside && m_go_inside->select(el) )
+		{
+			stack_item si;
+			si.idx		= m_idx;
+			si.el		= m_el;
+			m_stack.push_back(si);
+			m_el		= el;
+			m_idx		= -1;
+			if(ret_parent)
+			{
+				return el;
+			}
+			next_idx();
+		} else
+		{
+			if( !m_select || (m_select && m_select->select(m_el->get_child(m_idx))) )
+			{
+				return m_el->get_child(m_idx);
+			} else
+			{
+				next_idx();
+			}
+		}
+	}
+
+	return 0;
+}
+
+void litehtml::elements_iterator::next_idx()
+{
+	m_idx++;
+	while(m_idx >= (int) m_el->get_children_count() && m_stack.size())
+	{
+		stack_item si = m_stack.back();
+		m_stack.pop_back();
+		m_idx	= si.idx;
+		m_el	= si.el;
+		m_idx++;
+		continue;
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+
+bool litehtml::go_inside_inline::select(const element::ptr& el)
+{
+	if(el->get_display() == display_inline || el->get_display() == display_inline_text)
+	{
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::go_inside_table::select(const element::ptr& el)
+{
+	if(	el->get_display() == display_table_row_group ||
+		el->get_display() == display_table_header_group ||
+		el->get_display() == display_table_footer_group)
+	{
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::table_rows_selector::select(const element::ptr& el)
+{
+	if(	el->get_display() == display_table_row)
+	{
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::table_cells_selector::select(const element::ptr& el)
+{
+	if(	el->get_display() == display_table_cell)
+	{
+		return true;
+	}
+	return false;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/iterators.h b/src/plugins/litehtml_viewer/litehtml/iterators.h
index df60dc5..53f23c3 100644
--- a/src/plugins/litehtml_viewer/litehtml/iterators.h
+++ b/src/plugins/litehtml_viewer/litehtml/iterators.h
@@ -1,87 +1,90 @@
-#pragma once
-
-#include "types.h"
-
-namespace litehtml
-{
-	class element;
-
-	class iterator_selector
-	{
-	public:
-		virtual bool select(const element::ptr& el) = 0;
-	};
-
-	class elements_iterator
-	{
-	private:
-		struct stack_item
-		{
-			int				idx;
-			element::ptr	el;
-			stack_item()
-			{
-
-			}
-			stack_item(const stack_item& val)
-			{
-				idx = val.idx;
-				el = val.el;
-			}
-			stack_item(stack_item&& val)
-			{
-				idx = val.idx;
-				el = std::move(val.el);
-			}
-		};
-
-		std::vector<stack_item>		m_stack;
-		element::ptr				m_el;
-		int							m_idx;
-		iterator_selector*			m_go_inside;
-		iterator_selector*			m_select;
-	public:
-
-		elements_iterator(const element::ptr& el, iterator_selector* go_inside, iterator_selector* select)
-		{ 
-			m_el			= el;
-			m_idx			= -1; 
-			m_go_inside		= go_inside;
-			m_select		= select;
-		}
-
-		~elements_iterator()
-		{
-
-		}
-
-		element::ptr next(bool ret_parent = true);
-	
-	private:
-		void next_idx();
-	};
-
-	class go_inside_inline : public iterator_selector
-	{
-	public:
-		virtual bool select(const element::ptr& el);
-	};
-
-	class go_inside_table : public iterator_selector
-	{
-	public:
-		virtual bool select(const element::ptr& el);
-	};
-
-	class table_rows_selector : public iterator_selector
-	{
-	public:
-		virtual bool select(const element::ptr& el);
-	};
-
-	class table_cells_selector : public iterator_selector
-	{
-	public:
-		virtual bool select(const element::ptr& el);
-	};
-}
+#ifndef LH_ITERATORS_H
+#define LH_ITERATORS_H
+
+#include "types.h"
+
+namespace litehtml
+{
+	class element;
+
+	class iterator_selector
+	{
+	public:
+		virtual bool select(const element::ptr& el) = 0;
+	};
+
+	class elements_iterator
+	{
+	private:
+		struct stack_item
+		{
+			int				idx;
+			element::ptr	el;
+			stack_item()
+			{
+
+			}
+			stack_item(const stack_item& val)
+			{
+				idx = val.idx;
+				el = val.el;
+			}
+			stack_item(stack_item&& val)
+			{
+				idx = val.idx;
+				el = std::move(val.el);
+			}
+		};
+
+		std::vector<stack_item>		m_stack;
+		element::ptr				m_el;
+		int							m_idx;
+		iterator_selector*			m_go_inside;
+		iterator_selector*			m_select;
+	public:
+
+		elements_iterator(const element::ptr& el, iterator_selector* go_inside, iterator_selector* select)
+		{ 
+			m_el			= el;
+			m_idx			= -1; 
+			m_go_inside		= go_inside;
+			m_select		= select;
+		}
+
+		~elements_iterator()
+		{
+
+		}
+
+		element::ptr next(bool ret_parent = true);
+	
+	private:
+		void next_idx();
+	};
+
+	class go_inside_inline : public iterator_selector
+	{
+	public:
+		virtual bool select(const element::ptr& el);
+	};
+
+	class go_inside_table : public iterator_selector
+	{
+	public:
+		virtual bool select(const element::ptr& el);
+	};
+
+	class table_rows_selector : public iterator_selector
+	{
+	public:
+		virtual bool select(const element::ptr& el);
+	};
+
+	class table_cells_selector : public iterator_selector
+	{
+	public:
+		virtual bool select(const element::ptr& el);
+	};
+}
+
+#endif  // LH_ITERATORS_H
diff --git a/src/plugins/litehtml_viewer/litehtml/litehtml.h b/src/plugins/litehtml_viewer/litehtml/litehtml.h
index 02e5b8d..75db830 100644
--- a/src/plugins/litehtml_viewer/litehtml/litehtml.h
+++ b/src/plugins/litehtml_viewer/litehtml/litehtml.h
@@ -1,10 +1,12 @@
-#pragma once
+#ifndef LITEHTML_H
+#define LITEHTML_H
 
-#include "litehtml/os_types.h"
-#include "litehtml/types.h"
 #include "litehtml/html.h"
-#include "litehtml/element.h"
 #include "litehtml/document.h"
-#include "litehtml/context.h"
+#include "litehtml/html_tag.h"
+#include "litehtml/stylesheet.h"
+#include "litehtml/stylesheet.h"
 #include "litehtml/element.h"
+#include "litehtml/html_tag.h"
 
+#endif  // LITEHTML_H
diff --git a/src/plugins/litehtml_viewer/litehtml/media_query.cpp b/src/plugins/litehtml_viewer/litehtml/media_query.cpp
index 6cc66da..41ff39e 100644
--- a/src/plugins/litehtml_viewer/litehtml/media_query.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/media_query.cpp
@@ -1,432 +1,432 @@
-#include "html.h"
-#include "media_query.h"
-#include "document.h"
-
-
-litehtml::media_query::media_query()
-{
-	m_media_type	= media_type_all;
-	m_not			= false;
-}
-
-litehtml::media_query::media_query( const media_query& val )
-{
-	m_not			= val.m_not;
-	m_expressions	= val.m_expressions;
-	m_media_type	= val.m_media_type;
-}
-
-litehtml::media_query::ptr litehtml::media_query::create_from_string(const tstring& str, const std::shared_ptr<document>& doc)
-{
-	media_query::ptr query = std::make_shared<media_query>();
-
-	string_vector tokens;
-	split_string(str, tokens, _t(" \t\r\n"), _t(""), _t("("));
-
-	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
-	{
-		if((*tok) == _t("not"))
-		{
-			query->m_not = true;
-		} else if(tok->at(0) == _t('('))
-		{
-			tok->erase(0, 1);
-			if(tok->at(tok->length() - 1) == _t(')'))
-			{
-				tok->erase(tok->length() - 1, 1);
-			}
-			media_query_expression expr;
-			string_vector expr_tokens;
-			split_string((*tok), expr_tokens, _t(":"));
-			if(!expr_tokens.empty())
-			{
-				trim(expr_tokens[0]);
-				expr.feature = (media_feature) value_index(expr_tokens[0], media_feature_strings, media_feature_none);
-				if(expr.feature != media_feature_none)
-				{
-					if(expr_tokens.size() == 1)
-					{
-						expr.check_as_bool = true;
-					} else
-					{
-						trim(expr_tokens[1]);
-						expr.check_as_bool = false;
-						if(expr.feature == media_feature_orientation)
-						{
-							expr.val = value_index(expr_tokens[1], media_orientation_strings, media_orientation_landscape);
-						} else
-						{
-							tstring::size_type slash_pos = expr_tokens[1].find(_t('/'));
-							if( slash_pos != tstring::npos )
-							{
-								tstring val1 = expr_tokens[1].substr(0, slash_pos);
-								tstring val2 = expr_tokens[1].substr(slash_pos + 1);
-								trim(val1);
-								trim(val2);
-								expr.val = t_atoi(val1.c_str());
-								expr.val2 = t_atoi(val2.c_str());
-							} else
-							{
-								css_length length;
-								length.fromString(expr_tokens[1]);
-								if(length.units() == css_units_dpcm)
-								{
-									expr.val = (int) (length.val() * 2.54);
-								} else if(length.units() == css_units_dpi)
-								{
-									expr.val = (int) (length.val() * 2.54);
-								} else
-								{
-									if(doc)
-									{
-										doc->cvt_units(length, doc->container()->get_default_font_size());
-									}
-									expr.val = (int) length.val();
-								}
-							}
-						}
-					}
-					query->m_expressions.push_back(expr);
-				}
-			}
-		} else
-		{
-			query->m_media_type = (media_type) value_index((*tok), media_type_strings, media_type_all);
-
-		}
-	}
-
-	return query;
-}
-
-bool litehtml::media_query::check( const media_features& features ) const
-{
-	bool res = false;
-	if(m_media_type == media_type_all || m_media_type == features.type)
-	{
-		res = true;
-		for(media_query_expression::vector::const_iterator expr = m_expressions.begin(); expr != m_expressions.end() && res; expr++)
-		{
-			if(!expr->check(features))
-			{
-				res = false;
-			}
-		}
-	}
-
-	if(m_not)
-	{
-		res = !res;
-	}
-
-	return res;
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-litehtml::media_query_list::ptr litehtml::media_query_list::create_from_string(const tstring& str, const std::shared_ptr<document>& doc)
-{
-	media_query_list::ptr list = std::make_shared<media_query_list>();
-
-	string_vector tokens;
-	split_string(str, tokens, _t(","));
-
-	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
-	{
-		trim(*tok);
-		lcase(*tok);
-
-		litehtml::media_query::ptr query = media_query::create_from_string(*tok, doc);
-		if(query)
-		{
-			list->m_queries.push_back(query);
-		}
-	}
-	if(list->m_queries.empty())
-	{
-		list = 0;
-	}
-
-	return list;
-}
-
-bool litehtml::media_query_list::apply_media_features( const media_features& features )
-{
-	bool apply = false;
-	
-	for(media_query::vector::iterator iter = m_queries.begin(); iter != m_queries.end() && !apply; iter++)
-	{
-		if((*iter)->check(features))
-		{
-			apply = true;
-		}
-	}
-
-	bool ret = (apply != m_is_used);
-	m_is_used = apply;
-	return ret;
-}
-
-bool litehtml::media_query_expression::check( const media_features& features ) const
-{
-	switch(feature)
-	{
-	case media_feature_width:
-		if(check_as_bool)
-		{
-			return (features.width != 0);
-		} else if(features.width == val)
-		{
-			return true;
-		}
-		break;
-	case media_feature_min_width:
-		if(features.width >= val)
-		{
-			return true;
-		}
-		break;
-	case media_feature_max_width:
-		if(features.width <= val)
-		{
-			return true;
-		}
-		break;
-	case media_feature_height:
-		if(check_as_bool)
-		{
-			return (features.height != 0);
-		} else if(features.height == val)
-		{
-			return true;
-		}
-		break;
-	case media_feature_min_height:
-		if(features.height >= val)
-		{
-			return true;
-		}
-		break;
-	case media_feature_max_height:
-		if(features.height <= val)
-		{
-			return true;
-		}
-		break;
-
-	case media_feature_device_width:
-		if(check_as_bool)
-		{
-			return (features.device_width != 0);
-		} else if(features.device_width == val)
-		{
-			return true;
-		}
-		break;
-	case media_feature_min_device_width:
-		if(features.device_width >= val)
-		{
-			return true;
-		}
-		break;
-	case media_feature_max_device_width:
-		if(features.device_width <= val)
-		{
-			return true;
-		}
-		break;
-	case media_feature_device_height:
-		if(check_as_bool)
-		{
-			return (features.device_height != 0);
-		} else if(features.device_height == val)
-		{
-			return true;
-		}
-		break;
-	case media_feature_min_device_height:
-		if(features.device_height <= val)
-		{
-			return true;
-		}
-		break;
-	case media_feature_max_device_height:
-		if(features.device_height <= val)
-		{
-			return true;
-		}
-		break;
-
-	case media_feature_orientation:
-		if(features.height >= features.width)
-		{
-			if(val == media_orientation_portrait)
-			{
-				return true;
-			}
-		} else
-		{
-			if(val == media_orientation_landscape)
-			{
-				return true;
-			}
-		}
-		break;
-	case media_feature_aspect_ratio:
-		if(features.height && val2)
-		{
-			int ratio_this = round_d( (double) val / (double) val2 * 100 );
-			int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 );
-			if(ratio_this == ratio_feat)
-			{
-				return true;
-			}
-		}
-		break;
-	case media_feature_min_aspect_ratio:
-		if(features.height && val2)
-		{
-			int ratio_this = round_d( (double) val / (double) val2 * 100 );
-			int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 );
-			if(ratio_feat >= ratio_this)
-			{
-				return true;
-			}
-		}
-		break;
-	case media_feature_max_aspect_ratio:
-		if(features.height && val2)
-		{
-			int ratio_this = round_d( (double) val / (double) val2 * 100 );
-			int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 );
-			if(ratio_feat <= ratio_this)
-			{
-				return true;
-			}
-		}
-		break;
-
-	case media_feature_device_aspect_ratio:
-		if(features.device_height && val2)
-		{
-			int ratio_this = round_d( (double) val / (double) val2 * 100 );
-			int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 );
-			if(ratio_feat == ratio_this)
-			{
-				return true;
-			}
-		}
-		break;
-	case media_feature_min_device_aspect_ratio:
-		if(features.device_height && val2)
-		{
-			int ratio_this = round_d( (double) val / (double) val2 * 100 );
-			int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 );
-			if(ratio_feat >= ratio_this)
-			{
-				return true;
-			}
-		}
-		break;
-	case media_feature_max_device_aspect_ratio:
-		if(features.device_height && val2)
-		{
-			int ratio_this = round_d( (double) val / (double) val2 * 100 );
-			int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 );
-			if(ratio_feat <= ratio_this)
-			{
-				return true;
-			}
-		}
-		break;
-
-	case media_feature_color:
-		if(check_as_bool)
-		{
-			return (features.color != 0);
-		} else if(features.color == val)
-		{
-			return true;
-		}
-		break;
-	case media_feature_min_color:
-		if(features.color >= val)
-		{
-			return true;
-		}
-		break;
-	case media_feature_max_color:
-		if(features.color <= val)
-		{
-			return true;
-		}
-		break;
-
-	case media_feature_color_index:
-		if(check_as_bool)
-		{
-			return (features.color_index != 0);
-		} else if(features.color_index == val)
-		{
-			return true;
-		}
-		break;
-	case media_feature_min_color_index:
-		if(features.color_index >= val)
-		{
-			return true;
-		}
-		break;
-	case media_feature_max_color_index:
-		if(features.color_index <= val)
-		{
-			return true;
-		}
-		break;
-
-	case media_feature_monochrome:
-		if(check_as_bool)
-		{
-			return (features.monochrome != 0);
-		} else if(features.monochrome == val)
-		{
-			return true;
-		}
-		break;
-	case media_feature_min_monochrome:
-		if(features.monochrome >= val)
-		{
-			return true;
-		}
-		break;
-	case media_feature_max_monochrome:
-		if(features.monochrome <= val)
-		{
-			return true;
-		}
-		break;
-
-	case media_feature_resolution:
-		if(features.resolution == val)
-		{
-			return true;
-		}
-		break;
-	case media_feature_min_resolution:
-		if(features.resolution >= val)
-		{
-			return true;
-		}
-		break;
-	case media_feature_max_resolution:
-		if(features.resolution <= val)
-		{
-			return true;
-		}
-		break;
-	default:
-		return false;
-	}
-
-	return false;
-}
+#include "html.h"
+#include "media_query.h"
+#include "document.h"
+
+
+litehtml::media_query::media_query()
+{
+	m_media_type	= media_type_all;
+	m_not			= false;
+}
+
+litehtml::media_query::media_query( const media_query& val )
+{
+	m_not			= val.m_not;
+	m_expressions	= val.m_expressions;
+	m_media_type	= val.m_media_type;
+}
+
+litehtml::media_query::ptr litehtml::media_query::create_from_string(const tstring& str, const std::shared_ptr<document>& doc)
+{
+	media_query::ptr query = std::make_shared<media_query>();
+
+	string_vector tokens;
+	split_string(str, tokens, _t(" \t\r\n"), _t(""), _t("("));
+
+	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+	{
+		if((*tok) == _t("not"))
+		{
+			query->m_not = true;
+		} else if(tok->at(0) == _t('('))
+		{
+			tok->erase(0, 1);
+			if(tok->at(tok->length() - 1) == _t(')'))
+			{
+				tok->erase(tok->length() - 1, 1);
+			}
+			media_query_expression expr;
+			string_vector expr_tokens;
+			split_string((*tok), expr_tokens, _t(":"));
+			if(!expr_tokens.empty())
+			{
+				trim(expr_tokens[0]);
+				expr.feature = (media_feature) value_index(expr_tokens[0], media_feature_strings, media_feature_none);
+				if(expr.feature != media_feature_none)
+				{
+					if(expr_tokens.size() == 1)
+					{
+						expr.check_as_bool = true;
+					} else
+					{
+						trim(expr_tokens[1]);
+						expr.check_as_bool = false;
+						if(expr.feature == media_feature_orientation)
+						{
+							expr.val = value_index(expr_tokens[1], media_orientation_strings, media_orientation_landscape);
+						} else
+						{
+							tstring::size_type slash_pos = expr_tokens[1].find(_t('/'));
+							if( slash_pos != tstring::npos )
+							{
+								tstring val1 = expr_tokens[1].substr(0, slash_pos);
+								tstring val2 = expr_tokens[1].substr(slash_pos + 1);
+								trim(val1);
+								trim(val2);
+								expr.val = t_atoi(val1.c_str());
+								expr.val2 = t_atoi(val2.c_str());
+							} else
+							{
+								css_length length;
+								length.fromString(expr_tokens[1]);
+								if(length.units() == css_units_dpcm)
+								{
+									expr.val = (int) (length.val() * 2.54);
+								} else if(length.units() == css_units_dpi)
+								{
+									expr.val = (int) (length.val() * 2.54);
+								} else
+								{
+									if(doc)
+									{
+										doc->cvt_units(length, doc->container()->get_default_font_size());
+									}
+									expr.val = (int) length.val();
+								}
+							}
+						}
+					}
+					query->m_expressions.push_back(expr);
+				}
+			}
+		} else
+		{
+			query->m_media_type = (media_type) value_index((*tok), media_type_strings, media_type_all);
+
+		}
+	}
+
+	return query;
+}
+
+bool litehtml::media_query::check( const media_features& features ) const
+{
+	bool res = false;
+	if(m_media_type == media_type_all || m_media_type == features.type)
+	{
+		res = true;
+		for(media_query_expression::vector::const_iterator expr = m_expressions.begin(); expr != m_expressions.end() && res; expr++)
+		{
+			if(!expr->check(features))
+			{
+				res = false;
+			}
+		}
+	}
+
+	if(m_not)
+	{
+		res = !res;
+	}
+
+	return res;
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+litehtml::media_query_list::ptr litehtml::media_query_list::create_from_string(const tstring& str, const std::shared_ptr<document>& doc)
+{
+	media_query_list::ptr list = std::make_shared<media_query_list>();
+
+	string_vector tokens;
+	split_string(str, tokens, _t(","));
+
+	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+	{
+		trim(*tok);
+		lcase(*tok);
+
+		litehtml::media_query::ptr query = media_query::create_from_string(*tok, doc);
+		if(query)
+		{
+			list->m_queries.push_back(query);
+		}
+	}
+	if(list->m_queries.empty())
+	{
+		list = 0;
+	}
+
+	return list;
+}
+
+bool litehtml::media_query_list::apply_media_features( const media_features& features )
+{
+	bool apply = false;
+	
+	for(media_query::vector::iterator iter = m_queries.begin(); iter != m_queries.end() && !apply; iter++)
+	{
+		if((*iter)->check(features))
+		{
+			apply = true;
+		}
+	}
+
+	bool ret = (apply != m_is_used);
+	m_is_used = apply;
+	return ret;
+}
+
+bool litehtml::media_query_expression::check( const media_features& features ) const
+{
+	switch(feature)
+	{
+	case media_feature_width:
+		if(check_as_bool)
+		{
+			return (features.width != 0);
+		} else if(features.width == val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_min_width:
+		if(features.width >= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_max_width:
+		if(features.width <= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_height:
+		if(check_as_bool)
+		{
+			return (features.height != 0);
+		} else if(features.height == val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_min_height:
+		if(features.height >= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_max_height:
+		if(features.height <= val)
+		{
+			return true;
+		}
+		break;
+
+	case media_feature_device_width:
+		if(check_as_bool)
+		{
+			return (features.device_width != 0);
+		} else if(features.device_width == val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_min_device_width:
+		if(features.device_width >= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_max_device_width:
+		if(features.device_width <= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_device_height:
+		if(check_as_bool)
+		{
+			return (features.device_height != 0);
+		} else if(features.device_height == val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_min_device_height:
+		if(features.device_height <= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_max_device_height:
+		if(features.device_height <= val)
+		{
+			return true;
+		}
+		break;
+
+	case media_feature_orientation:
+		if(features.height >= features.width)
+		{
+			if(val == media_orientation_portrait)
+			{
+				return true;
+			}
+		} else
+		{
+			if(val == media_orientation_landscape)
+			{
+				return true;
+			}
+		}
+		break;
+	case media_feature_aspect_ratio:
+		if(features.height && val2)
+		{
+			int ratio_this = round_d( (double) val / (double) val2 * 100 );
+			int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 );
+			if(ratio_this == ratio_feat)
+			{
+				return true;
+			}
+		}
+		break;
+	case media_feature_min_aspect_ratio:
+		if(features.height && val2)
+		{
+			int ratio_this = round_d( (double) val / (double) val2 * 100 );
+			int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 );
+			if(ratio_feat >= ratio_this)
+			{
+				return true;
+			}
+		}
+		break;
+	case media_feature_max_aspect_ratio:
+		if(features.height && val2)
+		{
+			int ratio_this = round_d( (double) val / (double) val2 * 100 );
+			int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 );
+			if(ratio_feat <= ratio_this)
+			{
+				return true;
+			}
+		}
+		break;
+
+	case media_feature_device_aspect_ratio:
+		if(features.device_height && val2)
+		{
+			int ratio_this = round_d( (double) val / (double) val2 * 100 );
+			int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 );
+			if(ratio_feat == ratio_this)
+			{
+				return true;
+			}
+		}
+		break;
+	case media_feature_min_device_aspect_ratio:
+		if(features.device_height && val2)
+		{
+			int ratio_this = round_d( (double) val / (double) val2 * 100 );
+			int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 );
+			if(ratio_feat >= ratio_this)
+			{
+				return true;
+			}
+		}
+		break;
+	case media_feature_max_device_aspect_ratio:
+		if(features.device_height && val2)
+		{
+			int ratio_this = round_d( (double) val / (double) val2 * 100 );
+			int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 );
+			if(ratio_feat <= ratio_this)
+			{
+				return true;
+			}
+		}
+		break;
+
+	case media_feature_color:
+		if(check_as_bool)
+		{
+			return (features.color != 0);
+		} else if(features.color == val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_min_color:
+		if(features.color >= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_max_color:
+		if(features.color <= val)
+		{
+			return true;
+		}
+		break;
+
+	case media_feature_color_index:
+		if(check_as_bool)
+		{
+			return (features.color_index != 0);
+		} else if(features.color_index == val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_min_color_index:
+		if(features.color_index >= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_max_color_index:
+		if(features.color_index <= val)
+		{
+			return true;
+		}
+		break;
+
+	case media_feature_monochrome:
+		if(check_as_bool)
+		{
+			return (features.monochrome != 0);
+		} else if(features.monochrome == val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_min_monochrome:
+		if(features.monochrome >= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_max_monochrome:
+		if(features.monochrome <= val)
+		{
+			return true;
+		}
+		break;
+
+	case media_feature_resolution:
+		if(features.resolution == val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_min_resolution:
+		if(features.resolution >= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_max_resolution:
+		if(features.resolution <= val)
+		{
+			return true;
+		}
+		break;
+	default:
+		return false;
+	}
+
+	return false;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/media_query.h b/src/plugins/litehtml_viewer/litehtml/media_query.h
index 52c7f3f..6a81bcb 100644
--- a/src/plugins/litehtml_viewer/litehtml/media_query.h
+++ b/src/plugins/litehtml_viewer/litehtml/media_query.h
@@ -1,74 +1,77 @@
-#pragma once
-
-namespace litehtml
-{
-	struct media_query_expression
-	{
-		typedef std::vector<media_query_expression>	vector;
-		media_feature	feature;
-		int				val;
-		int				val2;
-		bool			check_as_bool;
-		
-		media_query_expression()
-		{
-			check_as_bool	= false;
-			feature			= media_feature_none;
-			val				= 0;
-			val2			= 0;
-		}
-
-		bool check(const media_features& features) const;
-	};
-
-	class media_query
-	{
-	public:
-		typedef std::shared_ptr<media_query>	ptr;
-		typedef std::vector<media_query::ptr>	vector;
-	private:
-		media_query_expression::vector	m_expressions;
-		bool							m_not;
-		media_type						m_media_type;
-	public:
-		media_query();
-		media_query(const media_query& val);
-
-		static media_query::ptr create_from_string(const tstring& str, const std::shared_ptr<document>& doc);
-		bool check(const media_features& features) const;
-	};
-
-	class media_query_list
-	{
-	public:
-		typedef std::shared_ptr<media_query_list>	ptr;
-		typedef std::vector<media_query_list::ptr>	vector;
-	private:
-		media_query::vector	m_queries;
-		bool				m_is_used;
-	public:
-		media_query_list();
-		media_query_list(const media_query_list& val);
-
-		static media_query_list::ptr create_from_string(const tstring& str, const std::shared_ptr<document>& doc);
-		bool is_used() const;
-		bool apply_media_features(const media_features& features);	// returns true if the m_is_used changed
-	};
-
-	inline media_query_list::media_query_list(const media_query_list& val)
-	{
-		m_is_used	= val.m_is_used;
-		m_queries	= val.m_queries;
-	}
-
-	inline media_query_list::media_query_list()
-	{
-		m_is_used = false;
-	}
-
-	inline bool media_query_list::is_used() const
-	{
-		return m_is_used;
-	}
-
-}
\ No newline at end of file
+#ifndef LH_MEDIA_QUERY_H
+#define LH_MEDIA_QUERY_H
+
+namespace litehtml
+{
+	struct media_query_expression
+	{
+		typedef std::vector<media_query_expression>	vector;
+		media_feature	feature;
+		int				val;
+		int				val2;
+		bool			check_as_bool;
+		
+		media_query_expression()
+		{
+			check_as_bool	= false;
+			feature			= media_feature_none;
+			val				= 0;
+			val2			= 0;
+		}
+
+		bool check(const media_features& features) const;
+	};
+
+	class media_query
+	{
+	public:
+		typedef std::shared_ptr<media_query>	ptr;
+		typedef std::vector<media_query::ptr>	vector;
+	private:
+		media_query_expression::vector	m_expressions;
+		bool							m_not;
+		media_type						m_media_type;
+	public:
+		media_query();
+		media_query(const media_query& val);
+
+		static media_query::ptr create_from_string(const tstring& str, const std::shared_ptr<document>& doc);
+		bool check(const media_features& features) const;
+	};
+
+	class media_query_list
+	{
+	public:
+		typedef std::shared_ptr<media_query_list>	ptr;
+		typedef std::vector<media_query_list::ptr>	vector;
+	private:
+		media_query::vector	m_queries;
+		bool				m_is_used;
+	public:
+		media_query_list();
+		media_query_list(const media_query_list& val);
+
+		static media_query_list::ptr create_from_string(const tstring& str, const std::shared_ptr<document>& doc);
+		bool is_used() const;
+		bool apply_media_features(const media_features& features);	// returns true if the m_is_used changed
+	};
+
+	inline media_query_list::media_query_list(const media_query_list& val)
+	{
+		m_is_used	= val.m_is_used;
+		m_queries	= val.m_queries;
+	}
+
+	inline media_query_list::media_query_list()
+	{
+		m_is_used = false;
+	}
+
+	inline bool media_query_list::is_used() const
+	{
+		return m_is_used;
+	}
+
+}
+
+#endif  // LH_MEDIA_QUERY_H
diff --git a/src/plugins/litehtml_viewer/litehtml/os_types.h b/src/plugins/litehtml_viewer/litehtml/os_types.h
index 4fb638f..39b0270 100644
--- a/src/plugins/litehtml_viewer/litehtml/os_types.h
+++ b/src/plugins/litehtml_viewer/litehtml/os_types.h
@@ -1,83 +1,86 @@
-#pragma once
-
-namespace litehtml
-{
-#if defined( WIN32 ) || defined( WINCE )
-
-#ifndef LITEHTML_UTF8
-
-	typedef std::wstring		tstring;
-	typedef wchar_t				tchar_t;
-	typedef std::wstringstream	tstringstream;
-
-	#define _t(quote)			L##quote
-
-	#define t_strlen			wcslen
-	#define t_strcmp			wcscmp
-	#define t_strncmp			wcsncmp
-	#define t_strcasecmp		_wcsicmp
-	#define t_strncasecmp		_wcsnicmp
-	#define t_strtol			wcstol
-	#define t_atoi				_wtoi
-	#define t_strtod			wcstod
-	#define t_itoa(value, buffer, size, radix)	_itow_s(value, buffer, size, radix)
-	#define t_strstr			wcsstr
-	#define t_tolower			towlower
-	#define t_isdigit			iswdigit
-
-#else
-
-	typedef std::string			tstring;
-	typedef char				tchar_t;
-	typedef std::stringstream	tstringstream;
-
-	#define _t(quote)			quote
-
-	#define t_strlen			strlen
-	#define t_strcmp			strcmp
-	#define t_strncmp			strncmp
-	#define t_strcasecmp		_stricmp
-	#define t_strncasecmp		_strnicmp
-	#define t_strtol			strtol
-	#define t_atoi				atoi
-	#define t_strtod			strtod
-	#define t_itoa(value, buffer, size, radix)	_itoa_s(value, buffer, size, radix)
-	#define t_strstr			strstr
-	#define t_tolower			tolower
-	#define t_isdigit			isdigit
-
-#endif
-
-	#ifdef _WIN64
-		typedef unsigned __int64 uint_ptr;
-	#else
-		typedef unsigned int	uint_ptr;
-	#endif
-
-#else
-	#define LITEHTML_UTF8
-
-	typedef std::string			tstring;
-	typedef char				tchar_t;
-	typedef void*				uint_ptr;
-	typedef std::stringstream	tstringstream;
-
-	#define _t(quote)			quote
-
-	#define t_strlen			strlen
-	#define t_strcmp			strcmp
-	#define t_strncmp			strncmp
-
-	#define t_strcasecmp		strcasecmp
-	#define t_strncasecmp		strncasecmp
-	#define t_itoa(value, buffer, size, radix)	snprintf(buffer, size, "%d", value)
-
-	#define t_strtol			strtol
-	#define t_atoi				atoi
-	#define t_strtod			strtod
-	#define t_strstr			strstr
-	#define t_tolower			tolower
-	#define t_isdigit			isdigit
-
-#endif
-}
+#ifndef LH_OS_TYPES_H
+#define LH_OS_TYPES_H
+
+namespace litehtml
+{
+#if defined( WIN32 ) || defined( WINCE )
+
+#ifndef LITEHTML_UTF8
+
+	typedef std::wstring		tstring;
+	typedef wchar_t				tchar_t;
+	typedef std::wstringstream	tstringstream;
+
+	#define _t(quote)			L##quote
+
+	#define t_strlen			wcslen
+	#define t_strcmp			wcscmp
+	#define t_strncmp			wcsncmp
+	#define t_strcasecmp		_wcsicmp
+	#define t_strncasecmp		_wcsnicmp
+	#define t_strtol			wcstol
+	#define t_atoi				_wtoi
+	#define t_strtod			wcstod
+	#define t_itoa(value, buffer, size, radix)	_itow_s(value, buffer, size, radix)
+	#define t_strstr			wcsstr
+	#define t_tolower			towlower
+	#define t_isdigit			iswdigit
+
+#else
+
+	typedef std::string			tstring;
+	typedef char				tchar_t;
+	typedef std::stringstream	tstringstream;
+
+	#define _t(quote)			quote
+
+	#define t_strlen			strlen
+	#define t_strcmp			strcmp
+	#define t_strncmp			strncmp
+	#define t_strcasecmp		_stricmp
+	#define t_strncasecmp		_strnicmp
+	#define t_strtol			strtol
+	#define t_atoi				atoi
+	#define t_strtod			strtod
+	#define t_itoa(value, buffer, size, radix)	_itoa_s(value, buffer, size, radix)
+	#define t_strstr			strstr
+	#define t_tolower			tolower
+	#define t_isdigit			isdigit
+
+#endif
+
+	#ifdef _WIN64
+		typedef unsigned __int64 uint_ptr;
+	#else
+		typedef unsigned int	uint_ptr;
+	#endif
+
+#else
+	#define LITEHTML_UTF8
+
+	typedef std::string			tstring;
+	typedef char				tchar_t;
+	typedef void*				uint_ptr;
+	typedef std::stringstream	tstringstream;
+
+	#define _t(quote)			quote
+
+	#define t_strlen			strlen
+	#define t_strcmp			strcmp
+	#define t_strncmp			strncmp
+
+	#define t_strcasecmp		strcasecmp
+	#define t_strncasecmp		strncasecmp
+	#define t_itoa(value, buffer, size, radix)	snprintf(buffer, size, "%d", value)
+
+	#define t_strtol			strtol
+	#define t_atoi				atoi
+	#define t_strtod			strtod
+	#define t_strstr			strstr
+	#define t_tolower			tolower
+	#define t_isdigit			isdigit
+
+#endif
+}
+
+#endif  // LH_OS_TYPES_H
diff --git a/src/plugins/litehtml_viewer/litehtml/style.cpp b/src/plugins/litehtml_viewer/litehtml/style.cpp
index 60b8738..be06870 100644
--- a/src/plugins/litehtml_viewer/litehtml/style.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/style.cpp
@@ -1,654 +1,656 @@
-#include "html.h"
-#include "style.h"
-#include <functional>
-#include <algorithm>
-#ifndef WINCE
-#include <locale>
-#endif
-
-litehtml::string_map litehtml::style::m_valid_values =
-{
-	{ _t("white-space"), white_space_strings }
-};
-
-litehtml::style::style()
-{
-}
-
-litehtml::style::style( const style& val )
-{
-	m_properties = val.m_properties;
-}
-
-litehtml::style::~style()
-{
-
-}
-
-void litehtml::style::parse( const tchar_t* txt, const tchar_t* baseurl )
-{
-	std::vector<tstring> properties;
-	split_string(txt, properties, _t(";"));
-
-	for(std::vector<tstring>::const_iterator i = properties.begin(); i != properties.end(); i++)
-	{
-		parse_property(*i, baseurl);
-	}
-}
-
-void litehtml::style::parse_property( const tstring& txt, const tchar_t* baseurl )
-{
-	tstring::size_type pos = txt.find_first_of(_t(":"));
-	if(pos != tstring::npos)
-	{
-		tstring name	= txt.substr(0, pos);
-		tstring val	= txt.substr(pos + 1);
-
-		trim(name);
-		trim(val);
-
-		lcase(name);
-
-		if(!name.empty() && !val.empty())
-		{
-			string_vector vals;
-			split_string(val, vals, _t("!"));
-			if(vals.size() == 1)
-			{
-				add_property(name.c_str(), val.c_str(), baseurl, false);
-			} else if(vals.size() > 1)
-			{
-				trim(vals[0]);
-				lcase(vals[1]);
-				if(vals[1] == _t("important"))
-				{
-					add_property(name.c_str(), vals[0].c_str(), baseurl, true);
-				} else
-				{
-					add_property(name.c_str(), vals[0].c_str(), baseurl, false);
-				}
-			}
-		}
-	}
-}
-
-void litehtml::style::combine( const litehtml::style& src )
-{
-	for(props_map::const_iterator i = src.m_properties.begin(); i != src.m_properties.end(); i++)
-	{
-		add_parsed_property(i->first.c_str(), i->second.m_value.c_str(), i->second.m_important);
-	}
-}
-
-void litehtml::style::add_property( const tchar_t* name, const tchar_t* val, const tchar_t* baseurl, bool important )
-{
-	if(!name || !val)
-	{
-		return;
-	}
-
-	// Add baseurl for background image 
-	if(	!t_strcmp(name, _t("background-image")))
-	{
-		add_parsed_property(name, val, important);
-		if(baseurl)
-		{
-			add_parsed_property(_t("background-image-baseurl"), baseurl, important);
-		}
-	} else
-
-	// Parse border spacing properties 
-	if(	!t_strcmp(name, _t("border-spacing")))
-	{
-		string_vector tokens;
-		split_string(val, tokens, _t(" "));
-		if(tokens.size() == 1)
-		{
-			add_property(_t("-litehtml-border-spacing-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("-litehtml-border-spacing-y"), tokens[0].c_str(), baseurl, important);
-		} else if(tokens.size() == 2)
-		{
-			add_property(_t("-litehtml-border-spacing-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("-litehtml-border-spacing-y"), tokens[1].c_str(), baseurl, important);
-		}
-	} else
-
-	// Parse borders shorthand properties 
-
-	if(	!t_strcmp(name, _t("border")))
-	{
-		string_vector tokens;
-		split_string(val, tokens, _t(" "), _t(""), _t("("));
-		int idx;
-		tstring str;
-		for(string_vector::const_iterator tok = tokens.begin(); tok != tokens.end(); tok++)
-		{
-			idx = value_index(tok->c_str(), border_style_strings, -1);
-			if(idx >= 0)
-			{
-				add_property(_t("border-left-style"), tok->c_str(), baseurl, important);
-				add_property(_t("border-right-style"), tok->c_str(), baseurl, important);
-				add_property(_t("border-top-style"), tok->c_str(), baseurl, important);
-				add_property(_t("border-bottom-style"), tok->c_str(), baseurl, important);
-			} else
-			{
-				if(web_color::is_color(tok->c_str()))
-				{
-					add_property(_t("border-left-color"), tok->c_str(), baseurl, important);
-					add_property(_t("border-right-color"), tok->c_str(), baseurl, important);
-					add_property(_t("border-top-color"), tok->c_str(), baseurl, important);
-					add_property(_t("border-bottom-color"), tok->c_str(), baseurl, important);
-				} else
-				{
-					add_property(_t("border-left-width"), tok->c_str(), baseurl, important);
-					add_property(_t("border-right-width"), tok->c_str(), baseurl, important);
-					add_property(_t("border-top-width"), tok->c_str(), baseurl, important);
-					add_property(_t("border-bottom-width"), tok->c_str(), baseurl, important);
-				}
-			}
-		}
-	} else if(	!t_strcmp(name, _t("border-left"))	||
-		!t_strcmp(name, _t("border-right"))	||
-		!t_strcmp(name, _t("border-top"))	||
-		!t_strcmp(name, _t("border-bottom")) )
-	{
-		string_vector tokens;
-		split_string(val, tokens, _t(" "), _t(""), _t("("));
-		int idx;
-		tstring str;
-		for(string_vector::const_iterator tok = tokens.begin(); tok != tokens.end(); tok++)
-		{
-			idx = value_index(tok->c_str(), border_style_strings, -1);
-			if(idx >= 0)
-			{
-				str = name;
-				str += _t("-style");
-				add_property(str.c_str(), tok->c_str(), baseurl, important);
-			} else
-			{
-				if(web_color::is_color(tok->c_str()))
-				{
-					str = name;
-					str += _t("-color");
-					add_property(str.c_str(), tok->c_str(), baseurl, important);
-				} else
-				{
-					str = name;
-					str += _t("-width");
-					add_property(str.c_str(), tok->c_str(), baseurl, important);
-				}
-			}
-		}
-	} else 
-
-	// Parse border radius shorthand properties 
-	if(!t_strcmp(name, _t("border-bottom-left-radius")))
-	{
-		string_vector tokens;
-		split_string(val, tokens, _t(" "));
-		if(tokens.size() >= 2)
-		{
-			add_property(_t("border-bottom-left-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-y"), tokens[1].c_str(), baseurl, important);
-		} else if(tokens.size() == 1)
-		{
-			add_property(_t("border-bottom-left-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-y"), tokens[0].c_str(), baseurl, important);
-		}
-
-	} else if(!t_strcmp(name, _t("border-bottom-right-radius")))
-	{
-		string_vector tokens;
-		split_string(val, tokens, _t(" "));
-		if(tokens.size() >= 2)
-		{
-			add_property(_t("border-bottom-right-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-y"), tokens[1].c_str(), baseurl, important);
-		} else if(tokens.size() == 1)
-		{
-			add_property(_t("border-bottom-right-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-y"), tokens[0].c_str(), baseurl, important);
-		}
-
-	} else if(!t_strcmp(name, _t("border-top-right-radius")))
-	{
-		string_vector tokens;
-		split_string(val, tokens, _t(" "));
-		if(tokens.size() >= 2)
-		{
-			add_property(_t("border-top-right-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-y"), tokens[1].c_str(), baseurl, important);
-		} else if(tokens.size() == 1)
-		{
-			add_property(_t("border-top-right-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-y"), tokens[0].c_str(), baseurl, important);
-		}
-
-	} else if(!t_strcmp(name, _t("border-top-left-radius")))
-	{
-		string_vector tokens;
-		split_string(val, tokens, _t(" "));
-		if(tokens.size() >= 2)
-		{
-			add_property(_t("border-top-left-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-left-radius-y"), tokens[1].c_str(), baseurl, important);
-		} else if(tokens.size() == 1)
-		{
-			add_property(_t("border-top-left-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-left-radius-y"), tokens[0].c_str(), baseurl, important);
-		}
-
-	} else 
-
-	// Parse border-radius shorthand properties 
-	if(!t_strcmp(name, _t("border-radius")))
-	{
-		string_vector tokens;
-		split_string(val, tokens, _t("/"));
-		if(tokens.size() == 1)
-		{
-			add_property(_t("border-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-radius-y"), tokens[0].c_str(), baseurl, important);
-		} else if(tokens.size() >= 2)
-		{
-			add_property(_t("border-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-radius-y"), tokens[1].c_str(), baseurl, important);
-		}
-	} else if(!t_strcmp(name, _t("border-radius-x")))
-	{
-		string_vector tokens;
-		split_string(val, tokens, _t(" "));
-		if(tokens.size() == 1)
-		{
-			add_property(_t("border-top-left-radius-x"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-x"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-x"),	tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-x"),	tokens[0].c_str(), baseurl, important);
-		} else if(tokens.size() == 2)
-		{
-			add_property(_t("border-top-left-radius-x"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-x"),		tokens[1].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-x"),	tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-x"),	tokens[1].c_str(), baseurl, important);
-		} else if(tokens.size() == 3)
-		{
-			add_property(_t("border-top-left-radius-x"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-x"),		tokens[1].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-x"),	tokens[2].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-x"),	tokens[1].c_str(), baseurl, important);
-		} else if(tokens.size() == 4)
-		{
-			add_property(_t("border-top-left-radius-x"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-x"),		tokens[1].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-x"),	tokens[2].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-x"),	tokens[3].c_str(), baseurl, important);
-		}
-	} else if(!t_strcmp(name, _t("border-radius-y")))
-	{
-		string_vector tokens;
-		split_string(val, tokens, _t(" "));
-		if(tokens.size() == 1)
-		{
-			add_property(_t("border-top-left-radius-y"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-y"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-y"),	tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-y"),	tokens[0].c_str(), baseurl, important);
-		} else if(tokens.size() == 2)
-		{
-			add_property(_t("border-top-left-radius-y"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-y"),		tokens[1].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-y"),	tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-y"),	tokens[1].c_str(), baseurl, important);
-		} else if(tokens.size() == 3)
-		{
-			add_property(_t("border-top-left-radius-y"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-y"),		tokens[1].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-y"),	tokens[2].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-y"),	tokens[1].c_str(), baseurl, important);
-		} else if(tokens.size() == 4)
-		{
-			add_property(_t("border-top-left-radius-y"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-y"),		tokens[1].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-y"),	tokens[2].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-y"),	tokens[3].c_str(), baseurl, important);
-		}
-	}
-	
-
-	// Parse list-style shorthand properties 
-	if(!t_strcmp(name, _t("list-style")))
-	{
-		add_parsed_property(_t("list-style-type"),			_t("disc"),		important);
-		add_parsed_property(_t("list-style-position"),		_t("outside"),	important);
-		add_parsed_property(_t("list-style-image"),			_t(""),			important);
-		add_parsed_property(_t("list-style-image-baseurl"),	_t(""),			important);
-
-		string_vector tokens;
-		split_string(val, tokens, _t(" "), _t(""), _t("("));
-		for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
-		{
-			int idx = value_index(tok->c_str(), list_style_type_strings, -1);
-			if(idx >= 0)
-			{
-				add_parsed_property(_t("list-style-type"), *tok, important);
-			} else
-			{
-				idx = value_index(tok->c_str(), list_style_position_strings, -1);
-				if(idx >= 0)
-				{
-					add_parsed_property(_t("list-style-position"), *tok, important);
-				} else if(!t_strncmp(val, _t("url"), 3))
-				{
-					add_parsed_property(_t("list-style-image"), *tok, important);
-					if(baseurl)
-					{
-						add_parsed_property(_t("list-style-image-baseurl"), baseurl, important);
-					}
-				}
-			}
-		}
-	} else 
-
-	// Add baseurl for background image 
-	if(	!t_strcmp(name, _t("list-style-image")))
-	{
-		add_parsed_property(name, val, important);
-		if(baseurl)
-		{
-			add_parsed_property(_t("list-style-image-baseurl"), baseurl, important);
-		}
-	} else
-		
-	// Parse background shorthand properties 
-	if(!t_strcmp(name, _t("background")))
-	{
-		parse_short_background(val, baseurl, important);
-
-	} else 
-		
-	// Parse margin and padding shorthand properties 
-	if(!t_strcmp(name, _t("margin")) || !t_strcmp(name, _t("padding")))
-	{
-		string_vector tokens;
-		split_string(val, tokens, _t(" "));
-		if(tokens.size() >= 4)
-		{
-			add_parsed_property(tstring(name) + _t("-top"),		tokens[0], important);
-			add_parsed_property(tstring(name) + _t("-right"),		tokens[1], important);
-			add_parsed_property(tstring(name) + _t("-bottom"),	tokens[2], important);
-			add_parsed_property(tstring(name) + _t("-left"),		tokens[3], important);
-		} else if(tokens.size() == 3)
-		{
-			add_parsed_property(tstring(name) + _t("-top"),		tokens[0], important);
-			add_parsed_property(tstring(name) + _t("-right"),		tokens[1], important);
-			add_parsed_property(tstring(name) + _t("-left"),		tokens[1], important);
-			add_parsed_property(tstring(name) + _t("-bottom"),	tokens[2], important);
-		} else if(tokens.size() == 2)
-		{
-			add_parsed_property(tstring(name) + _t("-top"),		tokens[0], important);
-			add_parsed_property(tstring(name) + _t("-bottom"),	tokens[0], important);
-			add_parsed_property(tstring(name) + _t("-right"),		tokens[1], important);
-			add_parsed_property(tstring(name) + _t("-left"),		tokens[1], important);
-		} else if(tokens.size() == 1)
-		{
-			add_parsed_property(tstring(name) + _t("-top"),		tokens[0], important);
-			add_parsed_property(tstring(name) + _t("-bottom"),	tokens[0], important);
-			add_parsed_property(tstring(name) + _t("-right"),		tokens[0], important);
-			add_parsed_property(tstring(name) + _t("-left"),		tokens[0], important);
-		}
-	} else 
-		
-		
-	// Parse border-* shorthand properties 
-	if(	!t_strcmp(name, _t("border-left")) || 
-		!t_strcmp(name, _t("border-right")) ||
-		!t_strcmp(name, _t("border-top"))  || 
-		!t_strcmp(name, _t("border-bottom")))
-	{
-		parse_short_border(name, val, important);
-	} else 
-		
-	// Parse border-width/style/color shorthand properties 
-	if(	!t_strcmp(name, _t("border-width")) ||
-		!t_strcmp(name, _t("border-style"))  ||
-		!t_strcmp(name, _t("border-color")) )
-	{
-		string_vector nametokens;
-		split_string(name, nametokens, _t("-"));
-
-		string_vector tokens;
-		split_string(val, tokens, _t(" "));
-		if(tokens.size() >= 4)
-		{
-			add_parsed_property(nametokens[0] + _t("-top-")		+ nametokens[1],	tokens[0], important);
-			add_parsed_property(nametokens[0] + _t("-right-")	+ nametokens[1],	tokens[1], important);
-			add_parsed_property(nametokens[0] + _t("-bottom-")	+ nametokens[1],	tokens[2], important);
-			add_parsed_property(nametokens[0] + _t("-left-")	+ nametokens[1],	tokens[3], important);
-		} else if(tokens.size() == 3)
-		{
-			add_parsed_property(nametokens[0] + _t("-top-")		+ nametokens[1],	tokens[0], important);
-			add_parsed_property(nametokens[0] + _t("-right-")	+ nametokens[1],	tokens[1], important);
-			add_parsed_property(nametokens[0] + _t("-left-")	+ nametokens[1],	tokens[1], important);
-			add_parsed_property(nametokens[0] + _t("-bottom-")	+ nametokens[1],	tokens[2], important);
-		} else if(tokens.size() == 2)
-		{
-			add_parsed_property(nametokens[0] + _t("-top-")		+ nametokens[1],	tokens[0], important);
-			add_parsed_property(nametokens[0] + _t("-bottom-")	+ nametokens[1],	tokens[0], important);
-			add_parsed_property(nametokens[0] + _t("-right-")	+ nametokens[1],	tokens[1], important);
-			add_parsed_property(nametokens[0] + _t("-left-")	+ nametokens[1],	tokens[1], important);
-		} else if(tokens.size() == 1)
-		{
-			add_parsed_property(nametokens[0] + _t("-top-")		+ nametokens[1],	tokens[0], important);
-			add_parsed_property(nametokens[0] + _t("-bottom-")	+ nametokens[1],	tokens[0], important);
-			add_parsed_property(nametokens[0] + _t("-right-")	+ nametokens[1],	tokens[0], important);
-			add_parsed_property(nametokens[0] + _t("-left-")	+ nametokens[1],	tokens[0], important);
-		}
-	} else 
-		
-	// Parse font shorthand properties 
-	if(!t_strcmp(name, _t("font")))
-	{
-		parse_short_font(val, important);
-	} else 
-	{
-		add_parsed_property(name, val, important);
-	}
-}
-
-void litehtml::style::parse_short_border( const tstring& prefix, const tstring& val, bool important )
-{
-	string_vector tokens;
-	split_string(val, tokens, _t(" "), _t(""), _t("("));
-	if(tokens.size() >= 3)
-	{
-		add_parsed_property(prefix + _t("-width"),	tokens[0], important);
-		add_parsed_property(prefix + _t("-style"),	tokens[1], important);
-		add_parsed_property(prefix + _t("-color"),	tokens[2], important);
-	} else if(tokens.size() == 2)
-	{
-		if(iswdigit(tokens[0][0]) || value_index(val.c_str(), border_width_strings) >= 0)
-		{
-			add_parsed_property(prefix + _t("-width"),	tokens[0], important);
-			add_parsed_property(prefix + _t("-style"),	tokens[1], important);
-		} else
-		{
-			add_parsed_property(prefix + _t("-style"),	tokens[0], important);
-			add_parsed_property(prefix + _t("-color"),	tokens[1], important);
-		}
-	}
-}
-
-void litehtml::style::parse_short_background( const tstring& val, const tchar_t* baseurl, bool important )
-{
-	add_parsed_property(_t("background-color"),			_t("transparent"),	important);
-	add_parsed_property(_t("background-image"),			_t(""),				important);
-	add_parsed_property(_t("background-image-baseurl"), _t(""),				important);
-	add_parsed_property(_t("background-repeat"),		_t("repeat"),		important);
-	add_parsed_property(_t("background-origin"),		_t("padding-box"),	important);
-	add_parsed_property(_t("background-clip"),			_t("border-box"),	important);
-	add_parsed_property(_t("background-attachment"),	_t("scroll"),		important);
-
-	if(val == _t("none"))
-	{
-		return;
-	}
-
-	string_vector tokens;
-	split_string(val, tokens, _t(" "), _t(""), _t("("));
-	bool origin_found = false;
-	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
-	{
-		if(web_color::is_color(tok->c_str()))
-		{
-			add_parsed_property(_t("background-color"), *tok, important);
-		} else if(tok->substr(0, 3) == _t("url"))
-		{
-			add_parsed_property(_t("background-image"), *tok, important);
-			if(baseurl)
-			{
-				add_parsed_property(_t("background-image-baseurl"), baseurl, important);
-			}
-
-		} else if( value_in_list(tok->c_str(), background_repeat_strings) )
-		{
-			add_parsed_property(_t("background-repeat"), *tok, important);
-		} else if( value_in_list(tok->c_str(), background_attachment_strings) )
-		{
-			add_parsed_property(_t("background-attachment"), *tok, important);
-		} else if( value_in_list(tok->c_str(), background_box_strings) )
-		{
-			if(!origin_found)
-			{
-				add_parsed_property(_t("background-origin"), *tok, important);
-				origin_found = true;
-			} else
-			{
-				add_parsed_property(_t("background-clip"),*tok, important);
-			}
-		} else if(	value_in_list(tok->c_str(), _t("left;right;top;bottom;center")) ||
-					iswdigit((*tok)[0]) ||
-					(*tok)[0] == _t('-')	||
-					(*tok)[0] == _t('.')	||
-					(*tok)[0] == _t('+'))
-		{
-			if(m_properties.find(_t("background-position")) != m_properties.end())
-			{
-				m_properties[_t("background-position")].m_value = m_properties[_t("background-position")].m_value + _t(" ") + *tok;
-			} else
-			{
-				add_parsed_property(_t("background-position"), *tok, important);
-			}
-		}
-	}
-}
-
-void litehtml::style::parse_short_font( const tstring& val, bool important )
-{
-	add_parsed_property(_t("font-style"),	_t("normal"),	important);
-	add_parsed_property(_t("font-variant"),	_t("normal"),	important);
-	add_parsed_property(_t("font-weight"),	_t("normal"),	important);
-	add_parsed_property(_t("font-size"),		_t("medium"),	important);
-	add_parsed_property(_t("line-height"),	_t("normal"),	important);
-
-	string_vector tokens;
-	split_string(val, tokens, _t(" "), _t(""), _t("\""));
-
-	int idx = 0;
-	bool was_normal = false;
-	bool is_family = false;
-	tstring font_family;
-	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
-	{
-		idx = value_index(tok->c_str(), font_style_strings);
-		if(!is_family)
-		{
-			if(idx >= 0)
-			{
-				if(idx == 0 && !was_normal)
-				{
-					add_parsed_property(_t("font-weight"),		*tok, important);
-					add_parsed_property(_t("font-variant"),		*tok, important);
-					add_parsed_property(_t("font-style"),		*tok, important);
-				} else
-				{
-					add_parsed_property(_t("font-style"),		*tok, important);
-				}
-			} else
-			{
-				if(value_in_list(tok->c_str(), font_weight_strings))
-				{
-					add_parsed_property(_t("font-weight"),		*tok, important);
-				} else
-				{
-					if(value_in_list(tok->c_str(), font_variant_strings))
-					{
-						add_parsed_property(_t("font-variant"),	*tok, important);
-					} else if( iswdigit((*tok)[0]) )
-					{
-						string_vector szlh;
-						split_string(*tok, szlh, _t("/"));
-
-						if(szlh.size() == 1)
-						{
-							add_parsed_property(_t("font-size"),	szlh[0], important);
-						} else	if(szlh.size() >= 2)
-						{
-							add_parsed_property(_t("font-size"),	szlh[0], important);
-							add_parsed_property(_t("line-height"),	szlh[1], important);
-						}
-					} else
-					{
-						is_family = true;
-						font_family += *tok;
-					}
-				}
-			}
-		} else
-		{
-			font_family += *tok;
-		}
-	}
-	add_parsed_property(_t("font-family"), font_family, important);
-}
-
-void litehtml::style::add_parsed_property( const tstring& name, const tstring& val, bool important )
-{
-	bool is_valid = true;
-	string_map::iterator vals = m_valid_values.find(name);
-	if (vals != m_valid_values.end())
-	{
-		if (!value_in_list(val, vals->second))
-		{
-			is_valid = false;
-		}
-	}
-
-	if (is_valid)
-	{
-		props_map::iterator prop = m_properties.find(name);
-		if (prop != m_properties.end())
-		{
-			if (!prop->second.m_important || (important && prop->second.m_important))
-			{
-				prop->second.m_value = val;
-				prop->second.m_important = important;
-			}
-		}
-		else
-		{
-			m_properties[name] = property_value(val.c_str(), important);
-		}
-	}
-}
-
-void litehtml::style::remove_property( const tstring& name, bool important )
-{
-	props_map::iterator prop = m_properties.find(name);
-	if(prop != m_properties.end())
-	{
-		if( !prop->second.m_important || (important && prop->second.m_important) )
-		{
-			m_properties.erase(prop);
-		}
-	}
-}
+#include "html.h"
+#include "style.h"
+#include <functional>
+#include <algorithm>
+#ifndef WINCE
+#include <locale>
+#endif
+
+litehtml::string_map litehtml::style::m_valid_values =
+{
+	{ _t("white-space"), white_space_strings }
+};
+
+litehtml::style::style()
+{
+}
+
+litehtml::style::style( const style& val )
+{
+	m_properties = val.m_properties;
+}
+
+litehtml::style::~style()
+{
+
+}
+
+void litehtml::style::parse( const tchar_t* txt, const tchar_t* baseurl )
+{
+	std::vector<tstring> properties;
+	split_string(txt, properties, _t(";"));
+
+	for(std::vector<tstring>::const_iterator i = properties.begin(); i != properties.end(); i++)
+	{
+		parse_property(*i, baseurl);
+	}
+}
+
+void litehtml::style::parse_property( const tstring& txt, const tchar_t* baseurl )
+{
+	tstring::size_type pos = txt.find_first_of(_t(":"));
+	if(pos != tstring::npos)
+	{
+		tstring name	= txt.substr(0, pos);
+		tstring val	= txt.substr(pos + 1);
+
+		trim(name);
+		trim(val);
+
+		lcase(name);
+
+		if(!name.empty() && !val.empty())
+		{
+			string_vector vals;
+			split_string(val, vals, _t("!"));
+			if(vals.size() == 1)
+			{
+				add_property(name.c_str(), val.c_str(), baseurl, false);
+			} else if(vals.size() > 1)
+			{
+				trim(vals[0]);
+				lcase(vals[1]);
+				if(vals[1] == _t("important"))
+				{
+					add_property(name.c_str(), vals[0].c_str(), baseurl, true);
+				} else
+				{
+					add_property(name.c_str(), vals[0].c_str(), baseurl, false);
+				}
+			}
+		}
+	}
+}
+
+void litehtml::style::combine( const litehtml::style& src )
+{
+	for(props_map::const_iterator i = src.m_properties.begin(); i != src.m_properties.end(); i++)
+	{
+		add_parsed_property(i->first.c_str(), i->second.m_value.c_str(), i->second.m_important);
+	}
+}
+
+void litehtml::style::add_property( const tchar_t* name, const tchar_t* val, const tchar_t* baseurl, bool important )
+{
+	if(!name || !val)
+	{
+		return;
+	}
+
+	// Add baseurl for background image 
+	if(	!t_strcmp(name, _t("background-image")))
+	{
+		add_parsed_property(name, val, important);
+		if(baseurl)
+		{
+			add_parsed_property(_t("background-image-baseurl"), baseurl, important);
+		}
+	} else
+
+	// Parse border spacing properties 
+	if(	!t_strcmp(name, _t("border-spacing")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "));
+		if(tokens.size() == 1)
+		{
+			add_property(_t("-litehtml-border-spacing-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("-litehtml-border-spacing-y"), tokens[0].c_str(), baseurl, important);
+		} else if(tokens.size() == 2)
+		{
+			add_property(_t("-litehtml-border-spacing-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("-litehtml-border-spacing-y"), tokens[1].c_str(), baseurl, important);
+		}
+	} else
+
+	// Parse borders shorthand properties 
+
+	if(	!t_strcmp(name, _t("border")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "), _t(""), _t("("));
+		int idx;
+		tstring str;
+		for(string_vector::const_iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+		{
+			idx = value_index(tok->c_str(), border_style_strings, -1);
+			if(idx >= 0)
+			{
+				add_property(_t("border-left-style"), tok->c_str(), baseurl, important);
+				add_property(_t("border-right-style"), tok->c_str(), baseurl, important);
+				add_property(_t("border-top-style"), tok->c_str(), baseurl, important);
+				add_property(_t("border-bottom-style"), tok->c_str(), baseurl, important);
+			} else
+			{
+				if (t_isdigit((*tok)[0]) || (*tok)[0] == _t('.') ||
+					value_in_list((*tok), _t("thin;medium;thick")))
+				{
+					add_property(_t("border-left-width"), tok->c_str(), baseurl, important);
+					add_property(_t("border-right-width"), tok->c_str(), baseurl, important);
+					add_property(_t("border-top-width"), tok->c_str(), baseurl, important);
+					add_property(_t("border-bottom-width"), tok->c_str(), baseurl, important);
+				} 
+				else
+				{
+					add_property(_t("border-left-color"), tok->c_str(), baseurl, important);
+					add_property(_t("border-right-color"), tok->c_str(), baseurl, important);
+					add_property(_t("border-top-color"), tok->c_str(), baseurl, important);
+					add_property(_t("border-bottom-color"), tok->c_str(), baseurl, important);
+				}
+			}
+		}
+	} else if(	!t_strcmp(name, _t("border-left"))	||
+		!t_strcmp(name, _t("border-right"))	||
+		!t_strcmp(name, _t("border-top"))	||
+		!t_strcmp(name, _t("border-bottom")) )
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "), _t(""), _t("("));
+		int idx;
+		tstring str;
+		for(string_vector::const_iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+		{
+			idx = value_index(tok->c_str(), border_style_strings, -1);
+			if(idx >= 0)
+			{
+				str = name;
+				str += _t("-style");
+				add_property(str.c_str(), tok->c_str(), baseurl, important);
+			} else
+			{
+				if(web_color::is_color(tok->c_str()))
+				{
+					str = name;
+					str += _t("-color");
+					add_property(str.c_str(), tok->c_str(), baseurl, important);
+				} else
+				{
+					str = name;
+					str += _t("-width");
+					add_property(str.c_str(), tok->c_str(), baseurl, important);
+				}
+			}
+		}
+	} else 
+
+	// Parse border radius shorthand properties 
+	if(!t_strcmp(name, _t("border-bottom-left-radius")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "));
+		if(tokens.size() >= 2)
+		{
+			add_property(_t("border-bottom-left-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-y"), tokens[1].c_str(), baseurl, important);
+		} else if(tokens.size() == 1)
+		{
+			add_property(_t("border-bottom-left-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-y"), tokens[0].c_str(), baseurl, important);
+		}
+
+	} else if(!t_strcmp(name, _t("border-bottom-right-radius")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "));
+		if(tokens.size() >= 2)
+		{
+			add_property(_t("border-bottom-right-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-y"), tokens[1].c_str(), baseurl, important);
+		} else if(tokens.size() == 1)
+		{
+			add_property(_t("border-bottom-right-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-y"), tokens[0].c_str(), baseurl, important);
+		}
+
+	} else if(!t_strcmp(name, _t("border-top-right-radius")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "));
+		if(tokens.size() >= 2)
+		{
+			add_property(_t("border-top-right-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-y"), tokens[1].c_str(), baseurl, important);
+		} else if(tokens.size() == 1)
+		{
+			add_property(_t("border-top-right-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-y"), tokens[0].c_str(), baseurl, important);
+		}
+
+	} else if(!t_strcmp(name, _t("border-top-left-radius")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "));
+		if(tokens.size() >= 2)
+		{
+			add_property(_t("border-top-left-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-left-radius-y"), tokens[1].c_str(), baseurl, important);
+		} else if(tokens.size() == 1)
+		{
+			add_property(_t("border-top-left-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-left-radius-y"), tokens[0].c_str(), baseurl, important);
+		}
+
+	} else 
+
+	// Parse border-radius shorthand properties 
+	if(!t_strcmp(name, _t("border-radius")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t("/"));
+		if(tokens.size() == 1)
+		{
+			add_property(_t("border-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-radius-y"), tokens[0].c_str(), baseurl, important);
+		} else if(tokens.size() >= 2)
+		{
+			add_property(_t("border-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-radius-y"), tokens[1].c_str(), baseurl, important);
+		}
+	} else if(!t_strcmp(name, _t("border-radius-x")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "));
+		if(tokens.size() == 1)
+		{
+			add_property(_t("border-top-left-radius-x"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-x"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-x"),	tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-x"),	tokens[0].c_str(), baseurl, important);
+		} else if(tokens.size() == 2)
+		{
+			add_property(_t("border-top-left-radius-x"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-x"),		tokens[1].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-x"),	tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-x"),	tokens[1].c_str(), baseurl, important);
+		} else if(tokens.size() == 3)
+		{
+			add_property(_t("border-top-left-radius-x"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-x"),		tokens[1].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-x"),	tokens[2].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-x"),	tokens[1].c_str(), baseurl, important);
+		} else if(tokens.size() == 4)
+		{
+			add_property(_t("border-top-left-radius-x"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-x"),		tokens[1].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-x"),	tokens[2].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-x"),	tokens[3].c_str(), baseurl, important);
+		}
+	} else if(!t_strcmp(name, _t("border-radius-y")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "));
+		if(tokens.size() == 1)
+		{
+			add_property(_t("border-top-left-radius-y"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-y"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-y"),	tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-y"),	tokens[0].c_str(), baseurl, important);
+		} else if(tokens.size() == 2)
+		{
+			add_property(_t("border-top-left-radius-y"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-y"),		tokens[1].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-y"),	tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-y"),	tokens[1].c_str(), baseurl, important);
+		} else if(tokens.size() == 3)
+		{
+			add_property(_t("border-top-left-radius-y"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-y"),		tokens[1].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-y"),	tokens[2].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-y"),	tokens[1].c_str(), baseurl, important);
+		} else if(tokens.size() == 4)
+		{
+			add_property(_t("border-top-left-radius-y"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-y"),		tokens[1].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-y"),	tokens[2].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-y"),	tokens[3].c_str(), baseurl, important);
+		}
+	}
+	
+
+	// Parse list-style shorthand properties 
+	if(!t_strcmp(name, _t("list-style")))
+	{
+		add_parsed_property(_t("list-style-type"),			_t("disc"),		important);
+		add_parsed_property(_t("list-style-position"),		_t("outside"),	important);
+		add_parsed_property(_t("list-style-image"),			_t(""),			important);
+		add_parsed_property(_t("list-style-image-baseurl"),	_t(""),			important);
+
+		string_vector tokens;
+		split_string(val, tokens, _t(" "), _t(""), _t("("));
+		for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+		{
+			int idx = value_index(tok->c_str(), list_style_type_strings, -1);
+			if(idx >= 0)
+			{
+				add_parsed_property(_t("list-style-type"), *tok, important);
+			} else
+			{
+				idx = value_index(tok->c_str(), list_style_position_strings, -1);
+				if(idx >= 0)
+				{
+					add_parsed_property(_t("list-style-position"), *tok, important);
+				} else if(!t_strncmp(val, _t("url"), 3))
+				{
+					add_parsed_property(_t("list-style-image"), *tok, important);
+					if(baseurl)
+					{
+						add_parsed_property(_t("list-style-image-baseurl"), baseurl, important);
+					}
+				}
+			}
+		}
+	} else 
+
+	// Add baseurl for background image 
+	if(	!t_strcmp(name, _t("list-style-image")))
+	{
+		add_parsed_property(name, val, important);
+		if(baseurl)
+		{
+			add_parsed_property(_t("list-style-image-baseurl"), baseurl, important);
+		}
+	} else
+		
+	// Parse background shorthand properties 
+	if(!t_strcmp(name, _t("background")))
+	{
+		parse_short_background(val, baseurl, important);
+
+	} else 
+		
+	// Parse margin and padding shorthand properties 
+	if(!t_strcmp(name, _t("margin")) || !t_strcmp(name, _t("padding")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "));
+		if(tokens.size() >= 4)
+		{
+			add_parsed_property(tstring(name) + _t("-top"),		tokens[0], important);
+			add_parsed_property(tstring(name) + _t("-right"),		tokens[1], important);
+			add_parsed_property(tstring(name) + _t("-bottom"),	tokens[2], important);
+			add_parsed_property(tstring(name) + _t("-left"),		tokens[3], important);
+		} else if(tokens.size() == 3)
+		{
+			add_parsed_property(tstring(name) + _t("-top"),		tokens[0], important);
+			add_parsed_property(tstring(name) + _t("-right"),		tokens[1], important);
+			add_parsed_property(tstring(name) + _t("-left"),		tokens[1], important);
+			add_parsed_property(tstring(name) + _t("-bottom"),	tokens[2], important);
+		} else if(tokens.size() == 2)
+		{
+			add_parsed_property(tstring(name) + _t("-top"),		tokens[0], important);
+			add_parsed_property(tstring(name) + _t("-bottom"),	tokens[0], important);
+			add_parsed_property(tstring(name) + _t("-right"),		tokens[1], important);
+			add_parsed_property(tstring(name) + _t("-left"),		tokens[1], important);
+		} else if(tokens.size() == 1)
+		{
+			add_parsed_property(tstring(name) + _t("-top"),		tokens[0], important);
+			add_parsed_property(tstring(name) + _t("-bottom"),	tokens[0], important);
+			add_parsed_property(tstring(name) + _t("-right"),		tokens[0], important);
+			add_parsed_property(tstring(name) + _t("-left"),		tokens[0], important);
+		}
+	} else 
+		
+		
+	// Parse border-* shorthand properties 
+	if(	!t_strcmp(name, _t("border-left")) || 
+		!t_strcmp(name, _t("border-right")) ||
+		!t_strcmp(name, _t("border-top"))  || 
+		!t_strcmp(name, _t("border-bottom")))
+	{
+		parse_short_border(name, val, important);
+	} else 
+		
+	// Parse border-width/style/color shorthand properties 
+	if(	!t_strcmp(name, _t("border-width")) ||
+		!t_strcmp(name, _t("border-style"))  ||
+		!t_strcmp(name, _t("border-color")) )
+	{
+		string_vector nametokens;
+		split_string(name, nametokens, _t("-"));
+
+		string_vector tokens;
+		split_string(val, tokens, _t(" "));
+		if(tokens.size() >= 4)
+		{
+			add_parsed_property(nametokens[0] + _t("-top-")		+ nametokens[1],	tokens[0], important);
+			add_parsed_property(nametokens[0] + _t("-right-")	+ nametokens[1],	tokens[1], important);
+			add_parsed_property(nametokens[0] + _t("-bottom-")	+ nametokens[1],	tokens[2], important);
+			add_parsed_property(nametokens[0] + _t("-left-")	+ nametokens[1],	tokens[3], important);
+		} else if(tokens.size() == 3)
+		{
+			add_parsed_property(nametokens[0] + _t("-top-")		+ nametokens[1],	tokens[0], important);
+			add_parsed_property(nametokens[0] + _t("-right-")	+ nametokens[1],	tokens[1], important);
+			add_parsed_property(nametokens[0] + _t("-left-")	+ nametokens[1],	tokens[1], important);
+			add_parsed_property(nametokens[0] + _t("-bottom-")	+ nametokens[1],	tokens[2], important);
+		} else if(tokens.size() == 2)
+		{
+			add_parsed_property(nametokens[0] + _t("-top-")		+ nametokens[1],	tokens[0], important);
+			add_parsed_property(nametokens[0] + _t("-bottom-")	+ nametokens[1],	tokens[0], important);
+			add_parsed_property(nametokens[0] + _t("-right-")	+ nametokens[1],	tokens[1], important);
+			add_parsed_property(nametokens[0] + _t("-left-")	+ nametokens[1],	tokens[1], important);
+		} else if(tokens.size() == 1)
+		{
+			add_parsed_property(nametokens[0] + _t("-top-")		+ nametokens[1],	tokens[0], important);
+			add_parsed_property(nametokens[0] + _t("-bottom-")	+ nametokens[1],	tokens[0], important);
+			add_parsed_property(nametokens[0] + _t("-right-")	+ nametokens[1],	tokens[0], important);
+			add_parsed_property(nametokens[0] + _t("-left-")	+ nametokens[1],	tokens[0], important);
+		}
+	} else 
+		
+	// Parse font shorthand properties 
+	if(!t_strcmp(name, _t("font")))
+	{
+		parse_short_font(val, important);
+	} else 
+	{
+		add_parsed_property(name, val, important);
+	}
+}
+
+void litehtml::style::parse_short_border( const tstring& prefix, const tstring& val, bool important )
+{
+	string_vector tokens;
+	split_string(val, tokens, _t(" "), _t(""), _t("("));
+	if(tokens.size() >= 3)
+	{
+		add_parsed_property(prefix + _t("-width"),	tokens[0], important);
+		add_parsed_property(prefix + _t("-style"),	tokens[1], important);
+		add_parsed_property(prefix + _t("-color"),	tokens[2], important);
+	} else if(tokens.size() == 2)
+	{
+		if(iswdigit(tokens[0][0]) || value_index(val.c_str(), border_width_strings) >= 0)
+		{
+			add_parsed_property(prefix + _t("-width"),	tokens[0], important);
+			add_parsed_property(prefix + _t("-style"),	tokens[1], important);
+		} else
+		{
+			add_parsed_property(prefix + _t("-style"),	tokens[0], important);
+			add_parsed_property(prefix + _t("-color"),	tokens[1], important);
+		}
+	}
+}
+
+void litehtml::style::parse_short_background( const tstring& val, const tchar_t* baseurl, bool important )
+{
+	add_parsed_property(_t("background-color"),			_t("transparent"),	important);
+	add_parsed_property(_t("background-image"),			_t(""),				important);
+	add_parsed_property(_t("background-image-baseurl"), _t(""),				important);
+	add_parsed_property(_t("background-repeat"),		_t("repeat"),		important);
+	add_parsed_property(_t("background-origin"),		_t("padding-box"),	important);
+	add_parsed_property(_t("background-clip"),			_t("border-box"),	important);
+	add_parsed_property(_t("background-attachment"),	_t("scroll"),		important);
+
+	if(val == _t("none"))
+	{
+		return;
+	}
+
+	string_vector tokens;
+	split_string(val, tokens, _t(" "), _t(""), _t("("));
+	bool origin_found = false;
+	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+	{
+		if(tok->substr(0, 3) == _t("url"))
+		{
+			add_parsed_property(_t("background-image"), *tok, important);
+			if(baseurl)
+			{
+				add_parsed_property(_t("background-image-baseurl"), baseurl, important);
+			}
+
+		} else if( value_in_list(tok->c_str(), background_repeat_strings) )
+		{
+			add_parsed_property(_t("background-repeat"), *tok, important);
+		} else if( value_in_list(tok->c_str(), background_attachment_strings) )
+		{
+			add_parsed_property(_t("background-attachment"), *tok, important);
+		} else if( value_in_list(tok->c_str(), background_box_strings) )
+		{
+			if(!origin_found)
+			{
+				add_parsed_property(_t("background-origin"), *tok, important);
+				origin_found = true;
+			} else
+			{
+				add_parsed_property(_t("background-clip"),*tok, important);
+			}
+		} else if(	value_in_list(tok->c_str(), _t("left;right;top;bottom;center")) ||
+					iswdigit((*tok)[0]) ||
+					(*tok)[0] == _t('-')	||
+					(*tok)[0] == _t('.')	||
+					(*tok)[0] == _t('+'))
+		{
+			if(m_properties.find(_t("background-position")) != m_properties.end())
+			{
+				m_properties[_t("background-position")].m_value = m_properties[_t("background-position")].m_value + _t(" ") + *tok;
+			} else
+			{
+				add_parsed_property(_t("background-position"), *tok, important);
+			}
+		} else if (web_color::is_color(tok->c_str()))
+		{
+			add_parsed_property(_t("background-color"), *tok, important);
+		}
+	}
+}
+
+void litehtml::style::parse_short_font( const tstring& val, bool important )
+{
+	add_parsed_property(_t("font-style"),	_t("normal"),	important);
+	add_parsed_property(_t("font-variant"),	_t("normal"),	important);
+	add_parsed_property(_t("font-weight"),	_t("normal"),	important);
+	add_parsed_property(_t("font-size"),		_t("medium"),	important);
+	add_parsed_property(_t("line-height"),	_t("normal"),	important);
+
+	string_vector tokens;
+	split_string(val, tokens, _t(" "), _t(""), _t("\""));
+
+	int idx = 0;
+	bool was_normal = false;
+	bool is_family = false;
+	tstring font_family;
+	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+	{
+		idx = value_index(tok->c_str(), font_style_strings);
+		if(!is_family)
+		{
+			if(idx >= 0)
+			{
+				if(idx == 0 && !was_normal)
+				{
+					add_parsed_property(_t("font-weight"),		*tok, important);
+					add_parsed_property(_t("font-variant"),		*tok, important);
+					add_parsed_property(_t("font-style"),		*tok, important);
+				} else
+				{
+					add_parsed_property(_t("font-style"),		*tok, important);
+				}
+			} else
+			{
+				if(value_in_list(tok->c_str(), font_weight_strings))
+				{
+					add_parsed_property(_t("font-weight"),		*tok, important);
+				} else
+				{
+					if(value_in_list(tok->c_str(), font_variant_strings))
+					{
+						add_parsed_property(_t("font-variant"),	*tok, important);
+					} else if( iswdigit((*tok)[0]) )
+					{
+						string_vector szlh;
+						split_string(*tok, szlh, _t("/"));
+
+						if(szlh.size() == 1)
+						{
+							add_parsed_property(_t("font-size"),	szlh[0], important);
+						} else	if(szlh.size() >= 2)
+						{
+							add_parsed_property(_t("font-size"),	szlh[0], important);
+							add_parsed_property(_t("line-height"),	szlh[1], important);
+						}
+					} else
+					{
+						is_family = true;
+						font_family += *tok;
+					}
+				}
+			}
+		} else
+		{
+			font_family += *tok;
+		}
+	}
+	add_parsed_property(_t("font-family"), font_family, important);
+}
+
+void litehtml::style::add_parsed_property( const tstring& name, const tstring& val, bool important )
+{
+	bool is_valid = true;
+	string_map::iterator vals = m_valid_values.find(name);
+	if (vals != m_valid_values.end())
+	{
+		if (!value_in_list(val, vals->second))
+		{
+			is_valid = false;
+		}
+	}
+
+	if (is_valid)
+	{
+		props_map::iterator prop = m_properties.find(name);
+		if (prop != m_properties.end())
+		{
+			if (!prop->second.m_important || (important && prop->second.m_important))
+			{
+				prop->second.m_value = val;
+				prop->second.m_important = important;
+			}
+		}
+		else
+		{
+			m_properties[name] = property_value(val.c_str(), important);
+		}
+	}
+}
+
+void litehtml::style::remove_property( const tstring& name, bool important )
+{
+	props_map::iterator prop = m_properties.find(name);
+	if(prop != m_properties.end())
+	{
+		if( !prop->second.m_important || (important && prop->second.m_important) )
+		{
+			m_properties.erase(prop);
+		}
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/style.h b/src/plugins/litehtml_viewer/litehtml/style.h
index bf05772..d84ee20 100644
--- a/src/plugins/litehtml_viewer/litehtml/style.h
+++ b/src/plugins/litehtml_viewer/litehtml/style.h
@@ -1,91 +1,95 @@
-#pragma once
-#include "attributes.h"
-#include <string>
-
-namespace litehtml
-{
-	class property_value
-	{
-	public:
-		tstring	m_value;
-		bool			m_important;
-
-		property_value()
-		{
-			m_important = false;
-		}
-		property_value(const tchar_t* val, bool imp)
-		{
-			m_important = imp;
-			m_value		= val;
-		}
-		property_value(const property_value& val)
-		{
-			m_value		= val.m_value;
-			m_important	= val.m_important;
-		}
-
-		property_value& operator=(const property_value& val)
-		{
-			m_value		= val.m_value;
-			m_important	= val.m_important;
-			return *this;
-		}
-	};
-
-	typedef std::map<tstring, property_value>	props_map;
-
-	class style
-	{
-	public:
-		typedef std::shared_ptr<style>		ptr;
-		typedef std::vector<style::ptr>		vector;
-	private:
-		props_map			m_properties;
-		static string_map	m_valid_values;
-	public:
-		style();
-		style(const style& val);
-		virtual ~style();
-
-		void operator=(const style& val)
-		{
-			m_properties = val.m_properties;
-		}
-
-		void add(const tchar_t* txt, const tchar_t* baseurl)
-		{
-			parse(txt, baseurl);
-		}
-
-		void add_property(const tchar_t* name, const tchar_t* val, const tchar_t* baseurl, bool important);
-
-		const tchar_t* get_property(const tchar_t* name) const
-		{
-			if(name)
-			{
-				props_map::const_iterator f = m_properties.find(name);
-				if(f != m_properties.end())
-				{
-					return f->second.m_value.c_str();
-				}
-			}
-			return 0;
-		}
-
-		void combine(const litehtml::style& src);
-		void clear()
-		{
-			m_properties.clear();
-		}
-
-	private:
-		void parse_property(const tstring& txt, const tchar_t* baseurl);
-		void parse(const tchar_t* txt, const tchar_t* baseurl);
-		void parse_short_border(const tstring& prefix, const tstring& val, bool important);
-		void parse_short_background(const tstring& val, const tchar_t* baseurl, bool important);
-		void parse_short_font(const tstring& val, bool important);
-		void add_parsed_property(const tstring& name, const tstring& val, bool important);
-		void remove_property(const tstring& name, bool important);
-	};
-}
\ No newline at end of file
+#ifndef LH_STYLE_H
+#define LH_STYLE_H
+
+#include "attributes.h"
+#include <string>
+
+namespace litehtml
+{
+	class property_value
+	{
+	public:
+		tstring	m_value;
+		bool			m_important;
+
+		property_value()
+		{
+			m_important = false;
+		}
+		property_value(const tchar_t* val, bool imp)
+		{
+			m_important = imp;
+			m_value		= val;
+		}
+		property_value(const property_value& val)
+		{
+			m_value		= val.m_value;
+			m_important	= val.m_important;
+		}
+
+		property_value& operator=(const property_value& val)
+		{
+			m_value		= val.m_value;
+			m_important	= val.m_important;
+			return *this;
+		}
+	};
+
+	typedef std::map<tstring, property_value>	props_map;
+
+	class style
+	{
+	public:
+		typedef std::shared_ptr<style>		ptr;
+		typedef std::vector<style::ptr>		vector;
+	private:
+		props_map			m_properties;
+		static string_map	m_valid_values;
+	public:
+		style();
+		style(const style& val);
+		virtual ~style();
+
+		void operator=(const style& val)
+		{
+			m_properties = val.m_properties;
+		}
+
+		void add(const tchar_t* txt, const tchar_t* baseurl)
+		{
+			parse(txt, baseurl);
+		}
+
+		void add_property(const tchar_t* name, const tchar_t* val, const tchar_t* baseurl, bool important);
+
+		const tchar_t* get_property(const tchar_t* name) const
+		{
+			if(name)
+			{
+				props_map::const_iterator f = m_properties.find(name);
+				if(f != m_properties.end())
+				{
+					return f->second.m_value.c_str();
+				}
+			}
+			return 0;
+		}
+
+		void combine(const litehtml::style& src);
+		void clear()
+		{
+			m_properties.clear();
+		}
+
+	private:
+		void parse_property(const tstring& txt, const tchar_t* baseurl);
+		void parse(const tchar_t* txt, const tchar_t* baseurl);
+		void parse_short_border(const tstring& prefix, const tstring& val, bool important);
+		void parse_short_background(const tstring& val, const tchar_t* baseurl, bool important);
+		void parse_short_font(const tstring& val, bool important);
+		void add_parsed_property(const tstring& name, const tstring& val, bool important);
+		void remove_property(const tstring& name, bool important);
+	};
+}
+
+#endif  // LH_STYLE_H
diff --git a/src/plugins/litehtml_viewer/litehtml/stylesheet.cpp b/src/plugins/litehtml_viewer/litehtml/stylesheet.cpp
index 7f0a2be..08ace62 100644
--- a/src/plugins/litehtml_viewer/litehtml/stylesheet.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/stylesheet.cpp
@@ -1,219 +1,219 @@
-#include "html.h"
-#include "stylesheet.h"
-#include <algorithm>
-#include "document.h"
-
-
-void litehtml::css::parse_stylesheet(const tchar_t* str, const tchar_t* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media)
-{
-	tstring text = str;
-
-	// remove comments
-	tstring::size_type c_start = text.find(_t("/*"));
-	while(c_start != tstring::npos)
-	{
-		tstring::size_type c_end = text.find(_t("*/"), c_start + 2);
-		text.erase(c_start, c_end - c_start + 2);
-		c_start = text.find(_t("/*"));
-	}
-
-	tstring::size_type pos = text.find_first_not_of(_t(" \n\r\t"));
-	while(pos != tstring::npos)
-	{
-		while(pos != tstring::npos && text[pos] == _t('@'))
-		{
-			tstring::size_type sPos = pos;
-			pos = text.find_first_of(_t("{"), pos);
-			if(pos != tstring::npos && text[pos] == _t('{'))
-			{
-				pos = find_close_bracket(text, pos, _t('{'), _t('}'));
-			}
-			if(pos != tstring::npos)
-			{
-				parse_atrule(text.substr(sPos, pos - sPos + 1), baseurl, doc, media);
-			} else
-			{
-				parse_atrule(text.substr(sPos), baseurl, doc, media);
-			}
-
-			if(pos != tstring::npos)
-			{
-				pos = text.find_first_not_of(_t(" \n\r\t"), pos + 1);
-			}
-		}
-
-		if(pos == tstring::npos)
-		{
-			break;
-		}
-
-		tstring::size_type style_start = text.find(_t("{"), pos);
-		tstring::size_type style_end	= text.find(_t("}"), pos);
-		if(style_start != tstring::npos && style_end != tstring::npos)
-		{
-			style::ptr st = std::make_shared<style>();
-			st->add(text.substr(style_start + 1, style_end - style_start - 1).c_str(), baseurl);
-
-			parse_selectors(text.substr(pos, style_start - pos), st, media);
-
-			if(media && doc)
-			{
-				doc->add_media_list(media);
-			}
-
-			pos = style_end + 1;
-		} else
-		{
-			pos = tstring::npos;
-		}
-
-		if(pos != tstring::npos)
-		{
-			pos = text.find_first_not_of(_t(" \n\r\t"), pos);
-		}
-	}
-}
-
-void litehtml::css::parse_css_url( const tstring& str, tstring& url )
-{
-	url = _t("");
-	size_t pos1 = str.find(_t('('));
-	size_t pos2 = str.find(_t(')'));
-	if(pos1 != tstring::npos && pos2 != tstring::npos)
-	{
-		url = str.substr(pos1 + 1, pos2 - pos1 - 1);
-		if(url.length())
-		{
-			if(url[0] == _t('\'') || url[0] == _t('"'))
-			{
-				url.erase(0, 1);
-			}
-		}
-		if(url.length())
-		{
-			if(url[url.length() - 1] == _t('\'') || url[url.length() - 1] == _t('"'))
-			{
-				url.erase(url.length() - 1, 1);
-			}
-		}
-	}
-}
-
-bool litehtml::css::parse_selectors( const tstring& txt, const litehtml::style::ptr& styles, const media_query_list::ptr& media )
-{
-	tstring selector = txt;
-	trim(selector);
-	string_vector tokens;
-	split_string(selector, tokens, _t(","));
-
-	bool added_something = false;
-
-	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
-	{
-		css_selector::ptr selector = std::make_shared<css_selector>(media);
-		selector->m_style = styles;
-		trim(*tok);
-		if(selector->parse(*tok))
-		{
-			selector->calc_specificity();
-			add_selector(selector);
-			added_something = true;
-		}
-	}
-
-	return added_something;
-}
-
-void litehtml::css::sort_selectors()
-{
-	std::sort(m_selectors.begin(), m_selectors.end(),
-		 [](const css_selector::ptr& v1, const css_selector::ptr& v2)
-		 {
-			 return (*v1) < (*v2);
-		 }
-	);
-}
-
-void litehtml::css::parse_atrule(const tstring& text, const tchar_t* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media)
-{
-	if(text.substr(0, 7) == _t("@import"))
-	{
-		int sPos = 7;
-		tstring iStr;
-		iStr = text.substr(sPos);
-		if(iStr[iStr.length() - 1] == _t(';'))
-		{
-			iStr.erase(iStr.length() - 1);
-		}
-		trim(iStr);
-		string_vector tokens;
-		split_string(iStr, tokens, _t(" "), _t(""), _t("(\""));
-		if(!tokens.empty())
-		{
-			tstring url;
-			parse_css_url(tokens.front(), url);
-			if(url.empty())
-			{
-				url = tokens.front();
-			}
-			tokens.erase(tokens.begin());
-			if(doc)
-			{
-				document_container* doc_cont = doc->container();
-				if(doc_cont)
-				{
-					tstring css_text;
-					tstring css_baseurl;
-					if(baseurl)
-					{
-						css_baseurl = baseurl;
-					}
-					doc_cont->import_css(css_text, url, css_baseurl);
-					if(!css_text.empty())
-					{
-						media_query_list::ptr new_media = media;
-						if(!tokens.empty())
-						{
-							tstring media_str;
-							for(string_vector::iterator iter = tokens.begin(); iter != tokens.end(); iter++)
-							{
-								if(iter != tokens.begin())
-								{
-									media_str += _t(" ");
-								}
-								media_str += (*iter);
-							}
-							new_media = media_query_list::create_from_string(media_str, doc);
-							if(!new_media)
-							{
-								new_media = media;
-							}
-						}
-						parse_stylesheet(css_text.c_str(), css_baseurl.c_str(), doc, new_media);
-					}
-				}
-			}
-		}
-	} else if(text.substr(0, 6) == _t("@media"))
-	{
-		tstring::size_type b1 = text.find_first_of(_t('{'));
-		tstring::size_type b2 = text.find_last_of(_t('}'));
-		if(b1 != tstring::npos)
-		{
-			tstring media_type = text.substr(6, b1 - 6);
-			trim(media_type);
-			media_query_list::ptr new_media = media_query_list::create_from_string(media_type, doc);
-
-			tstring media_style;
-			if(b2 != tstring::npos)
-			{
-				media_style = text.substr(b1 + 1, b2 - b1 - 1);
-			} else
-			{
-				media_style = text.substr(b1 + 1);
-			}
-
-			parse_stylesheet(media_style.c_str(), baseurl, doc, new_media);
-		}
-	}
-}
+#include "html.h"
+#include "stylesheet.h"
+#include <algorithm>
+#include "document.h"
+
+
+void litehtml::css::parse_stylesheet(const tchar_t* str, const tchar_t* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media)
+{
+	tstring text = str;
+
+	// remove comments
+	tstring::size_type c_start = text.find(_t("/*"));
+	while(c_start != tstring::npos)
+	{
+		tstring::size_type c_end = text.find(_t("*/"), c_start + 2);
+		text.erase(c_start, c_end - c_start + 2);
+		c_start = text.find(_t("/*"));
+	}
+
+	tstring::size_type pos = text.find_first_not_of(_t(" \n\r\t"));
+	while(pos != tstring::npos)
+	{
+		while(pos != tstring::npos && text[pos] == _t('@'))
+		{
+			tstring::size_type sPos = pos;
+			pos = text.find_first_of(_t("{;"), pos);
+			if(pos != tstring::npos && text[pos] == _t('{'))
+			{
+				pos = find_close_bracket(text, pos, _t('{'), _t('}'));
+			}
+			if(pos != tstring::npos)
+			{
+				parse_atrule(text.substr(sPos, pos - sPos + 1), baseurl, doc, media);
+			} else
+			{
+				parse_atrule(text.substr(sPos), baseurl, doc, media);
+			}
+
+			if(pos != tstring::npos)
+			{
+				pos = text.find_first_not_of(_t(" \n\r\t"), pos + 1);
+			}
+		}
+
+		if(pos == tstring::npos)
+		{
+			break;
+		}
+
+		tstring::size_type style_start = text.find(_t("{"), pos);
+		tstring::size_type style_end	= text.find(_t("}"), pos);
+		if(style_start != tstring::npos && style_end != tstring::npos)
+		{
+			style::ptr st = std::make_shared<style>();
+			st->add(text.substr(style_start + 1, style_end - style_start - 1).c_str(), baseurl);
+
+			parse_selectors(text.substr(pos, style_start - pos), st, media);
+
+			if(media && doc)
+			{
+				doc->add_media_list(media);
+			}
+
+			pos = style_end + 1;
+		} else
+		{
+			pos = tstring::npos;
+		}
+
+		if(pos != tstring::npos)
+		{
+			pos = text.find_first_not_of(_t(" \n\r\t"), pos);
+		}
+	}
+}
+
+void litehtml::css::parse_css_url( const tstring& str, tstring& url )
+{
+	url = _t("");
+	size_t pos1 = str.find(_t('('));
+	size_t pos2 = str.find(_t(')'));
+	if(pos1 != tstring::npos && pos2 != tstring::npos)
+	{
+		url = str.substr(pos1 + 1, pos2 - pos1 - 1);
+		if(url.length())
+		{
+			if(url[0] == _t('\'') || url[0] == _t('"'))
+			{
+				url.erase(0, 1);
+			}
+		}
+		if(url.length())
+		{
+			if(url[url.length() - 1] == _t('\'') || url[url.length() - 1] == _t('"'))
+			{
+				url.erase(url.length() - 1, 1);
+			}
+		}
+	}
+}
+
+bool litehtml::css::parse_selectors( const tstring& txt, const litehtml::style::ptr& styles, const media_query_list::ptr& media )
+{
+	tstring selector = txt;
+	trim(selector);
+	string_vector tokens;
+	split_string(selector, tokens, _t(","));
+
+	bool added_something = false;
+
+	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+	{
+		css_selector::ptr selector = std::make_shared<css_selector>(media);
+		selector->m_style = styles;
+		trim(*tok);
+		if(selector->parse(*tok))
+		{
+			selector->calc_specificity();
+			add_selector(selector);
+			added_something = true;
+		}
+	}
+
+	return added_something;
+}
+
+void litehtml::css::sort_selectors()
+{
+	std::sort(m_selectors.begin(), m_selectors.end(),
+		 [](const css_selector::ptr& v1, const css_selector::ptr& v2)
+		 {
+			 return (*v1) < (*v2);
+		 }
+	);
+}
+
+void litehtml::css::parse_atrule(const tstring& text, const tchar_t* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media)
+{
+	if(text.substr(0, 7) == _t("@import"))
+	{
+		int sPos = 7;
+		tstring iStr;
+		iStr = text.substr(sPos);
+		if(iStr[iStr.length() - 1] == _t(';'))
+		{
+			iStr.erase(iStr.length() - 1);
+		}
+		trim(iStr);
+		string_vector tokens;
+		split_string(iStr, tokens, _t(" "), _t(""), _t("(\""));
+		if(!tokens.empty())
+		{
+			tstring url;
+			parse_css_url(tokens.front(), url);
+			if(url.empty())
+			{
+				url = tokens.front();
+			}
+			tokens.erase(tokens.begin());
+			if(doc)
+			{
+				document_container* doc_cont = doc->container();
+				if(doc_cont)
+				{
+					tstring css_text;
+					tstring css_baseurl;
+					if(baseurl)
+					{
+						css_baseurl = baseurl;
+					}
+					doc_cont->import_css(css_text, url, css_baseurl);
+					if(!css_text.empty())
+					{
+						media_query_list::ptr new_media = media;
+						if(!tokens.empty())
+						{
+							tstring media_str;
+							for(string_vector::iterator iter = tokens.begin(); iter != tokens.end(); iter++)
+							{
+								if(iter != tokens.begin())
+								{
+									media_str += _t(" ");
+								}
+								media_str += (*iter);
+							}
+							new_media = media_query_list::create_from_string(media_str, doc);
+							if(!new_media)
+							{
+								new_media = media;
+							}
+						}
+						parse_stylesheet(css_text.c_str(), css_baseurl.c_str(), doc, new_media);
+					}
+				}
+			}
+		}
+	} else if(text.substr(0, 6) == _t("@media"))
+	{
+		tstring::size_type b1 = text.find_first_of(_t('{'));
+		tstring::size_type b2 = text.find_last_of(_t('}'));
+		if(b1 != tstring::npos)
+		{
+			tstring media_type = text.substr(6, b1 - 6);
+			trim(media_type);
+			media_query_list::ptr new_media = media_query_list::create_from_string(media_type, doc);
+
+			tstring media_style;
+			if(b2 != tstring::npos)
+			{
+				media_style = text.substr(b1 + 1, b2 - b1 - 1);
+			} else
+			{
+				media_style = text.substr(b1 + 1);
+			}
+
+			parse_stylesheet(media_style.c_str(), baseurl, doc, new_media);
+		}
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/stylesheet.h b/src/plugins/litehtml_viewer/litehtml/stylesheet.h
index 04536c3..84c5f1f 100644
--- a/src/plugins/litehtml_viewer/litehtml/stylesheet.h
+++ b/src/plugins/litehtml_viewer/litehtml/stylesheet.h
@@ -1,50 +1,54 @@
-#pragma once
-#include "style.h"
-#include "css_selector.h"
-
-namespace litehtml
-{
-	class document_container;
-
-	class css
-	{
-		css_selector::vector	m_selectors;
-	public:
-		css()
-		{
-
-		}
-		
-		~css()
-		{
-
-		}
-
-		const css_selector::vector& selectors() const
-		{
-			return m_selectors;
-		}
-
-		void clear()
-		{
-			m_selectors.clear();
-		}
-
-		void	parse_stylesheet(const tchar_t* str, const tchar_t* baseurl, const std::shared_ptr <document>& doc, const media_query_list::ptr& media);
-		void	sort_selectors();
-		static void	parse_css_url(const tstring& str, tstring& url);
-
-	private:
-		void	parse_atrule(const tstring& text, const tchar_t* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media);
-		void	add_selector(css_selector::ptr selector);
-		bool	parse_selectors(const tstring& txt, const litehtml::style::ptr& styles, const media_query_list::ptr& media);
-
-	};
-
-	inline void litehtml::css::add_selector( css_selector::ptr selector )
-	{
-		selector->m_order = (int) m_selectors.size();
-		m_selectors.push_back(selector);
-	}
-
-}
+#ifndef LH_STYLESHEET_H
+#define LH_STYLESHEET_H
+
+#include "style.h"
+#include "css_selector.h"
+
+namespace litehtml
+{
+	class document_container;
+
+	class css
+	{
+		css_selector::vector	m_selectors;
+	public:
+		css()
+		{
+
+		}
+		
+		~css()
+		{
+
+		}
+
+		const css_selector::vector& selectors() const
+		{
+			return m_selectors;
+		}
+
+		void clear()
+		{
+			m_selectors.clear();
+		}
+
+		void	parse_stylesheet(const tchar_t* str, const tchar_t* baseurl, const std::shared_ptr <document>& doc, const media_query_list::ptr& media);
+		void	sort_selectors();
+		static void	parse_css_url(const tstring& str, tstring& url);
+
+	private:
+		void	parse_atrule(const tstring& text, const tchar_t* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media);
+		void	add_selector(css_selector::ptr selector);
+		bool	parse_selectors(const tstring& txt, const litehtml::style::ptr& styles, const media_query_list::ptr& media);
+
+	};
+
+	inline void litehtml::css::add_selector( css_selector::ptr selector )
+	{
+		selector->m_order = (int) m_selectors.size();
+		m_selectors.push_back(selector);
+	}
+
+}
+
+#endif  // LH_STYLESHEET_H
diff --git a/src/plugins/litehtml_viewer/litehtml/table.cpp b/src/plugins/litehtml_viewer/litehtml/table.cpp
index 23d1e9a..c53509c 100644
--- a/src/plugins/litehtml_viewer/litehtml/table.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/table.cpp
@@ -1,566 +1,566 @@
-#include "html.h"
-#include "table.h"
-#include "html_tag.h"
-
-void litehtml::table_grid::add_cell(element::ptr& el)
-{
-	table_cell cell;
-	cell.el = el;
-	cell.colspan	= t_atoi(el->get_attr(_t("colspan"), _t("1")));
-	cell.rowspan	= t_atoi(el->get_attr(_t("rowspan"), _t("1")));
-	cell.borders	= el->get_borders();
-
-	while( is_rowspanned( (int) m_cells.size() - 1, (int) m_cells.back().size() ) )
-	{
-		m_cells.back().push_back(table_cell());
-	}
-
-	m_cells.back().push_back(cell);
-	for(int i = 1; i < cell.colspan; i++)
-	{
-		table_cell empty_cell;
-		m_cells.back().push_back(empty_cell);
-	}
-}
-
-
-void litehtml::table_grid::begin_row(element::ptr& row)
-{
-	std::vector<table_cell> r;
-	m_cells.push_back(r);
-	
-	m_rows.push_back(table_row(0, row));
-
-}
-
-
-bool litehtml::table_grid::is_rowspanned( int r, int c )
-{
-	for(int row = r - 1; row >= 0; row--)
-	{
-		if(c < (int) m_cells[row].size())
-		{
-			if(m_cells[row][c].rowspan > 1)
-			{
-				if(m_cells[row][c].rowspan >= r - row + 1)
-				{
-					return true;
-				}
-			}
-		}
-	}
-	return false;
-}
-
-void litehtml::table_grid::finish()
-{
-	m_rows_count	= (int) m_cells.size();
-	m_cols_count	= 0;
-	for(int i = 0; i < (int) m_cells.size(); i++)
-	{
-		m_cols_count = std::max(m_cols_count, (int) m_cells[i].size());
-	}
-	for(int i = 0; i < (int) m_cells.size(); i++)
-	{
-		for(int j = (int) m_cells[i].size(); j < m_cols_count; j++)
-		{
-			table_cell empty_cell;
-			m_cells[i].push_back(empty_cell);
-		}
-	}
-
-	m_columns.clear();
-	for(int i = 0; i < m_cols_count; i++)
-	{
-		m_columns.push_back(table_column(0, 0));
-	}
-
-	for(int col = 0; col < m_cols_count; col++)
-	{
-		for(int row = 0; row < m_rows_count; row++)
-		{
-			if(cell(col, row)->el)
-			{
-				// find minimum left border width
-				if(m_columns[col].border_left)
-				{
-					m_columns[col].border_left = std::min(m_columns[col].border_left, cell(col, row)->borders.left);
-				} else
-				{
-					m_columns[col].border_left = cell(col, row)->borders.left;
-				}
-				// find minimum right border width
-				if(m_columns[col].border_right)
-				{
-					m_columns[col].border_right = std::min(m_columns[col].border_right, cell(col, row)->borders.right);
-				} else
-				{
-					m_columns[col].border_right = cell(col, row)->borders.right;
-				}
-				// find minimum top border width
-				if(m_rows[row].border_top)
-				{
-					m_rows[row].border_top = std::min(m_rows[row].border_top, cell(col, row)->borders.top);
-				} else
-				{
-					m_rows[row].border_top = cell(col, row)->borders.top;
-				}
-				// find minimum bottom border width
-				if(m_rows[row].border_bottom)
-				{
-					m_rows[row].border_bottom = std::min(m_rows[row].border_bottom, cell(col, row)->borders.bottom);
-				} else
-				{
-					m_rows[row].border_bottom = cell(col, row)->borders.bottom;
-				}
-			}
-
-			if(cell(col, row)->el && cell(col, row)->colspan <= 1)
-			{
-				if (!cell(col, row)->el->get_css_width().is_predefined() && m_columns[col].css_width.is_predefined())
-				{
-					m_columns[col].css_width = cell(col, row)->el->get_css_width();
-				}
-			}
-		}
-	}
-
-	for(int col = 0; col < m_cols_count; col++)
-	{
-		for(int row = 0; row < m_rows_count; row++)
-		{
-			if(cell(col, row)->el)
-			{
-				cell(col, row)->el->set_css_width(m_columns[col].css_width);
-			}
-		}
-	}
-}
-
-litehtml::table_cell* litehtml::table_grid::cell( int t_col, int t_row )
-{
-	if(t_col >= 0 && t_col < m_cols_count && t_row >= 0 && t_row < m_rows_count)
-	{
-		return &m_cells[t_row][t_col];
-	}
-	return 0;
-}
-
-void litehtml::table_grid::distribute_max_width( int width, int start, int end )
-{
-	table_column_accessor_max_width selector;
-	distribute_width(width, start, end, &selector);
-}
-
-void litehtml::table_grid::distribute_min_width( int width, int start, int end )
-{
-	table_column_accessor_min_width selector;
-	distribute_width(width, start, end, &selector);
-}
-
-void litehtml::table_grid::distribute_width( int width, int start, int end, table_column_accessor* acc )
-{
-	if(!(start >= 0 && start < m_cols_count && end >= 0 && end < m_cols_count))
-	{
-		return;
-	}
-
-	int cols_width = 0;
-	for(int col = start; col <= end; col++)
-	{
-		cols_width		+= m_columns[col].max_width;
-	}
-
-	int add = width / (end - start + 1);
-	int added_width = 0;
-	for(int col = start; col <= end; col++)
-	{
-		if(cols_width)
-		{
-			add = round_f( (float) width * ((float) m_columns[col].max_width / (float) cols_width) );
-		}
-		added_width += add;
-		acc->get(m_columns[col]) += add;
-	}
-	if(added_width < width)
-	{
-		acc->get(m_columns[start]) += width - added_width;
-	}
-}
-
-void litehtml::table_grid::distribute_width( int width, int start, int end )
-{
-	if(!(start >= 0 && start < m_cols_count && end >= 0 && end < m_cols_count))
-	{
-		return;
-	}
-
-	std::vector<table_column*> distribute_columns;
-
-	for(int step = 0; step < 3; step++)
-	{
-		distribute_columns.clear();
-
-		switch(step)
-		{
-		case 0:
-			{
-				// distribute between the columns with width == auto
-				for(int col = start; col <= end; col++)
-				{
-					if(m_columns[col].css_width.is_predefined())
-					{
-						distribute_columns.push_back(&m_columns[col]);
-					}
-				}
-			}
-			break;
-		case 1:
-			{
-				// distribute between the columns with percents
-				for(int col = start; col <= end; col++)
-				{
-					if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
-					{
-						distribute_columns.push_back(&m_columns[col]);
-					}
-				}
-			}
-			break;
-		case 2:
-			{
-				//well distribute between all columns
-				for(int col = start; col <= end; col++)
-				{
-					distribute_columns.push_back(&m_columns[col]);
-				}
-			}
-			break;
-		}
-
-		int added_width = 0;
-
-		if(!distribute_columns.empty() || step == 2)
-		{
-			int cols_width = 0;
-			for(std::vector<table_column*>::iterator col = distribute_columns.begin(); col != distribute_columns.end(); col++)
-			{
-				cols_width += (*col)->max_width - (*col)->min_width;
-			}
-
-			if(cols_width)
-			{
-				int add = width / (int) distribute_columns.size();
-				for(std::vector<table_column*>::iterator col = distribute_columns.begin(); col != distribute_columns.end(); col++)
-				{
-					add = round_f( (float) width * ((float) ((*col)->max_width - (*col)->min_width) / (float) cols_width) );
-					if((*col)->width + add >= (*col)->min_width)
-					{
-						(*col)->width	+= add;
-						added_width		+= add;
-					} else
-					{
-						added_width	+= ((*col)->width - (*col)->min_width) * (add / abs(add));
-						(*col)->width = (*col)->min_width;
-					}
-				}
-				if(added_width < width && step)
-				{
-					distribute_columns.front()->width += width - added_width;
-					added_width = width;
-				}
-			} else
-			{
-				distribute_columns.back()->width += width;
-				added_width = width;
-			}
-		}
-
-		if(added_width == width)
-		{
-			break;
-		} else
-		{
-			width -= added_width;
-		}
-	}
-}
-
-int litehtml::table_grid::calc_table_width(int block_width, bool is_auto, int& min_table_width, int& max_table_width)
-{
-	//int table_width = 0;
-
-	min_table_width = 0; // MIN
-	max_table_width = 0; // MAX
-
-	int cur_width = 0;
-	int max_w = 0;
-	int min_w = 0;
-
-	for(int col = 0; col < m_cols_count; col++)
-	{
-		min_table_width += m_columns[col].min_width;
-		max_table_width += m_columns[col].max_width;
-
-		if(!m_columns[col].css_width.is_predefined())
-		{
-			m_columns[col].width = m_columns[col].css_width.calc_percent(block_width);
-			m_columns[col].width = std::max(m_columns[col].width, m_columns[col].min_width);
-		} else
-		{
-			m_columns[col].width = m_columns[col].min_width;
-			max_w += m_columns[col].max_width;
-			min_w += m_columns[col].min_width;
-		}
-
-		cur_width += m_columns[col].width;
-	}
-
-	if(cur_width == block_width)
-	{
-		return cur_width;
-	}
-
-	if(cur_width < block_width)
-	{
-		if(cur_width - min_w + max_w <= block_width)
-		{
-			cur_width = 0;
-			for(int col = 0; col < m_cols_count; col++)
-			{
-				if(m_columns[col].css_width.is_predefined())
-				{
-					m_columns[col].width = m_columns[col].max_width;
-				}
-				cur_width += m_columns[col].width;
-			}
-			if(cur_width == block_width || is_auto)
-			{
-				return cur_width;
-			}
-		}
-		distribute_width(block_width - cur_width, 0, m_cols_count - 1);
-		cur_width = 0;
-		for(int col = 0; col < m_cols_count; col++)
-		{
-			cur_width += m_columns[col].width;
-		}
-	} else
-	{
-		int fixed_width = 0;
-		float percent = 0;
-		for(int col = 0; col < m_cols_count; col++)
-		{
-			if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
-			{
-				percent += m_columns[col].css_width.val();
-			} else
-			{
-				fixed_width += m_columns[col].width;
-			}
-		}
-		float scale = (float) (100.0 / percent);
-		cur_width = 0;
-		for(int col = 0; col < m_cols_count; col++)
-		{
-			if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
-			{
-				css_length w;
-				w.set_value(m_columns[col].css_width.val() * scale, css_units_percentage);
-				m_columns[col].width = w.calc_percent(block_width - fixed_width);
-				if(m_columns[col].width < m_columns[col].min_width)
-				{
-					m_columns[col].width = m_columns[col].min_width;
-				}
-			}
-			cur_width += m_columns[col].width;
-		}
-	}
-	return cur_width;
-}
-
-void litehtml::table_grid::clear()
-{
-	m_rows_count	= 0;
-	m_cols_count	= 0;
-	m_cells.clear();
-	m_columns.clear();
-	m_rows.clear();
-}
-
-void litehtml::table_grid::calc_horizontal_positions( margins& table_borders, border_collapse bc, int bdr_space_x)
-{
-	if(bc == border_collapse_separate)
-	{
-		int left = bdr_space_x;
-		for(int i = 0; i < m_cols_count; i++)
-		{
-			m_columns[i].left	= left;
-			m_columns[i].right	= m_columns[i].left + m_columns[i].width;
-			left = m_columns[i].right + bdr_space_x;
-		}
-	} else
-	{
-		int left = 0;
-		if(m_cols_count)
-		{
-			left -= std::min(table_borders.left, m_columns[0].border_left);
-		}
-		for(int i = 0; i < m_cols_count; i++)
-		{
-			if(i > 0)
-			{
-				left -= std::min(m_columns[i - 1].border_right, m_columns[i].border_left);
-			}
-
-			m_columns[i].left	= left;
-			m_columns[i].right	= m_columns[i].left + m_columns[i].width;
-			left = m_columns[i].right;
-		}
-	}
-}
-
-void litehtml::table_grid::calc_vertical_positions( margins& table_borders, border_collapse bc, int bdr_space_y )
-{
-	if(bc == border_collapse_separate)
-	{
-		int top = bdr_space_y;
-		for(int i = 0; i < m_rows_count; i++)
-		{
-			m_rows[i].top		= top;
-			m_rows[i].bottom	= m_rows[i].top + m_rows[i].height;
-			top = m_rows[i].bottom + bdr_space_y;
-		}
-	} else
-	{
-		int top = 0;
-		if(m_rows_count)
-		{
-			top -= std::min(table_borders.top, m_rows[0].border_top);
-		}
-		for(int i = 0; i < m_rows_count; i++)
-		{
-			if(i > 0)
-			{
-				top -= std::min(m_rows[i - 1].border_bottom, m_rows[i].border_top);
-			}
-
-			m_rows[i].top		= top;
-			m_rows[i].bottom	= m_rows[i].top + m_rows[i].height;
-			top = m_rows[i].bottom;
-		}
-	}
-}
-
-void litehtml::table_grid::calc_rows_height(int blockHeight, int borderSpacingY)
-{
-	int min_table_height = 0;
-
-	// compute vertical size inferred by cells
-	for (auto& row : m_rows)
-	{
-		if (!row.css_height.is_predefined())
-		{
-			if (row.css_height.units() != css_units_percentage)
-			{
-				if (row.height < (int)row.css_height.val())
-				{
-					row.height = (int)row.css_height.val();
-				}
-			}
-		}
-		row.min_height = row.height;
-		min_table_height += row.height;
-	}
-
-	//min_table_height += borderSpacingY * ((int) m_rows.size() + 1);
-
-	if (blockHeight > min_table_height)
-	{
-		int extra_height = blockHeight - min_table_height;
-		int auto_count = 0; // number of rows with height=auto
-		for (auto& row : m_rows)
-		{
-			if (!row.css_height.is_predefined() && row.css_height.units() == css_units_percentage)
-			{
-				row.height = row.css_height.calc_percent(blockHeight);
-				if (row.height < row.min_height)
-				{
-					row.height = row.min_height;
-				}
-
-				extra_height -= row.height - row.min_height;
-
-				if (extra_height <= 0) break;
-			}
-			else if (row.css_height.is_predefined())
-			{
-				auto_count++;
-			}
-		}
-		if (extra_height > 0)
-		{
-			if (auto_count)
-			{
-				// distribute height to the rows with height=auto
-				int extra_row_height = (int)(extra_height / auto_count);
-				for (auto& row : m_rows)
-				{
-					if (row.css_height.is_predefined())
-					{
-						row.height += extra_row_height;
-					}
-				}
-			}
-			else
-			{
-				// We don't have rows with height=auto, so distribute height to all rows
-				if (!m_rows.empty())
-				{
-					int extra_row_height = (int)(extra_height / m_rows.size());
-					for (auto& row : m_rows)
-					{
-						row.height += extra_row_height;
-					}
-				}
-			}
-		}
-		else if (extra_height < 0)
-		{
-			extra_height = -extra_height;
-			for (auto row = m_rows.rbegin(); row < m_rows.rend() && extra_height > 0; row++)
-			{
-				if (row->height > row->min_height)
-				{
-					if (row->height - extra_height >= row->min_height)
-					{
-						row->height -= extra_height;
-						extra_height = 0;
-					}
-					else
-					{
-						extra_height -= row->height - row->min_height;
-						row->height = row->min_height;
-					}
-				}
-			}
-		}
-	}
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-int& litehtml::table_column_accessor_max_width::get( table_column& col )
-{
-	return col.max_width;
-}
-
-int& litehtml::table_column_accessor_min_width::get( table_column& col )
-{
-	return col.min_width;
-}
-
-int& litehtml::table_column_accessor_width::get( table_column& col )
-{
-	return col.width;
-}
+#include "html.h"
+#include "table.h"
+#include "html_tag.h"
+
+void litehtml::table_grid::add_cell(element::ptr& el)
+{
+	table_cell cell;
+	cell.el = el;
+	cell.colspan	= t_atoi(el->get_attr(_t("colspan"), _t("1")));
+	cell.rowspan	= t_atoi(el->get_attr(_t("rowspan"), _t("1")));
+	cell.borders	= el->get_borders();
+
+	while( is_rowspanned( (int) m_cells.size() - 1, (int) m_cells.back().size() ) )
+	{
+		m_cells.back().push_back(table_cell());
+	}
+
+	m_cells.back().push_back(cell);
+	for(int i = 1; i < cell.colspan; i++)
+	{
+		table_cell empty_cell;
+		m_cells.back().push_back(empty_cell);
+	}
+}
+
+
+void litehtml::table_grid::begin_row(element::ptr& row)
+{
+	std::vector<table_cell> r;
+	m_cells.push_back(r);
+	
+	m_rows.push_back(table_row(0, row));
+
+}
+
+
+bool litehtml::table_grid::is_rowspanned( int r, int c )
+{
+	for(int row = r - 1; row >= 0; row--)
+	{
+		if(c < (int) m_cells[row].size())
+		{
+			if(m_cells[row][c].rowspan > 1)
+			{
+				if(m_cells[row][c].rowspan >= r - row + 1)
+				{
+					return true;
+				}
+			}
+		}
+	}
+	return false;
+}
+
+void litehtml::table_grid::finish()
+{
+	m_rows_count	= (int) m_cells.size();
+	m_cols_count	= 0;
+	for(int i = 0; i < (int) m_cells.size(); i++)
+	{
+		m_cols_count = std::max(m_cols_count, (int) m_cells[i].size());
+	}
+	for(int i = 0; i < (int) m_cells.size(); i++)
+	{
+		for(int j = (int) m_cells[i].size(); j < m_cols_count; j++)
+		{
+			table_cell empty_cell;
+			m_cells[i].push_back(empty_cell);
+		}
+	}
+
+	m_columns.clear();
+	for(int i = 0; i < m_cols_count; i++)
+	{
+		m_columns.push_back(table_column(0, 0));
+	}
+
+	for(int col = 0; col < m_cols_count; col++)
+	{
+		for(int row = 0; row < m_rows_count; row++)
+		{
+			if(cell(col, row)->el)
+			{
+				// find minimum left border width
+				if(m_columns[col].border_left)
+				{
+					m_columns[col].border_left = std::min(m_columns[col].border_left, cell(col, row)->borders.left);
+				} else
+				{
+					m_columns[col].border_left = cell(col, row)->borders.left;
+				}
+				// find minimum right border width
+				if(m_columns[col].border_right)
+				{
+					m_columns[col].border_right = std::min(m_columns[col].border_right, cell(col, row)->borders.right);
+				} else
+				{
+					m_columns[col].border_right = cell(col, row)->borders.right;
+				}
+				// find minimum top border width
+				if(m_rows[row].border_top)
+				{
+					m_rows[row].border_top = std::min(m_rows[row].border_top, cell(col, row)->borders.top);
+				} else
+				{
+					m_rows[row].border_top = cell(col, row)->borders.top;
+				}
+				// find minimum bottom border width
+				if(m_rows[row].border_bottom)
+				{
+					m_rows[row].border_bottom = std::min(m_rows[row].border_bottom, cell(col, row)->borders.bottom);
+				} else
+				{
+					m_rows[row].border_bottom = cell(col, row)->borders.bottom;
+				}
+			}
+
+			if(cell(col, row)->el && cell(col, row)->colspan <= 1)
+			{
+				if (!cell(col, row)->el->get_css_width().is_predefined() && m_columns[col].css_width.is_predefined())
+				{
+					m_columns[col].css_width = cell(col, row)->el->get_css_width();
+				}
+			}
+		}
+	}
+
+	for(int col = 0; col < m_cols_count; col++)
+	{
+		for(int row = 0; row < m_rows_count; row++)
+		{
+			if(cell(col, row)->el)
+			{
+				cell(col, row)->el->set_css_width(m_columns[col].css_width);
+			}
+		}
+	}
+}
+
+litehtml::table_cell* litehtml::table_grid::cell( int t_col, int t_row )
+{
+	if(t_col >= 0 && t_col < m_cols_count && t_row >= 0 && t_row < m_rows_count)
+	{
+		return &m_cells[t_row][t_col];
+	}
+	return 0;
+}
+
+void litehtml::table_grid::distribute_max_width( int width, int start, int end )
+{
+	table_column_accessor_max_width selector;
+	distribute_width(width, start, end, &selector);
+}
+
+void litehtml::table_grid::distribute_min_width( int width, int start, int end )
+{
+	table_column_accessor_min_width selector;
+	distribute_width(width, start, end, &selector);
+}
+
+void litehtml::table_grid::distribute_width( int width, int start, int end, table_column_accessor* acc )
+{
+	if(!(start >= 0 && start < m_cols_count && end >= 0 && end < m_cols_count))
+	{
+		return;
+	}
+
+	int cols_width = 0;
+	for(int col = start; col <= end; col++)
+	{
+		cols_width		+= m_columns[col].max_width;
+	}
+
+	int add = width / (end - start + 1);
+	int added_width = 0;
+	for(int col = start; col <= end; col++)
+	{
+		if(cols_width)
+		{
+			add = round_f( (float) width * ((float) m_columns[col].max_width / (float) cols_width) );
+		}
+		added_width += add;
+		acc->get(m_columns[col]) += add;
+	}
+	if(added_width < width)
+	{
+		acc->get(m_columns[start]) += width - added_width;
+	}
+}
+
+void litehtml::table_grid::distribute_width( int width, int start, int end )
+{
+	if(!(start >= 0 && start < m_cols_count && end >= 0 && end < m_cols_count))
+	{
+		return;
+	}
+
+	std::vector<table_column*> distribute_columns;
+
+	for(int step = 0; step < 3; step++)
+	{
+		distribute_columns.clear();
+
+		switch(step)
+		{
+		case 0:
+			{
+				// distribute between the columns with width == auto
+				for(int col = start; col <= end; col++)
+				{
+					if(m_columns[col].css_width.is_predefined())
+					{
+						distribute_columns.push_back(&m_columns[col]);
+					}
+				}
+			}
+			break;
+		case 1:
+			{
+				// distribute between the columns with percents
+				for(int col = start; col <= end; col++)
+				{
+					if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
+					{
+						distribute_columns.push_back(&m_columns[col]);
+					}
+				}
+			}
+			break;
+		case 2:
+			{
+				//well distribute between all columns
+				for(int col = start; col <= end; col++)
+				{
+					distribute_columns.push_back(&m_columns[col]);
+				}
+			}
+			break;
+		}
+
+		int added_width = 0;
+
+		if(!distribute_columns.empty() || step == 2)
+		{
+			int cols_width = 0;
+			for(std::vector<table_column*>::iterator col = distribute_columns.begin(); col != distribute_columns.end(); col++)
+			{
+				cols_width += (*col)->max_width - (*col)->min_width;
+			}
+
+			if(cols_width)
+			{
+				int add = width / (int) distribute_columns.size();
+				for(std::vector<table_column*>::iterator col = distribute_columns.begin(); col != distribute_columns.end(); col++)
+				{
+					add = round_f( (float) width * ((float) ((*col)->max_width - (*col)->min_width) / (float) cols_width) );
+					if((*col)->width + add >= (*col)->min_width)
+					{
+						(*col)->width	+= add;
+						added_width		+= add;
+					} else
+					{
+						added_width	+= ((*col)->width - (*col)->min_width) * (add / abs(add));
+						(*col)->width = (*col)->min_width;
+					}
+				}
+				if(added_width < width && step)
+				{
+					distribute_columns.front()->width += width - added_width;
+					added_width = width;
+				}
+			} else
+			{
+				distribute_columns.back()->width += width;
+				added_width = width;
+			}
+		}
+
+		if(added_width == width)
+		{
+			break;
+		} else
+		{
+			width -= added_width;
+		}
+	}
+}
+
+int litehtml::table_grid::calc_table_width(int block_width, bool is_auto, int& min_table_width, int& max_table_width)
+{
+	//int table_width = 0;
+
+	min_table_width = 0; // MIN
+	max_table_width = 0; // MAX
+
+	int cur_width = 0;
+	int max_w = 0;
+	int min_w = 0;
+
+	for(int col = 0; col < m_cols_count; col++)
+	{
+		min_table_width += m_columns[col].min_width;
+		max_table_width += m_columns[col].max_width;
+
+		if(!m_columns[col].css_width.is_predefined())
+		{
+			m_columns[col].width = m_columns[col].css_width.calc_percent(block_width);
+			m_columns[col].width = std::max(m_columns[col].width, m_columns[col].min_width);
+		} else
+		{
+			m_columns[col].width = m_columns[col].min_width;
+			max_w += m_columns[col].max_width;
+			min_w += m_columns[col].min_width;
+		}
+
+		cur_width += m_columns[col].width;
+	}
+
+	if(cur_width == block_width)
+	{
+		return cur_width;
+	}
+
+	if(cur_width < block_width)
+	{
+		if(cur_width - min_w + max_w <= block_width)
+		{
+			cur_width = 0;
+			for(int col = 0; col < m_cols_count; col++)
+			{
+				if(m_columns[col].css_width.is_predefined())
+				{
+					m_columns[col].width = m_columns[col].max_width;
+				}
+				cur_width += m_columns[col].width;
+			}
+			if(cur_width == block_width || is_auto)
+			{
+				return cur_width;
+			}
+		}
+		distribute_width(block_width - cur_width, 0, m_cols_count - 1);
+		cur_width = 0;
+		for(int col = 0; col < m_cols_count; col++)
+		{
+			cur_width += m_columns[col].width;
+		}
+	} else
+	{
+		int fixed_width = 0;
+		float percent = 0;
+		for(int col = 0; col < m_cols_count; col++)
+		{
+			if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
+			{
+				percent += m_columns[col].css_width.val();
+			} else
+			{
+				fixed_width += m_columns[col].width;
+			}
+		}
+		float scale = (float) (100.0 / percent);
+		cur_width = 0;
+		for(int col = 0; col < m_cols_count; col++)
+		{
+			if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
+			{
+				css_length w;
+				w.set_value(m_columns[col].css_width.val() * scale, css_units_percentage);
+				m_columns[col].width = w.calc_percent(block_width - fixed_width);
+				if(m_columns[col].width < m_columns[col].min_width)
+				{
+					m_columns[col].width = m_columns[col].min_width;
+				}
+			}
+			cur_width += m_columns[col].width;
+		}
+	}
+	return cur_width;
+}
+
+void litehtml::table_grid::clear()
+{
+	m_rows_count	= 0;
+	m_cols_count	= 0;
+	m_cells.clear();
+	m_columns.clear();
+	m_rows.clear();
+}
+
+void litehtml::table_grid::calc_horizontal_positions( margins& table_borders, border_collapse bc, int bdr_space_x)
+{
+	if(bc == border_collapse_separate)
+	{
+		int left = bdr_space_x;
+		for(int i = 0; i < m_cols_count; i++)
+		{
+			m_columns[i].left	= left;
+			m_columns[i].right	= m_columns[i].left + m_columns[i].width;
+			left = m_columns[i].right + bdr_space_x;
+		}
+	} else
+	{
+		int left = 0;
+		if(m_cols_count)
+		{
+			left -= std::min(table_borders.left, m_columns[0].border_left);
+		}
+		for(int i = 0; i < m_cols_count; i++)
+		{
+			if(i > 0)
+			{
+				left -= std::min(m_columns[i - 1].border_right, m_columns[i].border_left);
+			}
+
+			m_columns[i].left	= left;
+			m_columns[i].right	= m_columns[i].left + m_columns[i].width;
+			left = m_columns[i].right;
+		}
+	}
+}
+
+void litehtml::table_grid::calc_vertical_positions( margins& table_borders, border_collapse bc, int bdr_space_y )
+{
+	if(bc == border_collapse_separate)
+	{
+		int top = bdr_space_y;
+		for(int i = 0; i < m_rows_count; i++)
+		{
+			m_rows[i].top		= top;
+			m_rows[i].bottom	= m_rows[i].top + m_rows[i].height;
+			top = m_rows[i].bottom + bdr_space_y;
+		}
+	} else
+	{
+		int top = 0;
+		if(m_rows_count)
+		{
+			top -= std::min(table_borders.top, m_rows[0].border_top);
+		}
+		for(int i = 0; i < m_rows_count; i++)
+		{
+			if(i > 0)
+			{
+				top -= std::min(m_rows[i - 1].border_bottom, m_rows[i].border_top);
+			}
+
+			m_rows[i].top		= top;
+			m_rows[i].bottom	= m_rows[i].top + m_rows[i].height;
+			top = m_rows[i].bottom;
+		}
+	}
+}
+
+void litehtml::table_grid::calc_rows_height(int blockHeight, int borderSpacingY)
+{
+	int min_table_height = 0;
+
+	// compute vertical size inferred by cells
+	for (auto& row : m_rows)
+	{
+		if (!row.css_height.is_predefined())
+		{
+			if (row.css_height.units() != css_units_percentage)
+			{
+				if (row.height < (int)row.css_height.val())
+				{
+					row.height = (int)row.css_height.val();
+				}
+			}
+		}
+		row.min_height = row.height;
+		min_table_height += row.height;
+	}
+
+	//min_table_height += borderSpacingY * ((int) m_rows.size() + 1);
+
+	if (blockHeight > min_table_height)
+	{
+		int extra_height = blockHeight - min_table_height;
+		int auto_count = 0; // number of rows with height=auto
+		for (auto& row : m_rows)
+		{
+			if (!row.css_height.is_predefined() && row.css_height.units() == css_units_percentage)
+			{
+				row.height = row.css_height.calc_percent(blockHeight);
+				if (row.height < row.min_height)
+				{
+					row.height = row.min_height;
+				}
+
+				extra_height -= row.height - row.min_height;
+
+				if (extra_height <= 0) break;
+			}
+			else if (row.css_height.is_predefined())
+			{
+				auto_count++;
+			}
+		}
+		if (extra_height > 0)
+		{
+			if (auto_count)
+			{
+				// distribute height to the rows with height=auto
+				int extra_row_height = (int)(extra_height / auto_count);
+				for (auto& row : m_rows)
+				{
+					if (row.css_height.is_predefined())
+					{
+						row.height += extra_row_height;
+					}
+				}
+			}
+			else
+			{
+				// We don't have rows with height=auto, so distribute height to all rows
+				if (!m_rows.empty())
+				{
+					int extra_row_height = (int)(extra_height / m_rows.size());
+					for (auto& row : m_rows)
+					{
+						row.height += extra_row_height;
+					}
+				}
+			}
+		}
+		else if (extra_height < 0)
+		{
+			extra_height = -extra_height;
+			for (auto row = m_rows.rbegin(); row < m_rows.rend() && extra_height > 0; row++)
+			{
+				if (row->height > row->min_height)
+				{
+					if (row->height - extra_height >= row->min_height)
+					{
+						row->height -= extra_height;
+						extra_height = 0;
+					}
+					else
+					{
+						extra_height -= row->height - row->min_height;
+						row->height = row->min_height;
+					}
+				}
+			}
+		}
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+int& litehtml::table_column_accessor_max_width::get( table_column& col )
+{
+	return col.max_width;
+}
+
+int& litehtml::table_column_accessor_min_width::get( table_column& col )
+{
+	return col.min_width;
+}
+
+int& litehtml::table_column_accessor_width::get( table_column& col )
+{
+	return col.width;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/table.h b/src/plugins/litehtml_viewer/litehtml/table.h
index 6f23b97..ca95feb 100644
--- a/src/plugins/litehtml_viewer/litehtml/table.h
+++ b/src/plugins/litehtml_viewer/litehtml/table.h
@@ -1,238 +1,241 @@
-#pragma once
-
-namespace litehtml
-{
-	struct table_row
-	{
-		typedef std::vector<table_row>	vector;
-
-		int				height;
-		int				border_top;
-		int				border_bottom;
-		element::ptr	el_row;
-		int				top;
-		int				bottom;
-		css_length		css_height;
-		int				min_height;
-
-		table_row()
-		{
-			min_height		= 0;
-			top				= 0;
-			bottom			= 0;
-			border_bottom	= 0;
-			border_top		= 0;
-			height			= 0;
-			el_row			= nullptr;
-			css_height.predef(0);
-		}
-
-		table_row(int h, element::ptr& row)
-		{
-			min_height		= 0;
-			height			= h;
-			el_row			= row;
-			border_bottom	= 0;
-			border_top		= 0;
-			top				= 0;
-			bottom			= 0;
-			if (row)
-			{
-				css_height = row->get_css_height();
-			}
-		}
-
-		table_row(const table_row& val)
-		{
-			min_height = val.min_height;
-			top = val.top;
-			bottom = val.bottom;
-			border_bottom = val.border_bottom;
-			border_top = val.border_top;
-			height = val.height;
-			css_height = val.css_height;
-			el_row = val.el_row;
-		}
-
-		table_row(table_row&& val)
-		{
-			min_height = val.min_height;
-			top = val.top;
-			bottom = val.bottom;
-			border_bottom = val.border_bottom;
-			border_top = val.border_top;
-			height = val.height;
-			css_height = val.css_height;
-			el_row = std::move(val.el_row);
-		}
-	};
-
-	struct table_column
-	{
-		typedef std::vector<table_column>	vector;
-		
-		int			min_width;
-		int			max_width;
-		int			width;
-		css_length	css_width;
-		int			border_left;
-		int			border_right;
-		int			left;
-		int			right;
-
-		table_column()
-		{
-			left			= 0;
-			right			= 0;
-			border_left		= 0;
-			border_right	= 0;
-			min_width		= 0;
-			max_width		= 0;
-			width			= 0;
-			css_width.predef(0);
-		}
-
-		table_column(int min_w, int max_w)
-		{
-			left			= 0;
-			right			= 0;
-			border_left		= 0;
-			border_right	= 0;
-			max_width		= max_w;
-			min_width		= min_w;
-			width			= 0;
-			css_width.predef(0);
-		}
-
-		table_column(const table_column& val)
-		{
-			left			= val.left;
-			right			= val.right;
-			border_left		= val.border_left;
-			border_right	= val.border_right;
-			max_width		= val.max_width;
-			min_width		= val.min_width;
-			width			= val.width;
-			css_width		= val.css_width;
-		}
-	};
-
-	class table_column_accessor
-	{
-	public:
-		virtual int& get(table_column& col) = 0;
-	};
-
-	class table_column_accessor_max_width : public table_column_accessor
-	{
-	public:
-		virtual int& get(table_column& col);
-	};
-
-	class table_column_accessor_min_width : public table_column_accessor
-	{
-	public:
-		virtual int& get(table_column& col);
-	};
-
-	class table_column_accessor_width : public table_column_accessor
-	{
-	public:
-		virtual int& get(table_column& col);
-	};
-
-	struct table_cell
-	{
-		element::ptr	el;
-		int				colspan;
-		int				rowspan;
-		int				min_width;
-		int				min_height;
-		int				max_width;
-		int				max_height;
-		int				width;
-		int				height;
-		margins			borders;
-
-		table_cell()
-		{
-			min_width		= 0;
-			min_height		= 0;
-			max_width		= 0;
-			max_height		= 0;
-			width			= 0;
-			height			= 0;
-			colspan			= 1;
-			rowspan			= 1;
-			el				= nullptr;
-		}
-
-		table_cell(const table_cell& val)
-		{
-			el				= val.el;
-			colspan			= val.colspan;
-			rowspan			= val.rowspan;
-			width			= val.width;
-			height			= val.height;
-			min_width		= val.min_width;
-			min_height		= val.min_height;
-			max_width		= val.max_width;
-			max_height		= val.max_height;
-			borders			= val.borders;
-		}
-
-		table_cell(const table_cell&& val)
-		{
-			el = std::move(val.el);
-			colspan = val.colspan;
-			rowspan = val.rowspan;
-			width = val.width;
-			height = val.height;
-			min_width = val.min_width;
-			min_height = val.min_height;
-			max_width = val.max_width;
-			max_height = val.max_height;
-			borders = val.borders;
-		}
-	};
-
-	class table_grid
-	{
-	public:
-		typedef std::vector< std::vector<table_cell> >	rows;
-	private:
-		int						m_rows_count;
-		int						m_cols_count;
-		rows					m_cells;
-		table_column::vector	m_columns;
-		table_row::vector		m_rows;
-	public:
-
-		table_grid()
-		{
-			m_rows_count	= 0;
-			m_cols_count	= 0;
-		}
-
-		void			clear();
-		void			begin_row(element::ptr& row);
-		void			add_cell(element::ptr& el);
-		bool			is_rowspanned(int r, int c);
-		void			finish();
-		table_cell*		cell(int t_col, int t_row);
-		table_column&	column(int c)	{ return m_columns[c];	}
-		table_row&		row(int r)		{ return m_rows[r];		}
-
-		int				rows_count()	{ return m_rows_count;	}
-		int				cols_count()	{ return m_cols_count;	}
-
-		void			distribute_max_width(int width, int start, int end);
-		void			distribute_min_width(int width, int start, int end);
-		void			distribute_width(int width, int start, int end);
-		void			distribute_width(int width, int start, int end, table_column_accessor* acc);
-		int				calc_table_width(int block_width, bool is_auto, int& min_table_width, int& max_table_width);
-		void			calc_horizontal_positions(margins& table_borders, border_collapse bc, int bdr_space_x);
-		void			calc_vertical_positions(margins& table_borders, border_collapse bc, int bdr_space_y);
-		void			calc_rows_height(int blockHeight, int borderSpacingY);
-	};
-}
\ No newline at end of file
+#ifndef LH_TABLE_H
+#define LH_TABLE_H
+
+namespace litehtml
+{
+	struct table_row
+	{
+		typedef std::vector<table_row>	vector;
+
+		int				height;
+		int				border_top;
+		int				border_bottom;
+		element::ptr	el_row;
+		int				top;
+		int				bottom;
+		css_length		css_height;
+		int				min_height;
+
+		table_row()
+		{
+			min_height		= 0;
+			top				= 0;
+			bottom			= 0;
+			border_bottom	= 0;
+			border_top		= 0;
+			height			= 0;
+			el_row			= nullptr;
+			css_height.predef(0);
+		}
+
+		table_row(int h, element::ptr& row)
+		{
+			min_height		= 0;
+			height			= h;
+			el_row			= row;
+			border_bottom	= 0;
+			border_top		= 0;
+			top				= 0;
+			bottom			= 0;
+			if (row)
+			{
+				css_height = row->get_css_height();
+			}
+		}
+
+		table_row(const table_row& val)
+		{
+			min_height = val.min_height;
+			top = val.top;
+			bottom = val.bottom;
+			border_bottom = val.border_bottom;
+			border_top = val.border_top;
+			height = val.height;
+			css_height = val.css_height;
+			el_row = val.el_row;
+		}
+
+		table_row(table_row&& val)
+		{
+			min_height = val.min_height;
+			top = val.top;
+			bottom = val.bottom;
+			border_bottom = val.border_bottom;
+			border_top = val.border_top;
+			height = val.height;
+			css_height = val.css_height;
+			el_row = std::move(val.el_row);
+		}
+	};
+
+	struct table_column
+	{
+		typedef std::vector<table_column>	vector;
+		
+		int			min_width;
+		int			max_width;
+		int			width;
+		css_length	css_width;
+		int			border_left;
+		int			border_right;
+		int			left;
+		int			right;
+
+		table_column()
+		{
+			left			= 0;
+			right			= 0;
+			border_left		= 0;
+			border_right	= 0;
+			min_width		= 0;
+			max_width		= 0;
+			width			= 0;
+			css_width.predef(0);
+		}
+
+		table_column(int min_w, int max_w)
+		{
+			left			= 0;
+			right			= 0;
+			border_left		= 0;
+			border_right	= 0;
+			max_width		= max_w;
+			min_width		= min_w;
+			width			= 0;
+			css_width.predef(0);
+		}
+
+		table_column(const table_column& val)
+		{
+			left			= val.left;
+			right			= val.right;
+			border_left		= val.border_left;
+			border_right	= val.border_right;
+			max_width		= val.max_width;
+			min_width		= val.min_width;
+			width			= val.width;
+			css_width		= val.css_width;
+		}
+	};
+
+	class table_column_accessor
+	{
+	public:
+		virtual int& get(table_column& col) = 0;
+	};
+
+	class table_column_accessor_max_width : public table_column_accessor
+	{
+	public:
+		virtual int& get(table_column& col);
+	};
+
+	class table_column_accessor_min_width : public table_column_accessor
+	{
+	public:
+		virtual int& get(table_column& col);
+	};
+
+	class table_column_accessor_width : public table_column_accessor
+	{
+	public:
+		virtual int& get(table_column& col);
+	};
+
+	struct table_cell
+	{
+		element::ptr	el;
+		int				colspan;
+		int				rowspan;
+		int				min_width;
+		int				min_height;
+		int				max_width;
+		int				max_height;
+		int				width;
+		int				height;
+		margins			borders;
+
+		table_cell()
+		{
+			min_width		= 0;
+			min_height		= 0;
+			max_width		= 0;
+			max_height		= 0;
+			width			= 0;
+			height			= 0;
+			colspan			= 1;
+			rowspan			= 1;
+			el				= nullptr;
+		}
+
+		table_cell(const table_cell& val)
+		{
+			el				= val.el;
+			colspan			= val.colspan;
+			rowspan			= val.rowspan;
+			width			= val.width;
+			height			= val.height;
+			min_width		= val.min_width;
+			min_height		= val.min_height;
+			max_width		= val.max_width;
+			max_height		= val.max_height;
+			borders			= val.borders;
+		}
+
+		table_cell(const table_cell&& val)
+		{
+			el = std::move(val.el);
+			colspan = val.colspan;
+			rowspan = val.rowspan;
+			width = val.width;
+			height = val.height;
+			min_width = val.min_width;
+			min_height = val.min_height;
+			max_width = val.max_width;
+			max_height = val.max_height;
+			borders = val.borders;
+		}
+	};
+
+	class table_grid
+	{
+	public:
+		typedef std::vector< std::vector<table_cell> >	rows;
+	private:
+		int						m_rows_count;
+		int						m_cols_count;
+		rows					m_cells;
+		table_column::vector	m_columns;
+		table_row::vector		m_rows;
+	public:
+
+		table_grid()
+		{
+			m_rows_count	= 0;
+			m_cols_count	= 0;
+		}
+
+		void			clear();
+		void			begin_row(element::ptr& row);
+		void			add_cell(element::ptr& el);
+		bool			is_rowspanned(int r, int c);
+		void			finish();
+		table_cell*		cell(int t_col, int t_row);
+		table_column&	column(int c)	{ return m_columns[c];	}
+		table_row&		row(int r)		{ return m_rows[r];		}
+
+		int				rows_count()	{ return m_rows_count;	}
+		int				cols_count()	{ return m_cols_count;	}
+
+		void			distribute_max_width(int width, int start, int end);
+		void			distribute_min_width(int width, int start, int end);
+		void			distribute_width(int width, int start, int end);
+		void			distribute_width(int width, int start, int end, table_column_accessor* acc);
+		int				calc_table_width(int block_width, bool is_auto, int& min_table_width, int& max_table_width);
+		void			calc_horizontal_positions(margins& table_borders, border_collapse bc, int bdr_space_x);
+		void			calc_vertical_positions(margins& table_borders, border_collapse bc, int bdr_space_y);
+		void			calc_rows_height(int blockHeight, int borderSpacingY);
+	};
+}
+
+#endif  // LH_TABLE_H
diff --git a/src/plugins/litehtml_viewer/litehtml/types.h b/src/plugins/litehtml_viewer/litehtml/types.h
index bb292a4..7d3b6dc 100644
--- a/src/plugins/litehtml_viewer/litehtml/types.h
+++ b/src/plugins/litehtml_viewer/litehtml/types.h
@@ -1,733 +1,736 @@
-#pragma once
-
-#include <stdlib.h>
-#include <memory>
-#include <map>
-#include <vector>
-
-namespace litehtml
-{
-	class document;
-	class element;
-
-	typedef std::map<litehtml::tstring, litehtml::tstring>			string_map;
-	typedef std::vector< std::shared_ptr<litehtml::element> >		elements_vector;
-	typedef std::vector<int>										int_vector;
-	typedef std::vector<litehtml::tstring>							string_vector;
-
-	const unsigned int font_decoration_none			= 0x00;
-	const unsigned int font_decoration_underline	= 0x01;
-	const unsigned int font_decoration_linethrough	= 0x02;
-	const unsigned int font_decoration_overline		= 0x04;
-
-	typedef unsigned char	byte;
-	typedef unsigned int	ucode_t;
-
-	struct margins
-	{
-		int	left;
-		int	right;
-		int top;
-		int bottom;
-
-		margins()
-		{
-			left = right = top = bottom = 0;
-		}
-
-		int width()		const	{ return left + right; } 
-		int height()	const	{ return top + bottom; } 
-	};
-
-	struct size
-	{
-		int		width;
-		int		height;
-
-		size()
-		{
-			width	= 0;
-			height	= 0;
-		}
-	};
-
-	struct position
-	{
-		typedef std::vector<position>	vector;
-
-		int	x;
-		int	y;
-		int	width;
-		int	height;
-
-		position()
-		{
-			x = y = width = height = 0;
-		}
-
-		position(int x, int y, int width, int height)
-		{
-			this->x			= x;
-			this->y			= y;
-			this->width		= width;
-			this->height	= height;
-		}
-
-		int right()		const		{ return x + width;		}
-		int bottom()	const		{ return y + height;	}
-		int left()		const		{ return x;				}
-		int top()		const		{ return y;				}
-
-		void operator+=(const margins& mg)
-		{
-			x		-= mg.left;
-			y		-= mg.top;
-			width	+= mg.left + mg.right;
-			height	+= mg.top + mg.bottom;
-		}
-		void operator-=(const margins& mg)
-		{
-			x		+= mg.left;
-			y		+= mg.top;
-			width	-= mg.left + mg.right;
-			height	-= mg.top + mg.bottom;
-		}
-
-		void clear()
-		{
-			x = y = width = height = 0;
-		}
-
-		void operator=(const size& sz)
-		{
-			width	= sz.width;
-			height	= sz.height;
-		}
-
-		void move_to(int x, int y)
-		{
-			this->x = x;
-			this->y = y;
-		}
-
-		bool does_intersect(const position* val) const
-		{
-			if(!val) return true;
-
-			return (
-				left()			<= val->right()		&& 
-				right()			>= val->left()		&& 
-				bottom()		>= val->top()		&& 
-				top()			<= val->bottom()	)
-				|| (
-				val->left()		<= right()			&& 
-				val->right()	>= left()			&& 
-				val->bottom()	>= top()			&& 
-				val->top()		<= bottom()			);
-		}
-
-		bool empty() const
-		{
-			if(!width && !height)
-			{
-				return true;
-			}
-			return false;
-		}
-
-		bool is_point_inside(int x, int y) const
-		{
-			if(x >= left() && x <= right() && y >= top() && y <= bottom())
-			{
-				return true;
-			}
-			return false;
-		}
-	};
-
-	struct font_metrics
-	{
-		int		height;
-		int		ascent;
-		int		descent;
-		int		x_height;
-		bool	draw_spaces;
-
-		font_metrics()
-		{
-			height			= 0;
-			ascent			= 0;
-			descent			= 0;
-			x_height		= 0;
-			draw_spaces		= true;
-		}
-		int base_line()	{ return descent; }
-	};
-
-	struct font_item
-	{
-		uint_ptr		font;
-		font_metrics	metrics;
-	};
-
-	typedef std::map<tstring, font_item>	fonts_map;
-
-	enum draw_flag
-	{
-		draw_root,
-		draw_block,
-		draw_floats,
-		draw_inlines,
-		draw_positioned,
-	};
-
-#define  style_display_strings		_t("none;block;inline;inline-block;inline-table;list-item;table;table-caption;table-cell;table-column;table-column-group;table-footer-group;table-header-group;table-row;table-row-group")
-
-	enum style_display
-	{
-		display_none,
-		display_block,
-		display_inline,
-		display_inline_block,
-		display_inline_table,
-		display_list_item,
-		display_table,
-		display_table_caption,
-		display_table_cell,
-		display_table_column,
-		display_table_column_group,
-		display_table_footer_group,
-		display_table_header_group,
-		display_table_row,
-		display_table_row_group,
-		display_inline_text,
-	};
-
-	enum style_border
-	{
-		borderNope,
-		borderNone,
-		borderHidden,
-		borderDotted,
-		borderDashed,
-		borderSolid,
-		borderDouble
-	};
-
-#define  font_size_strings		_t("xx-small;x-small;small;medium;large;x-large;xx-large;smaller;larger")
-
-	enum font_size
-	{
-		fontSize_xx_small,
-		fontSize_x_small,
-		fontSize_small,
-		fontSize_medium,
-		fontSize_large,
-		fontSize_x_large,
-		fontSize_xx_large,
-		fontSize_smaller,
-		fontSize_larger,
-	};
-
-#define  font_style_strings		_t("normal;italic")
-
-	enum font_style
-	{
-		fontStyleNormal,
-		fontStyleItalic
-	};
-
-#define  font_variant_strings		_t("normal;small-caps")
-
-	enum font_variant
-	{
-		font_variant_normal,
-		font_variant_italic
-	};
-
-#define  font_weight_strings	_t("normal;bold;bolder;lighter100;200;300;400;500;600;700")
-
-	enum font_weight
-	{
-		fontWeightNormal,
-		fontWeightBold,
-		fontWeightBolder,
-		fontWeightLighter,
-		fontWeight100,
-		fontWeight200,
-		fontWeight300,
-		fontWeight400,
-		fontWeight500,
-		fontWeight600,
-		fontWeight700
-	};
-
-#define  list_style_type_strings	_t("none;circle;disc;square;armenian;cjk-ideographic;decimal;decimal-leading-zero;georgian;hebrew;hiragana;hiragana-iroha;katakana;katakana-iroha;lower-alpha;lower-greek;lower-latin;lower-roman;upper-alpha;upper-latin;upper-roman")
-
-	enum list_style_type
-	{
-		list_style_type_none,
-		list_style_type_circle,
-		list_style_type_disc,
-		list_style_type_square,
-		list_style_type_armenian,
-		list_style_type_cjk_ideographic,
-		list_style_type_decimal,
-		list_style_type_decimal_leading_zero,
-		list_style_type_georgian,
-		list_style_type_hebrew,
-		list_style_type_hiragana,
-		list_style_type_hiragana_iroha,
-		list_style_type_katakana,
-		list_style_type_katakana_iroha,
-		list_style_type_lower_alpha,
-		list_style_type_lower_greek,
-		list_style_type_lower_latin,
-		list_style_type_lower_roman,
-		list_style_type_upper_alpha,
-		list_style_type_upper_latin,
-		list_style_type_upper_roman,
-	};
-
-#define  list_style_position_strings	_t("inside;outside")
-
-	enum list_style_position
-	{
-		list_style_position_inside,
-		list_style_position_outside
-	};
-
-#define  vertical_align_strings	_t("baseline;sub;super;top;text-top;middle;bottom;text-bottom")
-
-	enum vertical_align
-	{
-		va_baseline,
-		va_sub,
-		va_super,
-		va_top,
-		va_text_top,
-		va_middle,
-		va_bottom,
-		va_text_bottom
-	};
-
-#define  border_width_strings	_t("thin;medium;thick")
-
-	enum border_width
-	{
-		border_width_thin,
-		border_width_medium,
-		border_width_thick
-	};
-
-#define  border_style_strings	_t("none;hidden;dotted;dashed;solid;double;groove;ridge;inset;outset")
-
-	enum border_style
-	{
-		border_style_none,
-		border_style_hidden,
-		border_style_dotted,
-		border_style_dashed,
-		border_style_solid,
-		border_style_double,
-		border_style_groove,
-		border_style_ridge,
-		border_style_inset,
-		border_style_outset
-	};
-
-#define  element_float_strings	_t("none;left;right")
-
-	enum element_float
-	{
-		float_none,
-		float_left,
-		float_right
-	};
-
-#define  element_clear_strings	_t("none;left;right;both")
-
-	enum element_clear
-	{
-		clear_none,
-		clear_left,
-		clear_right,
-		clear_both
-	};
-
-#define  css_units_strings	_t("none;%;in;cm;mm;em;ex;pt;pc;px;dpi;dpcm;vw;vh;vmin;vmax")
-
-	enum css_units
-	{
-		css_units_none,
-		css_units_percentage,
-		css_units_in,
-		css_units_cm,
-		css_units_mm,
-		css_units_em,
-		css_units_ex,
-		css_units_pt,
-		css_units_pc,
-		css_units_px,
-		css_units_dpi,
-		css_units_dpcm,
-		css_units_vw,
-		css_units_vh,
-		css_units_vmin,
-		css_units_vmax,
-	};
-
-#define  background_attachment_strings	_t("scroll;fixed")
-
-	enum background_attachment
-	{
-		background_attachment_scroll,
-		background_attachment_fixed
-	};
-
-#define  background_repeat_strings	_t("repeat;repeat-x;repeat-y;no-repeat")
-
-	enum background_repeat
-	{
-		background_repeat_repeat,
-		background_repeat_repeat_x,
-		background_repeat_repeat_y,
-		background_repeat_no_repeat
-	};
-
-#define  background_box_strings	_t("border-box;padding-box;content-box")
-
-	enum background_box
-	{
-		background_box_border,
-		background_box_padding,
-		background_box_content
-	};
-
-#define element_position_strings	_t("static;relative;absolute;fixed")
-
-	enum element_position
-	{
-		element_position_static,
-		element_position_relative,
-		element_position_absolute,
-		element_position_fixed,
-	};
-
-#define text_align_strings		_t("left;right;center;justify")
-
-	enum text_align
-	{
-		text_align_left,
-		text_align_right,
-		text_align_center,
-		text_align_justify
-	};
-
-#define text_transform_strings		_t("none;capitalize;uppercase;lowercase")
-
-	enum text_transform
-	{
-		text_transform_none,
-		text_transform_capitalize,
-		text_transform_uppercase,
-		text_transform_lowercase
-	};
-
-#define white_space_strings		_t("normal;nowrap;pre;pre-line;pre-wrap")
-
-	enum white_space
-	{
-		white_space_normal,
-		white_space_nowrap,
-		white_space_pre,
-		white_space_pre_line,
-		white_space_pre_wrap
-	};
-
-#define overflow_strings		_t("visible;hidden;scroll;auto;no-display;no-content")
-
-	enum overflow
-	{
-		overflow_visible,
-		overflow_hidden,
-		overflow_scroll,
-		overflow_auto,
-		overflow_no_display,
-		overflow_no_content
-	};
-
-#define background_size_strings		_t("auto;cover;contain")
-
-	enum background_size
-	{
-		background_size_auto,
-		background_size_cover,
-		background_size_contain,
-	};
-
-#define visibility_strings			_t("visible;hidden;collapse")
-
-	enum visibility
-	{
-		visibility_visible,
-		visibility_hidden,
-		visibility_collapse,
-	};
-
-#define border_collapse_strings		_t("collapse;separate")
-
-	enum border_collapse
-	{
-		border_collapse_collapse,
-		border_collapse_separate,
-	};
-
-
-#define pseudo_class_strings		_t("only-child;only-of-type;first-child;first-of-type;last-child;last-of-type;nth-child;nth-of-type;nth-last-child;nth-last-of-type;not;lang")
-
-	enum pseudo_class
-	{
-		pseudo_class_only_child,
-		pseudo_class_only_of_type,
-		pseudo_class_first_child,
-		pseudo_class_first_of_type,
-		pseudo_class_last_child,
-		pseudo_class_last_of_type,
-		pseudo_class_nth_child,
-		pseudo_class_nth_of_type,
-		pseudo_class_nth_last_child,
-		pseudo_class_nth_last_of_type,
-		pseudo_class_not,
-		pseudo_class_lang,
-	};
-
-#define content_property_string		_t("none;normal;open-quote;close-quote;no-open-quote;no-close-quote")
-
-	enum content_property
-	{
-		content_property_none,
-		content_property_normal,
-		content_property_open_quote,
-		content_property_close_quote,
-		content_property_no_open_quote,
-		content_property_no_close_quote,
-	};
-
-
-	struct floated_box
-	{
-		typedef std::vector<floated_box>	vector;
-
-		position		pos;
-		element_float	float_side;
-		element_clear	clear_floats;
-		std::shared_ptr<element>	el;
-
-		floated_box() = default;
-		floated_box(const floated_box& val)
-		{
-			pos = val.pos;
-			float_side = val.float_side;
-			clear_floats = val.clear_floats;
-			el = val.el;
-		}
-		floated_box& operator=(const floated_box& val)
-		{
-			pos = val.pos;
-			float_side = val.float_side;
-			clear_floats = val.clear_floats;
-			el = val.el;
-			return *this;
-		}
-		floated_box(floated_box&& val)
-		{
-			pos = val.pos;
-			float_side = val.float_side;
-			clear_floats = val.clear_floats;
-			el = std::move(val.el);
-		}
-		void operator=(floated_box&& val)
-		{
-			pos = val.pos;
-			float_side = val.float_side;
-			clear_floats = val.clear_floats;
-			el = std::move(val.el);
-		}
-	};
-
-	struct int_int_cache
-	{
-		int		hash;
-		int		val;
-		bool	is_valid;
-		bool	is_default;
-
-		int_int_cache()
-		{
-			hash		= 0;
-			val			= 0;
-			is_valid	= false;
-			is_default	= false;
-		}
-		void invalidate()
-		{
-			is_valid	= false;
-			is_default	= false;
-		}
-		void set_value(int vHash, int vVal)
-		{
-			hash		= vHash;
-			val			= vVal;
-			is_valid	= true;
-		}
-	};
-
-	enum select_result
-	{
-		select_no_match				= 0x00,
-		select_match				= 0x01,
-		select_match_pseudo_class	= 0x02,
-		select_match_with_before	= 0x10,
-		select_match_with_after		= 0x20,
-	};
-
-	template<class T>
-	class def_value
-	{
-		T		m_val;
-		bool	m_is_default;
-	public:
-		def_value(T def_val)
-		{
-			m_is_default	= true;
-			m_val			= def_val;
-		}
-		void reset(T def_val)
-		{
-			m_is_default	= true;
-			m_val			= def_val;
-		}
-		bool is_default()
-		{
-			return m_is_default;
-		}
-		T operator=(T new_val)
-		{
-			m_val			= new_val;
-			m_is_default	= false;
-			return m_val;
-		}
-		operator T()
-		{
-			return m_val;
-		}
-	};
-
-
-#define media_orientation_strings		_t("portrait;landscape")
-
-	enum media_orientation
-	{
-		media_orientation_portrait,
-		media_orientation_landscape,
-	};
-
-#define media_feature_strings		_t("none;width;min-width;max-width;height;min-height;max-height;device-width;min-device-width;max-device-width;device-height;min-device-height;max-device-height;orientation;aspect-ratio;min-aspect-ratio;max-aspect-ratio;device-aspect-ratio;min-device-aspect-ratio;max-device-aspect-ratio;color;min-color;max-color;color-index;min-color-index;max-color-index;monochrome;min-monochrome;max-monochrome;resolution;min-resolution;max-resolution")
-
-	enum media_feature
-	{
-		media_feature_none,
-
-		media_feature_width,
-		media_feature_min_width,
-		media_feature_max_width,
-
-		media_feature_height,
-		media_feature_min_height,
-		media_feature_max_height,
-
-		media_feature_device_width,
-		media_feature_min_device_width,
-		media_feature_max_device_width,
-
-		media_feature_device_height,
-		media_feature_min_device_height,
-		media_feature_max_device_height,
-
-		media_feature_orientation,
-
-		media_feature_aspect_ratio,
-		media_feature_min_aspect_ratio,
-		media_feature_max_aspect_ratio,
-
-		media_feature_device_aspect_ratio,
-		media_feature_min_device_aspect_ratio,
-		media_feature_max_device_aspect_ratio,
-
-		media_feature_color,
-		media_feature_min_color,
-		media_feature_max_color,
-
-		media_feature_color_index,
-		media_feature_min_color_index,
-		media_feature_max_color_index,
-
-		media_feature_monochrome,
-		media_feature_min_monochrome,
-		media_feature_max_monochrome,
-
-		media_feature_resolution,
-		media_feature_min_resolution,
-		media_feature_max_resolution,
-	};
-
-#define box_sizing_strings		_t("content-box;border-box")
-
-	enum box_sizing
-	{
-		box_sizing_content_box,
-		box_sizing_border_box,
-	};
-
-
-#define media_type_strings		_t("none;all;screen;print;braille;embossed;handheld;projection;speech;tty;tv")
-
-	enum media_type
-	{
-		media_type_none,
-		media_type_all,
-		media_type_screen,
-		media_type_print,
-		media_type_braille,
-		media_type_embossed,
-		media_type_handheld,
-		media_type_projection,
-		media_type_speech,
-		media_type_tty,
-		media_type_tv,
-	};
-
-	struct media_features
-	{
-		media_type	type;
-		int			width;			// (pixels) For continuous media, this is the width of the viewport including the size of a rendered scroll bar (if any). For paged media, this is the width of the page box.
-		int			height;			// (pixels) The height of the targeted display area of the output device. For continuous media, this is the height of the viewport including the size of a rendered scroll bar (if any). For paged media, this is the height of the page box.
-		int			device_width;	// (pixels) The width of the rendering surface of the output device. For continuous media, this is the width of the screen. For paged media, this is the width of the page sheet size.
-		int			device_height;	// (pixels) The height of the rendering surface of the output device. For continuous media, this is the height of the screen. For paged media, this is the height of the page sheet size.
-		int			color;			// The number of bits per color component of the output device. If the device is not a color device, the value is zero.
-		int			color_index;	// The number of entries in the color lookup table of the output device. If the device does not use a color lookup table, the value is zero.
-		int			monochrome;		// The number of bits per pixel in a monochrome frame buffer. If the device is not a monochrome device, the output device value will be 0.
-		int			resolution;		// The resolution of the output device (in DPI)
-	};
-
-	enum render_type
-	{
-		render_all,
-		render_no_fixed,
-		render_fixed_only,
-	};
-
-	// List of the Void Elements (can't have any contents)
-	const litehtml::tchar_t* const void_elements = _t("area;base;br;col;command;embed;hr;img;input;keygen;link;meta;param;source;track;wbr");
-}
+#ifndef LH_TYPES_H
+#define LH_TYPES_H
+
+#include <stdlib.h>
+#include <memory>
+#include <map>
+#include <vector>
+
+namespace litehtml
+{
+	class document;
+	class element;
+
+	typedef std::map<litehtml::tstring, litehtml::tstring>			string_map;
+	typedef std::vector< std::shared_ptr<litehtml::element> >		elements_vector;
+	typedef std::vector<int>										int_vector;
+	typedef std::vector<litehtml::tstring>							string_vector;
+
+	const unsigned int font_decoration_none			= 0x00;
+	const unsigned int font_decoration_underline	= 0x01;
+	const unsigned int font_decoration_linethrough	= 0x02;
+	const unsigned int font_decoration_overline		= 0x04;
+
+	typedef unsigned char	byte;
+	typedef unsigned int	ucode_t;
+
+	struct margins
+	{
+		int	left;
+		int	right;
+		int top;
+		int bottom;
+
+		margins()
+		{
+			left = right = top = bottom = 0;
+		}
+
+		int width()		const	{ return left + right; } 
+		int height()	const	{ return top + bottom; } 
+	};
+
+	struct size
+	{
+		int		width;
+		int		height;
+
+		size()
+		{
+			width	= 0;
+			height	= 0;
+		}
+	};
+
+	struct position
+	{
+		typedef std::vector<position>	vector;
+
+		int	x;
+		int	y;
+		int	width;
+		int	height;
+
+		position()
+		{
+			x = y = width = height = 0;
+		}
+
+		position(int x, int y, int width, int height)
+		{
+			this->x			= x;
+			this->y			= y;
+			this->width		= width;
+			this->height	= height;
+		}
+
+		int right()		const		{ return x + width;		}
+		int bottom()	const		{ return y + height;	}
+		int left()		const		{ return x;				}
+		int top()		const		{ return y;				}
+
+		void operator+=(const margins& mg)
+		{
+			x		-= mg.left;
+			y		-= mg.top;
+			width	+= mg.left + mg.right;
+			height	+= mg.top + mg.bottom;
+		}
+		void operator-=(const margins& mg)
+		{
+			x		+= mg.left;
+			y		+= mg.top;
+			width	-= mg.left + mg.right;
+			height	-= mg.top + mg.bottom;
+		}
+
+		void clear()
+		{
+			x = y = width = height = 0;
+		}
+
+		void operator=(const size& sz)
+		{
+			width	= sz.width;
+			height	= sz.height;
+		}
+
+		void move_to(int x, int y)
+		{
+			this->x = x;
+			this->y = y;
+		}
+
+		bool does_intersect(const position* val) const
+		{
+			if(!val) return true;
+
+			return (
+				left()			<= val->right()		&& 
+				right()			>= val->left()		&& 
+				bottom()		>= val->top()		&& 
+				top()			<= val->bottom()	)
+				|| (
+				val->left()		<= right()			&& 
+				val->right()	>= left()			&& 
+				val->bottom()	>= top()			&& 
+				val->top()		<= bottom()			);
+		}
+
+		bool empty() const
+		{
+			if(!width && !height)
+			{
+				return true;
+			}
+			return false;
+		}
+
+		bool is_point_inside(int x, int y) const
+		{
+			if(x >= left() && x <= right() && y >= top() && y <= bottom())
+			{
+				return true;
+			}
+			return false;
+		}
+	};
+
+	struct font_metrics
+	{
+		int		height;
+		int		ascent;
+		int		descent;
+		int		x_height;
+		bool	draw_spaces;
+
+		font_metrics()
+		{
+			height			= 0;
+			ascent			= 0;
+			descent			= 0;
+			x_height		= 0;
+			draw_spaces		= true;
+		}
+		int base_line()	{ return descent; }
+	};
+
+	struct font_item
+	{
+		uint_ptr		font;
+		font_metrics	metrics;
+	};
+
+	typedef std::map<tstring, font_item>	fonts_map;
+
+	enum draw_flag
+	{
+		draw_root,
+		draw_block,
+		draw_floats,
+		draw_inlines,
+		draw_positioned,
+	};
+
+#define  style_display_strings		_t("none;block;inline;inline-block;inline-table;list-item;table;table-caption;table-cell;table-column;table-column-group;table-footer-group;table-header-group;table-row;table-row-group")
+
+	enum style_display
+	{
+		display_none,
+		display_block,
+		display_inline,
+		display_inline_block,
+		display_inline_table,
+		display_list_item,
+		display_table,
+		display_table_caption,
+		display_table_cell,
+		display_table_column,
+		display_table_column_group,
+		display_table_footer_group,
+		display_table_header_group,
+		display_table_row,
+		display_table_row_group,
+		display_inline_text,
+	};
+
+	enum style_border
+	{
+		borderNope,
+		borderNone,
+		borderHidden,
+		borderDotted,
+		borderDashed,
+		borderSolid,
+		borderDouble
+	};
+
+#define  font_size_strings		_t("xx-small;x-small;small;medium;large;x-large;xx-large;smaller;larger")
+
+	enum font_size
+	{
+		fontSize_xx_small,
+		fontSize_x_small,
+		fontSize_small,
+		fontSize_medium,
+		fontSize_large,
+		fontSize_x_large,
+		fontSize_xx_large,
+		fontSize_smaller,
+		fontSize_larger,
+	};
+
+#define  font_style_strings		_t("normal;italic")
+
+	enum font_style
+	{
+		fontStyleNormal,
+		fontStyleItalic
+	};
+
+#define  font_variant_strings		_t("normal;small-caps")
+
+	enum font_variant
+	{
+		font_variant_normal,
+		font_variant_italic
+	};
+
+#define  font_weight_strings	_t("normal;bold;bolder;lighter100;200;300;400;500;600;700")
+
+	enum font_weight
+	{
+		fontWeightNormal,
+		fontWeightBold,
+		fontWeightBolder,
+		fontWeightLighter,
+		fontWeight100,
+		fontWeight200,
+		fontWeight300,
+		fontWeight400,
+		fontWeight500,
+		fontWeight600,
+		fontWeight700
+	};
+
+#define  list_style_type_strings	_t("none;circle;disc;square;armenian;cjk-ideographic;decimal;decimal-leading-zero;georgian;hebrew;hiragana;hiragana-iroha;katakana;katakana-iroha;lower-alpha;lower-greek;lower-latin;lower-roman;upper-alpha;upper-latin;upper-roman")
+
+	enum list_style_type
+	{
+		list_style_type_none,
+		list_style_type_circle,
+		list_style_type_disc,
+		list_style_type_square,
+		list_style_type_armenian,
+		list_style_type_cjk_ideographic,
+		list_style_type_decimal,
+		list_style_type_decimal_leading_zero,
+		list_style_type_georgian,
+		list_style_type_hebrew,
+		list_style_type_hiragana,
+		list_style_type_hiragana_iroha,
+		list_style_type_katakana,
+		list_style_type_katakana_iroha,
+		list_style_type_lower_alpha,
+		list_style_type_lower_greek,
+		list_style_type_lower_latin,
+		list_style_type_lower_roman,
+		list_style_type_upper_alpha,
+		list_style_type_upper_latin,
+		list_style_type_upper_roman,
+	};
+
+#define  list_style_position_strings	_t("inside;outside")
+
+	enum list_style_position
+	{
+		list_style_position_inside,
+		list_style_position_outside
+	};
+
+#define  vertical_align_strings	_t("baseline;sub;super;top;text-top;middle;bottom;text-bottom")
+
+	enum vertical_align
+	{
+		va_baseline,
+		va_sub,
+		va_super,
+		va_top,
+		va_text_top,
+		va_middle,
+		va_bottom,
+		va_text_bottom
+	};
+
+#define  border_width_strings	_t("thin;medium;thick")
+
+	enum border_width
+	{
+		border_width_thin,
+		border_width_medium,
+		border_width_thick
+	};
+
+#define  border_style_strings	_t("none;hidden;dotted;dashed;solid;double;groove;ridge;inset;outset")
+
+	enum border_style
+	{
+		border_style_none,
+		border_style_hidden,
+		border_style_dotted,
+		border_style_dashed,
+		border_style_solid,
+		border_style_double,
+		border_style_groove,
+		border_style_ridge,
+		border_style_inset,
+		border_style_outset
+	};
+
+#define  element_float_strings	_t("none;left;right")
+
+	enum element_float
+	{
+		float_none,
+		float_left,
+		float_right
+	};
+
+#define  element_clear_strings	_t("none;left;right;both")
+
+	enum element_clear
+	{
+		clear_none,
+		clear_left,
+		clear_right,
+		clear_both
+	};
+
+#define  css_units_strings	_t("none;%;in;cm;mm;em;ex;pt;pc;px;dpi;dpcm;vw;vh;vmin;vmax")
+
+	enum css_units
+	{
+		css_units_none,
+		css_units_percentage,
+		css_units_in,
+		css_units_cm,
+		css_units_mm,
+		css_units_em,
+		css_units_ex,
+		css_units_pt,
+		css_units_pc,
+		css_units_px,
+		css_units_dpi,
+		css_units_dpcm,
+		css_units_vw,
+		css_units_vh,
+		css_units_vmin,
+		css_units_vmax,
+	};
+
+#define  background_attachment_strings	_t("scroll;fixed")
+
+	enum background_attachment
+	{
+		background_attachment_scroll,
+		background_attachment_fixed
+	};
+
+#define  background_repeat_strings	_t("repeat;repeat-x;repeat-y;no-repeat")
+
+	enum background_repeat
+	{
+		background_repeat_repeat,
+		background_repeat_repeat_x,
+		background_repeat_repeat_y,
+		background_repeat_no_repeat
+	};
+
+#define  background_box_strings	_t("border-box;padding-box;content-box")
+
+	enum background_box
+	{
+		background_box_border,
+		background_box_padding,
+		background_box_content
+	};
+
+#define element_position_strings	_t("static;relative;absolute;fixed")
+
+	enum element_position
+	{
+		element_position_static,
+		element_position_relative,
+		element_position_absolute,
+		element_position_fixed,
+	};
+
+#define text_align_strings		_t("left;right;center;justify")
+
+	enum text_align
+	{
+		text_align_left,
+		text_align_right,
+		text_align_center,
+		text_align_justify
+	};
+
+#define text_transform_strings		_t("none;capitalize;uppercase;lowercase")
+
+	enum text_transform
+	{
+		text_transform_none,
+		text_transform_capitalize,
+		text_transform_uppercase,
+		text_transform_lowercase
+	};
+
+#define white_space_strings		_t("normal;nowrap;pre;pre-line;pre-wrap")
+
+	enum white_space
+	{
+		white_space_normal,
+		white_space_nowrap,
+		white_space_pre,
+		white_space_pre_line,
+		white_space_pre_wrap
+	};
+
+#define overflow_strings		_t("visible;hidden;scroll;auto;no-display;no-content")
+
+	enum overflow
+	{
+		overflow_visible,
+		overflow_hidden,
+		overflow_scroll,
+		overflow_auto,
+		overflow_no_display,
+		overflow_no_content
+	};
+
+#define background_size_strings		_t("auto;cover;contain")
+
+	enum background_size
+	{
+		background_size_auto,
+		background_size_cover,
+		background_size_contain,
+	};
+
+#define visibility_strings			_t("visible;hidden;collapse")
+
+	enum visibility
+	{
+		visibility_visible,
+		visibility_hidden,
+		visibility_collapse,
+	};
+
+#define border_collapse_strings		_t("collapse;separate")
+
+	enum border_collapse
+	{
+		border_collapse_collapse,
+		border_collapse_separate,
+	};
+
+
+#define pseudo_class_strings		_t("only-child;only-of-type;first-child;first-of-type;last-child;last-of-type;nth-child;nth-of-type;nth-last-child;nth-last-of-type;not;lang")
+
+	enum pseudo_class
+	{
+		pseudo_class_only_child,
+		pseudo_class_only_of_type,
+		pseudo_class_first_child,
+		pseudo_class_first_of_type,
+		pseudo_class_last_child,
+		pseudo_class_last_of_type,
+		pseudo_class_nth_child,
+		pseudo_class_nth_of_type,
+		pseudo_class_nth_last_child,
+		pseudo_class_nth_last_of_type,
+		pseudo_class_not,
+		pseudo_class_lang,
+	};
+
+#define content_property_string		_t("none;normal;open-quote;close-quote;no-open-quote;no-close-quote")
+
+	enum content_property
+	{
+		content_property_none,
+		content_property_normal,
+		content_property_open_quote,
+		content_property_close_quote,
+		content_property_no_open_quote,
+		content_property_no_close_quote,
+	};
+
+
+	struct floated_box
+	{
+		typedef std::vector<floated_box>	vector;
+
+		position		pos;
+		element_float	float_side;
+		element_clear	clear_floats;
+		std::shared_ptr<element>	el;
+
+		floated_box() = default;
+		floated_box(const floated_box& val)
+		{
+			pos = val.pos;
+			float_side = val.float_side;
+			clear_floats = val.clear_floats;
+			el = val.el;
+		}
+		floated_box& operator=(const floated_box& val)
+		{
+			pos = val.pos;
+			float_side = val.float_side;
+			clear_floats = val.clear_floats;
+			el = val.el;
+			return *this;
+		}
+		floated_box(floated_box&& val)
+		{
+			pos = val.pos;
+			float_side = val.float_side;
+			clear_floats = val.clear_floats;
+			el = std::move(val.el);
+		}
+		void operator=(floated_box&& val)
+		{
+			pos = val.pos;
+			float_side = val.float_side;
+			clear_floats = val.clear_floats;
+			el = std::move(val.el);
+		}
+	};
+
+	struct int_int_cache
+	{
+		int		hash;
+		int		val;
+		bool	is_valid;
+		bool	is_default;
+
+		int_int_cache()
+		{
+			hash		= 0;
+			val			= 0;
+			is_valid	= false;
+			is_default	= false;
+		}
+		void invalidate()
+		{
+			is_valid	= false;
+			is_default	= false;
+		}
+		void set_value(int vHash, int vVal)
+		{
+			hash		= vHash;
+			val			= vVal;
+			is_valid	= true;
+		}
+	};
+
+	enum select_result
+	{
+		select_no_match				= 0x00,
+		select_match				= 0x01,
+		select_match_pseudo_class	= 0x02,
+		select_match_with_before	= 0x10,
+		select_match_with_after		= 0x20,
+	};
+
+	template<class T>
+	class def_value
+	{
+		T		m_val;
+		bool	m_is_default;
+	public:
+		def_value(T def_val)
+		{
+			m_is_default	= true;
+			m_val			= def_val;
+		}
+		void reset(T def_val)
+		{
+			m_is_default	= true;
+			m_val			= def_val;
+		}
+		bool is_default()
+		{
+			return m_is_default;
+		}
+		T operator=(T new_val)
+		{
+			m_val			= new_val;
+			m_is_default	= false;
+			return m_val;
+		}
+		operator T()
+		{
+			return m_val;
+		}
+	};
+
+
+#define media_orientation_strings		_t("portrait;landscape")
+
+	enum media_orientation
+	{
+		media_orientation_portrait,
+		media_orientation_landscape,
+	};
+
+#define media_feature_strings		_t("none;width;min-width;max-width;height;min-height;max-height;device-width;min-device-width;max-device-width;device-height;min-device-height;max-device-height;orientation;aspect-ratio;min-aspect-ratio;max-aspect-ratio;device-aspect-ratio;min-device-aspect-ratio;max-device-aspect-ratio;color;min-color;max-color;color-index;min-color-index;max-color-index;monochrome;min-monochrome;max-monochrome;resolution;min-resolution;max-resolution")
+
+	enum media_feature
+	{
+		media_feature_none,
+
+		media_feature_width,
+		media_feature_min_width,
+		media_feature_max_width,
+
+		media_feature_height,
+		media_feature_min_height,
+		media_feature_max_height,
+
+		media_feature_device_width,
+		media_feature_min_device_width,
+		media_feature_max_device_width,
+
+		media_feature_device_height,
+		media_feature_min_device_height,
+		media_feature_max_device_height,
+
+		media_feature_orientation,
+
+		media_feature_aspect_ratio,
+		media_feature_min_aspect_ratio,
+		media_feature_max_aspect_ratio,
+
+		media_feature_device_aspect_ratio,
+		media_feature_min_device_aspect_ratio,
+		media_feature_max_device_aspect_ratio,
+
+		media_feature_color,
+		media_feature_min_color,
+		media_feature_max_color,
+
+		media_feature_color_index,
+		media_feature_min_color_index,
+		media_feature_max_color_index,
+
+		media_feature_monochrome,
+		media_feature_min_monochrome,
+		media_feature_max_monochrome,
+
+		media_feature_resolution,
+		media_feature_min_resolution,
+		media_feature_max_resolution,
+	};
+
+#define box_sizing_strings		_t("content-box;border-box")
+
+	enum box_sizing
+	{
+		box_sizing_content_box,
+		box_sizing_border_box,
+	};
+
+
+#define media_type_strings		_t("none;all;screen;print;braille;embossed;handheld;projection;speech;tty;tv")
+
+	enum media_type
+	{
+		media_type_none,
+		media_type_all,
+		media_type_screen,
+		media_type_print,
+		media_type_braille,
+		media_type_embossed,
+		media_type_handheld,
+		media_type_projection,
+		media_type_speech,
+		media_type_tty,
+		media_type_tv,
+	};
+
+	struct media_features
+	{
+		media_type	type;
+		int			width;			// (pixels) For continuous media, this is the width of the viewport including the size of a rendered scroll bar (if any). For paged media, this is the width of the page box.
+		int			height;			// (pixels) The height of the targeted display area of the output device. For continuous media, this is the height of the viewport including the size of a rendered scroll bar (if any). For paged media, this is the height of the page box.
+		int			device_width;	// (pixels) The width of the rendering surface of the output device. For continuous media, this is the width of the screen. For paged media, this is the width of the page sheet size.
+		int			device_height;	// (pixels) The height of the rendering surface of the output device. For continuous media, this is the height of the screen. For paged media, this is the height of the page sheet size.
+		int			color;			// The number of bits per color component of the output device. If the device is not a color device, the value is zero.
+		int			color_index;	// The number of entries in the color lookup table of the output device. If the device does not use a color lookup table, the value is zero.
+		int			monochrome;		// The number of bits per pixel in a monochrome frame buffer. If the device is not a monochrome device, the output device value will be 0.
+		int			resolution;		// The resolution of the output device (in DPI)
+	};
+
+	enum render_type
+	{
+		render_all,
+		render_no_fixed,
+		render_fixed_only,
+	};
+
+	// List of the Void Elements (can't have any contents)
+	const litehtml::tchar_t* const void_elements = _t("area;base;br;col;command;embed;hr;img;input;keygen;link;meta;param;source;track;wbr");
+}
+
+#endif  // LH_TYPES_H
diff --git a/src/plugins/litehtml_viewer/litehtml/utf8_strings.cpp b/src/plugins/litehtml_viewer/litehtml/utf8_strings.cpp
index fcb18c8..cdd58e1 100644
--- a/src/plugins/litehtml_viewer/litehtml/utf8_strings.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/utf8_strings.cpp
@@ -1,97 +1,97 @@
-#include "html.h"
-#include "utf8_strings.h"
-
-
-litehtml::utf8_to_wchar::utf8_to_wchar(const char* val)
-{
-	m_utf8 = (const byte*) val;
-	while (true)
-	{
-		ucode_t wch = get_char();
-		if (!wch) break;
-		m_str += wch;
-	}
-}
-
-litehtml::ucode_t litehtml::utf8_to_wchar::get_char()
-{
-	ucode_t b1 = getb();
-
-	if (!b1)
-	{
-		return 0;
-	}
-
-	// Determine whether we are dealing
-	// with a one-, two-, three-, or four-
-	// byte sequence.
-	if ((b1 & 0x80) == 0)
-	{
-		// 1-byte sequence: 000000000xxxxxxx = 0xxxxxxx
-		return b1;
-	}
-	else if ((b1 & 0xe0) == 0xc0)
-	{
-		// 2-byte sequence: 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
-		ucode_t r = (b1 & 0x1f) << 6;
-		r |= get_next_utf8(getb());
-		return r;
-	}
-	else if ((b1 & 0xf0) == 0xe0)
-	{
-		// 3-byte sequence: zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
-		ucode_t r = (b1 & 0x0f) << 12;
-		r |= get_next_utf8(getb()) << 6;
-		r |= get_next_utf8(getb());
-		return r;
-	}
-	else if ((b1 & 0xf8) == 0xf0)
-	{
-		// 4-byte sequence: 11101110wwwwzzzzyy + 110111yyyyxxxxxx
-		//     = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
-		// (uuuuu = wwww + 1)
-		int b2 = get_next_utf8(getb());
-		int b3 = get_next_utf8(getb());
-		int b4 = get_next_utf8(getb());
-		return ((b1 & 7) << 18) | ((b2 & 0x3f) << 12) |
-			((b3 & 0x3f) << 6) | (b4 & 0x3f);
-	}
-
-	//bad start for UTF-8 multi-byte sequence
-	return '?';
-}
-
-litehtml::wchar_to_utf8::wchar_to_utf8(const wchar_t* val)
-{
-	unsigned int code;
-	for (int i = 0; val[i]; i++)
-	{
-		code = val[i];
-		if (code <= 0x7F)
-		{
-			m_str += (char)code;
-		}
-		else if (code <= 0x7FF)
-		{
-			m_str += (code >> 6) + 192;
-			m_str += (code & 63) + 128;
-		}
-		else if (0xd800 <= code && code <= 0xdfff)
-		{
-			//invalid block of utf8
-		}
-		else if (code <= 0xFFFF)
-		{
-			m_str += (code >> 12) + 224;
-			m_str += ((code >> 6) & 63) + 128;
-			m_str += (code & 63) + 128;
-		}
-		else if (code <= 0x10FFFF)
-		{
-			m_str += (code >> 18) + 240;
-			m_str += ((code >> 12) & 63) + 128;
-			m_str += ((code >> 6) & 63) + 128;
-			m_str += (code & 63) + 128;
-		}
-	}
-}
+#include "html.h"
+#include "utf8_strings.h"
+
+
+litehtml::utf8_to_wchar::utf8_to_wchar(const char* val)
+{
+	m_utf8 = (const byte*) val;
+	while (true)
+	{
+		ucode_t wch = get_char();
+		if (!wch) break;
+		m_str += wch;
+	}
+}
+
+litehtml::ucode_t litehtml::utf8_to_wchar::get_char()
+{
+	ucode_t b1 = getb();
+
+	if (!b1)
+	{
+		return 0;
+	}
+
+	// Determine whether we are dealing
+	// with a one-, two-, three-, or four-
+	// byte sequence.
+	if ((b1 & 0x80) == 0)
+	{
+		// 1-byte sequence: 000000000xxxxxxx = 0xxxxxxx
+		return b1;
+	}
+	else if ((b1 & 0xe0) == 0xc0)
+	{
+		// 2-byte sequence: 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
+		ucode_t r = (b1 & 0x1f) << 6;
+		r |= get_next_utf8(getb());
+		return r;
+	}
+	else if ((b1 & 0xf0) == 0xe0)
+	{
+		// 3-byte sequence: zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
+		ucode_t r = (b1 & 0x0f) << 12;
+		r |= get_next_utf8(getb()) << 6;
+		r |= get_next_utf8(getb());
+		return r;
+	}
+	else if ((b1 & 0xf8) == 0xf0)
+	{
+		// 4-byte sequence: 11101110wwwwzzzzyy + 110111yyyyxxxxxx
+		//     = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
+		// (uuuuu = wwww + 1)
+		int b2 = get_next_utf8(getb());
+		int b3 = get_next_utf8(getb());
+		int b4 = get_next_utf8(getb());
+		return ((b1 & 7) << 18) | ((b2 & 0x3f) << 12) |
+			((b3 & 0x3f) << 6) | (b4 & 0x3f);
+	}
+
+	//bad start for UTF-8 multi-byte sequence
+	return '?';
+}
+
+litehtml::wchar_to_utf8::wchar_to_utf8(const wchar_t* val)
+{
+	unsigned int code;
+	for (int i = 0; val[i]; i++)
+	{
+		code = val[i];
+		if (code <= 0x7F)
+		{
+			m_str += (char)code;
+		}
+		else if (code <= 0x7FF)
+		{
+			m_str += (code >> 6) + 192;
+			m_str += (code & 63) + 128;
+		}
+		else if (0xd800 <= code && code <= 0xdfff)
+		{
+			//invalid block of utf8
+		}
+		else if (code <= 0xFFFF)
+		{
+			m_str += (code >> 12) + 224;
+			m_str += ((code >> 6) & 63) + 128;
+			m_str += (code & 63) + 128;
+		}
+		else if (code <= 0x10FFFF)
+		{
+			m_str += (code >> 18) + 240;
+			m_str += ((code >> 12) & 63) + 128;
+			m_str += ((code >> 6) & 63) + 128;
+			m_str += (code & 63) + 128;
+		}
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/utf8_strings.h b/src/plugins/litehtml_viewer/litehtml/utf8_strings.h
index c932ed5..0120262 100644
--- a/src/plugins/litehtml_viewer/litehtml/utf8_strings.h
+++ b/src/plugins/litehtml_viewer/litehtml/utf8_strings.h
@@ -1,48 +1,51 @@
-#pragma once
-
-namespace litehtml
-{
-	class utf8_to_wchar
-	{
-		const byte* m_utf8;
-		std::wstring m_str;
-	public:
-		utf8_to_wchar(const char* val);
-		operator const wchar_t*() const
-		{
-			return m_str.c_str();
-		}
-	private:
-		ucode_t getb()
-		{
-			if (!(*m_utf8)) return 0;
-			return *m_utf8++;
-		}
-		ucode_t get_next_utf8(ucode_t val)
-		{
-			return (val & 0x3f);
-		}
-		ucode_t get_char();
-	};
-
-	class wchar_to_utf8
-	{
-		std::string m_str;
-	public:
-		wchar_to_utf8(const wchar_t* val);
-		operator const char*() const
-		{
-			return m_str.c_str();
-		}
-	};
-
-#ifdef LITEHTML_UTF8
-#define litehtml_from_utf8(str)		str
-#define litehtml_to_utf8(str)		str
-#define litehtml_from_wchar(str)	wchar_to_utf8(str)
-#else
-#define litehtml_from_utf8(str)		utf8_to_wchar(str)
-#define litehtml_from_wchar(str)	str
-#define litehtml_to_utf8(str)		wchar_to_utf8(str)
-#endif
-}
\ No newline at end of file
+#ifndef LH_UTF8_STRINGS_H
+#define LH_UTF8_STRINGS_H
+
+namespace litehtml
+{
+	class utf8_to_wchar
+	{
+		const byte* m_utf8;
+		std::wstring m_str;
+	public:
+		utf8_to_wchar(const char* val);
+		operator const wchar_t*() const
+		{
+			return m_str.c_str();
+		}
+	private:
+		ucode_t getb()
+		{
+			if (!(*m_utf8)) return 0;
+			return *m_utf8++;
+		}
+		ucode_t get_next_utf8(ucode_t val)
+		{
+			return (val & 0x3f);
+		}
+		ucode_t get_char();
+	};
+
+	class wchar_to_utf8
+	{
+		std::string m_str;
+	public:
+		wchar_to_utf8(const wchar_t* val);
+		operator const char*() const
+		{
+			return m_str.c_str();
+		}
+	};
+
+#ifdef LITEHTML_UTF8
+#define litehtml_from_utf8(str)		str
+#define litehtml_to_utf8(str)		str
+#define litehtml_from_wchar(str)	wchar_to_utf8(str)
+#else
+#define litehtml_from_utf8(str)		utf8_to_wchar(str)
+#define litehtml_from_wchar(str)	str
+#define litehtml_to_utf8(str)		wchar_to_utf8(str)
+#endif
+}
+
+#endif  // LH_UTF8_STRINGS_H
diff --git a/src/plugins/litehtml_viewer/litehtml/web_color.cpp b/src/plugins/litehtml_viewer/litehtml/web_color.cpp
index 814765d..39ce2d7 100644
--- a/src/plugins/litehtml_viewer/litehtml/web_color.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/web_color.cpp
@@ -1,28 +1,28 @@
-#include "html.h"
-#include "web_color.h"
-#include <string.h>
-
-litehtml::def_color litehtml::g_def_colors[] = 
-{
-	{_t("transparent"),_t("rgba(0, 0, 0, 0)")},
-	{_t("AliceBlue"),_t("#F0F8FF")},
-	{_t("AntiqueWhite"),_t("#FAEBD7")},
-	{_t("Aqua"),_t("#00FFFF")},
-	{_t("Aquamarine"),_t("#7FFFD4")},
-	{_t("Azure"),_t("#F0FFFF")},
-	{_t("Beige"),_t("#F5F5DC")},
-	{_t("Bisque"),_t("#FFE4C4")},
-	{_t("Black"),_t("#000000")},
-	{_t("BlanchedAlmond"),_t("#FFEBCD")},
-	{_t("Blue"),_t("#0000FF")},
-	{_t("BlueViolet"),_t("#8A2BE2")},
-	{_t("Brown"),_t("#A52A2A")},
-	{_t("BurlyWood"),_t("#DEB887")},
-	{_t("CadetBlue"),_t("#5F9EA0")},
-	{_t("Chartreuse"),_t("#7FFF00")},
-	{_t("Chocolate"),_t("#D2691E")},
-	{_t("Coral"),_t("#FF7F50")},
-	{_t("CornflowerBlue"),_t("#6495ED")},
+#include "html.h"
+#include "web_color.h"
+#include <string.h>
+
+litehtml::def_color litehtml::g_def_colors[] = 
+{
+	{_t("transparent"),_t("rgba(0, 0, 0, 0)")},
+	{_t("AliceBlue"),_t("#F0F8FF")},
+	{_t("AntiqueWhite"),_t("#FAEBD7")},
+	{_t("Aqua"),_t("#00FFFF")},
+	{_t("Aquamarine"),_t("#7FFFD4")},
+	{_t("Azure"),_t("#F0FFFF")},
+	{_t("Beige"),_t("#F5F5DC")},
+	{_t("Bisque"),_t("#FFE4C4")},
+	{_t("Black"),_t("#000000")},
+	{_t("BlanchedAlmond"),_t("#FFEBCD")},
+	{_t("Blue"),_t("#0000FF")},
+	{_t("BlueViolet"),_t("#8A2BE2")},
+	{_t("Brown"),_t("#A52A2A")},
+	{_t("BurlyWood"),_t("#DEB887")},
+	{_t("CadetBlue"),_t("#5F9EA0")},
+	{_t("Chartreuse"),_t("#7FFF00")},
+	{_t("Chocolate"),_t("#D2691E")},
+	{_t("Coral"),_t("#FF7F50")},
+	{_t("CornflowerBlue"),_t("#6495ED")},
 	{_t("Cornsilk"),_t("#FFF8DC")},
 	{_t("Crimson"),_t("#DC143C")},
 	{_t("Cyan"),_t("#00FFFF")},
@@ -149,103 +149,108 @@ litehtml::def_color litehtml::g_def_colors[] =
 	{_t("White"),_t("#FFFFFF")},
 	{_t("WhiteSmoke"),_t("#F5F5F5")},
 	{_t("Yellow"),_t("#FFFF00")},
-	{_t("YellowGreen"),_t("#9ACD32")},
-	{0,0}
-};
-
-
-litehtml::web_color litehtml::web_color::from_string( const tchar_t* str )
-{
-	if(!str)
-	{
-		return web_color(0, 0, 0);
-	}
-	if(str[0] == _t('#'))
-	{
-		tstring red		= _t("");
-		tstring green		= _t("");
-		tstring blue		= _t("");
-		if(t_strlen(str + 1) == 3)
-		{
-			red		+= str[1];
-			red		+= str[1];
-			green	+= str[2];
-			green	+= str[2];
-			blue	+= str[3];
-			blue	+= str[3];
-		} else if(t_strlen(str + 1) == 6)
-		{
-			red		+= str[1];
-			red		+= str[2];
-			green	+= str[3];
-			green	+= str[4];
-			blue	+= str[5];
-			blue	+= str[6];
-		}
-		tchar_t* sss = 0;
-		web_color clr;
-		clr.red		= (byte) t_strtol(red.c_str(),	&sss, 16);
-		clr.green	= (byte) t_strtol(green.c_str(),	&sss, 16);
-		clr.blue	= (byte) t_strtol(blue.c_str(),	&sss, 16);
-		return clr;
-	} else if(!t_strncmp(str, _t("rgb"), 3))
-	{
-		tstring s = str;
-
-		tstring::size_type pos = s.find_first_of(_t("("));
-		if(pos != tstring::npos)
-		{
-			s.erase(s.begin(), s.begin() + pos + 1);
-		}
-		pos = s.find_last_of(_t(")"));
-		if(pos != tstring::npos)
-		{
-			s.erase(s.begin() + pos, s.end());
-		}
-
-		std::vector<tstring> tokens;
-		split_string(s, tokens, _t(", \t"));
-
-		web_color clr;
-
-		if(tokens.size() >= 1)	clr.red		= (byte) t_atoi(tokens[0].c_str());
-		if(tokens.size() >= 2)	clr.green	= (byte) t_atoi(tokens[1].c_str());
-		if(tokens.size() >= 3)	clr.blue	= (byte) t_atoi(tokens[2].c_str());
-		if(tokens.size() >= 4)	clr.alpha	= (byte) (t_strtod(tokens[3].c_str(), 0) * 255.0);
-
-		return clr;
-	} else
-	{
-		const tchar_t* rgb = resolve_name(str);
-		if(rgb)
-		{
-			return from_string(rgb);
-		}
-	}
-	return web_color(0, 0, 0);
-}
-
-const litehtml::tchar_t* litehtml::web_color::resolve_name( const tchar_t* name )
-{
-	for(int i=0; g_def_colors[i].name; i++)
-	{
-		if(!t_strcasecmp(name, g_def_colors[i].name))
-		{
-			return g_def_colors[i].rgb;
-		}
-	}
-	return 0;
-}
-
-bool litehtml::web_color::is_color( const tchar_t* str )
-{
-	if(!t_strncasecmp(str, _t("rgb"), 3) || str[0] == _t('#'))
-	{
-		return true;
-	}
-	if(resolve_name(str))
-	{
-		return true;
-	}
-	return false;
-}
+	{_t("YellowGreen"),_t("#9ACD32")},
+	{0,0}
+};
+
+
+litehtml::web_color litehtml::web_color::from_string(const tchar_t* str, litehtml::document_container* callback)
+{
+	if(!str || !str[0])
+	{
+		return web_color(0, 0, 0);
+	}
+	if(str[0] == _t('#'))
+	{
+		tstring red		= _t("");
+		tstring green		= _t("");
+		tstring blue		= _t("");
+		if(t_strlen(str + 1) == 3)
+		{
+			red		+= str[1];
+			red		+= str[1];
+			green	+= str[2];
+			green	+= str[2];
+			blue	+= str[3];
+			blue	+= str[3];
+		} else if(t_strlen(str + 1) == 6)
+		{
+			red		+= str[1];
+			red		+= str[2];
+			green	+= str[3];
+			green	+= str[4];
+			blue	+= str[5];
+			blue	+= str[6];
+		}
+		tchar_t* sss = 0;
+		web_color clr;
+		clr.red		= (byte) t_strtol(red.c_str(),	&sss, 16);
+		clr.green	= (byte) t_strtol(green.c_str(),	&sss, 16);
+		clr.blue	= (byte) t_strtol(blue.c_str(),	&sss, 16);
+		return clr;
+	} else if(!t_strncmp(str, _t("rgb"), 3))
+	{
+		tstring s = str;
+
+		tstring::size_type pos = s.find_first_of(_t("("));
+		if(pos != tstring::npos)
+		{
+			s.erase(s.begin(), s.begin() + pos + 1);
+		}
+		pos = s.find_last_of(_t(")"));
+		if(pos != tstring::npos)
+		{
+			s.erase(s.begin() + pos, s.end());
+		}
+
+		std::vector<tstring> tokens;
+		split_string(s, tokens, _t(", \t"));
+
+		web_color clr;
+
+		if(tokens.size() >= 1)	clr.red		= (byte) t_atoi(tokens[0].c_str());
+		if(tokens.size() >= 2)	clr.green	= (byte) t_atoi(tokens[1].c_str());
+		if(tokens.size() >= 3)	clr.blue	= (byte) t_atoi(tokens[2].c_str());
+		if(tokens.size() >= 4)	clr.alpha	= (byte) (t_strtod(tokens[3].c_str(), 0) * 255.0);
+
+		return clr;
+	} else
+	{
+		tstring rgb = resolve_name(str, callback);
+		if(!rgb.empty())
+		{
+			return from_string(rgb.c_str(), callback);
+		}
+	}
+	return web_color(0, 0, 0);
+}
+
+litehtml::tstring litehtml::web_color::resolve_name(const tchar_t* name, litehtml::document_container* callback)
+{
+	for(int i=0; g_def_colors[i].name; i++)
+	{
+		if(!t_strcasecmp(name, g_def_colors[i].name))
+		{
+            return std::move(litehtml::tstring(g_def_colors[i].rgb));
+		}
+	}
+    if (callback)
+    {
+        litehtml::tstring clr = callback->resolve_color(name);
+        return std::move(clr);
+    }
+    return std::move(litehtml::tstring());
+}
+
+bool litehtml::web_color::is_color(const tchar_t* str)
+{
+	if(!t_strncasecmp(str, _t("rgb"), 3) || str[0] == _t('#'))
+	{
+		return true;
+	}
+    if (!t_isdigit(str[0]) && str[0] != _t('.'))
+	{
+		return true;
+	}
+	return false;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/web_color.h b/src/plugins/litehtml_viewer/litehtml/web_color.h
index 8d4829f..fa3b370 100644
--- a/src/plugins/litehtml_viewer/litehtml/web_color.h
+++ b/src/plugins/litehtml_viewer/litehtml/web_color.h
@@ -1,56 +1,61 @@
-#pragma once
-
-namespace litehtml
-{
-	struct def_color
-	{
-		const tchar_t*	name;
-		const tchar_t*	rgb;
-	};
-
-	extern def_color g_def_colors[];
-
-	struct web_color
-	{
-		byte    blue;
-		byte    green;
-		byte    red;
-		byte    alpha;
-
-		web_color(byte r, byte g, byte b, byte a = 255)
-		{
-			blue	= b;
-			green	= g;
-			red		= r;
-			alpha	= a;
-		}
-
-		web_color()
-		{
-			blue	= 0;
-			green	= 0;
-			red		= 0;
-			alpha	= 0xFF;
-		}
-
-		web_color(const web_color& val)
-		{
-			blue	= val.blue;
-			green	= val.green;
-			red		= val.red;
-			alpha	= val.alpha;
-		}
-
-		web_color& operator=(const web_color& val)
-		{
-			blue	= val.blue;
-			green	= val.green;
-			red		= val.red;
-			alpha	= val.alpha;
-			return *this;
-		}
-		static web_color		from_string(const tchar_t* str);
-		static const tchar_t*	resolve_name(const tchar_t* name);
-		static bool				is_color(const tchar_t* str);
-	};
-}
\ No newline at end of file
+#ifndef LH_WEB_COLOR_H
+#define LH_WEB_COLOR_H
+
+namespace litehtml
+{
+	struct def_color
+	{
+		const tchar_t*	name;
+		const tchar_t*	rgb;
+	};
+
+	extern def_color g_def_colors[];
+
+    class document_container;
+
+	struct web_color
+	{
+		byte    blue;
+		byte    green;
+		byte    red;
+		byte    alpha;
+
+		web_color(byte r, byte g, byte b, byte a = 255)
+		{
+			blue	= b;
+			green	= g;
+			red		= r;
+			alpha	= a;
+		}
+
+		web_color()
+		{
+			blue	= 0;
+			green	= 0;
+			red		= 0;
+			alpha	= 0xFF;
+		}
+
+		web_color(const web_color& val)
+		{
+			blue	= val.blue;
+			green	= val.green;
+			red		= val.red;
+			alpha	= val.alpha;
+		}
+
+		web_color& operator=(const web_color& val)
+		{
+			blue	= val.blue;
+			green	= val.green;
+			red		= val.red;
+			alpha	= val.alpha;
+			return *this;
+		}
+        static web_color            from_string(const tchar_t* str, litehtml::document_container* callback);
+		static litehtml::tstring    resolve_name(const tchar_t* name, litehtml::document_container* callback);
+        static bool                 is_color(const tchar_t* str);
+	};
+}
+
+#endif  // LH_WEB_COLOR_H

commit 2ce3418fef6b233faf18abd7d67add1c1baf41d0
Author: Michael Rasmussen <mir at datanom.net>
Date:   Fri Nov 16 17:18:45 2018 +0100

    Use statusbar for notification. Begin print implementation
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/litehtml_viewer/lh_viewer.c b/src/plugins/litehtml_viewer/lh_viewer.c
index c8912e2..f127917 100644
--- a/src/plugins/litehtml_viewer/lh_viewer.c
+++ b/src/plugins/litehtml_viewer/lh_viewer.c
@@ -24,6 +24,8 @@
 
 #include <codeconv.h>
 #include "common/utils.h"
+#include "mainwindow.h"
+#include "statusbar.h"
 #include "lh_viewer.h"
 
 static gchar *content_types[] = { "text/html", NULL };
@@ -44,20 +46,32 @@ static GtkWidget *lh_get_widget(MimeViewer *_viewer)
 }
 
 static gchar *get_utf8_string(const gchar *string) {
-        gchar *utf8;
+        gchar *utf8 = NULL;
         gsize length;
         GError *error = NULL;
+        gchar *locale = 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;
+		gchar* split = g_strstr_len(cur_locale, -1, ".");
+		if (split) {
+		    locale = ++split;
+		} else {
+		    locale = (gchar *) cur_locale;
+		}
+		debug_print("Try converting to UTF-8 from %s\n", locale);
+		if (g_ascii_strcasecmp("utf-8", locale) != 0) {
+		    utf8 = g_convert(string, -1, "utf-8", locale, NULL, &length, &error);
+		    if (error) {
+			    debug_print("Failed convertion to current locale: %s\n", error->message);
+			    g_clear_error(&error);
+			}
+	    }
+	    if (!utf8) {
+	        debug_print("Use iso-8859-1 as last resort\n");
 			utf8 = g_convert(string, -1, "utf-8", "iso-8859-1", NULL, &length, &error);
 			if (error) {
-				debug_print("Charset detection failed");
+				debug_print("Charset detection failed. Use text as is\n");
 				utf8 = g_strdup(string);
 				g_clear_error(&error);
 			}
@@ -121,6 +135,14 @@ static void lh_destroy_viewer(MimeViewer *_viewer)
 //	lh_widget_destroy(viewer->widget);
 }
 
+static void lh_print_viewer (MimeViewer *_viewer)
+{
+    debug_print("LH: print_viewer\n");
+    
+    LHViewer* viewer = (LHViewer *) _viewer;
+    lh_widget_print(viewer->widget);    
+}
+
 /***************************************************************/
 MimeViewer *lh_viewer_create()
 {
@@ -135,6 +157,8 @@ MimeViewer *lh_viewer_create()
 
 	viewer->mimeviewer.clear_viewer = lh_clear_viewer;
 	viewer->mimeviewer.destroy_viewer = lh_destroy_viewer;
+	
+	viewer->mimeviewer.print = lh_print_viewer;
 
 	viewer->vbox = gtk_vbox_new(FALSE, 0);
 
@@ -147,3 +171,15 @@ MimeViewer *lh_viewer_create()
 	return (MimeViewer *)viewer;
 }
 
+void lh_widget_statusbar_push(gchar* msg)
+{
+	MainWindow *mainwin = mainwindow_get_mainwindow();
+	STATUSBAR_PUSH(mainwin, msg);
+        g_free(msg);
+}
+
+void lh_widget_statusbar_pop()
+{
+        MainWindow *mainwin = mainwindow_get_mainwindow();
+        STATUSBAR_POP(mainwin);
+}
diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index ec96a16..a4528c0 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -149,12 +149,19 @@ GdkPixbuf *lh_widget::get_image(const litehtml::tchar_t* url, bool redraw_on_rea
 	GdkPixbuf *pixbuf = NULL;
 
 	g_log(NULL, G_LOG_LEVEL_MESSAGE, "Loading... %s", url);
-
+        lh_widget_statusbar_push(g_strconcat("Loading ", url, " ...", NULL));
+	
 	http http_loader;
 	GInputStream *image = http_loader.load_url(url, &error);
     
-	if (!image) return NULL;
-	
+	if (error || !image) {
+	    if (error) {
+		g_log(NULL, G_LOG_LEVEL_WARNING, "lh_widget::get_image: Could not create pixbuf %s", error->message);
+		g_clear_error(&error);
+	    }
+	    goto statusbar_pop;
+	}
+
 	pixbuf = gdk_pixbuf_new_from_stream(image, NULL, &error);
 	if (error) {
 	    g_log(NULL, G_LOG_LEVEL_WARNING, "lh_widget::get_image: Could not create pixbuf %s", error->message);
@@ -167,18 +174,23 @@ GdkPixbuf *lh_widget::get_image(const litehtml::tchar_t* url, bool redraw_on_rea
 /*	if (redraw_on_ready) {
 		redraw();
 	}*/
+
+statusbar_pop:
+	lh_widget_statusbar_pop();
 	
 	return pixbuf;
 }
 
 void lh_widget::open_html(const gchar *contents)
 {
+	lh_widget_statusbar_push(g_strconcat("Loading HTML part", " ...", NULL));
 	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();
 	}
+	lh_widget_statusbar_pop();
 }
 
 void lh_widget::draw(cairo_t *cr)
@@ -281,7 +293,7 @@ void lh_widget::clear()
 
 void lh_widget::set_cursor(const litehtml::tchar_t* cursor)
 {
-    g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget set_cursor %s:%s", m_cursor, cursor);
+    //g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget set_cursor %s:%s", m_cursor, cursor);
     if (cursor)
     {
 	if (m_cursor != cursor)
@@ -294,7 +306,7 @@ void lh_widget::set_cursor(const litehtml::tchar_t* cursor)
 
 void lh_widget::update_cursor()
 {
-    g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget update_cursor %s", m_cursor);
+    //g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget update_cursor %s", m_cursor);
     GdkCursorType cursType = GDK_ARROW;
     if(m_cursor == _t("pointer"))
     {
@@ -309,6 +321,12 @@ void lh_widget::update_cursor()
     }
 }
 
+void lh_widget::print()
+{
+    g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget print");
+    gtk_widget_realize(GTK_WIDGET(m_drawing_area));
+}
+
 static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
 		gpointer user_data)
 {
@@ -358,7 +376,7 @@ static gboolean motion_notify_event(GtkWidget *widget, GdkEventButton *event,
     litehtml::position::vector redraw_boxes;
     lh_widget *w = (lh_widget *)user_data;
     
-    g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget on_motion_notify_event");
+    //g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget on_motion_notify_event");
 
     if(w->m_html)
     {    
@@ -440,4 +458,8 @@ void lh_widget_destroy(lh_widget_wrapped *w)
 	delete w;
 }
 
+void lh_widget_print(lh_widget_wrapped *w) {
+	w->print();
+}
+
 } /* extern "C" */
diff --git a/src/plugins/litehtml_viewer/lh_widget.h b/src/plugins/litehtml_viewer/lh_widget.h
index 2f4eb11..ed56f7d 100644
--- a/src/plugins/litehtml_viewer/lh_widget.h
+++ b/src/plugins/litehtml_viewer/lh_widget.h
@@ -29,6 +29,7 @@ class lh_widget : public container_linux
 		void open_html(const gchar *contents);
 		void clear();
 		void update_cursor();
+		void print();
 
 		litehtml::document::ptr m_html;
 		litehtml::tstring m_clicked_url;
diff --git a/src/plugins/litehtml_viewer/lh_widget_wrapped.h b/src/plugins/litehtml_viewer/lh_widget_wrapped.h
index 521c7f4..64085fa 100644
--- a/src/plugins/litehtml_viewer/lh_widget_wrapped.h
+++ b/src/plugins/litehtml_viewer/lh_widget_wrapped.h
@@ -12,6 +12,9 @@ GtkWidget *lh_widget_get_widget(lh_widget_wrapped *w);
 void lh_widget_open_html(lh_widget_wrapped *w, const gchar *path);
 void lh_widget_clear(lh_widget_wrapped *w);
 void lh_widget_destroy(lh_widget_wrapped *w);
+void lh_widget_statusbar_push(gchar* msg);
+void lh_widget_statusbar_pop();
+void lh_widget_print(lh_widget_wrapped *w);
 
 #ifdef __cplusplus
 } /* extern "C" */

commit e905518e7224100e3bb0970c7615069c525ce56b
Author: Michael Rasmussen <mir at datanom.net>
Date:   Fri Nov 16 17:13:05 2018 +0100

    Proper fix for memory leak
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/litehtml_viewer/http.cpp b/src/plugins/litehtml_viewer/http.cpp
index 68af736..92023be 100644
--- a/src/plugins/litehtml_viewer/http.cpp
+++ b/src/plugins/litehtml_viewer/http.cpp
@@ -80,10 +80,9 @@ GInputStream *http::load_url(const gchar *url, GError **error)
 	if (res != CURLE_OK) {
 	    _error = g_error_new_literal(G_FILE_ERROR, res, curl_easy_strerror(res));
 	} else {
-	    void *bytes = g_memdup(data.memory, data.size);
+	    g_log(NULL, G_LOG_LEVEL_MESSAGE, "Image size: %d", data.size);
+	    stream = g_memory_input_stream_new_from_data(g_memdup(data.memory, data.size), data.size, http::destroy_giostream);
 	    g_free(data.memory);
-	    stream = g_memory_input_stream_new_from_data(bytes, data.size, http::destroy_giostream);
-	    g_free(bytes);
 	}
     }
 

commit f1227adc26b0eda9b4852578212398f5320ebe4d
Author: Michael Rasmussen <mir at datanom.net>
Date:   Thu Nov 15 23:12:11 2018 +0100

    Fix memory leak
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/litehtml_viewer/http.cpp b/src/plugins/litehtml_viewer/http.cpp
index e6547eb..68af736 100644
--- a/src/plugins/litehtml_viewer/http.cpp
+++ b/src/plugins/litehtml_viewer/http.cpp
@@ -80,8 +80,10 @@ GInputStream *http::load_url(const gchar *url, GError **error)
 	if (res != CURLE_OK) {
 	    _error = g_error_new_literal(G_FILE_ERROR, res, curl_easy_strerror(res));
 	} else {
-	    stream = g_memory_input_stream_new_from_data(g_memdup(data.memory, data.size), data.size, http::destroy_giostream);
+	    void *bytes = g_memdup(data.memory, data.size);
 	    g_free(data.memory);
+	    stream = g_memory_input_stream_new_from_data(bytes, data.size, http::destroy_giostream);
+	    g_free(bytes);
 	}
     }
 

commit 8f42ff225dfbafbf80c05754855a5c0d888528e5
Author: Michael Rasmussen <mir at datanom.net>
Date:   Thu Nov 15 23:06:29 2018 +0100

    Do not use G_LOG_LEVEL_ERROR. Makes claws crash
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/litehtml_viewer/http.cpp b/src/plugins/litehtml_viewer/http.cpp
index 3cfa36e..e6547eb 100644
--- a/src/plugins/litehtml_viewer/http.cpp
+++ b/src/plugins/litehtml_viewer/http.cpp
@@ -30,7 +30,7 @@ size_t http::curl_write_data(char* ptr, size_t size, size_t nmemb, void* data_pt
     char *input = (char *) g_realloc(data->memory, data->size + realsize + 1);
     if(input == NULL) {
         /* out of memory! */
-        g_log(NULL, G_LOG_LEVEL_ERROR, "not enough memory (realloc returned NULL)");
+        g_log(NULL, G_LOG_LEVEL_WARNING, "not enough memory (realloc returned NULL)");
         return 0;
     }
     
diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index 432a169..ec96a16 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -150,14 +150,14 @@ GdkPixbuf *lh_widget::get_image(const litehtml::tchar_t* url, bool redraw_on_rea
 
 	g_log(NULL, G_LOG_LEVEL_MESSAGE, "Loading... %s", url);
 
-    http http_loader;
-    GInputStream *image = http_loader.load_url(url, &error);
+	http http_loader;
+	GInputStream *image = http_loader.load_url(url, &error);
     
 	if (!image) return NULL;
 	
 	pixbuf = gdk_pixbuf_new_from_stream(image, NULL, &error);
 	if (error) {
-	    g_log(NULL, G_LOG_LEVEL_ERROR, "lh_widget::get_image: Could not create pixbuf %s", error->message);
+	    g_log(NULL, G_LOG_LEVEL_WARNING, "lh_widget::get_image: Could not create pixbuf %s", error->message);
 	    //g_object_unref(pixbuf);
 	    pixbuf = NULL;
 	    g_clear_error(&error);
@@ -403,7 +403,7 @@ static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event,
 			     w->m_clicked_url.c_str(),
 			     GDK_CURRENT_TIME, &error);
                 if (error) {
-                    g_log(NULL, G_LOG_LEVEL_ERROR, "Failed opening url(%s): %s", w->m_clicked_url, error->message);
+                    g_log(NULL, G_LOG_LEVEL_WARNING, "Failed opening url(%s): %s", w->m_clicked_url, error->message);
                     g_clear_error(&error);
                 }
         }

commit 636f075a395c3c010ff077410b429265b061d8bb
Author: Michael Rasmussen <mir at datanom.net>
Date:   Sat Nov 10 03:11:21 2018 +0100

    Fix missing includes
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/litehtml_viewer/http.cpp b/src/plugins/litehtml_viewer/http.cpp
index 5f24e2a..3cfa36e 100644
--- a/src/plugins/litehtml_viewer/http.cpp
+++ b/src/plugins/litehtml_viewer/http.cpp
@@ -1,3 +1,4 @@
+#include <string.h>
 #include "http.h"
 
 struct Data {
@@ -26,7 +27,7 @@ size_t http::curl_write_data(char* ptr, size_t size, size_t nmemb, void* data_pt
     struct Data* data = (struct Data *) data_ptr;
     size_t realsize = size * nmemb;
     
-    char *input = (char *) realloc(data->memory, data->size + realsize + 1);
+    char *input = (char *) g_realloc(data->memory, data->size + realsize + 1);
     if(input == NULL) {
         /* out of memory! */
         g_log(NULL, G_LOG_LEVEL_ERROR, "not enough memory (realloc returned NULL)");
@@ -42,50 +43,50 @@ size_t http::curl_write_data(char* ptr, size_t size, size_t nmemb, void* data_pt
 }
 
 void http::destroy_giostream(gpointer data) {
-	GInputStream* gio;
-	if (data) {
-		gio = G_INPUT_STREAM(data);
-		g_input_stream_close(gio, NULL, NULL);
-		gio = NULL;
-	}
+    GInputStream* gio;
+    if (data) {
+	gio = G_INPUT_STREAM(data);
+	g_input_stream_close(gio, NULL, NULL);
+	gio = NULL;
+    }
 }
 
 GInputStream *http::load_url(const gchar *url, GError **error)
 {
-	GError* _error = NULL;
-	CURLcode res = CURLE_OK;
-	gsize len;
-	gchar* content;
+    GError* _error = NULL;
+    CURLcode res = CURLE_OK;
+    gsize len;
+    gchar* content;
     GInputStream* stream = NULL;
     struct Data data;
 
-    data.memory = (char *) malloc(1);
+    data.memory = (char *) g_malloc(1);
     data.size = 0;
     
-	if (!strncmp(url, "file:///", 8) || g_file_test(url, G_FILE_TEST_EXISTS)) {
-		gchar* newurl = g_filename_from_uri(url, NULL, NULL);
-		if (g_file_get_contents(newurl ? newurl : url, &content, &len, &_error)) {
-			stream = g_memory_input_stream_new_from_data(content, len, http::destroy_giostream);
-		} else {
-			g_log(NULL, G_LOG_LEVEL_MESSAGE, "%s", _error->message);
-		}
-		g_free(newurl);
+    if (!strncmp(url, "file:///", 8) || g_file_test(url, G_FILE_TEST_EXISTS)) {
+	gchar* newurl = g_filename_from_uri(url, NULL, NULL);
+	if (g_file_get_contents(newurl ? newurl : url, &content, &len, &_error)) {
+	    stream = g_memory_input_stream_new_from_data(content, len, http::destroy_giostream);
 	} else {
-		if (!curl) return NULL;
-	    curl_easy_setopt(curl, CURLOPT_URL, url);
-	    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_data);
-	    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&data);
-	    res = curl_easy_perform(curl);
-	    if (res != CURLE_OK) {
-		    _error = g_error_new_literal(G_FILE_ERROR, res, curl_easy_strerror(res));
-	    } else {
-	        stream = g_memory_input_stream_new_from_data(g_memdup(data.memory, data.size), data.size, http::destroy_giostream);
-	        g_free(data.memory);
-	    }
+	    g_log(NULL, G_LOG_LEVEL_MESSAGE, "%s", _error->message);
 	}
+	g_free(newurl);
+    } else {
+	if (!curl) return NULL;
+	curl_easy_setopt(curl, CURLOPT_URL, url);
+	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_data);
+	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&data);
+	res = curl_easy_perform(curl);
+	if (res != CURLE_OK) {
+	    _error = g_error_new_literal(G_FILE_ERROR, res, curl_easy_strerror(res));
+	} else {
+	    stream = g_memory_input_stream_new_from_data(g_memdup(data.memory, data.size), data.size, http::destroy_giostream);
+	    g_free(data.memory);
+	}
+    }
 
-	if (error && _error) *error = _error;
+    if (error && _error) *error = _error;
 
-	return stream;
+    return stream;
 }
 

commit 5f100b9612fc42434d8793bc78a8241ec5fb7669
Author: Michael Rasmussen <mir at datanom.net>
Date:   Fri Nov 9 17:08:56 2018 +0100

    Fix wrong cursor type
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index 0b0839b..432a169 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -298,7 +298,7 @@ void lh_widget::update_cursor()
     GdkCursorType cursType = GDK_ARROW;
     if(m_cursor == _t("pointer"))
     {
-        cursType = GDK_HAND1;
+        cursType = GDK_HAND2;
     }
     if(cursType == GDK_ARROW)
     {

commit 1e2ed07afeefa2bb748f273a8d3ad0519d78c54e
Author: Michael Rasmussen <mir at datanom.net>
Date:   Fri Nov 9 17:00:50 2018 +0100

    Change cursor type when hoover over link
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index f92cd3d..0b0839b 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -123,13 +123,6 @@ void lh_widget::on_anchor_click(const litehtml::tchar_t* url, const litehtml::el
 	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");
@@ -286,6 +279,36 @@ void lh_widget::clear()
 	m_rendered_width = 0;
 }
 
+void lh_widget::set_cursor(const litehtml::tchar_t* cursor)
+{
+    g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget set_cursor %s:%s", m_cursor, cursor);
+    if (cursor)
+    {
+	if (m_cursor != cursor)
+	{
+	    m_cursor = cursor;
+	    update_cursor();
+	}
+    }
+}
+
+void lh_widget::update_cursor()
+{
+    g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget update_cursor %s", m_cursor);
+    GdkCursorType cursType = GDK_ARROW;
+    if(m_cursor == _t("pointer"))
+    {
+        cursType = GDK_HAND1;
+    }
+    if(cursType == GDK_ARROW)
+    {
+        gdk_window_set_cursor(gtk_widget_get_window(m_drawing_area), NULL);
+    } else
+    {
+        gdk_window_set_cursor(gtk_widget_get_window(m_drawing_area), gdk_cursor_new(cursType));
+    }
+}
+
 static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
 		gpointer user_data)
 {
@@ -320,6 +343,7 @@ static gboolean button_press_event(GtkWidget *widget, GdkEventButton *event,
         {
             for(auto& pos : redraw_boxes)
             {
+		g_log(NULL, G_LOG_LEVEL_MESSAGE, "x: %d y:%d w: %d h: %d", pos.x, pos.y, pos.width, pos.height);
                 gtk_widget_queue_draw_area(widget, pos.x, pos.y, pos.width, pos.height);
             }
         }
@@ -342,6 +366,7 @@ static gboolean motion_notify_event(GtkWidget *widget, GdkEventButton *event,
         {
             for (auto& pos : redraw_boxes)
             {
+		g_log(NULL, G_LOG_LEVEL_MESSAGE, "x: %d y:%d w: %d h: %d", pos.x, pos.y, pos.width, pos.height);
                 gtk_widget_queue_draw_area(widget, pos.x, pos.y, pos.width, pos.height);
             }
         }
@@ -366,6 +391,7 @@ static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event,
         {
             for (auto& pos : redraw_boxes)
             {
+		g_log(NULL, G_LOG_LEVEL_MESSAGE, "x: %d y:%d w: %d h: %d", pos.x, pos.y, pos.width, pos.height);
                 gtk_widget_queue_draw_area(widget, pos.x, pos.y, pos.width, pos.height);
             }
         }
@@ -373,7 +399,9 @@ static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event,
         if (!w->m_clicked_url.empty())
         {
                 g_log(NULL, G_LOG_LEVEL_MESSAGE, "Open in browser: %s", w->m_clicked_url.c_str());
-                gtk_show_uri(NULL, w->m_clicked_url.c_str(), GDK_CURRENT_TIME, &error);
+		gtk_show_uri(gdk_screen_get_default(),
+			     w->m_clicked_url.c_str(),
+			     GDK_CURRENT_TIME, &error);
                 if (error) {
                     g_log(NULL, G_LOG_LEVEL_ERROR, "Failed opening url(%s): %s", w->m_clicked_url, error->message);
                     g_clear_error(&error);
diff --git a/src/plugins/litehtml_viewer/lh_widget.h b/src/plugins/litehtml_viewer/lh_widget.h
index 32d751c..2f4eb11 100644
--- a/src/plugins/litehtml_viewer/lh_widget.h
+++ b/src/plugins/litehtml_viewer/lh_widget.h
@@ -28,8 +28,9 @@ class lh_widget : public container_linux
 		void redraw();
 		void open_html(const gchar *contents);
 		void clear();
+		void update_cursor();
 
-        litehtml::document::ptr m_html;
+		litehtml::document::ptr m_html;
 		litehtml::tstring m_clicked_url;
 
 	private:

commit 6fdbe65294b86829889e2e583deaf63d664cf247
Author: Michael Rasmussen <mir at datanom.net>
Date:   Fri Nov 9 01:57:34 2018 +0100

    Update TODO
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/litehtml_viewer/TODO b/src/plugins/litehtml_viewer/TODO
index 56e3846..543238a 100644
--- a/src/plugins/litehtml_viewer/TODO
+++ b/src/plugins/litehtml_viewer/TODO
@@ -1,6 +1,4 @@
-- Add support for displaying images
 - Add support for printing
-- Add support for links (open in default browser)
 
 Images:
 https://developer.gnome.org/gio/unstable/GMemoryInputStream.html#g-memory-input-stream-new-from-data

commit f9ce00fb2e4d4d8ba3c1fd1060fb360f8f19cdc7
Author: Michael Rasmussen <mir at datanom.net>
Date:   Fri Nov 9 01:56:29 2018 +0100

    Implemented support for links
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/litehtml_viewer/lh_viewer.c b/src/plugins/litehtml_viewer/lh_viewer.c
index 0b3cf53..c8912e2 100644
--- a/src/plugins/litehtml_viewer/lh_viewer.c
+++ b/src/plugins/litehtml_viewer/lh_viewer.c
@@ -59,7 +59,7 @@ static gchar *get_utf8_string(const gchar *string) {
 			if (error) {
 				debug_print("Charset detection failed");
 				utf8 = g_strdup(string);
-				g_error_free(error);
+				g_clear_error(&error);
 			}
 		}
 	} else {
@@ -90,7 +90,7 @@ static void lh_show_mimepart(MimeViewer *_viewer, const gchar *infole,
 	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);
+		g_clear_error(&error);
 		return;
 	} else {
 		utf8 = get_utf8_string(contents);
diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index ba423a0..f92cd3d 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -28,6 +28,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <curl/curl.h>
+#include <gdk/gdk.h>
 #include "lh_widget.h"
 #include "lh_widget_wrapped.h"
 #include "http.h"
@@ -40,6 +41,12 @@ static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
 		gpointer user_data);
 static void size_allocate_cb(GtkWidget *widget, GdkRectangle *allocation,
 		gpointer user_data);
+static gboolean button_press_event(GtkWidget *widget, GdkEventButton *event,
+		gpointer user_data);
+static gboolean motion_notify_event(GtkWidget *widget, GdkEventButton *event,
+        gpointer user_data);
+static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event,
+        gpointer user_data);
 
 lh_widget::lh_widget()
 {
@@ -62,12 +69,24 @@ lh_widget::lh_widget()
 	gtk_container_add(GTK_CONTAINER(m_viewport), m_drawing_area);
 	g_signal_connect(m_drawing_area, "expose-event",
 			G_CALLBACK(expose_event_cb), this);
+	g_signal_connect(m_drawing_area, "motion_notify_event",
+			G_CALLBACK(motion_notify_event), this);
+	g_signal_connect(m_drawing_area, "button_press_event",
+			G_CALLBACK(button_press_event), this);
+	g_signal_connect(m_drawing_area, "button_release_event",
+			G_CALLBACK(button_release_event), this);
 
 	gtk_widget_show_all(m_scrolled_window);
 
 	m_html = NULL;
 	m_rendered_width = 0;
 	m_context.load_master_stylesheet(master_css);
+
+	gtk_widget_set_events(m_drawing_area,
+			        GDK_BUTTON_RELEASE_MASK
+			      | GDK_BUTTON_PRESS_MASK
+			      | GDK_POINTER_MOTION_MASK);
+
 }
 
 lh_widget::~lh_widget()
@@ -98,7 +117,9 @@ void lh_widget::set_base_url(const litehtml::tchar_t* base_url)
 
 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");
+	g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget on_anchor_click. url -> %s", url);
+	m_clicked_url = url;
+	
 	return;
 }
 
@@ -144,8 +165,11 @@ GdkPixbuf *lh_widget::get_image(const litehtml::tchar_t* url, bool redraw_on_rea
 	pixbuf = gdk_pixbuf_new_from_stream(image, NULL, &error);
 	if (error) {
 	    g_log(NULL, G_LOG_LEVEL_ERROR, "lh_widget::get_image: Could not create pixbuf %s", error->message);
+	    //g_object_unref(pixbuf);
 	    pixbuf = NULL;
+	    g_clear_error(&error);
 	}
+	g_input_stream_close(image, NULL, NULL);
 
 /*	if (redraw_on_ready) {
 		redraw();
@@ -262,7 +286,6 @@ void lh_widget::clear()
 	m_rendered_width = 0;
 }
 
-
 static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
 		gpointer user_data)
 {
@@ -283,6 +306,84 @@ static void size_allocate_cb(GtkWidget *widget, GdkRectangle *allocation,
 	w->redraw();
 }
 
+static gboolean button_press_event(GtkWidget *widget, GdkEventButton *event,
+		gpointer user_data)
+{
+    litehtml::position::vector redraw_boxes;
+    lh_widget *w = (lh_widget *)user_data;
+    
+    g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget on_button_press_event");
+
+    if(w->m_html)
+    {    
+        if(w->m_html->on_lbutton_down((int) event->x, (int) event->y, (int) event->x, (int) event->y, redraw_boxes))
+        {
+            for(auto& pos : redraw_boxes)
+            {
+                gtk_widget_queue_draw_area(widget, pos.x, pos.y, pos.width, pos.height);
+            }
+        }
+	}
+	
+	return true;
+}
+
+static gboolean motion_notify_event(GtkWidget *widget, GdkEventButton *event,
+        gpointer user_data)
+{
+    litehtml::position::vector redraw_boxes;
+    lh_widget *w = (lh_widget *)user_data;
+    
+    g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget on_motion_notify_event");
+
+    if(w->m_html)
+    {    
+        if(w->m_html->on_mouse_over((int) event->x, (int) event->y, (int) event->x, (int) event->y, redraw_boxes))
+        {
+            for (auto& pos : redraw_boxes)
+            {
+                gtk_widget_queue_draw_area(widget, pos.x, pos.y, pos.width, pos.height);
+            }
+        }
+	}
+	
+	return true;
+}
+
+static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event,
+        gpointer user_data)
+{
+    litehtml::position::vector redraw_boxes;
+    lh_widget *w = (lh_widget *)user_data;
+    GError* error = NULL;
+
+	g_log(NULL, G_LOG_LEVEL_MESSAGE, "lh_widget on_button_release_event");
+	
+	if(w->m_html)
+	{
+	    w->m_clicked_url.clear();
+        if(w->m_html->on_lbutton_up((int) event->x, (int) event->y, (int) event->x, (int) event->y, redraw_boxes))
+        {
+            for (auto& pos : redraw_boxes)
+            {
+                gtk_widget_queue_draw_area(widget, pos.x, pos.y, pos.width, pos.height);
+            }
+        }
+        
+        if (!w->m_clicked_url.empty())
+        {
+                g_log(NULL, G_LOG_LEVEL_MESSAGE, "Open in browser: %s", w->m_clicked_url.c_str());
+                gtk_show_uri(NULL, w->m_clicked_url.c_str(), GDK_CURRENT_TIME, &error);
+                if (error) {
+                    g_log(NULL, G_LOG_LEVEL_ERROR, "Failed opening url(%s): %s", w->m_clicked_url, error->message);
+                    g_clear_error(&error);
+                }
+        }
+    }
+
+	return true;
+}
+
 ///////////////////////////////////////////////////////////
 extern "C" {
 
diff --git a/src/plugins/litehtml_viewer/lh_widget.h b/src/plugins/litehtml_viewer/lh_widget.h
index 0cb97c6..32d751c 100644
--- a/src/plugins/litehtml_viewer/lh_widget.h
+++ b/src/plugins/litehtml_viewer/lh_widget.h
@@ -29,16 +29,18 @@ class lh_widget : public container_linux
 		void open_html(const gchar *contents);
 		void clear();
 
+        litehtml::document::ptr m_html;
+		litehtml::tstring m_clicked_url;
+
 	private:
 		void paint_white();
 		GInputStream *load_url(const gchar *url, GError **error);
 
-		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;
-
+		litehtml::tstring m_cursor;
 };

commit 2d53f85576e2db0783a121d7ceb83b5842226504
Author: Michael Rasmussen <mir at datanom.net>
Date:   Thu Nov 8 00:50:37 2018 +0100

    I am tired ;-)
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/litehtml_viewer/http.cpp b/src/plugins/litehtml_viewer/http.cpp
index 2a8709a..5f24e2a 100644
--- a/src/plugins/litehtml_viewer/http.cpp
+++ b/src/plugins/litehtml_viewer/http.cpp
@@ -27,7 +27,7 @@ size_t http::curl_write_data(char* ptr, size_t size, size_t nmemb, void* data_pt
     size_t realsize = size * nmemb;
     
     char *input = (char *) realloc(data->memory, data->size + realsize + 1);
-    if(ptr == NULL) {
+    if(input == NULL) {
         /* out of memory! */
         g_log(NULL, G_LOG_LEVEL_ERROR, "not enough memory (realloc returned NULL)");
         return 0;

commit 251d6bcffede3cac0453c377e84c9245cb0982b6
Author: Michael Rasmussen <mir at datanom.net>
Date:   Thu Nov 8 00:45:52 2018 +0100

    Cleaner code a fix memory leak
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/litehtml_viewer/http.cpp b/src/plugins/litehtml_viewer/http.cpp
index 46882e1..2a8709a 100644
--- a/src/plugins/litehtml_viewer/http.cpp
+++ b/src/plugins/litehtml_viewer/http.cpp
@@ -1,5 +1,10 @@
 #include "http.h"
 
+struct Data {
+  char *memory;
+  size_t size;
+};
+
 http::http()
 {
     curl = curl_easy_init();
@@ -10,28 +15,30 @@ http::http()
     curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);
     curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);
     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http::curl_write_data);
-    response_data = NULL;
-    response_size = 0;;
 }
 
 http::~http()
 {
     curl_easy_cleanup(curl);
-    if (response_data) {
-        g_free(response_data);
-    }
 }
 
-size_t http::curl_write_data(char* ptr, size_t size, size_t nmemb, void* data) {
-	if (!response_data)
-		response_data = (char *) malloc(size * nmemb);
-	else
-		response_data = (char *) realloc(response_data, response_size + size * nmemb);
-	if (response_data) {
-		memcpy(response_data + response_size, ptr, size * nmemb);
-		response_size += size * nmemb;
-	}
-	return size * nmemb;
+size_t http::curl_write_data(char* ptr, size_t size, size_t nmemb, void* data_ptr) {
+    struct Data* data = (struct Data *) data_ptr;
+    size_t realsize = size * nmemb;
+    
+    char *input = (char *) realloc(data->memory, data->size + realsize + 1);
+    if(ptr == NULL) {
+        /* out of memory! */
+        g_log(NULL, G_LOG_LEVEL_ERROR, "not enough memory (realloc returned NULL)");
+        return 0;
+    }
+    
+    data->memory = input;
+    memcpy(&(data->memory[data->size]), ptr, realsize);
+    data->size += realsize;
+    data->memory[data->size] = 0;
+    
+    return realsize;
 }
 
 void http::destroy_giostream(gpointer data) {
@@ -50,8 +57,11 @@ GInputStream *http::load_url(const gchar *url, GError **error)
 	gsize len;
 	gchar* content;
     GInputStream* stream = NULL;
+    struct Data data;
 
-
+    data.memory = (char *) malloc(1);
+    data.size = 0;
+    
 	if (!strncmp(url, "file:///", 8) || g_file_test(url, G_FILE_TEST_EXISTS)) {
 		gchar* newurl = g_filename_from_uri(url, NULL, NULL);
 		if (g_file_get_contents(newurl ? newurl : url, &content, &len, &_error)) {
@@ -64,11 +74,13 @@ GInputStream *http::load_url(const gchar *url, GError **error)
 		if (!curl) return NULL;
 	    curl_easy_setopt(curl, CURLOPT_URL, url);
 	    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_data);
+	    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&data);
 	    res = curl_easy_perform(curl);
 	    if (res != CURLE_OK) {
 		    _error = g_error_new_literal(G_FILE_ERROR, res, curl_easy_strerror(res));
 	    } else {
-	        stream = g_memory_input_stream_new_from_data(response_data, response_size, http::destroy_giostream);
+	        stream = g_memory_input_stream_new_from_data(g_memdup(data.memory, data.size), data.size, http::destroy_giostream);
+	        g_free(data.memory);
 	    }
 	}
 
diff --git a/src/plugins/litehtml_viewer/http.h b/src/plugins/litehtml_viewer/http.h
index 4c4b03f..c8c3bee 100644
--- a/src/plugins/litehtml_viewer/http.h
+++ b/src/plugins/litehtml_viewer/http.h
@@ -11,8 +11,6 @@
 class http
 {
     CURL*           curl;
-    static gchar*   response_data;
-    static size_t   response_size;
 
 public:
     http();
@@ -21,7 +19,7 @@ public:
     GInputStream *load_url(const gchar *url, GError **error);
 
 private:
-    static size_t curl_write_data(char* ptr, size_t size, size_t nmemb, void* data);
+    static size_t curl_write_data(char* ptr, size_t size, size_t nmemb, void* data_ptr);
     static void destroy_giostream(gpointer data);
 };
 

commit 97c3cabcf0e75a5b279e876cb353e9d92f775849
Author: Michael Rasmussen <mir at datanom.net>
Date:   Wed Nov 7 23:49:35 2018 +0100

    Refactor image loading to a separate class. Add dependency to curl
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/configure.ac b/configure.ac
index cc14acf..a23d8c7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1126,7 +1126,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 Litehtml		cairo, fontconfig, gumbo, curl
 dnl Libravatar:		libcurl
 dnl Notification:	optionally libnotify  unity/messaging-menu
 dnl 				   libcanberra_gtk hotkey
@@ -1638,6 +1638,10 @@ if test x"$enable_litehtml_viewer_plugin" != xno; then
 	if test x"$HAVE_LIBGUMBO" = xno; then
 		dependencies_missing="libgumbo $dependencies_missing"
 	fi
+        if test x"$HAVE_CURL" = xno; then
+                dependencies_missing="libcurl $dependencies_missing"
+        fi
+
 
         if test x"$dependencies_missing" = x; then
                 PLUGINS="$PLUGINS litehtml_viewer"
diff --git a/src/plugins/litehtml_viewer/Makefile.am b/src/plugins/litehtml_viewer/Makefile.am
index 15cb479..648960c 100644
--- a/src/plugins/litehtml_viewer/Makefile.am
+++ b/src/plugins/litehtml_viewer/Makefile.am
@@ -46,7 +46,9 @@ litehtml_viewer_la_SOURCES = \
 	container_linux.h \
 	lh_viewer.h \
 	lh_widget.h \
-	lh_widget_wrapped.h
+	lh_widget_wrapped.h \
+	http.h \
+	http.cpp
 
 litehtml_viewer_la_LDFLAGS = \
 	$(plugin_res_ldflag) $(no_undefined) $(export_symbols) \
diff --git a/src/plugins/litehtml_viewer/http.cpp b/src/plugins/litehtml_viewer/http.cpp
new file mode 100644
index 0000000..46882e1
--- /dev/null
+++ b/src/plugins/litehtml_viewer/http.cpp
@@ -0,0 +1,79 @@
+#include "http.h"
+
+http::http()
+{
+    curl = curl_easy_init();
+    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+    curl_easy_setopt(curl, CURLOPT_TIMEOUT, HTTP_GET_TIMEOUT);
+    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
+    curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
+    curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);
+    curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);
+    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http::curl_write_data);
+    response_data = NULL;
+    response_size = 0;;
+}
+
+http::~http()
+{
+    curl_easy_cleanup(curl);
+    if (response_data) {
+        g_free(response_data);
+    }
+}
+
+size_t http::curl_write_data(char* ptr, size_t size, size_t nmemb, void* data) {
+	if (!response_data)
+		response_data = (char *) malloc(size * nmemb);
+	else
+		response_data = (char *) realloc(response_data, response_size + size * nmemb);
+	if (response_data) {
+		memcpy(response_data + response_size, ptr, size * nmemb);
+		response_size += size * nmemb;
+	}
+	return size * nmemb;
+}
+
+void http::destroy_giostream(gpointer data) {
+	GInputStream* gio;
+	if (data) {
+		gio = G_INPUT_STREAM(data);
+		g_input_stream_close(gio, NULL, NULL);
+		gio = NULL;
+	}
+}
+
+GInputStream *http::load_url(const gchar *url, GError **error)
+{
+	GError* _error = NULL;
+	CURLcode res = CURLE_OK;
+	gsize len;
+	gchar* content;
+    GInputStream* stream = NULL;
+
+
+	if (!strncmp(url, "file:///", 8) || g_file_test(url, G_FILE_TEST_EXISTS)) {
+		gchar* newurl = g_filename_from_uri(url, NULL, NULL);
+		if (g_file_get_contents(newurl ? newurl : url, &content, &len, &_error)) {
+			stream = g_memory_input_stream_new_from_data(content, len, http::destroy_giostream);
+		} else {
+			g_log(NULL, G_LOG_LEVEL_MESSAGE, "%s", _error->message);
+		}
+		g_free(newurl);
+	} else {
+		if (!curl) return NULL;
+	    curl_easy_setopt(curl, CURLOPT_URL, url);
+	    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_data);
+	    res = curl_easy_perform(curl);
+	    if (res != CURLE_OK) {
+		    _error = g_error_new_literal(G_FILE_ERROR, res, curl_easy_strerror(res));
+	    } else {
+	        stream = g_memory_input_stream_new_from_data(response_data, response_size, http::destroy_giostream);
+	    }
+	}
+
+	if (error && _error) *error = _error;
+
+	return stream;
+}
+
diff --git a/src/plugins/litehtml_viewer/http.h b/src/plugins/litehtml_viewer/http.h
new file mode 100644
index 0000000..4c4b03f
--- /dev/null
+++ b/src/plugins/litehtml_viewer/http.h
@@ -0,0 +1,28 @@
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <curl/curl.h>
+#include <gio/gio.h>
+
+#define HTTP_GET_TIMEOUT 5L
+
+class http
+{
+    CURL*           curl;
+    static gchar*   response_data;
+    static size_t   response_size;
+
+public:
+    http();
+    ~http();
+
+    GInputStream *load_url(const gchar *url, GError **error);
+
+private:
+    static size_t curl_write_data(char* ptr, size_t size, size_t nmemb, void* data);
+    static void destroy_giostream(gpointer data);
+};
+
+
diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index 5c90005..ba423a0 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -30,24 +30,16 @@
 #include <curl/curl.h>
 #include "lh_widget.h"
 #include "lh_widget_wrapped.h"
+#include "http.h"
 
 char master_css[] = {
 #include "css.inc"
 };
 
-/**
-  * curl callback
-  */
-static char* response_mime = NULL;     /* response content-type. ex: "text/html" */
-static char* response_data = NULL;     /* response data from server. */
-static size_t response_size = 0;       /* response size of data */
-
 static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
 		gpointer user_data);
 static void size_allocate_cb(GtkWidget *widget, GdkRectangle *allocation,
 		gpointer user_data);
-static size_t handle_returned_data(char* ptr, size_t size, size_t nmemb, void* stream);
-static size_t handle_returned_header(void* ptr, size_t size, size_t nmemb, void* stream);
 
 lh_widget::lh_widget()
 {
@@ -76,7 +68,6 @@ lh_widget::lh_widget()
 	m_html = NULL;
 	m_rendered_width = 0;
 	m_context.load_master_stylesheet(master_css);
-	stream = NULL;
 }
 
 lh_widget::~lh_widget()
@@ -86,10 +77,6 @@ lh_widget::~lh_widget()
 	g_object_unref(m_scrolled_window);
 	m_scrolled_window = NULL;
 	m_html = NULL;
-	if (stream) {
-	    g_input_stream_close(stream, NULL, NULL);
-	    stream = NULL;
-	}
 }
 
 GtkWidget *lh_widget::get_widget() const
@@ -149,27 +136,20 @@ GdkPixbuf *lh_widget::get_image(const litehtml::tchar_t* url, bool redraw_on_rea
 
 	g_log(NULL, G_LOG_LEVEL_MESSAGE, "Loading... %s", url);
 
-	GInputStream *image = load_url(url, &error);
+    http http_loader;
+    GInputStream *image = http_loader.load_url(url, &error);
+    
+	if (!image) return NULL;
+	
+	pixbuf = gdk_pixbuf_new_from_stream(image, NULL, &error);
 	if (error) {
-		g_log(NULL, G_LOG_LEVEL_MESSAGE, "Error: %s", error->message);
-		g_error_free(error);
-		return NULL;
+	    g_log(NULL, G_LOG_LEVEL_ERROR, "lh_widget::get_image: Could not create pixbuf %s", error->message);
+	    pixbuf = NULL;
 	}
 
-	GdkPixbufLoader* loader = gdk_pixbuf_loader_new();
-	if (gdk_pixbuf_loader_write(loader, (const guchar*)response_data, response_size, &error)) {
-		pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
-	} else {
-		g_log(NULL, G_LOG_LEVEL_ERROR, "lh_widget::get_image: Could not create pixbuf");
-	}
-	gdk_pixbuf_loader_close(loader, NULL);
-
-        /* cleanup callback data */
-        if (response_mime) g_free(response_mime);
-        if (response_data) g_free(response_data);
-        response_data = NULL;
-        response_mime = NULL;
-        response_size = 0;
+/*	if (redraw_on_ready) {
+		redraw();
+	}*/
 	
 	return pixbuf;
 }
@@ -282,57 +262,6 @@ void lh_widget::clear()
 	m_rendered_width = 0;
 }
 
-GInputStream *lh_widget::load_url(const gchar *url, GError **error)
-{
-	GError* _error = NULL;
-	CURL* curl = NULL;
-	CURLcode res = CURLE_OK;
-	gsize len;
-	gchar* content;
-
-	/* initialize callback data */
-	response_mime = NULL;
-	response_data = NULL;
-	response_size = 0;
-	if (stream) {
-		g_input_stream_close(stream, NULL, &_error);
-		if (_error) {
-			if (error) *error = _error;
-			return NULL;
-		}
-	}
-		
-	stream = NULL;
-
-	if (!strncmp(url, "file:///", 8) || g_file_test(url, G_FILE_TEST_EXISTS)) {
-		gchar* newurl = g_filename_from_uri(url, NULL, NULL);
-		if (g_file_get_contents(newurl ? newurl : url, &content, &len, &_error)) {
-			stream = g_memory_input_stream_new_from_data(content, len, g_free);
-		} else {
-			g_log(NULL, G_LOG_LEVEL_MESSAGE, "%s", _error->message);
-		}
-		g_free(newurl);
-	} else {
-		curl = curl_easy_init();
-		if (!curl) return NULL;
-		curl_easy_setopt(curl, CURLOPT_URL, url);
-		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handle_returned_data);
-		curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, handle_returned_header);
-		curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
-		curl_easy_setopt(curl, CURLOPT_TIMEOUT, HTTP_GET_TIMEOUT);
-		curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
-		res = curl_easy_perform(curl);
-		curl_easy_cleanup(curl);
-		if (res == CURLE_OK) {
-			stream = g_memory_input_stream_new_from_data(content, response_size, g_free);
-		} else
-			_error = g_error_new_literal(G_FILE_ERROR, res, curl_easy_strerror(res));
-	}
-
-	if (error && _error) *error = _error;
-
-	return stream;
-}
 
 static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
 		gpointer user_data)
@@ -354,34 +283,6 @@ static void size_allocate_cb(GtkWidget *widget, GdkRectangle *allocation,
 	w->redraw();
 }
 
-static size_t handle_returned_data(char* ptr, size_t size, size_t nmemb, void* stream) {
-	if (!response_data)
-		response_data = (char*)malloc(size*nmemb);
-	else
-		response_data = (char*)realloc(response_data, response_size+size*nmemb);
-	if (response_data) {
-		memcpy(response_data+response_size, ptr, size*nmemb);
-		response_size += size*nmemb;
-	}
-	return size*nmemb;
-}
-
-static size_t handle_returned_header(void* ptr, size_t size, size_t nmemb, void* stream) {
-	char* header = NULL;
-
-	header = (char*) malloc(size*nmemb + 1);
-	memcpy(header, ptr, size*nmemb);
-	header[size*nmemb] = 0;
-	if (strncmp(header, "Content-Type: ", 14) == 0) {
-		char* stop = header + 14;
-		stop = strpbrk(header + 14, "\r\n;");
-		if (stop) *stop = 0;
-		response_mime = strdup(header + 14);
-	}
-	free(header);
-	return size*nmemb;
-}
-
 ///////////////////////////////////////////////////////////
 extern "C" {
 
diff --git a/src/plugins/litehtml_viewer/lh_widget.h b/src/plugins/litehtml_viewer/lh_widget.h
index b17b626..0cb97c6 100644
--- a/src/plugins/litehtml_viewer/lh_widget.h
+++ b/src/plugins/litehtml_viewer/lh_widget.h
@@ -4,7 +4,7 @@
 
 #include "container_linux.h"
 
-#define HTTP_GET_TIMEOUT 60L
+#define HTTP_GET_TIMEOUT 5L
 
 class lh_widget : public container_linux
 {
@@ -33,7 +33,6 @@ class lh_widget : public container_linux
 		void paint_white();
 		GInputStream *load_url(const gchar *url, GError **error);
 
-		GInputStream *stream;
 		litehtml::document::ptr m_html;
 		gint m_rendered_width;
 		GtkWidget *m_drawing_area;

commit 93e2128494e10fce46955429e8d6eeeef61ea468
Author: Michael Rasmussen <mir at datanom.net>
Date:   Wed Nov 7 03:20:11 2018 +0100

    Implement image handling
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/litehtml_viewer/Makefile.am b/src/plugins/litehtml_viewer/Makefile.am
index 5e4e732..15cb479 100644
--- a/src/plugins/litehtml_viewer/Makefile.am
+++ b/src/plugins/litehtml_viewer/Makefile.am
@@ -53,14 +53,16 @@ litehtml_viewer_la_LDFLAGS = \
 	-avoid-version -module \
 	$(GTK_LIBS) \
 	$(FONTCONFIG_LIBS) \
-	$(CAIRO_LIBS)
+	$(CAIRO_LIBS) \
+	$(CURL_LIBS)
 
 litehtml_viewer_la_CPPFLAGS = \
 	$(IFLAGS) \
 	$(GLIB_CFLAGS) \
 	$(GTK_CFLAGS) \
 	$(FONTCONFIG_CFLAGS) \
-	$(CAIRO_CFLAGS) 
+	$(CAIRO_CFLAGS) \
+	$(CURL_FLAGS)
 
 .PHONY: test
 
diff --git a/src/plugins/litehtml_viewer/TODO b/src/plugins/litehtml_viewer/TODO
index 912078f..56e3846 100644
--- a/src/plugins/litehtml_viewer/TODO
+++ b/src/plugins/litehtml_viewer/TODO
@@ -2,3 +2,6 @@
 - Add support for printing
 - Add support for links (open in default browser)
 
+Images:
+https://developer.gnome.org/gio/unstable/GMemoryInputStream.html#g-memory-input-stream-new-from-data
+http://darcs.cielonegro.org/gtktwitter/gtktwitter.c
diff --git a/src/plugins/litehtml_viewer/lh_viewer.c b/src/plugins/litehtml_viewer/lh_viewer.c
index 73c1b69..0b3cf53 100644
--- a/src/plugins/litehtml_viewer/lh_viewer.c
+++ b/src/plugins/litehtml_viewer/lh_viewer.c
@@ -23,6 +23,7 @@
 #endif
 
 #include <codeconv.h>
+#include "common/utils.h"
 #include "lh_viewer.h"
 
 static gchar *content_types[] = { "text/html", NULL };
diff --git a/src/plugins/litehtml_viewer/lh_widget.cpp b/src/plugins/litehtml_viewer/lh_widget.cpp
index a700b63..5c90005 100644
--- a/src/plugins/litehtml_viewer/lh_widget.cpp
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -22,6 +22,12 @@
 #include "claws-features.h"
 #endif
 
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <curl/curl.h>
 #include "lh_widget.h"
 #include "lh_widget_wrapped.h"
 
@@ -29,10 +35,19 @@ char master_css[] = {
 #include "css.inc"
 };
 
+/**
+  * curl callback
+  */
+static char* response_mime = NULL;     /* response content-type. ex: "text/html" */
+static char* response_data = NULL;     /* response data from server. */
+static size_t response_size = 0;       /* response size of data */
+
 static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
 		gpointer user_data);
 static void size_allocate_cb(GtkWidget *widget, GdkRectangle *allocation,
 		gpointer user_data);
+static size_t handle_returned_data(char* ptr, size_t size, size_t nmemb, void* stream);
+static size_t handle_returned_header(void* ptr, size_t size, size_t nmemb, void* stream);
 
 lh_widget::lh_widget()
 {
@@ -61,6 +76,7 @@ lh_widget::lh_widget()
 	m_html = NULL;
 	m_rendered_width = 0;
 	m_context.load_master_stylesheet(master_css);
+	stream = NULL;
 }
 
 lh_widget::~lh_widget()
@@ -70,6 +86,10 @@ lh_widget::~lh_widget()
 	g_object_unref(m_scrolled_window);
 	m_scrolled_window = NULL;
 	m_html = NULL;
+	if (stream) {
+	    g_input_stream_close(stream, NULL, NULL);
+	    stream = NULL;
+	}
 }
 
 GtkWidget *lh_widget::get_widget() const
@@ -124,7 +144,34 @@ void lh_widget::get_client_rect(litehtml::position& client) const
 
 GdkPixbuf *lh_widget::get_image(const litehtml::tchar_t* url, bool redraw_on_ready)
 {
-	return NULL;
+	GError *error = NULL;
+	GdkPixbuf *pixbuf = NULL;
+
+	g_log(NULL, G_LOG_LEVEL_MESSAGE, "Loading... %s", url);
+
+	GInputStream *image = load_url(url, &error);
+	if (error) {
+		g_log(NULL, G_LOG_LEVEL_MESSAGE, "Error: %s", error->message);
+		g_error_free(error);
+		return NULL;
+	}
+
+	GdkPixbufLoader* loader = gdk_pixbuf_loader_new();
+	if (gdk_pixbuf_loader_write(loader, (const guchar*)response_data, response_size, &error)) {
+		pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
+	} else {
+		g_log(NULL, G_LOG_LEVEL_ERROR, "lh_widget::get_image: Could not create pixbuf");
+	}
+	gdk_pixbuf_loader_close(loader, NULL);
+
+        /* cleanup callback data */
+        if (response_mime) g_free(response_mime);
+        if (response_data) g_free(response_data);
+        response_data = NULL;
+        response_mime = NULL;
+        response_size = 0;
+	
+	return pixbuf;
 }
 
 void lh_widget::open_html(const gchar *contents)
@@ -235,6 +282,58 @@ void lh_widget::clear()
 	m_rendered_width = 0;
 }
 
+GInputStream *lh_widget::load_url(const gchar *url, GError **error)
+{
+	GError* _error = NULL;
+	CURL* curl = NULL;
+	CURLcode res = CURLE_OK;
+	gsize len;
+	gchar* content;
+
+	/* initialize callback data */
+	response_mime = NULL;
+	response_data = NULL;
+	response_size = 0;
+	if (stream) {
+		g_input_stream_close(stream, NULL, &_error);
+		if (_error) {
+			if (error) *error = _error;
+			return NULL;
+		}
+	}
+		
+	stream = NULL;
+
+	if (!strncmp(url, "file:///", 8) || g_file_test(url, G_FILE_TEST_EXISTS)) {
+		gchar* newurl = g_filename_from_uri(url, NULL, NULL);
+		if (g_file_get_contents(newurl ? newurl : url, &content, &len, &_error)) {
+			stream = g_memory_input_stream_new_from_data(content, len, g_free);
+		} else {
+			g_log(NULL, G_LOG_LEVEL_MESSAGE, "%s", _error->message);
+		}
+		g_free(newurl);
+	} else {
+		curl = curl_easy_init();
+		if (!curl) return NULL;
+		curl_easy_setopt(curl, CURLOPT_URL, url);
+		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handle_returned_data);
+		curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, handle_returned_header);
+		curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
+		curl_easy_setopt(curl, CURLOPT_TIMEOUT, HTTP_GET_TIMEOUT);
+		curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
+		res = curl_easy_perform(curl);
+		curl_easy_cleanup(curl);
+		if (res == CURLE_OK) {
+			stream = g_memory_input_stream_new_from_data(content, response_size, g_free);
+		} else
+			_error = g_error_new_literal(G_FILE_ERROR, res, curl_easy_strerror(res));
+	}
+
+	if (error && _error) *error = _error;
+
+	return stream;
+}
+
 static gboolean expose_event_cb(GtkWidget *widget, GdkEvent *event,
 		gpointer user_data)
 {
@@ -255,6 +354,34 @@ static void size_allocate_cb(GtkWidget *widget, GdkRectangle *allocation,
 	w->redraw();
 }
 
+static size_t handle_returned_data(char* ptr, size_t size, size_t nmemb, void* stream) {
+	if (!response_data)
+		response_data = (char*)malloc(size*nmemb);
+	else
+		response_data = (char*)realloc(response_data, response_size+size*nmemb);
+	if (response_data) {
+		memcpy(response_data+response_size, ptr, size*nmemb);
+		response_size += size*nmemb;
+	}
+	return size*nmemb;
+}
+
+static size_t handle_returned_header(void* ptr, size_t size, size_t nmemb, void* stream) {
+	char* header = NULL;
+
+	header = (char*) malloc(size*nmemb + 1);
+	memcpy(header, ptr, size*nmemb);
+	header[size*nmemb] = 0;
+	if (strncmp(header, "Content-Type: ", 14) == 0) {
+		char* stop = header + 14;
+		stop = strpbrk(header + 14, "\r\n;");
+		if (stop) *stop = 0;
+		response_mime = strdup(header + 14);
+	}
+	free(header);
+	return size*nmemb;
+}
+
 ///////////////////////////////////////////////////////////
 extern "C" {
 
diff --git a/src/plugins/litehtml_viewer/lh_widget.h b/src/plugins/litehtml_viewer/lh_widget.h
index 4cdf8ce..b17b626 100644
--- a/src/plugins/litehtml_viewer/lh_widget.h
+++ b/src/plugins/litehtml_viewer/lh_widget.h
@@ -1,8 +1,11 @@
 #include <gtk/gtk.h>
 #include <glib.h>
+#include <gio/gio.h>
 
 #include "container_linux.h"
 
+#define HTTP_GET_TIMEOUT 60L
+
 class lh_widget : public container_linux
 {
 	public:
@@ -28,7 +31,9 @@ class lh_widget : public container_linux
 
 	private:
 		void paint_white();
+		GInputStream *load_url(const gchar *url, GError **error);
 
+		GInputStream *stream;
 		litehtml::document::ptr m_html;
 		gint m_rendered_width;
 		GtkWidget *m_drawing_area;
@@ -36,4 +41,5 @@ class lh_widget : public container_linux
 		GtkWidget *m_viewport;
 		litehtml::context m_context;
 		gint m_height;
+
 };

commit 4ae8864929ee38e8fd8c4648850adbb8acf8a737
Author: Michael Rasmussen <mir at datanom.net>
Date:   Tue Nov 6 19:50:31 2018 +0100

    Initial commit of litehtml_viewer
    See TODO for missing functionality.
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/configure.ac b/configure.ac
index 597b1d1..cc14acf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -109,6 +109,7 @@ LT_AC_PROG_RC
 AC_LIBTOOL_RC
 AC_PROG_LIBTOOL
 AC_PROG_AWK
+AC_PROG_CXX
 
 AC_SYS_LARGEFILE
 
@@ -1041,6 +1042,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])
@@ -1121,6 +1126,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
@@ -1194,6 +1200,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)
@@ -1604,6 +1625,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"
@@ -2017,6 +2069,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)
@@ -2066,6 +2119,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
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 1f88956..4af74dd 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -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
index 0000000..5e4e732
--- /dev/null
+++ b/src/plugins/litehtml_viewer/Makefile.am
@@ -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
index 0000000..912078f
--- /dev/null
+++ b/src/plugins/litehtml_viewer/TODO
@@ -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
index 0000000..9a6ff50
--- /dev/null
+++ b/src/plugins/litehtml_viewer/claws.def
@@ -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
index 0000000..2341da5
--- /dev/null
+++ b/src/plugins/litehtml_viewer/container_linux.cpp
@@ -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 at 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
index 0000000..94eafab
--- /dev/null
+++ b/src/plugins/litehtml_viewer/container_linux.h
@@ -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
index 0000000..3dc2ad7
--- /dev/null
+++ b/src/plugins/litehtml_viewer/css.inc
@@ -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
index 0000000..73c1b69
--- /dev/null
+++ b/src/plugins/litehtml_viewer/lh_viewer.c
@@ -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 at 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
index 0000000..d733642
--- /dev/null
+++ b/src/plugins/litehtml_viewer/lh_viewer.h
@@ -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
index 0000000..a700b63
--- /dev/null
+++ b/src/plugins/litehtml_viewer/lh_widget.cpp
@@ -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 at 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
index 0000000..4cdf8ce
--- /dev/null
+++ b/src/plugins/litehtml_viewer/lh_widget.h
@@ -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
index 0000000..521c7f4
--- /dev/null
+++ b/src/plugins/litehtml_viewer/lh_widget_wrapped.h
@@ -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
index 0000000..601e1c7
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/LICENSE
@@ -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
index 0000000..b412926
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/Makefile.am
@@ -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
index 0000000..86be96e
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/README.md
@@ -0,0 +1,42 @@
+#What is litehtml?
+
+**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. 
+
+#Where litehtml can be used
+
+**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.
+
+##HTML Parser
+
+**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.
+
+##Compatibility
+
+**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.
+
+##Support for HTML and CSS standards
+
+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**.
+
+##Testing litehtml
+
+You can [download the simple browser](http://www.litehtml.com/download.html) (**litebrowser**) to test the **litehtml** rendering engine. 
+
+The litebrowser source codes are available on GitHub:
+  * [For Windows](https://github.com/tordex/litebrowser)
+  * [For Linux](https://github.com/tordex/litebrowser-linux)
+
+##License
+
+**litehtml** is distributed under [New BSD License](http://opensource.org/licenses/BSD-3-Clause).
+The **gumbo-parser** is disributed under [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
+
+##Support litehtml project
+
+If you think litehtml is amazing please consider a small donation:
+
+[ ![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)
+
+Bitcoin: **1CS1174GVSLbP33TBp8RFwqPS6KmQK6kLY**
+
+![BitCoin](https://www.tordex.com/assets/images/litehtml-bitcoin.png)
diff --git a/src/plugins/litehtml_viewer/litehtml/attributes.h b/src/plugins/litehtml_viewer/litehtml/attributes.h
new file mode 100644
index 0000000..ca1c9a7
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/attributes.h
@@ -0,0 +1,32 @@
+#pragma once
+
+namespace litehtml
+{
+	struct attr_color
+	{
+		unsigned char    rgbBlue;
+		unsigned char    rgbGreen;
+		unsigned char    rgbRed;
+		unsigned char    rgbAlpha;
+		attr_color()
+		{
+			rgbAlpha	= 255;
+			rgbBlue		= 0;
+			rgbGreen	= 0;
+			rgbRed		= 0;
+		}
+	};
+
+	struct attr_border
+	{
+		style_border	border;
+		int				width;
+		attr_color		color;
+
+		attr_border()
+		{
+			border	= borderNone;
+			width	= 0;
+		}
+	};
+}
\ 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
index 0000000..87ce59e
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/background.cpp
@@ -0,0 +1,79 @@
+#include "html.h"
+#include "background.h"
+
+litehtml::background::background(void)
+{
+	m_attachment	= background_attachment_scroll;
+	m_repeat		= background_repeat_repeat;
+	m_clip			= background_box_border;
+	m_origin		= background_box_padding;
+	m_color.alpha	= 0;
+	m_color.red		= 0;
+	m_color.green	= 0;
+	m_color.blue	= 0;
+}
+
+litehtml::background::background( const background& val )
+{
+	m_image			= val.m_image;
+	m_baseurl		= val.m_baseurl;
+	m_color			= val.m_color;
+	m_attachment	= val.m_attachment;
+	m_position		= val.m_position;
+	m_repeat		= val.m_repeat;
+	m_clip			= val.m_clip;
+	m_origin		= val.m_origin;
+}
+
+litehtml::background::~background(void)
+{
+}
+
+litehtml::background& litehtml::background::operator=( const background& val )
+{
+	m_image			= val.m_image;
+	m_baseurl		= val.m_baseurl;
+	m_color			= val.m_color;
+	m_attachment	= val.m_attachment;
+	m_position		= val.m_position;
+	m_repeat		= val.m_repeat;
+	m_clip			= val.m_clip;
+	m_origin		= val.m_origin;
+	return *this;
+}
+
+
+litehtml::background_paint::background_paint() : color(0, 0, 0, 0)
+{
+	position_x		= 0;
+	position_y		= 0;
+	attachment		= background_attachment_scroll;
+	repeat			= background_repeat_repeat;
+	is_root			= false;
+}
+
+litehtml::background_paint::background_paint( const background_paint& val )
+{
+	image			= val.image;
+	baseurl			= val.baseurl;
+	attachment		= val.attachment;
+	repeat			= val.repeat;
+	color			= val.color;
+	clip_box		= val.clip_box;
+	origin_box		= val.origin_box;
+	border_box		= val.border_box;
+	border_radius	= val.border_radius;
+	image_size		= val.image_size;
+	position_x		= val.position_x;
+	position_y		= val.position_y;
+	is_root			= val.is_root;
+}
+
+void litehtml::background_paint::operator=( const background& val )
+{
+	attachment	= val.m_attachment;
+	baseurl		= val.m_baseurl;
+	image		= val.m_image;
+	repeat		= val.m_repeat;
+	color		= val.m_color;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/background.h b/src/plugins/litehtml_viewer/litehtml/background.h
new file mode 100644
index 0000000..e3fc2f6
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/background.h
@@ -0,0 +1,54 @@
+#pragma once
+#include "types.h"
+#include "attributes.h"
+#include "css_length.h"
+#include "css_position.h"
+#include "web_color.h"
+#include "borders.h"
+
+namespace litehtml
+{
+	class background
+	{
+	public:
+		tstring					m_image;
+		tstring					m_baseurl;
+		web_color				m_color;
+		background_attachment	m_attachment;
+		css_position			m_position;
+		background_repeat		m_repeat;
+		background_box			m_clip;
+		background_box			m_origin;
+		css_border_radius		m_radius;
+
+	public:
+		background(void);
+		background(const background& val);
+		~background(void);
+
+		background& operator=(const background& val);
+	};
+
+	class background_paint
+	{
+	public:
+		tstring					image;
+		tstring					baseurl;
+		background_attachment	attachment;
+		background_repeat		repeat;
+		web_color				color;
+		position				clip_box;
+		position				origin_box;
+		position				border_box;
+		border_radiuses			border_radius;
+		size					image_size;
+		int						position_x;
+		int						position_y;
+		bool					is_root;
+	public:
+		background_paint();
+		background_paint(const background_paint& val);
+		void operator=(const background& val);
+	};
+
+}
\ 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
index 0000000..a46a9f8
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/borders.h
@@ -0,0 +1,296 @@
+#pragma once
+#include "css_length.h"
+#include "types.h"
+
+namespace litehtml
+{
+	struct css_border
+	{
+		css_length		width;
+		border_style	style;
+		web_color		color;
+
+		css_border()
+		{
+			style = border_style_none;
+		}
+
+		css_border(const css_border& val)
+		{
+			width	= val.width;
+			style	= val.style;
+			color	= val.color;
+		}
+
+		css_border& operator=(const css_border& val)
+		{
+			width	= val.width;
+			style	= val.style;
+			color	= val.color;
+			return *this;
+		}
+	};
+
+	struct border
+	{
+		int				width;
+		border_style	style;
+		web_color		color;
+
+		border()
+		{
+			width = 0;
+		}
+		border(const border& val)
+		{
+			width = val.width;
+			style = val.style;
+			color = val.color;
+		}
+		border(const css_border& val)
+		{
+			width = (int) val.width.val();
+			style = val.style;
+			color = val.color;
+		}
+		border& operator=(const border& val)
+		{
+			width = val.width;
+			style = val.style;
+			color = val.color;
+			return *this;
+		}
+		border& operator=(const css_border& val)
+		{
+			width = (int) val.width.val();
+			style = val.style;
+			color = val.color;
+			return *this;
+		}
+	};
+
+	struct border_radiuses
+	{
+		int	top_left_x;
+		int	top_left_y;
+
+		int	top_right_x;
+		int	top_right_y;
+
+		int	bottom_right_x;
+		int	bottom_right_y;
+
+		int	bottom_left_x;
+		int	bottom_left_y;
+
+		border_radiuses()
+		{
+			top_left_x = 0;
+			top_left_y = 0;
+			top_right_x = 0;
+			top_right_y = 0;
+			bottom_right_x = 0;
+			bottom_right_y = 0;
+			bottom_left_x = 0;
+			bottom_left_y = 0;
+		}
+		border_radiuses(const border_radiuses& val)
+		{
+			top_left_x = val.top_left_x;
+			top_left_y = val.top_left_y;
+			top_right_x = val.top_right_x;
+			top_right_y = val.top_right_y;
+			bottom_right_x = val.bottom_right_x;
+			bottom_right_y = val.bottom_right_y;
+			bottom_left_x = val.bottom_left_x;
+			bottom_left_y = val.bottom_left_y;
+		}
+		border_radiuses& operator = (const border_radiuses& val)
+		{
+			top_left_x = val.top_left_x;
+			top_left_y = val.top_left_y;
+			top_right_x = val.top_right_x;
+			top_right_y = val.top_right_y;
+			bottom_right_x = val.bottom_right_x;
+			bottom_right_y = val.bottom_right_y;
+			bottom_left_x = val.bottom_left_x;
+			bottom_left_y = val.bottom_left_y;
+			return *this;
+		}
+		void operator += (const margins& mg)
+		{
+			top_left_x += mg.left;
+			top_left_y += mg.top;
+			top_right_x += mg.right;
+			top_right_y += mg.top;
+			bottom_right_x += mg.right;
+			bottom_right_y += mg.bottom;
+			bottom_left_x += mg.left;
+			bottom_left_y += mg.bottom;
+			fix_values();
+		}
+		void operator -= (const margins& mg)
+		{
+			top_left_x -= mg.left;
+			top_left_y -= mg.top;
+			top_right_x -= mg.right;
+			top_right_y -= mg.top;
+			bottom_right_x -= mg.right;
+			bottom_right_y -= mg.bottom;
+			bottom_left_x -= mg.left;
+			bottom_left_y -= mg.bottom;
+			fix_values();
+		}
+		void fix_values()
+		{
+			if (top_left_x < 0)	top_left_x = 0;
+			if (top_left_y < 0)	top_left_y = 0;
+			if (top_right_x < 0) top_right_x = 0;
+			if (bottom_right_x < 0) bottom_right_x = 0;
+			if (bottom_right_y < 0) bottom_right_y = 0;
+			if (bottom_left_x < 0) bottom_left_x = 0;
+			if (bottom_left_y < 0) bottom_left_y = 0;
+		}
+	};
+
+	struct css_border_radius
+	{
+		css_length	top_left_x;
+		css_length	top_left_y;
+
+		css_length	top_right_x;
+		css_length	top_right_y;
+
+		css_length	bottom_right_x;
+		css_length	bottom_right_y;
+
+		css_length	bottom_left_x;
+		css_length	bottom_left_y;
+
+		css_border_radius()
+		{
+
+		}
+
+		css_border_radius(const css_border_radius& val)
+		{
+			top_left_x		= val.top_left_x;
+			top_left_y		= val.top_left_y;
+			top_right_x		= val.top_right_x;
+			top_right_y		= val.top_right_y;
+			bottom_left_x	= val.bottom_left_x;
+			bottom_left_y	= val.bottom_left_y;
+			bottom_right_x	= val.bottom_right_x;
+			bottom_right_y	= val.bottom_right_y;
+		}
+
+		css_border_radius& operator=(const css_border_radius& val)
+		{
+			top_left_x		= val.top_left_x;
+			top_left_y		= val.top_left_y;
+			top_right_x		= val.top_right_x;
+			top_right_y		= val.top_right_y;
+			bottom_left_x	= val.bottom_left_x;
+			bottom_left_y	= val.bottom_left_y;
+			bottom_right_x	= val.bottom_right_x;
+			bottom_right_y	= val.bottom_right_y;
+			return *this;
+		}
+		border_radiuses calc_percents(int width, int height)
+		{
+			border_radiuses ret;
+			ret.bottom_left_x = bottom_left_x.calc_percent(width);
+			ret.bottom_left_y = bottom_left_y.calc_percent(height);
+			ret.top_left_x = top_left_x.calc_percent(width);
+			ret.top_left_y = top_left_y.calc_percent(height);
+			ret.top_right_x = top_right_x.calc_percent(width);
+			ret.top_right_y = top_right_y.calc_percent(height);
+			ret.bottom_right_x = bottom_right_x.calc_percent(width);
+			ret.bottom_right_y = bottom_right_y.calc_percent(height);
+			return ret;
+		}
+	};
+
+	struct css_borders
+	{
+		css_border			left;
+		css_border			top;
+		css_border			right;
+		css_border			bottom;
+		css_border_radius	radius;
+
+		css_borders()
+		{
+
+		}
+
+		css_borders(const css_borders& val)
+		{
+			left	= val.left;
+			right	= val.right;
+			top		= val.top;
+			bottom	= val.bottom;
+			radius	= val.radius;
+		}
+
+		css_borders& operator=(const css_borders& val)
+		{
+			left	= val.left;
+			right	= val.right;
+			top		= val.top;
+			bottom	= val.bottom;
+			radius	= val.radius;
+			return *this;
+		}
+	};
+
+	struct borders
+	{
+		border			left;
+		border			top;
+		border			right;
+		border			bottom;
+		border_radiuses	radius;
+
+		borders()
+		{
+
+		}
+
+		borders(const borders& val)
+		{
+			left = val.left;
+			right = val.right;
+			top = val.top;
+			bottom = val.bottom;
+			radius = val.radius;
+		}
+
+		borders(const css_borders& val)
+		{
+			left = val.left;
+			right = val.right;
+			top = val.top;
+			bottom = val.bottom;
+		}
+
+		borders& operator=(const borders& val)
+		{
+			left = val.left;
+			right = val.right;
+			top = val.top;
+			bottom = val.bottom;
+			radius = val.radius;
+			return *this;
+		}
+
+		borders& operator=(const css_borders& val)
+		{
+			left = val.left;
+			right = val.right;
+			top = val.top;
+			bottom = val.bottom;
+			return *this;
+		}
+	};
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/box.cpp b/src/plugins/litehtml_viewer/litehtml/box.cpp
new file mode 100644
index 0000000..023d15c
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/box.cpp
@@ -0,0 +1,434 @@
+#include "html.h"
+#include "box.h"
+#include "html_tag.h"
+
+
+litehtml::box_type litehtml::block_box::get_type()
+{
+	return box_block;
+}
+
+int litehtml::block_box::height()
+{
+	return m_element->height();
+}
+
+int litehtml::block_box::width()
+{
+	return m_element->width();
+}
+
+void litehtml::block_box::add_element(const element::ptr &el)
+{
+	m_element = el;
+	el->m_box = this;
+}
+
+void litehtml::block_box::finish(bool last_box)
+{
+	if(!m_element) return;
+	m_element->apply_relative_shift(m_box_right - m_box_left);
+}
+
+bool litehtml::block_box::can_hold(const element::ptr &el, white_space ws)
+{
+	if(m_element || el->is_inline_box())
+	{
+		return false;
+	}
+	return true;
+}
+
+bool litehtml::block_box::is_empty()
+{
+	if(m_element)
+	{
+		return false;
+	}
+	return true;
+}
+
+int litehtml::block_box::baseline()
+{
+	if(m_element)
+	{
+		return m_element->get_base_line();
+	}
+	return 0;
+}
+
+void litehtml::block_box::get_elements( elements_vector& els )
+{
+	els.push_back(m_element);
+}
+
+int litehtml::block_box::top_margin()
+{
+	if(m_element && m_element->collapse_top_margin())
+	{
+		return m_element->m_margins.top;
+	}
+	return 0;
+}
+
+int litehtml::block_box::bottom_margin()
+{
+	if(m_element && m_element->collapse_bottom_margin())
+	{
+		return m_element->m_margins.bottom;
+	}
+	return 0;
+}
+
+void litehtml::block_box::y_shift( int shift )
+{
+	m_box_top += shift;
+	if(m_element)
+	{
+		m_element->m_pos.y += shift;
+	}
+}
+
+void litehtml::block_box::new_width( int left, int right, elements_vector& els )
+{
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+litehtml::box_type litehtml::line_box::get_type()
+{
+	return box_line;
+}
+
+int litehtml::line_box::height()
+{
+	return m_height;
+}
+
+int litehtml::line_box::width()
+{
+	return m_width;
+}
+
+void litehtml::line_box::add_element(const element::ptr &el)
+{
+	el->m_skip	= false;
+	el->m_box	= 0;
+	bool add	= true;
+	if( (m_items.empty() && el->is_white_space()) || el->is_break() )
+	{
+		el->m_skip = true;
+	} else if(el->is_white_space())
+	{
+		if (have_last_space())
+		{
+			add = false;
+			el->m_skip = true;
+		}
+	}
+
+	if(add)
+	{
+		el->m_box = this;
+		m_items.push_back(el);
+
+		if(!el->m_skip)
+		{
+			int el_shift_left	= el->get_inline_shift_left();
+			int el_shift_right	= el->get_inline_shift_right();
+
+			el->m_pos.x	= m_box_left + m_width + el_shift_left + el->content_margins_left();
+			el->m_pos.y	= m_box_top + el->content_margins_top();
+			m_width		+= el->width() + el_shift_left + el_shift_right;
+		}
+	}
+}
+
+void litehtml::line_box::finish(bool last_box)
+{
+	if( is_empty() || (!is_empty() && last_box && is_break_only()) )
+	{
+		m_height = 0;
+		return;
+	}
+
+	for(auto i = m_items.rbegin(); i != m_items.rend(); i++)
+	{
+		if((*i)->is_white_space() || (*i)->is_break())
+		{
+			if(!(*i)->m_skip)
+			{
+				(*i)->m_skip = true;
+				m_width -= (*i)->width();
+			}
+		} else
+		{
+			break;
+		}
+	}
+
+	int base_line	= m_font_metrics.base_line();
+	int line_height = m_line_height;
+
+	int add_x = 0;
+	switch(m_text_align)
+	{
+	case text_align_right:
+		if(m_width < (m_box_right - m_box_left))
+		{
+			add_x = (m_box_right - m_box_left) - m_width;
+		}
+		break;
+	case text_align_center:
+		if(m_width < (m_box_right - m_box_left))
+		{
+			add_x = ((m_box_right - m_box_left) - m_width) / 2;
+		}
+		break;
+	default:
+		add_x = 0;
+	}
+
+	m_height = 0;
+	// find line box baseline and line-height
+	for(const auto& el : m_items)
+	{
+		if(el->get_display() == display_inline_text)
+		{
+			font_metrics fm;
+			el->get_font(&fm);
+			base_line	= std::max(base_line,	fm.base_line());
+			line_height = std::max(line_height, el->line_height());
+			m_height = std::max(m_height, fm.height);
+		}
+		el->m_pos.x += add_x;
+	}
+
+	if(m_height)
+	{
+		base_line += (line_height - m_height) / 2;
+	}
+
+	m_height = line_height;
+
+	int y1	= 0;
+	int y2	= m_height;
+
+	for (const auto& el : m_items)
+	{
+		if(el->get_display() == display_inline_text)
+		{
+			font_metrics fm;
+			el->get_font(&fm);
+			el->m_pos.y = m_height - base_line - fm.ascent;
+		} else
+		{
+			switch(el->get_vertical_align())
+			{
+			case va_super:
+			case va_sub:
+			case va_baseline:
+				el->m_pos.y = m_height - base_line - el->height() + el->get_base_line() + el->content_margins_top();
+				break;
+			case va_top:
+				el->m_pos.y = y1 + el->content_margins_top();
+				break;
+			case va_text_top:
+				el->m_pos.y = m_height - base_line - m_font_metrics.ascent + el->content_margins_top();
+				break;
+			case va_middle:
+				el->m_pos.y = m_height - base_line - m_font_metrics.x_height / 2 - el->height() / 2 + el->content_margins_top();
+				break;
+			case va_bottom:
+				el->m_pos.y = y2 - el->height() + el->content_margins_top();
+				break;
+			case va_text_bottom:
+				el->m_pos.y = m_height - base_line + m_font_metrics.descent - el->height() + el->content_margins_top();
+				break;
+			}
+			y1 = std::min(y1, el->top());
+			y2 = std::max(y2, el->bottom());
+		}
+	}
+
+	css_offsets offsets;
+
+	for (const auto& el : m_items)
+	{
+		el->m_pos.y -= y1;
+		el->m_pos.y += m_box_top;
+		if(el->get_display() != display_inline_text)
+		{
+			switch(el->get_vertical_align())
+			{
+			case va_top:
+				el->m_pos.y = m_box_top + el->content_margins_top();
+				break;
+			case va_bottom:
+				el->m_pos.y = m_box_top + (y2 - y1) - el->height() + el->content_margins_top();
+				break;
+			case va_baseline:
+				//TODO: process vertical align "baseline"
+				break;
+			case va_middle:
+				//TODO: process vertical align "middle"
+				break;
+			case va_sub:
+				//TODO: process vertical align "sub"
+				break;
+			case va_super:
+				//TODO: process vertical align "super"
+				break;
+			case va_text_bottom:
+				//TODO: process vertical align "text-bottom"
+				break;
+			case va_text_top:
+				//TODO: process vertical align "text-top"
+				break;
+			}
+		}
+
+		el->apply_relative_shift(m_box_right - m_box_left);
+	}
+	m_height = y2 - y1;
+	m_baseline = (base_line - y1) - (m_height - line_height);
+}
+
+bool litehtml::line_box::can_hold(const element::ptr &el, white_space ws)
+{
+	if(!el->is_inline_box()) return false;
+
+	if(el->is_break())
+	{
+		return false;
+	}
+
+	if(ws == white_space_nowrap || ws == white_space_pre)
+	{
+		return true;
+	}
+
+	if(m_box_left + m_width + el->width() + el->get_inline_shift_left() + el->get_inline_shift_right() > m_box_right)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+bool litehtml::line_box::have_last_space()
+{
+	bool ret = false;
+	for (auto i = m_items.rbegin(); i != m_items.rend() && !ret; i++)
+	{
+		if((*i)->is_white_space() || (*i)->is_break())
+		{
+			ret = true;
+		} else
+		{
+			break;
+		}
+	}
+	return ret;
+}
+
+bool litehtml::line_box::is_empty()
+{
+	if(m_items.empty()) return true;
+	for (auto i = m_items.rbegin(); i != m_items.rend(); i++)
+	{
+		if(!(*i)->m_skip || (*i)->is_break())
+		{
+			return false;
+		}
+	}
+	return true;
+}
+
+int litehtml::line_box::baseline()
+{
+	return m_baseline;
+}
+
+void litehtml::line_box::get_elements( elements_vector& els )
+{
+	els.insert(els.begin(), m_items.begin(), m_items.end());
+}
+
+int litehtml::line_box::top_margin()
+{
+	return 0;
+}
+
+int litehtml::line_box::bottom_margin()
+{
+	return 0;
+}
+
+void litehtml::line_box::y_shift( int shift )
+{
+	m_box_top += shift;
+	for (auto& el : m_items)
+	{
+		el->m_pos.y += shift;
+	}
+}
+
+bool litehtml::line_box::is_break_only()
+{
+	if(m_items.empty()) return true;
+
+	if(m_items.front()->is_break())
+	{
+		for (auto& el : m_items)
+		{
+			if(!el->m_skip)
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+	return false;
+}
+
+void litehtml::line_box::new_width( int left, int right, elements_vector& els )
+{
+	int add = left - m_box_left;
+	if(add)
+	{
+		m_box_left	= left;
+		m_box_right	= right;
+		m_width = 0;
+		auto remove_begin = m_items.end();
+		for (auto i = m_items.begin() + 1; i != m_items.end(); i++)
+		{
+			element::ptr el = (*i);
+
+			if(!el->m_skip)
+			{
+				if(m_box_left + m_width + el->width() + el->get_inline_shift_right() + el->get_inline_shift_left() > m_box_right)
+				{
+					remove_begin = i;
+					break;
+				} else
+				{
+					el->m_pos.x += add;
+					m_width += el->width() + el->get_inline_shift_right() + el->get_inline_shift_left();
+				}
+			}
+		}
+		if(remove_begin != m_items.end())
+		{
+			els.insert(els.begin(), remove_begin, m_items.end());
+			m_items.erase(remove_begin, m_items.end());
+
+			for(const auto& el : els)
+			{
+				el->m_box = 0;
+			}
+		}
+	}
+}
+
diff --git a/src/plugins/litehtml_viewer/litehtml/box.h b/src/plugins/litehtml_viewer/litehtml/box.h
new file mode 100644
index 0000000..d15a528
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/box.h
@@ -0,0 +1,117 @@
+#pragma once
+
+namespace litehtml
+{
+	class html_tag;
+
+	enum box_type
+	{
+		box_block,
+		box_line
+	};
+
+	class box
+	{
+	public:
+		typedef std::unique_ptr<litehtml::box>	ptr;
+		typedef std::vector< box::ptr >			vector;
+	protected:
+		int		m_box_top;
+		int		m_box_left;
+		int		m_box_right;
+	public:
+		box(int top, int left, int right)
+		{
+			m_box_top	= top;
+			m_box_left	= left;
+			m_box_right	= right;
+		}
+		virtual ~box() {}
+
+		int		bottom()	{ return m_box_top + height();	}
+		int		top()		{ return m_box_top;				}
+		int		right()		{ return m_box_left + width();	}
+		int		left()		{ return m_box_left;			}
+
+		virtual litehtml::box_type	get_type() = 0;
+		virtual int					height() = 0;
+		virtual int					width() = 0;
+		virtual void				add_element(const element::ptr &el) = 0;
+		virtual bool				can_hold(const element::ptr &el, white_space ws) = 0;
+		virtual void				finish(bool last_box = false) = 0;
+		virtual bool				is_empty() = 0;
+		virtual int					baseline() = 0;
+		virtual void				get_elements(elements_vector& els) = 0;
+		virtual int					top_margin() = 0;
+		virtual int					bottom_margin() = 0;
+		virtual void				y_shift(int shift) = 0;
+		virtual void				new_width(int left, int right, elements_vector& els) = 0;
+	};
+
+	//////////////////////////////////////////////////////////////////////////
+
+	class block_box : public box
+	{
+		element::ptr m_element;
+	public:
+		block_box(int top, int left, int right) : box(top, left, right)
+		{
+			m_element = 0;
+		}
+
+		virtual litehtml::box_type	get_type();
+		virtual int					height();
+		virtual int					width();
+		virtual void				add_element(const element::ptr &el);
+		virtual bool				can_hold(const element::ptr &el, white_space ws);
+		virtual void				finish(bool last_box = false);
+		virtual bool				is_empty();
+		virtual int					baseline();
+		virtual void				get_elements(elements_vector& els);
+		virtual int					top_margin();
+		virtual int					bottom_margin();
+		virtual void				y_shift(int shift);
+		virtual void				new_width(int left, int right, elements_vector& els);
+	};
+
+	//////////////////////////////////////////////////////////////////////////
+
+	class line_box : public box
+	{
+		elements_vector			m_items;
+		int						m_height;
+		int						m_width;
+		int						m_line_height;
+		font_metrics			m_font_metrics;
+		int						m_baseline;
+		text_align				m_text_align;
+	public:
+		line_box(int top, int left, int right, int line_height, font_metrics& fm, text_align align) : box(top, left, right)
+		{
+			m_height		= 0;
+			m_width			= 0;
+			m_font_metrics	= fm;
+			m_line_height	= line_height;
+			m_baseline		= 0;
+			m_text_align	= align;
+		}
+
+		virtual litehtml::box_type	get_type();
+		virtual int					height();
+		virtual int					width();
+		virtual void				add_element(const element::ptr &el);
+		virtual bool				can_hold(const element::ptr &el, white_space ws);
+		virtual void				finish(bool last_box = false);
+		virtual bool				is_empty();
+		virtual int					baseline();
+		virtual void				get_elements(elements_vector& els);
+		virtual int					top_margin();
+		virtual int					bottom_margin();
+		virtual void				y_shift(int shift);
+		virtual void				new_width(int left, int right, elements_vector& els);
+
+	private:
+		bool						have_last_space();
+		bool						is_break_only();
+	};
+}
\ 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
index 0000000..5f26269
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/context.cpp
@@ -0,0 +1,12 @@
+#include "html.h"
+#include "context.h"
+#include "stylesheet.h"
+
+
+void litehtml::context::load_master_stylesheet( const tchar_t* str )
+{
+	media_query_list::ptr media;
+
+	m_master_css.parse_stylesheet(str, 0, std::shared_ptr<litehtml::document>(), media_query_list::ptr());
+	m_master_css.sort_selectors();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/context.h b/src/plugins/litehtml_viewer/litehtml/context.h
new file mode 100644
index 0000000..ce62991
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/context.h
@@ -0,0 +1,16 @@
+#pragma once
+#include "stylesheet.h"
+
+namespace litehtml
+{
+	class context
+	{
+		litehtml::css	m_master_css;
+	public:
+		void			load_master_stylesheet(const tchar_t* str);
+		litehtml::css&	master_css()
+		{
+			return m_master_css;
+		}
+	};
+}
\ 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
index 0000000..06d5580
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/css_length.cpp
@@ -0,0 +1,54 @@
+#include "html.h"
+#include "css_length.h"
+
+void litehtml::css_length::fromString( const tstring& str, const tstring& predefs, int defValue )
+{
+	// TODO: Make support for calc
+	if(str.substr(0, 4) == _t("calc"))
+	{
+		m_is_predefined = true;
+		m_predef		= 0;
+		return;
+	}
+
+	int predef = value_index(str.c_str(), predefs.c_str(), -1);
+	if(predef >= 0)
+	{
+		m_is_predefined = true;
+		m_predef		= predef;
+	} else
+	{
+		m_is_predefined = false;
+
+		tstring num;
+		tstring un;
+		bool is_unit = false;
+		for(tstring::const_iterator chr = str.begin(); chr != str.end(); chr++)
+		{
+			if(!is_unit)
+			{
+				if(t_isdigit(*chr) || *chr == _t('.') || *chr == _t('+') || *chr == _t('-'))
+				{
+					num += *chr;
+				} else
+				{
+					is_unit = true;
+				}
+			}
+			if(is_unit)
+			{
+				un += *chr;
+			}
+		}
+		if(!num.empty())
+		{
+			m_value = (float) t_strtod(num.c_str(), 0);
+			m_units	= (css_units) value_index(un.c_str(), css_units_strings, css_units_none);
+		} else
+		{
+			// not a number so it is predefined
+			m_is_predefined = true;
+			m_predef = defValue;
+		}
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/css_length.h b/src/plugins/litehtml_viewer/litehtml/css_length.h
new file mode 100644
index 0000000..078f9dd
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/css_length.h
@@ -0,0 +1,131 @@
+#pragma once
+#include "types.h"
+
+namespace litehtml
+{
+	class css_length
+	{
+		union
+		{
+			float	m_value;
+			int		m_predef;
+		};
+		css_units	m_units;
+		bool		m_is_predefined;
+	public:
+		css_length();
+		css_length(const css_length& val);
+
+		css_length&	operator=(const css_length& val);
+		css_length&	operator=(float val);
+		bool		is_predefined() const;
+		void		predef(int val);
+		int			predef() const;
+		void		set_value(float val, css_units units);
+		float		val() const;
+		css_units	units() const;
+		int			calc_percent(int width) const;
+		void		fromString(const tstring& str, const tstring& predefs = _t(""), int defValue = 0);
+	};
+
+	// css_length inlines
+
+	inline css_length::css_length()
+	{
+		m_value			= 0;
+		m_predef		= 0;
+		m_units			= css_units_none;
+		m_is_predefined	= false;
+	}
+
+	inline css_length::css_length(const css_length& val)
+	{
+		if(val.is_predefined())
+		{
+			m_predef	= val.m_predef;
+		} else
+		{
+			m_value		= val.m_value;
+		}
+		m_units			= val.m_units;
+		m_is_predefined	= val.m_is_predefined;
+	}
+
+	inline css_length&	css_length::operator=(const css_length& val)
+	{
+		if(val.is_predefined())
+		{
+			m_predef	= val.m_predef;
+		} else
+		{
+			m_value		= val.m_value;
+		}
+		m_units			= val.m_units;
+		m_is_predefined	= val.m_is_predefined;
+		return *this;
+	}
+
+	inline css_length&	css_length::operator=(float val)
+	{
+		m_value = val;
+		m_units = css_units_px;
+		m_is_predefined = false;
+		return *this;
+	}
+
+	inline bool css_length::is_predefined() const
+	{ 
+		return m_is_predefined;					
+	}
+
+	inline void css_length::predef(int val)		
+	{ 
+		m_predef		= val; 
+		m_is_predefined = true;	
+	}
+
+	inline int css_length::predef() const
+	{ 
+		if(m_is_predefined)
+		{
+			return m_predef; 
+		}
+		return 0;
+	}
+
+	inline void css_length::set_value(float val, css_units units)		
+	{ 
+		m_value			= val; 
+		m_is_predefined = false;	
+		m_units			= units;
+	}
+
+	inline float css_length::val() const
+	{
+		if(!m_is_predefined)
+		{
+			return m_value;
+		}
+		return 0;
+	}
+
+	inline css_units css_length::units() const
+	{
+		return m_units;
+	}
+
+	inline int css_length::calc_percent(int width) const
+	{
+		if(!is_predefined())
+		{
+			if(units() == css_units_percentage)
+			{
+				return (int) ((double) width * (double) m_value / 100.0);
+			} else
+			{
+				return (int) val();
+			}
+		}
+		return 0;
+	}
+}
\ 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
index 0000000..fbe1d40
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/css_margins.h
@@ -0,0 +1,35 @@
+#pragma once
+#include "css_length.h"
+
+namespace litehtml
+{
+	struct css_margins
+	{
+		css_length	left;
+		css_length	right;
+		css_length	top;
+		css_length	bottom;
+
+		css_margins()
+		{
+
+		}
+
+		css_margins(const css_margins& val)
+		{
+			left	= val.left;
+			right	= val.right;
+			top		= val.top;
+			bottom	= val.bottom;
+		}
+
+		css_margins& operator=(const css_margins& val)
+		{
+			left	= val.left;
+			right	= val.right;
+			top		= val.top;
+			bottom	= val.bottom;
+			return *this;
+		}
+	};
+}
\ 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
index 0000000..e4ca723
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/css_offsets.h
@@ -0,0 +1,35 @@
+#pragma once
+#include "css_length.h"
+
+namespace litehtml
+{
+	struct css_offsets
+	{
+		css_length	left;
+		css_length	top;
+		css_length	right;
+		css_length	bottom;
+
+		css_offsets()
+		{
+
+		}
+
+		css_offsets(const css_offsets& val)
+		{
+			left	= val.left;
+			top		= val.top;
+			right	= val.right;
+			bottom	= val.bottom;
+		}
+
+		css_offsets& operator=(const css_offsets& val)
+		{
+			left	= val.left;
+			top		= val.top;
+			right	= val.right;
+			bottom	= val.bottom;
+			return *this;
+		}
+	};
+}
\ 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
index 0000000..05f046d
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/css_position.h
@@ -0,0 +1,35 @@
+#pragma once
+#include "css_length.h"
+
+namespace litehtml
+{
+	struct css_position
+	{
+		css_length	x;
+		css_length	y;
+		css_length	width;
+		css_length	height;
+
+		css_position()
+		{
+
+		}
+
+		css_position(const css_position& val)
+		{
+			x		= val.x;
+			y		= val.y;
+			width	= val.width;
+			height	= val.height;
+		}
+
+		css_position& operator=(const css_position& val)
+		{
+			x		= val.x;
+			y		= val.y;
+			width	= val.width;
+			height	= val.height;
+			return *this;
+		}
+	};
+}
\ 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
index 0000000..a8e5f41
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/css_selector.cpp
@@ -0,0 +1,266 @@
+#include "html.h"
+#include "css_selector.h"
+#include "document.h"
+
+void litehtml::css_element_selector::parse( const tstring& txt )
+{
+	tstring::size_type el_end = txt.find_first_of(_t(".#[:"));
+	m_tag = txt.substr(0, el_end);
+	litehtml::lcase(m_tag);
+	while(el_end != tstring::npos)
+	{
+		if(txt[el_end] == _t('.'))
+		{
+			css_attribute_selector attribute;
+
+			tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);
+			attribute.val		= txt.substr(el_end + 1, pos - el_end - 1);
+			split_string( attribute.val, attribute.class_val, _t(" ") );
+			attribute.condition	= select_equal;
+			attribute.attribute	= _t("class");
+			m_attrs.push_back(attribute);
+			el_end = pos;
+		} else if(txt[el_end] == _t(':'))
+		{
+			css_attribute_selector attribute;
+
+			if(txt[el_end + 1] == _t(':'))
+			{
+				tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 2);
+				attribute.val		= txt.substr(el_end + 2, pos - el_end - 2);
+				attribute.condition	= select_pseudo_element;
+				litehtml::lcase(attribute.val);
+				attribute.attribute	= _t("pseudo-el");
+				m_attrs.push_back(attribute);
+				el_end = pos;
+			} else
+			{
+				tstring::size_type pos = txt.find_first_of(_t(".#[:("), el_end + 1);
+				if(pos != tstring::npos && txt.at(pos) == _t('('))
+				{
+					pos = find_close_bracket(txt, pos);
+					if(pos != tstring::npos)
+					{
+						pos++;
+					} else
+					{
+						int iii = 0;
+						iii++;
+					}
+				}
+				if(pos != tstring::npos)
+				{
+					attribute.val		= txt.substr(el_end + 1, pos - el_end - 1);
+				} else
+				{
+					attribute.val		= txt.substr(el_end + 1);
+				}
+				litehtml::lcase(attribute.val);
+				if(attribute.val == _t("after") || attribute.val == _t("before"))
+				{
+					attribute.condition	= select_pseudo_element;
+				} else
+				{
+					attribute.condition	= select_pseudo_class;
+				}
+				attribute.attribute	= _t("pseudo");
+				m_attrs.push_back(attribute);
+				el_end = pos;
+			}
+		} else if(txt[el_end] == _t('#'))
+		{
+			css_attribute_selector attribute;
+
+			tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);
+			attribute.val		= txt.substr(el_end + 1, pos - el_end - 1);
+			attribute.condition	= select_equal;
+			attribute.attribute	= _t("id");
+			m_attrs.push_back(attribute);
+			el_end = pos;
+		} else if(txt[el_end] == _t('['))
+		{
+			css_attribute_selector attribute;
+
+			tstring::size_type pos = txt.find_first_of(_t("]~=|$*^"), el_end + 1);
+			tstring attr = txt.substr(el_end + 1, pos - el_end - 1);
+			trim(attr);
+			litehtml::lcase(attr);
+			if(pos != tstring::npos)
+			{
+				if(txt[pos] == _t(']'))
+				{
+					attribute.condition = select_exists;
+				} else if(txt[pos] == _t('='))
+				{
+					attribute.condition = select_equal;
+					pos++;
+				} else if(txt.substr(pos, 2) == _t("~="))
+				{
+					attribute.condition = select_contain_str;
+					pos += 2;
+				} else if(txt.substr(pos, 2) == _t("|="))
+				{
+					attribute.condition = select_start_str;
+					pos += 2;
+				} else if(txt.substr(pos, 2) == _t("^="))
+				{
+					attribute.condition = select_start_str;
+					pos += 2;
+				} else if(txt.substr(pos, 2) == _t("$="))
+				{
+					attribute.condition = select_end_str;
+					pos += 2;
+				} else if(txt.substr(pos, 2) == _t("*="))
+				{
+					attribute.condition = select_contain_str;
+					pos += 2;
+				} else
+				{
+					attribute.condition = select_exists;
+					pos += 1;
+				}
+				pos = txt.find_first_not_of(_t(" \t"), pos);
+				if(pos != tstring::npos)
+				{
+					if(txt[pos] == _t('"'))
+					{
+						tstring::size_type pos2 = txt.find_first_of(_t("\""), pos + 1);
+						attribute.val = txt.substr(pos + 1, pos2 == tstring::npos ? pos2 : (pos2 - pos - 1));
+						pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);
+					} else if(txt[pos] == _t(']'))
+					{
+						pos ++;
+					} else
+					{
+						tstring::size_type pos2 = txt.find_first_of(_t("]"), pos + 1);
+						attribute.val = txt.substr(pos, pos2 == tstring::npos ? pos2 : (pos2 - pos));
+						trim(attribute.val);
+						pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);
+					}
+				}
+			} else
+			{
+				attribute.condition = select_exists;
+			}
+			attribute.attribute	= attr;
+			m_attrs.push_back(attribute);
+			el_end = pos;
+		} else
+		{
+			el_end++;
+		}
+		el_end = txt.find_first_of(_t(".#[:"), el_end);
+	}
+}
+
+
+bool litehtml::css_selector::parse( const tstring& text )
+{
+	if(text.empty())
+	{
+		return false;
+	}
+	string_vector tokens;
+	split_string(text, tokens, _t(""), _t(" \t>+~"), _t("(["));
+
+	if(tokens.empty())
+	{
+		return false;
+	}
+
+	tstring left;
+	tstring right = tokens.back();
+	tchar_t combinator = 0;
+
+	tokens.pop_back();
+	while(!tokens.empty() && (tokens.back() == _t(" ") || tokens.back() == _t("\t") || tokens.back() == _t("+") || tokens.back() == _t("~") || tokens.back() == _t(">")))
+	{
+		if(combinator == _t(' ') || combinator == 0)
+		{
+			combinator = tokens.back()[0];
+		}
+		tokens.pop_back();
+	}
+
+	for(string_vector::const_iterator i = tokens.begin(); i != tokens.end(); i++)
+	{
+		left += *i;
+	}
+
+	trim(left);
+	trim(right);
+
+	if(right.empty())
+	{
+		return false;
+	}
+
+	m_right.parse(right);
+
+	switch(combinator)
+	{
+	case _t('>'):
+		m_combinator	= combinator_child;
+		break;
+	case _t('+'):
+		m_combinator	= combinator_adjacent_sibling;
+		break;
+	case _t('~'):
+		m_combinator	= combinator_general_sibling;
+		break;
+	default:
+		m_combinator	= combinator_descendant;
+		break;
+	}
+
+	m_left = 0;
+
+	if(!left.empty())
+	{
+		m_left = std::make_shared<css_selector>(media_query_list::ptr(0));
+		if(!m_left->parse(left))
+		{
+			return false;
+		}
+	}
+
+	return true;
+}
+
+void litehtml::css_selector::calc_specificity()
+{
+	if(!m_right.m_tag.empty() && m_right.m_tag != _t("*"))
+	{
+		m_specificity.d = 1;
+	}
+	for(css_attribute_selector::vector::iterator i = m_right.m_attrs.begin(); i != m_right.m_attrs.end(); i++)
+	{
+		if(i->attribute == _t("id"))
+		{
+			m_specificity.b++;
+		} else
+		{
+			if(i->attribute == _t("class"))
+			{
+				m_specificity.c += (int) i->class_val.size();
+			} else
+			{
+				m_specificity.c++;
+			}
+		}	
+	}
+	if(m_left)
+	{
+		m_left->calc_specificity();
+		m_specificity += m_left->m_specificity;
+	}
+}
+
+void litehtml::css_selector::add_media_to_doc( document* doc ) const
+{
+	if(m_media_query && doc)
+	{
+		doc->add_media_list(m_media_query);
+	}
+}
+
diff --git a/src/plugins/litehtml_viewer/litehtml/css_selector.h b/src/plugins/litehtml_viewer/litehtml/css_selector.h
new file mode 100644
index 0000000..ae8f9c9
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/css_selector.h
@@ -0,0 +1,274 @@
+#pragma once
+#include "style.h"
+#include "media_query.h"
+
+namespace litehtml
+{
+	//////////////////////////////////////////////////////////////////////////
+
+	struct selector_specificity
+	{
+		int		a;
+		int		b;
+		int		c;
+		int		d;
+
+		selector_specificity(int va = 0, int vb = 0, int vc = 0, int vd = 0)
+		{
+			a	= va;
+			b	= vb;
+			c	= vc;
+			d	= vd;
+		}
+
+		void operator += (const selector_specificity& val)
+		{
+			a	+= val.a;
+			b	+= val.b;
+			c	+= val.c;
+			d	+= val.d;
+		}
+
+		bool operator==(const selector_specificity& val) const
+		{
+			if(a == val.a && b == val.b && c == val.c && d == val.d)
+			{
+				return true;
+			}
+			return false;
+		}
+
+		bool operator!=(const selector_specificity& val) const
+		{
+			if(a != val.a || b != val.b || c != val.c || d != val.d)
+			{
+				return true;
+			}
+			return false;
+		}
+
+		bool operator > (const selector_specificity& val) const
+		{
+			if(a > val.a)
+			{
+				return true;
+			} else if(a < val.a)
+			{
+				return false;
+			} else
+			{
+				if(b > val.b)
+				{
+					return true;
+				} else if(b < val.b)
+				{
+					return false;
+				} else
+				{
+					if(c > val.c)
+					{
+						return true;
+					} else if(c < val.c)
+					{
+						return false;
+					} else
+					{
+						if(d > val.d)
+						{
+							return true;
+						} else if(d < val.d)
+						{
+							return false;
+						}
+					}
+				}
+			}
+			return false;
+		}
+
+		bool operator >= (const selector_specificity& val) const
+		{
+			if((*this) == val) return true;
+			if((*this) > val) return true;
+			return false;
+		}
+
+		bool operator <= (const selector_specificity& val) const
+		{
+			if((*this) > val)
+			{
+				return false;
+			}
+			return true;
+		}
+
+		bool operator < (const selector_specificity& val) const
+		{
+			if((*this) <= val && (*this) != val)
+			{
+				return true;
+			}
+			return false;
+		}
+
+	};
+
+	//////////////////////////////////////////////////////////////////////////
+
+	enum attr_select_condition
+	{
+		select_exists,
+		select_equal,
+		select_contain_str,
+		select_start_str,
+		select_end_str,
+		select_pseudo_class,
+		select_pseudo_element,
+	};
+
+	//////////////////////////////////////////////////////////////////////////
+
+	struct css_attribute_selector
+	{
+		typedef std::vector<css_attribute_selector>	vector;
+
+		tstring					attribute;
+		tstring					val;
+		string_vector			class_val;
+		attr_select_condition	condition;
+
+		css_attribute_selector()
+		{
+			condition = select_exists;
+		}
+	};
+
+	//////////////////////////////////////////////////////////////////////////
+
+	class css_element_selector
+	{
+	public:
+		tstring							m_tag;
+		css_attribute_selector::vector	m_attrs;
+	public:
+
+		void parse(const tstring& txt);
+	};
+
+	//////////////////////////////////////////////////////////////////////////
+
+	enum css_combinator
+	{
+		combinator_descendant,
+		combinator_child,
+		combinator_adjacent_sibling,
+		combinator_general_sibling
+	};
+
+	//////////////////////////////////////////////////////////////////////////
+
+	class css_selector
+	{
+	public:
+		typedef std::shared_ptr<css_selector>	ptr;
+		typedef std::vector<css_selector::ptr>	vector;
+	public:
+		selector_specificity	m_specificity;
+		css_element_selector	m_right;
+		css_selector::ptr		m_left;
+		css_combinator			m_combinator;
+		style::ptr				m_style;
+		int						m_order;
+		media_query_list::ptr	m_media_query;
+	public:
+		css_selector(media_query_list::ptr media)
+		{
+			m_media_query	= media;
+			m_combinator	= combinator_descendant;
+			m_order			= 0;
+		}
+
+		~css_selector()
+		{
+		}
+
+		css_selector(const css_selector& val)
+		{
+			m_right			= val.m_right;
+			if(val.m_left)
+			{
+				m_left			= std::make_shared<css_selector>(*val.m_left);
+			} else
+			{
+				m_left = 0;
+			}
+			m_combinator	= val.m_combinator;
+			m_specificity	= val.m_specificity;
+			m_order			= val.m_order;
+			m_media_query	= val.m_media_query;
+		}
+
+		bool parse(const tstring& text);
+		void calc_specificity();
+		bool is_media_valid() const;
+		void add_media_to_doc(document* doc) const;
+	};
+
+	inline bool css_selector::is_media_valid() const
+	{
+		if(!m_media_query)
+		{
+			return true;
+		}
+		return m_media_query->is_used();
+	}
+
+
+	//////////////////////////////////////////////////////////////////////////
+
+	inline bool operator > (const css_selector& v1, const css_selector& v2)
+	{
+		if(v1.m_specificity == v2.m_specificity)
+		{
+			return (v1.m_order > v2.m_order);
+		}
+		return (v1.m_specificity > v2.m_specificity);
+	}
+
+	inline bool operator < (const css_selector& v1, const css_selector& v2)
+	{
+		if(v1.m_specificity == v2.m_specificity)
+		{
+			return (v1.m_order < v2.m_order);
+		}
+		return (v1.m_specificity < v2.m_specificity);
+	}
+
+	inline bool operator >(const css_selector::ptr& v1, const css_selector::ptr& v2)
+	{
+		return (*v1 > *v2);
+	}
+
+	inline bool operator < (const css_selector::ptr& v1, const css_selector::ptr& v2)
+	{
+		return (*v1 < *v2);
+	}
+
+	//////////////////////////////////////////////////////////////////////////
+
+	class used_selector
+	{
+	public:
+		typedef std::unique_ptr<used_selector>	ptr;
+		typedef std::vector<used_selector::ptr>	vector;
+
+		css_selector::ptr	m_selector;
+		bool				m_used;
+
+		used_selector(const css_selector::ptr& selector, bool used)
+		{
+			m_used		= used;
+			m_selector	= selector;
+		}
+	};
+}
\ 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
index 0000000..e9775aa
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/document.cpp
@@ -0,0 +1,930 @@
+#include "html.h"
+#include "document.h"
+#include "stylesheet.h"
+#include "html_tag.h"
+#include "el_text.h"
+#include "el_para.h"
+#include "el_space.h"
+#include "el_body.h"
+#include "el_image.h"
+#include "el_table.h"
+#include "el_td.h"
+#include "el_link.h"
+#include "el_title.h"
+#include "el_style.h"
+#include "el_script.h"
+#include "el_comment.h"
+#include "el_cdata.h"
+#include "el_base.h"
+#include "el_anchor.h"
+#include "el_break.h"
+#include "el_div.h"
+#include "el_font.h"
+#include "el_tr.h"
+#include <math.h>
+#include <stdio.h>
+#include <algorithm>
+#include "gumbo.h"
+#include "utf8_strings.h"
+
+litehtml::document::document(litehtml::document_container* objContainer, litehtml::context* ctx)
+{
+	m_container	= objContainer;
+	m_context	= ctx;
+}
+
+litehtml::document::~document()
+{
+	m_over_element = 0;
+	if(m_container)
+	{
+		for(fonts_map::iterator f = m_fonts.begin(); f != m_fonts.end(); f++)
+		{
+			m_container->delete_font(f->second.font);
+		}
+	}
+}
+
+litehtml::document::ptr litehtml::document::createFromString( const tchar_t* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles)
+{
+	return createFromUTF8(litehtml_to_utf8(str), objPainter, ctx, user_styles);
+}
+
+litehtml::document::ptr litehtml::document::createFromUTF8(const char* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles)
+{
+	// parse document into GumboOutput
+	GumboOutput* output = gumbo_parse((const char*) str);
+
+	// Create litehtml::document
+	litehtml::document::ptr doc = std::make_shared<litehtml::document>(objPainter, ctx);
+
+	// Create litehtml::elements.
+	elements_vector root_elements;
+	doc->create_node(output->root, root_elements);
+	if (!root_elements.empty())
+	{
+		doc->m_root = root_elements.back();
+	}
+	// Destroy GumboOutput
+	gumbo_destroy_output(&kGumboDefaultOptions, output);
+
+	// Let's process created elements tree
+	if (doc->m_root)
+	{
+		doc->container()->get_media_features(doc->m_media);
+
+		// apply master CSS
+		doc->m_root->apply_stylesheet(ctx->master_css());
+
+		// parse elements attributes
+		doc->m_root->parse_attributes();
+
+		// parse style sheets linked in document
+		media_query_list::ptr media;
+		for (css_text::vector::iterator css = doc->m_css.begin(); css != doc->m_css.end(); css++)
+		{
+			if (!css->media.empty())
+			{
+				media = media_query_list::create_from_string(css->media, doc);
+			}
+			else
+			{
+				media = 0;
+			}
+			doc->m_styles.parse_stylesheet(css->text.c_str(), css->baseurl.c_str(), doc, media);
+		}
+		// Sort css selectors using CSS rules.
+		doc->m_styles.sort_selectors();
+
+		// get current media features
+		if (!doc->m_media_lists.empty())
+		{
+			doc->update_media_lists(doc->m_media);
+		}
+
+		// Apply parsed styles.
+		doc->m_root->apply_stylesheet(doc->m_styles);
+
+		// Apply user styles if any
+		if (user_styles)
+		{
+			doc->m_root->apply_stylesheet(*user_styles);
+		}
+
+		// Parse applied styles in the elements
+		doc->m_root->parse_styles();
+
+		// Now the m_tabular_elements is filled with tabular elements.
+		// We have to check the tabular elements for missing table elements 
+		// and create the anonymous boxes in visual table layout
+		doc->fix_tables_layout();
+
+		// Fanaly initialize elements
+		doc->m_root->init();
+	}
+
+	return doc;
+}
+
+litehtml::uint_ptr litehtml::document::add_font( const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm )
+{
+	uint_ptr ret = 0;
+
+	if( !name || (name && !t_strcasecmp(name, _t("inherit"))) )
+	{
+		name = m_container->get_default_font_name();
+	}
+
+	if(!size)
+	{
+		size = container()->get_default_font_size();
+	}
+
+	tchar_t strSize[20];
+	t_itoa(size, strSize, 20, 10);
+
+	tstring key = name;
+	key += _t(":");
+	key += strSize;
+	key += _t(":");
+	key += weight;
+	key += _t(":");
+	key += style;
+	key += _t(":");
+	key += decoration;
+
+	if(m_fonts.find(key) == m_fonts.end())
+	{
+		font_style fs = (font_style) value_index(style, font_style_strings, fontStyleNormal);
+		int	fw = value_index(weight, font_weight_strings, -1);
+		if(fw >= 0)
+		{
+			switch(fw)
+			{
+			case litehtml::fontWeightBold:
+				fw = 700;
+				break;
+			case litehtml::fontWeightBolder:
+				fw = 600;
+				break;
+			case litehtml::fontWeightLighter:
+				fw = 300;
+				break;
+			default:
+				fw = 400;
+				break;
+			}
+		} else
+		{
+			fw = t_atoi(weight);
+			if(fw < 100)
+			{
+				fw = 400;
+			}
+		}
+
+		unsigned int decor = 0;
+
+		if(decoration)
+		{
+			std::vector<tstring> tokens;
+			split_string(decoration, tokens, _t(" "));
+			for(std::vector<tstring>::iterator i = tokens.begin(); i != tokens.end(); i++)
+			{
+				if(!t_strcasecmp(i->c_str(), _t("underline")))
+				{
+					decor |= font_decoration_underline;
+				} else if(!t_strcasecmp(i->c_str(), _t("line-through")))
+				{
+					decor |= font_decoration_linethrough;
+				} else if(!t_strcasecmp(i->c_str(), _t("overline")))
+				{
+					decor |= font_decoration_overline;
+				}
+			}
+		}
+
+		font_item fi= {0};
+
+		fi.font = m_container->create_font(name, size, fw, fs, decor, &fi.metrics);
+		m_fonts[key] = fi;
+		ret = fi.font;
+		if(fm)
+		{
+			*fm = fi.metrics;
+		}
+	}
+	return ret;
+}
+
+litehtml::uint_ptr litehtml::document::get_font( const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm )
+{
+	if( !name || (name && !t_strcasecmp(name, _t("inherit"))) )
+	{
+		name = m_container->get_default_font_name();
+	}
+
+	if(!size)
+	{
+		size = container()->get_default_font_size();
+	}
+
+	tchar_t strSize[20];
+	t_itoa(size, strSize, 20, 10);
+
+	tstring key = name;
+	key += _t(":");
+	key += strSize;
+	key += _t(":");
+	key += weight;
+	key += _t(":");
+	key += style;
+	key += _t(":");
+	key += decoration;
+
+	fonts_map::iterator el = m_fonts.find(key);
+
+	if(el != m_fonts.end())
+	{
+		if(fm)
+		{
+			*fm = el->second.metrics;
+		}
+		return el->second.font;
+	}
+	return add_font(name, size, weight, style, decoration, fm);
+}
+
+int litehtml::document::render( int max_width, render_type rt )
+{
+	int ret = 0;
+	if(m_root)
+	{
+		if(rt == render_fixed_only)
+		{
+			m_fixed_boxes.clear();
+			m_root->render_positioned(rt);
+		} else
+		{
+			ret = m_root->render(0, 0, max_width);
+			if(m_root->fetch_positioned())
+			{
+				m_fixed_boxes.clear();
+				m_root->render_positioned(rt);
+			}
+			m_size.width	= 0;
+			m_size.height	= 0;
+			m_root->calc_document_size(m_size);
+		}
+	}
+	return ret;
+}
+
+void litehtml::document::draw( uint_ptr hdc, int x, int y, const position* clip )
+{
+	if(m_root)
+	{
+		m_root->draw(hdc, x, y, clip);
+		m_root->draw_stacking_context(hdc, x, y, clip, true);
+	}
+}
+
+int litehtml::document::cvt_units( const tchar_t* str, int fontSize, bool* is_percent/*= 0*/ ) const
+{
+	if(!str)	return 0;
+	
+	css_length val;
+	val.fromString(str);
+	if(is_percent && val.units() == css_units_percentage && !val.is_predefined())
+	{
+		*is_percent = true;
+	}
+	return cvt_units(val, fontSize);
+}
+
+int litehtml::document::cvt_units( css_length& val, int fontSize, int size ) const
+{
+	if(val.is_predefined())
+	{
+		return 0;
+	}
+	int ret = 0;
+	switch(val.units())
+	{
+	case css_units_percentage:
+		ret = val.calc_percent(size);
+		break;
+	case css_units_em:
+		ret = round_f(val.val() * fontSize);
+		val.set_value((float) ret, css_units_px);
+		break;
+	case css_units_pt:
+		ret = m_container->pt_to_px((int) val.val());
+		val.set_value((float) ret, css_units_px);
+		break;
+	case css_units_in:
+		ret = m_container->pt_to_px((int) (val.val() * 72));
+		val.set_value((float) ret, css_units_px);
+		break;
+	case css_units_cm:
+		ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72));
+		val.set_value((float) ret, css_units_px);
+		break;
+	case css_units_mm:
+		ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72) / 10);
+		val.set_value((float) ret, css_units_px);
+		break;
+	case css_units_vw:
+		ret = (int)((double)m_media.width * (double)val.val() / 100.0);
+		break;
+	case css_units_vh:
+		ret = (int)((double)m_media.height * (double)val.val() / 100.0);
+		break;
+	case css_units_vmin:
+		ret = (int)((double)std::min(m_media.height, m_media.width) * (double)val.val() / 100.0);
+		break;
+	case css_units_vmax:
+		ret = (int)((double)std::max(m_media.height, m_media.width) * (double)val.val() / 100.0);
+		break;
+	default:
+		ret = (int) val.val();
+		break;
+	}
+	return ret;
+}
+
+int litehtml::document::width() const
+{
+	return m_size.width;
+}
+
+int litehtml::document::height() const
+{
+	return m_size.height;
+}
+
+void litehtml::document::add_stylesheet( const tchar_t* str, const tchar_t* baseurl, const tchar_t* media )
+{
+	if(str && str[0])
+	{
+		m_css.push_back(css_text(str, baseurl, media));
+	}
+}
+
+bool litehtml::document::on_mouse_over( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )
+{
+	if(!m_root)
+	{
+		return false;
+	}
+
+	element::ptr over_el = m_root->get_element_by_point(x, y, client_x, client_y);
+
+	bool state_was_changed = false;
+
+	if(over_el != m_over_element)
+	{
+		if(m_over_element)
+		{
+			if(m_over_element->on_mouse_leave())
+			{
+				state_was_changed = true;
+			}
+		}
+		m_over_element = over_el;
+	}
+
+	const tchar_t* cursor = 0;
+
+	if(m_over_element)
+	{
+		if(m_over_element->on_mouse_over())
+		{
+			state_was_changed = true;
+		}
+		cursor = m_over_element->get_cursor();
+	}
+	
+	m_container->set_cursor(cursor ? cursor : _t("auto"));
+	
+	if(state_was_changed)
+	{
+		return m_root->find_styles_changes(redraw_boxes, 0, 0);
+	}
+	return false;
+}
+
+bool litehtml::document::on_mouse_leave( position::vector& redraw_boxes )
+{
+	if(!m_root)
+	{
+		return false;
+	}
+	if(m_over_element)
+	{
+		if(m_over_element->on_mouse_leave())
+		{
+			return m_root->find_styles_changes(redraw_boxes, 0, 0);
+		}
+	}
+	return false;
+}
+
+bool litehtml::document::on_lbutton_down( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )
+{
+	if(!m_root)
+	{
+		return false;
+	}
+
+	element::ptr over_el = m_root->get_element_by_point(x, y, client_x, client_y);
+
+	bool state_was_changed = false;
+
+	if(over_el != m_over_element)
+	{
+		if(m_over_element)
+		{
+			if(m_over_element->on_mouse_leave())
+			{
+				state_was_changed = true;
+			}
+		}
+		m_over_element = over_el;
+		if(m_over_element)
+		{
+			if(m_over_element->on_mouse_over())
+			{
+				state_was_changed = true;
+			}
+		}
+	}
+
+	const tchar_t* cursor = 0;
+
+	if(m_over_element)
+	{
+		if(m_over_element->on_lbutton_down())
+		{
+			state_was_changed = true;
+		}
+		cursor = m_over_element->get_cursor();
+	}
+
+	m_container->set_cursor(cursor ? cursor : _t("auto"));
+
+	if(state_was_changed)
+	{
+		return m_root->find_styles_changes(redraw_boxes, 0, 0);
+	}
+
+	return false;
+}
+
+bool litehtml::document::on_lbutton_up( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )
+{
+	if(!m_root)
+	{
+		return false;
+	}
+	if(m_over_element)
+	{
+		if(m_over_element->on_lbutton_up())
+		{
+			return m_root->find_styles_changes(redraw_boxes, 0, 0);
+		}
+	}
+	return false;
+}
+
+litehtml::element::ptr litehtml::document::create_element(const tchar_t* tag_name, const string_map& attributes)
+{
+	element::ptr newTag;
+	document::ptr this_doc = shared_from_this();
+	if(m_container)
+	{
+		newTag = m_container->create_element(tag_name, attributes, this_doc);
+	}
+	if(!newTag)
+	{
+		if(!t_strcmp(tag_name, _t("br")))
+		{
+			newTag = std::make_shared<litehtml::el_break>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("p")))
+		{
+			newTag = std::make_shared<litehtml::el_para>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("img")))
+		{
+			newTag = std::make_shared<litehtml::el_image>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("table")))
+		{
+			newTag = std::make_shared<litehtml::el_table>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("td")) || !t_strcmp(tag_name, _t("th")))
+		{
+			newTag = std::make_shared<litehtml::el_td>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("link")))
+		{
+			newTag = std::make_shared<litehtml::el_link>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("title")))
+		{
+			newTag = std::make_shared<litehtml::el_title>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("a")))
+		{
+			newTag = std::make_shared<litehtml::el_anchor>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("tr")))
+		{
+			newTag = std::make_shared<litehtml::el_tr>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("style")))
+		{
+			newTag = std::make_shared<litehtml::el_style>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("base")))
+		{
+			newTag = std::make_shared<litehtml::el_base>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("body")))
+		{
+			newTag = std::make_shared<litehtml::el_body>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("div")))
+		{
+			newTag = std::make_shared<litehtml::el_div>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("script")))
+		{
+			newTag = std::make_shared<litehtml::el_script>(this_doc);
+		} else if(!t_strcmp(tag_name, _t("font")))
+		{
+			newTag = std::make_shared<litehtml::el_font>(this_doc);
+		} else
+		{
+			newTag = std::make_shared<litehtml::html_tag>(this_doc);
+		}
+	}
+
+	if(newTag)
+	{
+		newTag->set_tagName(tag_name);
+		for (string_map::const_iterator iter = attributes.begin(); iter != attributes.end(); iter++)
+		{
+			newTag->set_attr(iter->first.c_str(), iter->second.c_str());
+		}
+	}
+
+	return newTag;
+}
+
+void litehtml::document::get_fixed_boxes( position::vector& fixed_boxes )
+{
+	fixed_boxes = m_fixed_boxes;
+}
+
+void litehtml::document::add_fixed_box( const position& pos )
+{
+	m_fixed_boxes.push_back(pos);
+}
+
+bool litehtml::document::media_changed()
+{
+	if(!m_media_lists.empty())
+	{
+		container()->get_media_features(m_media);
+		if (update_media_lists(m_media))
+		{
+			m_root->refresh_styles();
+			m_root->parse_styles();
+			return true;
+		}
+	}
+	return false;
+}
+
+bool litehtml::document::lang_changed()
+{
+	if(!m_media_lists.empty())
+	{
+		tstring culture;
+		container()->get_language(m_lang, culture);
+		if(!culture.empty())
+		{
+			m_culture = m_lang + _t('-') + culture;
+		}
+		else
+		{
+			m_culture.clear();
+		}
+		m_root->refresh_styles();
+		m_root->parse_styles();
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::document::update_media_lists(const media_features& features)
+{
+	bool update_styles = false;
+	for(media_query_list::vector::iterator iter = m_media_lists.begin(); iter != m_media_lists.end(); iter++)
+	{
+		if((*iter)->apply_media_features(features))
+		{
+			update_styles = true;
+		}
+	}
+	return update_styles;
+}
+
+void litehtml::document::add_media_list( media_query_list::ptr list )
+{
+	if(list)
+	{
+		if(std::find(m_media_lists.begin(), m_media_lists.end(), list) == m_media_lists.end())
+		{
+			m_media_lists.push_back(list);
+		}
+	}
+}
+
+void litehtml::document::create_node(GumboNode* node, elements_vector& elements)
+{
+	switch (node->type)
+	{
+	case GUMBO_NODE_ELEMENT:
+		{
+			string_map attrs;
+			GumboAttribute* attr;
+			for (unsigned int i = 0; i < node->v.element.attributes.length; i++)
+			{
+				attr = (GumboAttribute*)node->v.element.attributes.data[i];
+				attrs[tstring(litehtml_from_utf8(attr->name))] = litehtml_from_utf8(attr->value);
+			}
+
+
+			element::ptr ret;
+			const char* tag = gumbo_normalized_tagname(node->v.element.tag);
+			if (tag[0])
+			{
+				ret = create_element(litehtml_from_utf8(tag), attrs);
+			}
+			else
+			{
+				if (node->v.element.original_tag.data && node->v.element.original_tag.length)
+				{
+					std::string strA;
+					gumbo_tag_from_original_text(&node->v.element.original_tag);
+					strA.append(node->v.element.original_tag.data, node->v.element.original_tag.length);
+					ret = create_element(litehtml_from_utf8(strA.c_str()), attrs);
+				}
+			}
+			if (ret)
+			{
+				elements_vector child;
+				for (unsigned int i = 0; i < node->v.element.children.length; i++)
+				{
+					child.clear();
+					create_node(static_cast<GumboNode*> (node->v.element.children.data[i]), child);
+					std::for_each(child.begin(), child.end(), 
+						[&ret](element::ptr& el)
+						{
+							ret->appendChild(el);
+						}
+					);
+				}
+				elements.push_back(ret);
+			}
+		}
+		break;
+	case GUMBO_NODE_TEXT:
+		{
+			std::wstring str;
+			std::wstring str_in = (const wchar_t*) (utf8_to_wchar(node->v.text.text));
+			ucode_t c;
+			for (size_t i = 0; i < str_in.length(); i++)
+			{
+				c = (ucode_t) str_in[i];
+				if (c <= ' ' && (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f'))
+				{
+					if (!str.empty())
+					{
+						elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
+						str.clear();
+					}
+					str += c;
+					elements.push_back(std::make_shared<el_space>(litehtml_from_wchar(str.c_str()), shared_from_this()));
+					str.clear();
+				}
+				// CJK character range
+				else if (c >= 0x4E00 && c <= 0x9FCC)
+				{
+					if (!str.empty())
+					{
+						elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
+						str.clear();
+					}
+					str += c;
+					elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
+					str.clear();
+				}
+				else
+				{
+					str += c;
+				}
+			}
+			if (!str.empty())
+			{
+				elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
+			}
+		}
+		break;
+	case GUMBO_NODE_CDATA:
+		{
+			element::ptr ret = std::make_shared<el_cdata>(shared_from_this());
+			ret->set_data(litehtml_from_utf8(node->v.text.text));
+			elements.push_back(ret);
+		}
+		break;
+	case GUMBO_NODE_COMMENT:
+		{
+			element::ptr ret = std::make_shared<el_comment>(shared_from_this());
+			ret->set_data(litehtml_from_utf8(node->v.text.text));
+			elements.push_back(ret);
+		}
+		break;
+	case GUMBO_NODE_WHITESPACE:
+		{
+			tstring str = litehtml_from_utf8(node->v.text.text);
+			for (size_t i = 0; i < str.length(); i++)
+			{
+				elements.push_back(std::make_shared<el_space>(str.substr(i, 1).c_str(), shared_from_this()));
+			}
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+void litehtml::document::fix_tables_layout()
+{
+	size_t i = 0;
+	while (i < m_tabular_elements.size())
+	{
+		element::ptr el_ptr = m_tabular_elements[i];
+
+		switch (el_ptr->get_display())
+		{
+		case display_inline_table:
+		case display_table:
+			fix_table_children(el_ptr, display_table_row_group, _t("table-row-group"));
+			break;
+		case display_table_footer_group:
+		case display_table_row_group:
+		case display_table_header_group:
+			fix_table_parent(el_ptr, display_table, _t("table"));
+			fix_table_children(el_ptr, display_table_row, _t("table-row"));
+			break;
+		case display_table_row:
+			fix_table_parent(el_ptr, display_table_row_group, _t("table-row-group"));
+			fix_table_children(el_ptr, display_table_cell, _t("table-cell"));
+			break;
+		case display_table_cell:
+			fix_table_parent(el_ptr, display_table_row, _t("table-row"));
+			break;
+		// TODO: make table layout fix for table-caption, table-column etc. elements
+		case display_table_caption:
+		case display_table_column:
+		case display_table_column_group:
+		default:
+			break;
+		}
+		i++;
+	}
+}
+
+void litehtml::document::fix_table_children(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str)
+{
+	elements_vector tmp;
+	elements_vector::iterator first_iter = el_ptr->m_children.begin();
+	elements_vector::iterator cur_iter = el_ptr->m_children.begin();
+
+	auto flush_elements = [&]()
+	{
+		element::ptr annon_tag = std::make_shared<html_tag>(shared_from_this());
+		style st;
+		st.add_property(_t("display"), disp_str, 0, false);
+		annon_tag->add_style(st);
+		annon_tag->parent(el_ptr);
+		annon_tag->parse_styles();
+		std::for_each(tmp.begin(), tmp.end(),
+			[&annon_tag](element::ptr& el)
+			{
+				annon_tag->appendChild(el);
+			}
+		);
+		first_iter = el_ptr->m_children.insert(first_iter, annon_tag);
+		cur_iter = first_iter + 1;
+		while (cur_iter != el_ptr->m_children.end() && (*cur_iter)->parent() != el_ptr)
+		{
+			cur_iter = el_ptr->m_children.erase(cur_iter);
+		}
+		first_iter = cur_iter;
+		tmp.clear();
+	};
+
+	while (cur_iter != el_ptr->m_children.end())
+	{
+		if ((*cur_iter)->get_display() != disp)
+		{
+			if (!(*cur_iter)->is_white_space() || ((*cur_iter)->is_white_space() && !tmp.empty()))
+			{
+				if (tmp.empty())
+				{
+					first_iter = cur_iter;
+				}
+				tmp.push_back((*cur_iter));
+			}
+			cur_iter++;
+		}
+		else if (!tmp.empty())
+		{
+			flush_elements();
+		}
+		else
+		{
+			cur_iter++;
+		}
+	}
+	if (!tmp.empty())
+	{
+		flush_elements();
+	}
+}
+
+void litehtml::document::fix_table_parent(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str)
+{
+	element::ptr parent = el_ptr->parent();
+
+	if (parent->get_display() != disp)
+	{
+		elements_vector::iterator this_element = std::find_if(parent->m_children.begin(), parent->m_children.end(),
+			[&](element::ptr& el)
+			{
+				if (el == el_ptr)
+				{
+					return true;
+				}
+				return false;
+			}
+		);
+		if (this_element != parent->m_children.end())
+		{
+			style_display el_disp = el_ptr->get_display();
+			elements_vector::iterator first = this_element;
+			elements_vector::iterator last = this_element;
+			elements_vector::iterator cur = this_element;
+
+			// find first element with same display
+			while (true)
+			{
+				if (cur == parent->m_children.begin()) break;
+				cur--;
+				if ((*cur)->is_white_space() || (*cur)->get_display() == el_disp)
+				{
+					first = cur;
+				}
+				else
+				{
+					break;
+				}
+			}
+
+			// find last element with same display
+			cur = this_element;
+			while (true)
+			{
+				cur++;
+				if (cur == parent->m_children.end()) break;
+
+				if ((*cur)->is_white_space() || (*cur)->get_display() == el_disp)
+				{
+					last = cur;
+				}
+				else
+				{
+					break;
+				}
+			}
+
+			// extract elements with the same display and wrap them with anonymous object
+			element::ptr annon_tag = std::make_shared<html_tag>(shared_from_this());
+			style st;
+			st.add_property(_t("display"), disp_str, 0, false);
+			annon_tag->add_style(st);
+			annon_tag->parent(parent);
+			annon_tag->parse_styles();
+			std::for_each(first, last + 1,
+				[&annon_tag](element::ptr& el)
+				{
+					annon_tag->appendChild(el);
+				}
+			);
+			first = parent->m_children.erase(first, last + 1);
+			parent->m_children.insert(first, annon_tag);
+		}
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/document.h b/src/plugins/litehtml_viewer/litehtml/document.h
new file mode 100644
index 0000000..33287f4
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/document.h
@@ -0,0 +1,124 @@
+#pragma once
+#include "style.h"
+#include "types.h"
+#include "context.h"
+#include "gumbo.h"
+
+namespace litehtml
+{
+	struct css_text
+	{
+		typedef std::vector<css_text>	vector;
+
+		tstring	text;
+		tstring	baseurl;
+		tstring	media;
+		
+		css_text()
+		{
+		}
+
+		css_text(const tchar_t* txt, const tchar_t* url, const tchar_t* media_str)
+		{
+			text	= txt ? txt : _t("");
+			baseurl	= url ? url : _t("");
+			media	= media_str ? media_str : _t("");
+		}
+
+		css_text(const css_text& val)
+		{
+			text	= val.text;
+			baseurl	= val.baseurl;
+			media	= val.media;
+		}
+	};
+
+	struct stop_tags_t
+	{
+		const litehtml::tchar_t*	tags;
+		const litehtml::tchar_t*	stop_parent;
+	};
+
+	struct ommited_end_tags_t
+	{
+		const litehtml::tchar_t*	tag;
+		const litehtml::tchar_t*	followed_tags;
+	};
+
+	class html_tag;
+
+	class document : public std::enable_shared_from_this<document>
+	{
+	public:
+		typedef std::shared_ptr<document>	ptr;
+		typedef std::weak_ptr<document>		weak_ptr;
+	private:
+		std::shared_ptr<element>			m_root;
+		document_container*					m_container;
+		fonts_map							m_fonts;
+		css_text::vector					m_css;
+		litehtml::css						m_styles;
+		litehtml::web_color					m_def_color;
+		litehtml::context*					m_context;
+		litehtml::size						m_size;
+		position::vector					m_fixed_boxes;
+		media_query_list::vector			m_media_lists;
+		element::ptr						m_over_element;
+		elements_vector						m_tabular_elements;
+		media_features						m_media;
+		tstring                             m_lang;
+		tstring                             m_culture;
+	public:
+		document(litehtml::document_container* objContainer, litehtml::context* ctx);
+		virtual ~document();
+
+		litehtml::document_container*	container()	{ return m_container; }
+		uint_ptr						get_font(const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm);
+		int								render(int max_width, render_type rt = render_all);
+		void							draw(uint_ptr hdc, int x, int y, const position* clip);
+		web_color						get_def_color()	{ return m_def_color; }
+		int								cvt_units(const tchar_t* str, int fontSize, bool* is_percent = 0) const;
+		int								cvt_units(css_length& val, int fontSize, int size = 0) const;
+		int								width() const;
+		int								height() const;
+		void							add_stylesheet(const tchar_t* str, const tchar_t* baseurl, const tchar_t* media);
+		bool							on_mouse_over(int x, int y, int client_x, int client_y, position::vector& redraw_boxes);
+		bool							on_lbutton_down(int x, int y, int client_x, int client_y, position::vector& redraw_boxes);
+		bool							on_lbutton_up(int x, int y, int client_x, int client_y, position::vector& redraw_boxes);
+		bool							on_mouse_leave(position::vector& redraw_boxes);
+		litehtml::element::ptr			create_element(const tchar_t* tag_name, const string_map& attributes);
+		element::ptr					root();
+		void							get_fixed_boxes(position::vector& fixed_boxes);
+		void							add_fixed_box(const position& pos);
+		void							add_media_list(media_query_list::ptr list);
+		bool							media_changed();
+		bool							lang_changed();
+		bool                            match_lang(const tstring & lang);
+		void							add_tabular(const element::ptr& el);
+
+		static litehtml::document::ptr createFromString(const tchar_t* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles = 0);
+		static litehtml::document::ptr createFromUTF8(const char* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles = 0);
+	
+	private:
+		litehtml::uint_ptr	add_font(const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm);
+
+		void create_node(GumboNode* node, elements_vector& elements);
+		bool update_media_lists(const media_features& features);
+		void fix_tables_layout();
+		void fix_table_children(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str);
+		void fix_table_parent(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str);
+	};
+
+	inline element::ptr document::root()
+	{
+		return m_root;
+	}
+	inline void document::add_tabular(const element::ptr& el)
+	{
+		m_tabular_elements.push_back(el);
+	}
+	inline bool document::match_lang(const tstring & lang)
+	{
+		return lang == m_lang || lang == m_culture;
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_anchor.cpp b/src/plugins/litehtml_viewer/litehtml/el_anchor.cpp
new file mode 100644
index 0000000..b48b3f9
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_anchor.cpp
@@ -0,0 +1,31 @@
+#include "html.h"
+#include "el_anchor.h"
+#include "document.h"
+
+litehtml::el_anchor::el_anchor(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+}
+
+litehtml::el_anchor::~el_anchor()
+{
+
+}
+
+void litehtml::el_anchor::on_click()
+{
+	const tchar_t* href = get_attr(_t("href"));
+
+	if(href)
+	{
+		get_document()->container()->on_anchor_click(href, shared_from_this());
+	}
+}
+
+void litehtml::el_anchor::apply_stylesheet( const litehtml::css& stylesheet )
+{
+	if( get_attr(_t("href")) )
+	{
+		m_pseudo_classes.push_back(_t("link"));
+	}
+	html_tag::apply_stylesheet(stylesheet);
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_anchor.h b/src/plugins/litehtml_viewer/litehtml/el_anchor.h
new file mode 100644
index 0000000..4e351ff
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_anchor.h
@@ -0,0 +1,15 @@
+#pragma once
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_anchor : public html_tag
+	{
+	public:
+		el_anchor(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_anchor();
+
+		virtual void	on_click() override;
+		virtual void	apply_stylesheet(const litehtml::css& stylesheet) override;
+	};
+}
\ 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
index 0000000..928bc2e
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_base.cpp
@@ -0,0 +1,18 @@
+#include "html.h"
+#include "el_base.h"
+#include "document.h"
+
+litehtml::el_base::el_base(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+	
+}
+
+litehtml::el_base::~el_base()
+{
+
+}
+
+void litehtml::el_base::parse_attributes()
+{
+	get_document()->container()->set_base_url(get_attr(_t("href")));
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_base.h b/src/plugins/litehtml_viewer/litehtml/el_base.h
new file mode 100644
index 0000000..c4c388f
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_base.h
@@ -0,0 +1,14 @@
+#pragma once
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_base : public html_tag
+	{
+	public:
+		el_base(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_base();
+
+		virtual void	parse_attributes() override;
+	};
+}
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
index 0000000..5c9ca34
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_before_after.cpp
@@ -0,0 +1,200 @@
+#include "html.h"
+#include "el_before_after.h"
+#include "el_text.h"
+#include "el_space.h"
+#include "el_image.h"
+
+litehtml::el_before_after_base::el_before_after_base(const std::shared_ptr<litehtml::document>& doc, bool before) : html_tag(doc)
+{
+	if(before)
+	{
+		set_tagName(_t("::before"));
+	} else
+	{
+		set_tagName(_t("::after"));
+	}
+}
+
+litehtml::el_before_after_base::~el_before_after_base()
+{
+
+}
+
+void litehtml::el_before_after_base::add_style(const litehtml::style& st)
+{
+	html_tag::add_style(st);
+
+	tstring content = get_style_property(_t("content"), false, _t(""));
+	if(!content.empty())
+	{
+		int idx = value_index(content.c_str(), content_property_string);
+		if(idx < 0)
+		{
+			tstring fnc;
+			tstring::size_type i = 0;
+			while(i < content.length() && i != tstring::npos)
+			{
+				if(content.at(i) == _t('"'))
+				{
+					fnc.clear();
+					i++;
+					tstring::size_type pos = content.find(_t('"'), i);
+					tstring txt;
+					if(pos == tstring::npos)
+					{
+						txt = content.substr(i);
+						i = tstring::npos;
+					} else
+					{
+						txt = content.substr(i, pos - i);
+						i = pos + 1;
+					}
+					add_text(txt);
+				} else if(content.at(i) == _t('('))
+				{
+					i++;
+					litehtml::trim(fnc);
+					litehtml::lcase(fnc);
+					tstring::size_type pos = content.find(_t(')'), i);
+					tstring params;
+					if(pos == tstring::npos)
+					{
+						params = content.substr(i);
+						i = tstring::npos;
+					} else
+					{
+						params = content.substr(i, pos - i);
+						i = pos + 1;
+					}
+					add_function(fnc, params);
+					fnc.clear();
+				} else
+				{
+					fnc += content.at(i);
+					i++;
+				}
+			}
+		}
+	}
+}
+
+void litehtml::el_before_after_base::add_text( const tstring& txt )
+{
+	tstring word;
+	tstring esc;
+	for(tstring::size_type i = 0; i < txt.length(); i++)
+	{
+		if( (txt.at(i) == _t(' ')) || (txt.at(i) == _t('\t')) || (txt.at(i) == _t('\\') && !esc.empty()) )
+		{
+			if(esc.empty())
+			{
+				if(!word.empty())
+				{
+					element::ptr el = std::make_shared<el_text>(word.c_str(), get_document());
+					appendChild(el);
+					word.clear();
+				}
+
+				element::ptr el = std::make_shared<el_space>(txt.substr(i, 1).c_str(), get_document());
+				appendChild(el);
+			} else
+			{
+				word += convert_escape(esc.c_str() + 1);
+				esc.clear();
+				if(txt.at(i) == _t('\\'))
+				{
+					esc += txt.at(i);
+				}
+			}
+		} else
+		{
+			if(!esc.empty() || txt.at(i) == _t('\\'))
+			{
+				esc += txt.at(i);
+			} else
+			{
+				word += txt.at(i);
+			}
+		}
+	}
+
+	if(!esc.empty())
+	{
+		word += convert_escape(esc.c_str() + 1);
+	}
+	if(!word.empty())
+	{
+		element::ptr el = std::make_shared<el_text>(word.c_str(), get_document());
+		appendChild(el);
+		word.clear();
+	}
+}
+
+void litehtml::el_before_after_base::add_function( const tstring& fnc, const tstring& params )
+{
+	int idx = value_index(fnc.c_str(), _t("attr;counter;url"));
+	switch(idx)
+	{
+	// attr
+	case 0:
+		{
+			tstring p_name = params;
+			trim(p_name);
+			lcase(p_name);
+			element::ptr el_parent = parent();
+			if (el_parent)
+			{
+				const tchar_t* attr_value = el_parent->get_attr(p_name.c_str());
+				if (attr_value)
+				{
+					add_text(attr_value);
+				}
+			}
+		}
+		break;
+	// counter
+	case 1:
+		break;
+	// url
+	case 2:
+		{
+			tstring p_url = params;
+			trim(p_url);
+			if(!p_url.empty())
+			{
+				if(p_url.at(0) == _t('\'') || p_url.at(0) == _t('\"'))
+				{
+					p_url.erase(0, 1);
+				}
+			}
+			if(!p_url.empty())
+			{
+				if(p_url.at(p_url.length() - 1) == _t('\'') || p_url.at(p_url.length() - 1) == _t('\"'))
+				{
+					p_url.erase(p_url.length() - 1, 1);
+				}
+			}
+			if(!p_url.empty())
+			{
+				element::ptr el = std::make_shared<el_image>(get_document());
+				el->set_attr(_t("src"), p_url.c_str());
+				el->set_attr(_t("style"), _t("display:inline-block"));
+				el->set_tagName(_t("img"));
+				appendChild(el);
+				el->parse_attributes();
+			}
+		}
+		break;
+	}
+}
+
+litehtml::tchar_t litehtml::el_before_after_base::convert_escape( const tchar_t* txt )
+{
+	tchar_t* sss = 0;
+	return (tchar_t) t_strtol(txt, &sss, 16);
+}
+
+void litehtml::el_before_after_base::apply_stylesheet( const litehtml::css& stylesheet )
+{
+
+}
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
index 0000000..5d0e9cb
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_before_after.h
@@ -0,0 +1,37 @@
+#pragma once
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_before_after_base : public html_tag
+	{
+	public:
+		el_before_after_base(const std::shared_ptr<litehtml::document>& doc, bool before);
+		virtual ~el_before_after_base();
+
+		virtual void add_style(const litehtml::style& st) override;
+		virtual void apply_stylesheet(const litehtml::css& stylesheet) override;
+	private:
+		void	add_text(const tstring& txt);
+		void	add_function(const tstring& fnc, const tstring& params);
+		tchar_t convert_escape(const tchar_t* txt);
+	};
+
+	class el_before : public el_before_after_base
+	{
+	public:
+		el_before(const std::shared_ptr<litehtml::document>& doc) : el_before_after_base(doc, true)
+		{
+
+		}
+	};
+
+	class el_after : public el_before_after_base
+	{
+	public:
+		el_after(const std::shared_ptr<litehtml::document>& doc) : el_before_after_base(doc, false)
+		{
+
+		}
+	};
+}
\ 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
index 0000000..7ada94b
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_body.cpp
@@ -0,0 +1,17 @@
+#include "html.h"
+#include "el_body.h"
+#include "document.h"
+
+litehtml::el_body::el_body(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
+{
+}
+
+litehtml::el_body::~el_body()
+{
+
+}
+
+bool litehtml::el_body::is_body()  const
+{
+	return true;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_body.h b/src/plugins/litehtml_viewer/litehtml/el_body.h
new file mode 100644
index 0000000..2248bbc
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_body.h
@@ -0,0 +1,14 @@
+#pragma once
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_body : public html_tag
+	{
+	public:
+		el_body(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_body();
+
+		virtual bool is_body() const override;
+	};
+}
\ 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
index 0000000..a798912
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_break.cpp
@@ -0,0 +1,18 @@
+#include "html.h"
+#include "el_break.h"
+
+litehtml::el_break::el_break(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+
+}
+
+litehtml::el_break::~el_break()
+{
+
+}
+
+bool litehtml::el_break::is_break() const
+{
+	return true;
+}
+
diff --git a/src/plugins/litehtml_viewer/litehtml/el_break.h b/src/plugins/litehtml_viewer/litehtml/el_break.h
new file mode 100644
index 0000000..dac1789
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_break.h
@@ -0,0 +1,14 @@
+#pragma once
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_break : public html_tag
+	{
+	public:
+		el_break(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_break();
+
+		virtual bool is_break() const override;
+	};
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_cdata.cpp b/src/plugins/litehtml_viewer/litehtml/el_cdata.cpp
new file mode 100644
index 0000000..6e785d1
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_cdata.cpp
@@ -0,0 +1,25 @@
+#include "html.h"
+#include "el_cdata.h"
+
+litehtml::el_cdata::el_cdata(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
+{
+	m_skip = true;
+}
+
+litehtml::el_cdata::~el_cdata()
+{
+
+}
+
+void litehtml::el_cdata::get_text( tstring& text )
+{
+	text += m_text;
+}
+
+void litehtml::el_cdata::set_data( const tchar_t* data )
+{
+	if(data)
+	{
+		m_text += data;
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_cdata.h b/src/plugins/litehtml_viewer/litehtml/el_cdata.h
new file mode 100644
index 0000000..e138f9d
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_cdata.h
@@ -0,0 +1,16 @@
+#pragma once
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_cdata : public element
+	{
+		tstring	m_text;
+	public:
+		el_cdata(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_cdata();
+
+		virtual void	get_text(tstring& text) override;
+		virtual void	set_data(const tchar_t* data) override;
+	};
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_comment.cpp b/src/plugins/litehtml_viewer/litehtml/el_comment.cpp
new file mode 100644
index 0000000..3b46e2a
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_comment.cpp
@@ -0,0 +1,25 @@
+#include "html.h"
+#include "el_comment.h"
+
+litehtml::el_comment::el_comment(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
+{
+	m_skip = true;
+}
+
+litehtml::el_comment::~el_comment()
+{
+
+}
+
+void litehtml::el_comment::get_text( tstring& text )
+{
+	text += m_text;
+}
+
+void litehtml::el_comment::set_data( const tchar_t* data )
+{
+	if(data)
+	{
+		m_text += data;
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_comment.h b/src/plugins/litehtml_viewer/litehtml/el_comment.h
new file mode 100644
index 0000000..5b8459d
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_comment.h
@@ -0,0 +1,16 @@
+#pragma once
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_comment : public element
+	{
+		tstring	m_text;
+	public:
+		el_comment(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_comment();
+
+		virtual void	get_text(tstring& text) override;
+		virtual void	set_data(const tchar_t* data) override;
+	};
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_div.cpp b/src/plugins/litehtml_viewer/litehtml/el_div.cpp
new file mode 100644
index 0000000..ec63963
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_div.cpp
@@ -0,0 +1,23 @@
+#include "html.h"
+#include "el_div.h"
+
+
+litehtml::el_div::el_div(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+
+}
+
+litehtml::el_div::~el_div()
+{
+
+}
+
+void litehtml::el_div::parse_attributes()
+{
+	const tchar_t* str = get_attr(_t("align"));
+	if(str)
+	{
+		m_style.add_property(_t("text-align"), str, 0, false);
+	}
+	html_tag::parse_attributes();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_div.h b/src/plugins/litehtml_viewer/litehtml/el_div.h
new file mode 100644
index 0000000..54eed84
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_div.h
@@ -0,0 +1,14 @@
+#pragma once
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_div : public html_tag
+	{
+	public:
+		el_div(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_div();
+
+		virtual void parse_attributes() override;
+	};
+}
\ 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
index 0000000..cef9aae
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_font.cpp
@@ -0,0 +1,60 @@
+#include "html.h"
+#include "el_font.h"
+
+
+litehtml::el_font::el_font(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+
+}
+
+litehtml::el_font::~el_font()
+{
+
+}
+
+void litehtml::el_font::parse_attributes()
+{
+	const tchar_t* str = get_attr(_t("color"));
+	if(str)
+	{
+		m_style.add_property(_t("color"), str, 0, false);
+	}
+
+	str = get_attr(_t("face"));
+	if(str)
+	{
+		m_style.add_property(_t("font-face"), str, 0, false);
+	}
+
+	str = get_attr(_t("size"));
+	if(str)
+	{
+		int sz = t_atoi(str);
+		if(sz <= 1)
+		{
+			m_style.add_property(_t("font-size"), _t("x-small"), 0, false);
+		} else if(sz >= 6)
+		{
+			m_style.add_property(_t("font-size"), _t("xx-large"), 0, false);
+		} else
+		{
+			switch(sz)
+			{
+			case 2:
+				m_style.add_property(_t("font-size"), _t("small"), 0, false);
+				break;
+			case 3:
+				m_style.add_property(_t("font-size"), _t("medium"), 0, false);
+				break;
+			case 4:
+				m_style.add_property(_t("font-size"), _t("large"), 0, false);
+				break;
+			case 5:
+				m_style.add_property(_t("font-size"), _t("x-large"), 0, false);
+				break;
+			}
+		}
+	}
+
+	html_tag::parse_attributes();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_font.h b/src/plugins/litehtml_viewer/litehtml/el_font.h
new file mode 100644
index 0000000..9d5e4a1
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_font.h
@@ -0,0 +1,14 @@
+#pragma once
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_font : public html_tag
+	{
+	public:
+		el_font(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_font();
+
+		virtual void parse_attributes() override;
+	};
+}
\ 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
index 0000000..4d5486b
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_image.cpp
@@ -0,0 +1,255 @@
+#include "html.h"
+#include "el_image.h"
+#include "document.h"
+
+litehtml::el_image::el_image(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+	m_display = display_inline_block;
+}
+
+litehtml::el_image::~el_image( void )
+{
+
+}
+
+void litehtml::el_image::get_content_size( size& sz, int max_width )
+{
+	get_document()->container()->get_image_size(m_src.c_str(), 0, sz);
+}
+
+int litehtml::el_image::line_height() const
+{
+	return height();
+}
+
+bool litehtml::el_image::is_replaced() const
+{
+	return true;
+}
+
+int litehtml::el_image::render( int x, int y, int max_width, bool second_pass )
+{
+	int parent_width = max_width;
+
+	calc_outlines(parent_width);
+
+	m_pos.move_to(x, y);
+
+	document::ptr doc = get_document();
+
+	litehtml::size sz;
+	doc->container()->get_image_size(m_src.c_str(), 0, sz);
+
+	m_pos.width		= sz.width;
+	m_pos.height	= sz.height;
+
+	if(m_css_height.is_predefined() && m_css_width.is_predefined())
+	{
+		m_pos.height	= sz.height;
+		m_pos.width		= sz.width;
+
+		// check for max-height
+		if(!m_css_max_width.is_predefined())
+		{
+			int max_width = doc->cvt_units(m_css_max_width, m_font_size, parent_width);
+			if(m_pos.width > max_width)
+			{
+				m_pos.width = max_width;
+			}
+			if(sz.width)
+			{
+				m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width);
+			} else
+			{
+				m_pos.height = sz.height;
+			}
+		}
+
+		// check for max-height
+		if(!m_css_max_height.is_predefined())
+		{
+			int max_height = doc->cvt_units(m_css_max_height, m_font_size);
+			if(m_pos.height > max_height)
+			{
+				m_pos.height = max_height;
+			}
+			if(sz.height)
+			{
+				m_pos.width = (int) (m_pos.height * (float)sz.width / (float)sz.height);
+			} else
+			{
+				m_pos.width = sz.width;
+			}
+		}
+	} else if(!m_css_height.is_predefined() && m_css_width.is_predefined())
+	{
+		if (!get_predefined_height(m_pos.height))
+		{
+			m_pos.height = (int)m_css_height.val();
+		}
+
+		// check for max-height
+		if(!m_css_max_height.is_predefined())
+		{
+			int max_height = doc->cvt_units(m_css_max_height, m_font_size);
+			if(m_pos.height > max_height)
+			{
+				m_pos.height = max_height;
+			}
+		}
+
+		if(sz.height)
+		{
+			m_pos.width = (int) (m_pos.height * (float)sz.width / (float)sz.height);
+		} else
+		{
+			m_pos.width = sz.width;
+		}
+	} else if(m_css_height.is_predefined() && !m_css_width.is_predefined())
+	{
+		m_pos.width = (int) m_css_width.calc_percent(parent_width);
+
+		// check for max-width
+		if(!m_css_max_width.is_predefined())
+		{
+			int max_width = doc->cvt_units(m_css_max_width, m_font_size, parent_width);
+			if(m_pos.width > max_width)
+			{
+				m_pos.width = max_width;
+			}
+		}
+
+		if(sz.width)
+		{
+			m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width);
+		} else
+		{
+			m_pos.height = sz.height;
+		}
+	} else
+	{
+		m_pos.width		= (int) m_css_width.calc_percent(parent_width);
+		m_pos.height	= 0;
+		if (!get_predefined_height(m_pos.height))
+		{
+			m_pos.height = (int)m_css_height.val();
+		}
+
+		// check for max-height
+		if(!m_css_max_height.is_predefined())
+		{
+			int max_height = doc->cvt_units(m_css_max_height, m_font_size);
+			if(m_pos.height > max_height)
+			{
+				m_pos.height = max_height;
+			}
+		}
+
+		// check for max-height
+		if(!m_css_max_width.is_predefined())
+		{
+			int max_width = doc->cvt_units(m_css_max_width, m_font_size, parent_width);
+			if(m_pos.width > max_width)
+			{
+				m_pos.width = max_width;
+			}
+		}
+	}
+
+	calc_auto_margins(parent_width);
+
+	m_pos.x	+= content_margins_left();
+	m_pos.y += content_margins_top();
+
+	return m_pos.width + content_margins_left() + content_margins_right();
+}
+
+void litehtml::el_image::parse_attributes()
+{
+	m_src = get_attr(_t("src"), _t(""));
+
+	const tchar_t* attr_height = get_attr(_t("height"));
+	if(attr_height)
+	{
+		m_style.add_property(_t("height"), attr_height, 0, false);
+	}
+	const tchar_t* attr_width = get_attr(_t("width"));
+	if(attr_width)
+	{
+		m_style.add_property(_t("width"), attr_width, 0, false);
+	}
+}
+
+void litehtml::el_image::draw( uint_ptr hdc, int x, int y, const position* clip )
+{
+	position pos = m_pos;
+	pos.x += x;
+	pos.y += y;
+
+	position el_pos = pos;
+	el_pos += m_padding;
+	el_pos += m_borders;
+
+	// draw standard background here
+	if (el_pos.does_intersect(clip))
+	{
+		const background* bg = get_background();
+		if (bg)
+		{
+			background_paint bg_paint;
+			init_background_paint(pos, bg_paint, bg);
+
+			get_document()->container()->draw_background(hdc, bg_paint);
+		}
+	}
+
+	// draw image as background
+	if(pos.does_intersect(clip))
+	{
+		if (pos.width > 0 && pos.height > 0) {
+			background_paint bg;
+			bg.image				= m_src;
+			bg.clip_box				= pos;
+			bg.origin_box			= pos;
+			bg.border_box			= pos;
+			bg.border_box			+= m_padding;
+			bg.border_box			+= m_borders;
+			bg.repeat				= background_repeat_no_repeat;
+			bg.image_size.width		= pos.width;
+			bg.image_size.height	= pos.height;
+			bg.border_radius		= m_css_borders.radius.calc_percents(bg.border_box.width, bg.border_box.height);
+			bg.position_x			= pos.x;
+			bg.position_y			= pos.y;
+			get_document()->container()->draw_background(hdc, bg);
+		}
+	}
+
+	// draw borders
+	if (el_pos.does_intersect(clip))
+	{
+		position border_box = pos;
+		border_box += m_padding;
+		border_box += m_borders;
+
+		borders bdr = m_css_borders;
+		bdr.radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
+
+		get_document()->container()->draw_borders(hdc, bdr, border_box, have_parent() ? false : true);
+	}
+}
+
+void litehtml::el_image::parse_styles( bool is_reparse /*= false*/ )
+{
+	html_tag::parse_styles(is_reparse);
+
+	if(!m_src.empty())
+	{
+		if(!m_css_height.is_predefined() && !m_css_width.is_predefined())
+		{
+			get_document()->container()->load_image(m_src.c_str(), 0, true);
+		} else
+		{
+			get_document()->container()->load_image(m_src.c_str(), 0, false);
+		}
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_image.h b/src/plugins/litehtml_viewer/litehtml/el_image.h
new file mode 100644
index 0000000..670aa66
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_image.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+
+	class el_image : public html_tag
+	{
+		tstring	m_src;
+	public:
+		el_image(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_image(void);
+
+		virtual int		line_height() const override;
+		virtual bool	is_replaced() const override;
+		virtual int		render(int x, int y, int max_width, bool second_pass = false) override;
+		virtual void	parse_attributes() override;
+		virtual void	parse_styles(bool is_reparse = false) override;
+		virtual void	draw(uint_ptr hdc, int x, int y, const position* clip) override;
+		virtual void	get_content_size(size& sz, int max_width) override;
+	};
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_link.cpp b/src/plugins/litehtml_viewer/litehtml/el_link.cpp
new file mode 100644
index 0000000..709c399
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_link.cpp
@@ -0,0 +1,44 @@
+#include "html.h"
+#include "el_link.h"
+#include "document.h"
+
+
+litehtml::el_link::el_link(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
+{
+
+}
+
+litehtml::el_link::~el_link()
+{
+
+}
+
+void litehtml::el_link::parse_attributes()
+{
+	bool processed = false;
+
+	document::ptr doc = get_document();
+
+	const tchar_t* rel = get_attr(_t("rel"));
+	if(rel && !t_strcmp(rel, _t("stylesheet")))
+	{
+		const tchar_t* media	= get_attr(_t("media"));
+		const tchar_t* href		= get_attr(_t("href"));
+		if(href && href[0])
+		{
+			tstring css_text;
+			tstring css_baseurl;
+			doc->container()->import_css(css_text, href, css_baseurl);
+			if(!css_text.empty())
+			{
+				doc->add_stylesheet(css_text.c_str(), css_baseurl.c_str(), media);
+				processed = true;
+			}
+		}
+	}
+
+	if(!processed)
+	{
+		doc->container()->link(doc, shared_from_this());
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_link.h b/src/plugins/litehtml_viewer/litehtml/el_link.h
new file mode 100644
index 0000000..ef94fb1
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_link.h
@@ -0,0 +1,15 @@
+#pragma once
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_link : public html_tag
+	{
+	public:
+		el_link(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_link();
+
+	protected:
+		virtual void	parse_attributes() override;
+	};
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_para.cpp b/src/plugins/litehtml_viewer/litehtml/el_para.cpp
new file mode 100644
index 0000000..f38baa1
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_para.cpp
@@ -0,0 +1,23 @@
+#include "html.h"
+#include "el_para.h"
+#include "document.h"
+
+litehtml::el_para::el_para(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
+{
+}
+
+litehtml::el_para::~el_para()
+{
+
+}
+
+void litehtml::el_para::parse_attributes()
+{
+	const tchar_t* str = get_attr(_t("align"));
+	if(str)
+	{
+		m_style.add_property(_t("text-align"), str, 0, false);
+	}
+
+	html_tag::parse_attributes();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_para.h b/src/plugins/litehtml_viewer/litehtml/el_para.h
new file mode 100644
index 0000000..cee990e
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_para.h
@@ -0,0 +1,15 @@
+#pragma once
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_para : public html_tag
+	{
+	public:
+		el_para(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_para();
+
+		virtual void	parse_attributes() override;
+
+	};
+}
\ No newline at end of file
diff --git a/src/plugins/litehtml_viewer/litehtml/el_script.cpp b/src/plugins/litehtml_viewer/litehtml/el_script.cpp
new file mode 100644
index 0000000..312c794
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_script.cpp
@@ -0,0 +1,30 @@
+#include "html.h"
+#include "el_script.h"
+#include "document.h"
+
+
+litehtml::el_script::el_script(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
+{
+
+}
+
+litehtml::el_script::~el_script()
+{
+
+}
+
+void litehtml::el_script::parse_attributes()
+{
+	//TODO: pass script text to document container
+}
+
+bool litehtml::el_script::appendChild(const ptr &el)
+{
+	el->get_text(m_text);
+	return true;
+}
+
+const litehtml::tchar_t* litehtml::el_script::get_tagName() const
+{
+	return _t("script");
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_script.h b/src/plugins/litehtml_viewer/litehtml/el_script.h
new file mode 100644
index 0000000..7c4c372
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_script.h
@@ -0,0 +1,17 @@
+#pragma once
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_script : public element
+	{
+		tstring m_text;
+	public:
+		el_script(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_script();
+
+		virtual void			parse_attributes() override;
+		virtual bool			appendChild(const ptr &el) override;
+		virtual const tchar_t*	get_tagName() const override;
+	};
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_space.cpp b/src/plugins/litehtml_viewer/litehtml/el_space.cpp
new file mode 100644
index 0000000..7114121
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_space.cpp
@@ -0,0 +1,39 @@
+#include "html.h"
+#include "document.h"
+#include "el_space.h"
+
+litehtml::el_space::el_space(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc) : el_text(text, doc)
+{
+}
+
+litehtml::el_space::~el_space()
+{
+
+}
+
+bool litehtml::el_space::is_white_space() const
+{
+	white_space ws = get_white_space();
+	if(	ws == white_space_normal || 
+		ws == white_space_nowrap ||
+		ws == white_space_pre_line )
+	{
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::el_space::is_break() const
+{
+	white_space ws = get_white_space();
+	if(	ws == white_space_pre ||
+		ws == white_space_pre_line ||
+		ws == white_space_pre_wrap)
+	{
+		if(m_text == _t("\n"))
+		{
+			return true;
+		}
+	}
+	return false;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_space.h b/src/plugins/litehtml_viewer/litehtml/el_space.h
new file mode 100644
index 0000000..7fd9ef1
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_space.h
@@ -0,0 +1,16 @@
+#pragma once
+#include "html_tag.h"
+#include "el_text.h"
+
+namespace litehtml
+{
+	class el_space : public el_text
+	{
+	public:
+		el_space(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_space();
+
+		virtual bool	is_white_space() const override;
+		virtual bool	is_break() const override;
+	};
+}
\ No newline at end of file
diff --git a/src/plugins/litehtml_viewer/litehtml/el_style.cpp b/src/plugins/litehtml_viewer/litehtml/el_style.cpp
new file mode 100644
index 0000000..26a640f
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_style.cpp
@@ -0,0 +1,36 @@
+#include "html.h"
+#include "el_style.h"
+#include "document.h"
+
+
+litehtml::el_style::el_style(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
+{
+
+}
+
+litehtml::el_style::~el_style()
+{
+
+}
+
+void litehtml::el_style::parse_attributes()
+{
+	tstring text;
+
+	for(auto& el : m_children)
+	{
+		el->get_text(text);
+	}
+	get_document()->add_stylesheet( text.c_str(), 0, get_attr(_t("media")) );
+}
+
+bool litehtml::el_style::appendChild(const ptr &el)
+{
+	m_children.push_back(el);
+	return true;
+}
+
+const litehtml::tchar_t* litehtml::el_style::get_tagName() const
+{
+	return _t("style");
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_style.h b/src/plugins/litehtml_viewer/litehtml/el_style.h
new file mode 100644
index 0000000..3f7b41d
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_style.h
@@ -0,0 +1,17 @@
+#pragma once
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_style : public element
+	{
+		elements_vector		m_children;
+	public:
+		el_style(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_style();
+
+		virtual void			parse_attributes() override;
+		virtual bool			appendChild(const ptr &el) override;
+		virtual const tchar_t*	get_tagName() const override;
+	};
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_table.cpp b/src/plugins/litehtml_viewer/litehtml/el_table.cpp
new file mode 100644
index 0000000..4f5ff75
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_table.cpp
@@ -0,0 +1,108 @@
+#include "html.h"
+#include "el_table.h"
+#include "document.h"
+#include "iterators.h"
+#include <algorithm>
+
+
+litehtml::el_table::el_table(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+	m_border_spacing_x	= 0;
+	m_border_spacing_y	= 0;
+	m_border_collapse	= border_collapse_separate;
+}
+
+
+litehtml::el_table::~el_table()
+{
+
+}
+
+bool litehtml::el_table::appendChild(const litehtml::element::ptr& el)
+{
+	if(!el)	return false;
+	if(!t_strcmp(el->get_tagName(), _t("tbody")) || !t_strcmp(el->get_tagName(), _t("thead")) || !t_strcmp(el->get_tagName(), _t("tfoot")))
+	{
+		return html_tag::appendChild(el);
+	}
+	return false;
+}
+
+void litehtml::el_table::parse_styles(bool is_reparse)
+{
+	html_tag::parse_styles(is_reparse);
+
+	m_border_collapse = (border_collapse) value_index(get_style_property(_t("border-collapse"), true, _t("separate")), border_collapse_strings, border_collapse_separate);
+
+	if(m_border_collapse == border_collapse_separate)
+	{
+		m_css_border_spacing_x.fromString(get_style_property(_t("-litehtml-border-spacing-x"), true, _t("0px")));
+		m_css_border_spacing_y.fromString(get_style_property(_t("-litehtml-border-spacing-y"), true, _t("0px")));
+
+		int fntsz = get_font_size();
+		document::ptr doc = get_document();
+		m_border_spacing_x = doc->cvt_units(m_css_border_spacing_x, fntsz);
+		m_border_spacing_y = doc->cvt_units(m_css_border_spacing_y, fntsz);
+	} else
+	{
+		m_border_spacing_x	= 0;
+		m_border_spacing_y	= 0;
+		m_padding.bottom	= 0;
+		m_padding.top		= 0;
+		m_padding.left		= 0;
+		m_padding.right		= 0;
+		m_css_padding.bottom.set_value(0, css_units_px);
+		m_css_padding.top.set_value(0, css_units_px);
+		m_css_padding.left.set_value(0, css_units_px);
+		m_css_padding.right.set_value(0, css_units_px);
+	}
+}
+
+void litehtml::el_table::parse_attributes()
+{
+	const tchar_t* str = get_attr(_t("width"));
+	if(str)
+	{
+		m_style.add_property(_t("width"), str, 0, false);
+	}
+
+	str = get_attr(_t("align"));
+	if(str)
+	{
+		int align = value_index(str, _t("left;center;right"));
+		switch(align)
+		{
+		case 1:
+			m_style.add_property(_t("margin-left"), _t("auto"), 0, false);
+			m_style.add_property(_t("margin-right"), _t("auto"), 0, false);
+			break;
+		case 2:
+			m_style.add_property(_t("margin-left"), _t("auto"), 0, false);
+			m_style.add_property(_t("margin-right"), _t("0"), 0, false);
+			break;
+		}
+	}
+
+	str = get_attr(_t("cellspacing"));
+	if(str)
+	{
+		tstring val = str;
+		val += _t(" ");
+		val += str;
+		m_style.add_property(_t("border-spacing"), val.c_str(), 0, false);
+	}
+	
+	str = get_attr(_t("border"));
+	if(str)
+	{
+		m_style.add_property(_t("border-width"), str, 0, false);
+	}
+
+	str = get_attr(_t("bgcolor"));
+	if (str)
+	{
+		m_style.add_property(_t("background-color"), str, 0, false);
+	}
+
+	html_tag::parse_attributes();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_table.h b/src/plugins/litehtml_viewer/litehtml/el_table.h
new file mode 100644
index 0000000..b298526
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_table.h
@@ -0,0 +1,23 @@
+#pragma once
+#include "html_tag.h"
+
+namespace litehtml
+{
+	struct col_info
+	{
+		int		width;
+		bool	is_auto;
+	};
+
+
+	class el_table : public html_tag
+	{
+	public:
+		el_table(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_table();
+
+		virtual bool	appendChild(const litehtml::element::ptr& el) override;
+		virtual void	parse_styles(bool is_reparse = false) override;
+		virtual void	parse_attributes() override;
+	};
+}
\ No newline at end of file
diff --git a/src/plugins/litehtml_viewer/litehtml/el_td.cpp b/src/plugins/litehtml_viewer/litehtml/el_td.cpp
new file mode 100644
index 0000000..f32cbcd
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_td.cpp
@@ -0,0 +1,49 @@
+#include "html.h"
+#include "el_td.h"
+
+
+litehtml::el_td::el_td(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+
+}
+
+litehtml::el_td::~el_td()
+{
+
+}
+
+void litehtml::el_td::parse_attributes()
+{
+	const tchar_t* str = get_attr(_t("width"));
+	if(str)
+	{
+		m_style.add_property(_t("width"), str, 0, false);
+	}
+	str = get_attr(_t("background"));
+	if(str)
+	{
+		tstring url = _t("url('");
+		url += str;
+		url += _t("')");
+		m_style.add_property(_t("background-image"), url.c_str(), 0, false);
+	}
+	str = get_attr(_t("align"));
+	if(str)
+	{
+		m_style.add_property(_t("text-align"), str, 0, false);
+	}
+
+	str = get_attr(_t("bgcolor"));
+	if (str)
+	{
+		m_style.add_property(_t("background-color"), str, 0, false);
+	}
+
+	str = get_attr(_t("valign"));
+	if(str)
+	{
+		m_style.add_property(_t("vertical-align"), str, 0, false);
+	}
+	html_tag::parse_attributes();
+}
+
diff --git a/src/plugins/litehtml_viewer/litehtml/el_td.h b/src/plugins/litehtml_viewer/litehtml/el_td.h
new file mode 100644
index 0000000..88d8d68
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_td.h
@@ -0,0 +1,14 @@
+#pragma once
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_td : public html_tag
+	{
+	public:
+		el_td(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_td();
+
+		virtual void parse_attributes() override;
+	};
+}
\ No newline at end of file
diff --git a/src/plugins/litehtml_viewer/litehtml/el_text.cpp b/src/plugins/litehtml_viewer/litehtml/el_text.cpp
new file mode 100644
index 0000000..f29e2aa
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_text.cpp
@@ -0,0 +1,188 @@
+#include "html.h"
+#include "el_text.h"
+#include "document.h"
+
+litehtml::el_text::el_text(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc) : element(doc)
+{
+	if(text)
+	{
+		m_text = text;
+	}
+	m_text_transform	= text_transform_none;
+	m_use_transformed	= false;
+	m_draw_spaces		= true;
+}
+
+litehtml::el_text::~el_text()
+{
+
+}
+
+void litehtml::el_text::get_content_size( size& sz, int max_width )
+{
+	sz = m_size;
+}
+
+void litehtml::el_text::get_text( tstring& text )
+{
+	text += m_text;
+}
+
+const litehtml::tchar_t* litehtml::el_text::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ )
+{
+	if(inherited)
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			return el_parent->get_style_property(name, inherited, def);
+		}
+	}
+	return def;
+}
+
+void litehtml::el_text::parse_styles(bool is_reparse)
+{
+	m_text_transform	= (text_transform)	value_index(get_style_property(_t("text-transform"), true,	_t("none")),	text_transform_strings,	text_transform_none);
+	if(m_text_transform != text_transform_none)
+	{
+		m_transformed_text	= m_text;
+		m_use_transformed = true;
+		get_document()->container()->transform_text(m_transformed_text, m_text_transform);
+	}
+
+	if(is_white_space())
+	{
+		m_transformed_text = _t(" ");
+		m_use_transformed = true;
+	} else
+	{
+		if(m_text == _t("\t"))
+		{
+			m_transformed_text = _t("    ");
+			m_use_transformed = true;
+		}
+		if(m_text == _t("\n") || m_text == _t("\r"))
+		{
+			m_transformed_text = _t("");
+			m_use_transformed = true;
+		}
+	}
+
+	font_metrics fm;
+	uint_ptr font = 0;
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		font = el_parent->get_font(&fm);
+	}
+	if(is_break())
+	{
+		m_size.height	= 0;
+		m_size.width	= 0;
+	} else
+	{
+		m_size.height	= fm.height;
+		m_size.width	= get_document()->container()->text_width(m_use_transformed ? m_transformed_text.c_str() : m_text.c_str(), font);
+	}
+	m_draw_spaces = fm.draw_spaces;
+}
+
+int litehtml::el_text::get_base_line()
+{
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		return el_parent->get_base_line();
+	}
+	return 0;
+}
+
+void litehtml::el_text::draw( uint_ptr hdc, int x, int y, const position* clip )
+{
+	if(is_white_space() && !m_draw_spaces)
+	{
+		return;
+	}
+
+	position pos = m_pos;
+	pos.x	+= x;
+	pos.y	+= y;
+
+	if(pos.does_intersect(clip))
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			document::ptr doc = get_document();
+
+			uint_ptr font = el_parent->get_font();
+			litehtml::web_color color = el_parent->get_color(_t("color"), true, doc->get_def_color());
+			doc->container()->draw_text(hdc, m_use_transformed ? m_transformed_text.c_str() : m_text.c_str(), font, color, pos);
+		}
+	}
+}
+
+int litehtml::el_text::line_height() const
+{
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		return el_parent->line_height();
+	}
+	return 0;
+}
+
+litehtml::uint_ptr litehtml::el_text::get_font( font_metrics* fm /*= 0*/ )
+{
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		return el_parent->get_font(fm);
+	}
+	return 0;
+}
+
+litehtml::style_display litehtml::el_text::get_display() const
+{
+	return display_inline_text;
+}
+
+litehtml::white_space litehtml::el_text::get_white_space() const
+{
+	element::ptr el_parent = parent();
+	if (el_parent) return el_parent->get_white_space();
+	return white_space_normal;
+}
+
+litehtml::element_position litehtml::el_text::get_element_position(css_offsets* offsets) const
+{
+	element::ptr p = parent();
+	while(p && p->get_display() == display_inline)
+	{
+		if(p->get_element_position() == element_position_relative)
+		{
+			if(offsets)
+			{
+				*offsets = p->get_css_offsets();
+			}
+			return element_position_relative;
+		}
+		p = p->parent();
+	}
+	return element_position_static;
+}
+
+litehtml::css_offsets litehtml::el_text::get_css_offsets() const
+{
+	element::ptr p = parent();
+	while(p && p->get_display() == display_inline)
+	{
+		if(p->get_element_position() == element_position_relative)
+		{
+			return p->get_css_offsets();
+		}
+		p = p->parent();
+	}
+	return css_offsets();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_text.h b/src/plugins/litehtml_viewer/litehtml/el_text.h
new file mode 100644
index 0000000..82c42bc
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_text.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_text : public element
+	{
+	protected:
+		tstring			m_text;
+		tstring			m_transformed_text;
+		size			m_size;
+		text_transform	m_text_transform;
+		bool			m_use_transformed;
+		bool			m_draw_spaces;
+	public:
+		el_text(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_text();
+
+		virtual void				get_text(tstring& text) override;
+		virtual const tchar_t*		get_style_property(const tchar_t* name, bool inherited, const tchar_t* def = 0) override;
+		virtual void				parse_styles(bool is_reparse) override;
+		virtual int					get_base_line() override;
+		virtual void				draw(uint_ptr hdc, int x, int y, const position* clip) override;
+		virtual int					line_height() const override;
+		virtual uint_ptr			get_font(font_metrics* fm = 0) override;
+		virtual style_display		get_display() const override;
+		virtual white_space			get_white_space() const override;
+		virtual element_position	get_element_position(css_offsets* offsets = 0) const override;
+		virtual css_offsets			get_css_offsets() const override;
+
+	protected:
+		virtual void				get_content_size(size& sz, int max_width) override;
+	};
+}
\ No newline at end of file
diff --git a/src/plugins/litehtml_viewer/litehtml/el_title.cpp b/src/plugins/litehtml_viewer/litehtml/el_title.cpp
new file mode 100644
index 0000000..399421f
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_title.cpp
@@ -0,0 +1,20 @@
+#include "html.h"
+#include "el_title.h"
+#include "document.h"
+
+litehtml::el_title::el_title(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
+{
+
+}
+
+litehtml::el_title::~el_title()
+{
+
+}
+
+void litehtml::el_title::parse_attributes()
+{
+	tstring text;
+	get_text(text);
+	get_document()->container()->set_caption(text.c_str());
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_title.h b/src/plugins/litehtml_viewer/litehtml/el_title.h
new file mode 100644
index 0000000..b1c7139
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_title.h
@@ -0,0 +1,15 @@
+#pragma once
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_title : public html_tag
+	{
+	public:
+		el_title(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_title();
+
+	protected:
+		virtual void	parse_attributes() override;
+	};
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_tr.cpp b/src/plugins/litehtml_viewer/litehtml/el_tr.cpp
new file mode 100644
index 0000000..a80dde4
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_tr.cpp
@@ -0,0 +1,51 @@
+#include "html.h"
+#include "el_tr.h"
+
+
+litehtml::el_tr::el_tr(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+{
+
+}
+
+litehtml::el_tr::~el_tr()
+{
+
+}
+
+void litehtml::el_tr::parse_attributes()
+{
+	const tchar_t* str = get_attr(_t("align"));
+	if(str)
+	{
+		m_style.add_property(_t("text-align"), str, 0, false);
+	}
+	str = get_attr(_t("valign"));
+	if(str)
+	{
+		m_style.add_property(_t("vertical-align"), str, 0, false);
+	}
+	str = get_attr(_t("bgcolor"));
+	if (str)
+	{
+		m_style.add_property(_t("background-color"), str, 0, false);
+	}
+	html_tag::parse_attributes();
+}
+
+void litehtml::el_tr::get_inline_boxes( position::vector& boxes )
+{
+	position pos;
+	for(auto& el : m_children)
+	{
+		if(el->get_display() == display_table_cell)
+		{
+			pos.x		= el->left() + el->margin_left();
+			pos.y		= el->top() - m_padding.top - m_borders.top;
+
+			pos.width	= el->right() - pos.x - el->margin_right() - el->margin_left();
+			pos.height	= el->height() + m_padding.top + m_padding.bottom + m_borders.top + m_borders.bottom;
+
+			boxes.push_back(pos);
+		}
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_tr.h b/src/plugins/litehtml_viewer/litehtml/el_tr.h
new file mode 100644
index 0000000..f4e50aa
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/el_tr.h
@@ -0,0 +1,15 @@
+#pragma once
+#include "html_tag.h"
+
+namespace litehtml
+{
+	class el_tr : public html_tag
+	{
+	public:
+		el_tr(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~el_tr();
+
+		virtual void	parse_attributes() override;
+		virtual void	get_inline_boxes(position::vector& boxes) override;
+	};
+}
\ No newline at end of file
diff --git a/src/plugins/litehtml_viewer/litehtml/element.cpp b/src/plugins/litehtml_viewer/litehtml/element.cpp
new file mode 100644
index 0000000..41a69e7
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/element.cpp
@@ -0,0 +1,409 @@
+#include "html.h"
+#include "element.h"
+#include "document.h"
+
+#define LITEHTML_EMPTY_FUNC			{}
+#define LITEHTML_RETURN_FUNC(ret)	{return ret;}
+
+litehtml::element::element(const std::shared_ptr<litehtml::document>& doc) : m_doc(doc)
+{
+	m_box		= 0;
+	m_skip		= false;
+}
+
+litehtml::element::~element()
+{
+
+}
+
+
+bool litehtml::element::is_point_inside( int x, int y )
+{
+	if(get_display() != display_inline && get_display() != display_table_row)
+	{
+		position pos = m_pos;
+		pos += m_padding;
+		pos += m_borders;
+		if(pos.is_point_inside(x, y))
+		{
+			return true;
+		} else
+		{
+			return false;
+		}
+	} else
+	{
+		position::vector boxes;
+		get_inline_boxes(boxes);
+		for(position::vector::iterator box = boxes.begin(); box != boxes.end(); box++)
+		{
+			if(box->is_point_inside(x, y))
+			{
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+litehtml::web_color litehtml::element::get_color( const tchar_t* prop_name, bool inherited, const litehtml::web_color& def_color )
+{
+	const tchar_t* clrstr = get_style_property(prop_name, inherited, 0);
+	if(!clrstr)
+	{
+		return def_color;
+	}
+	return web_color::from_string(clrstr);
+}
+
+litehtml::position litehtml::element::get_placement() const
+{
+	litehtml::position pos = m_pos;
+	element::ptr cur_el = parent();
+	while(cur_el)
+	{
+		pos.x += cur_el->m_pos.x;
+		pos.y += cur_el->m_pos.y;
+		cur_el = cur_el->parent();
+	}
+	return pos;
+}
+
+bool litehtml::element::is_inline_box() const
+{
+	style_display d = get_display();
+	if(	d == display_inline || 
+		d == display_inline_block || 
+		d == display_inline_text)
+	{
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::element::collapse_top_margin() const
+{
+	if(!m_borders.top && !m_padding.top && in_normal_flow() && get_float() == float_none && m_margins.top >= 0 && have_parent())
+	{
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::element::collapse_bottom_margin() const
+{
+	if(!m_borders.bottom && !m_padding.bottom && in_normal_flow() && get_float() == float_none && m_margins.bottom >= 0 && have_parent())
+	{
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::element::get_predefined_height(int& p_height) const
+{
+	css_length h = get_css_height();
+	if(h.is_predefined())
+	{
+		p_height = m_pos.height;
+		return false;
+	}
+	if(h.units() == css_units_percentage)
+	{
+		element::ptr el_parent = parent();
+		if (!el_parent)
+		{
+			position client_pos;
+			get_document()->container()->get_client_rect(client_pos);
+			p_height = h.calc_percent(client_pos.height);
+			return true;
+		} else
+		{
+			int ph = 0;
+			if (el_parent->get_predefined_height(ph))
+			{
+				p_height = h.calc_percent(ph);
+				if (is_body())
+				{
+					p_height -= content_margins_height();
+				}
+				return true;
+			} else
+			{
+				p_height = m_pos.height;
+				return false;
+			}
+		}
+	}
+	p_height = get_document()->cvt_units(h, get_font_size());
+	return true;
+}
+
+void litehtml::element::calc_document_size( litehtml::size& sz, int x /*= 0*/, int y /*= 0*/ )
+{
+	if(is_visible())
+	{
+		sz.width	= std::max(sz.width,	x + right());
+		sz.height	= std::max(sz.height,	y + bottom());
+	}
+}
+
+void litehtml::element::get_redraw_box(litehtml::position& pos, int x /*= 0*/, int y /*= 0*/)
+{
+	if(is_visible())
+	{
+		int p_left		= std::min(pos.left(),	x + m_pos.left() - m_padding.left - m_borders.left);
+		int p_right		= std::max(pos.right(), x + m_pos.right() + m_padding.left + m_borders.left);
+		int p_top		= std::min(pos.top(), y + m_pos.top() - m_padding.top - m_borders.top);
+		int p_bottom	= std::max(pos.bottom(), y + m_pos.bottom() + m_padding.bottom + m_borders.bottom);
+
+		pos.x = p_left;
+		pos.y = p_top;
+		pos.width	= p_right - p_left;
+		pos.height	= p_bottom - p_top;
+	}
+}
+
+int litehtml::element::calc_width(int defVal) const
+{
+	css_length w = get_css_width();
+	if(w.is_predefined())
+	{
+		return defVal;
+	}
+	if(w.units() == css_units_percentage)
+	{
+		element::ptr el_parent = parent();
+		if (!el_parent)
+		{
+			position client_pos;
+			get_document()->container()->get_client_rect(client_pos);
+			return w.calc_percent(client_pos.width);
+		} else
+		{
+			int pw = el_parent->calc_width(defVal);
+			if (is_body())
+			{
+				pw -= content_margins_width();
+			}
+			return w.calc_percent(pw);
+		}
+	}
+	return 	get_document()->cvt_units(w, get_font_size());
+}
+
+bool litehtml::element::is_ancestor(const ptr &el) const
+{
+	element::ptr el_parent = parent();
+	while(el_parent && el_parent != el)
+	{
+		el_parent = el_parent->parent();
+	}
+	if(el_parent)
+	{
+		return true;
+	}
+	return false;
+}
+
+int litehtml::element::get_inline_shift_left()
+{
+	int ret = 0;
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		if (el_parent->get_display() == display_inline)
+		{
+			style_display disp = get_display();
+
+			if (disp == display_inline_text || disp == display_inline_block)
+			{
+				element::ptr el = shared_from_this();
+				while (el_parent && el_parent->get_display() == display_inline)
+				{
+					if (el_parent->is_first_child_inline(el))
+					{
+						ret += el_parent->padding_left() + el_parent->border_left() + el_parent->margin_left();
+					}
+					el = el_parent;
+					el_parent = el_parent->parent();
+				}
+			}
+		}
+	}
+
+	return ret;
+}
+
+int litehtml::element::get_inline_shift_right()
+{
+	int ret = 0;
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		if (el_parent->get_display() == display_inline)
+		{
+			style_display disp = get_display();
+
+			if (disp == display_inline_text || disp == display_inline_block)
+			{
+				element::ptr el = shared_from_this();
+				while (el_parent && el_parent->get_display() == display_inline)
+				{
+					if (el_parent->is_last_child_inline(el))
+					{
+						ret += el_parent->padding_right() + el_parent->border_right() + el_parent->margin_right();
+					}
+					el = el_parent;
+					el_parent = el_parent->parent();
+				}
+			}
+		}
+	}
+
+	return ret;
+}
+
+void litehtml::element::apply_relative_shift(int parent_width)
+{
+	css_offsets offsets;
+	if (get_element_position(&offsets) == element_position_relative)
+	{
+		element::ptr parent_ptr = parent();
+		if (!offsets.left.is_predefined())
+		{
+			m_pos.x += offsets.left.calc_percent(parent_width);
+		}
+		else if (!offsets.right.is_predefined())
+		{
+			m_pos.x -= offsets.right.calc_percent(parent_width);
+		}
+		if (!offsets.top.is_predefined())
+		{
+			int h = 0;
+
+			if (offsets.top.units() == css_units_percentage)
+			{
+				element::ptr el_parent = parent();
+				if (el_parent)
+				{
+					el_parent->get_predefined_height(h);
+				}
+			}
+
+			m_pos.y += offsets.top.calc_percent(h);
+		}
+		else if (!offsets.bottom.is_predefined())
+		{
+			int h = 0;
+
+			if (offsets.top.units() == css_units_percentage)
+			{
+				element::ptr el_parent = parent();
+				if (el_parent)
+				{
+					el_parent->get_predefined_height(h);
+				}
+			}
+
+			m_pos.y -= offsets.bottom.calc_percent(h);
+		}
+	}
+}
+
+void litehtml::element::calc_auto_margins(int parent_width)							LITEHTML_EMPTY_FUNC
+const litehtml::background* litehtml::element::get_background(bool own_only)		LITEHTML_RETURN_FUNC(0)
+litehtml::element::ptr litehtml::element::get_element_by_point(int x, int y, int client_x, int client_y)	LITEHTML_RETURN_FUNC(0)
+litehtml::element::ptr litehtml::element::get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex) LITEHTML_RETURN_FUNC(0)
+void litehtml::element::get_line_left_right( int y, int def_right, int& ln_left, int& ln_right ) LITEHTML_EMPTY_FUNC
+void litehtml::element::add_style( const litehtml::style& st )						LITEHTML_EMPTY_FUNC
+void litehtml::element::select_all(const css_selector& selector, litehtml::elements_vector& res)	LITEHTML_EMPTY_FUNC
+litehtml::elements_vector litehtml::element::select_all(const litehtml::css_selector& selector)	 LITEHTML_RETURN_FUNC(litehtml::elements_vector())
+litehtml::elements_vector litehtml::element::select_all(const litehtml::tstring& selector)			 LITEHTML_RETURN_FUNC(litehtml::elements_vector())
+litehtml::element::ptr litehtml::element::select_one( const css_selector& selector ) LITEHTML_RETURN_FUNC(0)
+litehtml::element::ptr litehtml::element::select_one( const tstring& selector )		LITEHTML_RETURN_FUNC(0)
+litehtml::element::ptr litehtml::element::find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/) LITEHTML_RETURN_FUNC(0)
+litehtml::element::ptr litehtml::element::find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/) LITEHTML_RETURN_FUNC(0)
+bool litehtml::element::is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const		LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::is_nth_child(const element::ptr&, int num, int off, bool of_type) const		LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::is_only_child(const element::ptr& el, bool of_type)	 const	LITEHTML_RETURN_FUNC(false)
+litehtml::overflow litehtml::element::get_overflow() const							LITEHTML_RETURN_FUNC(overflow_visible)
+void litehtml::element::draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex ) LITEHTML_EMPTY_FUNC
+void litehtml::element::draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned ) LITEHTML_EMPTY_FUNC
+void litehtml::element::render_positioned(render_type rt)							LITEHTML_EMPTY_FUNC
+int litehtml::element::get_zindex() const											LITEHTML_RETURN_FUNC(0)
+bool litehtml::element::fetch_positioned()											LITEHTML_RETURN_FUNC(false)
+litehtml::visibility litehtml::element::get_visibility() const						LITEHTML_RETURN_FUNC(visibility_visible)
+void litehtml::element::apply_vertical_align()										LITEHTML_EMPTY_FUNC
+void litehtml::element::set_css_width( css_length& w )								LITEHTML_EMPTY_FUNC
+litehtml::element::ptr litehtml::element::get_child( int idx ) const				LITEHTML_RETURN_FUNC(0)
+size_t litehtml::element::get_children_count() const								LITEHTML_RETURN_FUNC(0)
+void litehtml::element::calc_outlines( int parent_width )							LITEHTML_EMPTY_FUNC
+litehtml::css_length litehtml::element::get_css_width() const						LITEHTML_RETURN_FUNC(css_length())
+litehtml::css_length litehtml::element::get_css_height() const						LITEHTML_RETURN_FUNC(css_length())
+litehtml::element_clear litehtml::element::get_clear() const						LITEHTML_RETURN_FUNC(clear_none)
+litehtml::css_length litehtml::element::get_css_left() const						LITEHTML_RETURN_FUNC(css_length())
+litehtml::css_length litehtml::element::get_css_right() const						LITEHTML_RETURN_FUNC(css_length())
+litehtml::css_length litehtml::element::get_css_top() const							LITEHTML_RETURN_FUNC(css_length())
+litehtml::css_length litehtml::element::get_css_bottom() const						LITEHTML_RETURN_FUNC(css_length())
+litehtml::css_offsets litehtml::element::get_css_offsets() const					LITEHTML_RETURN_FUNC(css_offsets())
+litehtml::vertical_align litehtml::element::get_vertical_align() const				LITEHTML_RETURN_FUNC(va_baseline)
+int litehtml::element::place_element(const ptr &el, int max_width)					LITEHTML_RETURN_FUNC(0)
+int litehtml::element::render_inline(const ptr &container, int max_width)			LITEHTML_RETURN_FUNC(0)
+void litehtml::element::add_positioned(const ptr &el)							LITEHTML_EMPTY_FUNC
+int litehtml::element::find_next_line_top( int top, int width, int def_right )		LITEHTML_RETURN_FUNC(0)
+litehtml::element_float litehtml::element::get_float() const						LITEHTML_RETURN_FUNC(float_none)
+void litehtml::element::add_float(const ptr &el, int x, int y)					LITEHTML_EMPTY_FUNC
+void litehtml::element::update_floats(int dy, const ptr &parent)					LITEHTML_EMPTY_FUNC
+int litehtml::element::get_line_left( int y )										LITEHTML_RETURN_FUNC(0)
+int litehtml::element::get_line_right( int y, int def_right )						LITEHTML_RETURN_FUNC(def_right)
+int litehtml::element::get_left_floats_height() const								LITEHTML_RETURN_FUNC(0)
+int litehtml::element::get_right_floats_height() const								LITEHTML_RETURN_FUNC(0)
+int litehtml::element::get_floats_height(element_float el_float) const				LITEHTML_RETURN_FUNC(0)
+bool litehtml::element::is_floats_holder() const									LITEHTML_RETURN_FUNC(false)
+void litehtml::element::get_content_size( size& sz, int max_width )					LITEHTML_EMPTY_FUNC
+void litehtml::element::init()														LITEHTML_EMPTY_FUNC
+int litehtml::element::render( int x, int y, int max_width, bool second_pass )		LITEHTML_RETURN_FUNC(0)
+bool litehtml::element::appendChild(const ptr &el)						LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::removeChild(const ptr &el)						LITEHTML_RETURN_FUNC(false)
+void litehtml::element::clearRecursive()											LITEHTML_EMPTY_FUNC
+const litehtml::tchar_t* litehtml::element::get_tagName() const						LITEHTML_RETURN_FUNC(_t(""))
+void litehtml::element::set_tagName( const tchar_t* tag )							LITEHTML_EMPTY_FUNC
+void litehtml::element::set_data( const tchar_t* data )								LITEHTML_EMPTY_FUNC
+void litehtml::element::set_attr( const tchar_t* name, const tchar_t* val )			LITEHTML_EMPTY_FUNC
+void litehtml::element::apply_stylesheet( const litehtml::css& stylesheet )			LITEHTML_EMPTY_FUNC
+void litehtml::element::refresh_styles()											LITEHTML_EMPTY_FUNC
+void litehtml::element::on_click()													LITEHTML_EMPTY_FUNC
+void litehtml::element::init_font()													LITEHTML_EMPTY_FUNC
+void litehtml::element::get_inline_boxes( position::vector& boxes )					LITEHTML_EMPTY_FUNC
+void litehtml::element::parse_styles( bool is_reparse /*= false*/ )					LITEHTML_EMPTY_FUNC
+const litehtml::tchar_t* litehtml::element::get_attr( const tchar_t* name, const tchar_t* def /*= 0*/ )	LITEHTML_RETURN_FUNC(def)
+bool litehtml::element::is_white_space() const										LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::is_body() const												LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::is_break() const											LITEHTML_RETURN_FUNC(false)
+int litehtml::element::get_base_line()												LITEHTML_RETURN_FUNC(0)
+bool litehtml::element::on_mouse_over()												LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::on_mouse_leave()											LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::on_lbutton_down()											LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::on_lbutton_up()												LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::find_styles_changes( position::vector& redraw_boxes, int x, int y )	LITEHTML_RETURN_FUNC(false)
+const litehtml::tchar_t* litehtml::element::get_cursor()							LITEHTML_RETURN_FUNC(0)
+litehtml::white_space litehtml::element::get_white_space() const					LITEHTML_RETURN_FUNC(white_space_normal)
+litehtml::style_display litehtml::element::get_display() const						LITEHTML_RETURN_FUNC(display_none)
+bool litehtml::element::set_pseudo_class( const tchar_t* pclass, bool add )			LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::set_class( const tchar_t* pclass, bool add )				LITEHTML_RETURN_FUNC(false)
+litehtml::element_position litehtml::element::get_element_position(css_offsets* offsets) const			LITEHTML_RETURN_FUNC(element_position_static)
+bool litehtml::element::is_replaced() const											LITEHTML_RETURN_FUNC(false)
+int litehtml::element::line_height() const											LITEHTML_RETURN_FUNC(0)
+void litehtml::element::draw( uint_ptr hdc, int x, int y, const position* clip )	LITEHTML_EMPTY_FUNC
+void litehtml::element::draw_background( uint_ptr hdc, int x, int y, const position* clip )	LITEHTML_EMPTY_FUNC
+const litehtml::tchar_t* litehtml::element::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ )	LITEHTML_RETURN_FUNC(0)
+litehtml::uint_ptr litehtml::element::get_font( font_metrics* fm /*= 0*/ )			LITEHTML_RETURN_FUNC(0)
+int litehtml::element::get_font_size()	const										LITEHTML_RETURN_FUNC(0)
+void litehtml::element::get_text( tstring& text )									LITEHTML_EMPTY_FUNC
+void litehtml::element::parse_attributes()											LITEHTML_EMPTY_FUNC
+int litehtml::element::select( const css_selector& selector, bool apply_pseudo)		LITEHTML_RETURN_FUNC(select_no_match)
+int litehtml::element::select( const css_element_selector& selector, bool apply_pseudo /*= true*/ )	LITEHTML_RETURN_FUNC(select_no_match)
+litehtml::element::ptr litehtml::element::find_ancestor(const css_selector& selector, bool apply_pseudo, bool* is_pseudo)	LITEHTML_RETURN_FUNC(0)
+bool litehtml::element::is_first_child_inline(const element::ptr& el) const			LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::is_last_child_inline(const element::ptr& el)				LITEHTML_RETURN_FUNC(false)
+bool litehtml::element::have_inline_child() const									LITEHTML_RETURN_FUNC(false)
diff --git a/src/plugins/litehtml_viewer/litehtml/element.h b/src/plugins/litehtml_viewer/litehtml/element.h
new file mode 100644
index 0000000..f1af05b
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/element.h
@@ -0,0 +1,399 @@
+#pragma once
+#include <memory>
+#include "stylesheet.h"
+#include "css_offsets.h"
+
+namespace litehtml
+{
+	class box;
+
+	class element : public std::enable_shared_from_this<element>
+	{
+		friend class block_box;
+		friend class line_box;
+		friend class html_tag;
+		friend class el_table;
+		friend class document;
+	public:
+		typedef std::shared_ptr<litehtml::element>		ptr;
+		typedef std::weak_ptr<litehtml::element>		weak_ptr;
+	protected:
+		std::weak_ptr<element>		m_parent;
+		std::weak_ptr<litehtml::document>	m_doc;
+		litehtml::box*				m_box;
+		elements_vector				m_children;
+		position					m_pos;
+		margins						m_margins;
+		margins						m_padding;
+		margins						m_borders;
+		bool						m_skip;
+		
+		virtual void select_all(const css_selector& selector, elements_vector& res);
+	public:
+		element(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~element();
+
+		// returns refer to m_pos member;
+		position&					get_position();
+
+		int							left()						const;
+		int							right()						const;
+		int							top()						const;
+		int							bottom()					const;
+		int							height()					const;
+		int							width()						const;
+
+		int							content_margins_top()		const;
+		int							content_margins_bottom()	const;
+		int							content_margins_left()		const;
+		int							content_margins_right()		const;
+		int							content_margins_width()		const;
+		int							content_margins_height()	const;
+
+		int							margin_top()				const;
+		int							margin_bottom()				const;
+		int							margin_left()				const;
+		int							margin_right()				const;
+		margins						get_margins()				const;
+
+		int							padding_top()				const;
+		int							padding_bottom()			const;
+		int							padding_left()				const;
+		int							padding_right()				const;
+		margins						get_paddings()				const;
+
+		int							border_top()				const;
+		int							border_bottom()				const;
+		int							border_left()				const;
+		int							border_right()				const;
+		margins						get_borders()				const;
+
+		bool						in_normal_flow()			const;
+		litehtml::web_color			get_color(const tchar_t* prop_name, bool inherited, const litehtml::web_color& def_color = litehtml::web_color());
+		bool						is_inline_box()				const;
+		position					get_placement()				const;
+		bool						collapse_top_margin()		const;
+		bool						collapse_bottom_margin()	const;
+		bool						is_positioned()				const;
+
+		bool						skip();
+		void						skip(bool val);
+		bool						have_parent() const;
+		element::ptr				parent() const;
+		void						parent(element::ptr par);
+		bool						is_visible() const;
+		int							calc_width(int defVal) const;
+		int							get_inline_shift_left();
+		int							get_inline_shift_right();
+		void						apply_relative_shift(int parent_width);
+
+		std::shared_ptr<document>	get_document() const;
+
+		virtual elements_vector		select_all(const tstring& selector);
+		virtual elements_vector		select_all(const css_selector& selector);
+
+		virtual element::ptr		select_one(const tstring& selector);
+		virtual element::ptr		select_one(const css_selector& selector);
+
+		virtual int					render(int x, int y, int max_width, bool second_pass = false);
+		virtual int					render_inline(const ptr &container, int max_width);
+		virtual int					place_element(const ptr &el, int max_width);
+		virtual void				calc_outlines( int parent_width );
+		virtual void				calc_auto_margins(int parent_width);
+		virtual void				apply_vertical_align();
+		virtual bool				fetch_positioned();
+		virtual void				render_positioned(render_type rt = render_all);
+
+		virtual bool				appendChild(const ptr &el);
+		virtual bool				removeChild(const ptr &el);
+		virtual void				clearRecursive();
+
+		virtual const tchar_t*		get_tagName() const;
+		virtual void				set_tagName(const tchar_t* tag);
+		virtual void				set_data(const tchar_t* data);
+		virtual element_float		get_float() const;
+		virtual vertical_align		get_vertical_align() const;
+		virtual element_clear		get_clear() const;
+		virtual size_t				get_children_count() const;
+		virtual element::ptr		get_child(int idx) const;
+		virtual overflow			get_overflow() const;
+
+		virtual css_length			get_css_left() const;
+		virtual css_length			get_css_right() const;
+		virtual css_length			get_css_top() const;
+		virtual css_length			get_css_bottom() const;
+		virtual css_offsets			get_css_offsets() const;
+		virtual css_length			get_css_width() const;
+		virtual void				set_css_width(css_length& w);
+		virtual css_length			get_css_height() const;
+
+		virtual void				set_attr(const tchar_t* name, const tchar_t* val);
+		virtual const tchar_t*		get_attr(const tchar_t* name, const tchar_t* def = 0);
+		virtual void				apply_stylesheet(const litehtml::css& stylesheet);
+		virtual void				refresh_styles();
+		virtual bool				is_white_space() const;
+		virtual bool				is_body() const;
+		virtual bool				is_break() const;
+		virtual int					get_base_line();
+		virtual bool				on_mouse_over();
+		virtual bool				on_mouse_leave();
+		virtual bool				on_lbutton_down();
+		virtual bool				on_lbutton_up();
+		virtual void				on_click();
+		virtual bool				find_styles_changes(position::vector& redraw_boxes, int x, int y);
+		virtual const tchar_t*		get_cursor();
+		virtual void				init_font();
+		virtual bool				is_point_inside(int x, int y);
+		virtual bool				set_pseudo_class(const tchar_t* pclass, bool add);
+		virtual bool				set_class(const tchar_t* pclass, bool add);
+		virtual bool				is_replaced() const;
+		virtual int					line_height() const;
+		virtual white_space			get_white_space() const;
+		virtual style_display		get_display() const;
+		virtual visibility			get_visibility() const;
+		virtual element_position	get_element_position(css_offsets* offsets = 0) const;
+		virtual void				get_inline_boxes(position::vector& boxes);
+		virtual void				parse_styles(bool is_reparse = false);
+		virtual void				draw(uint_ptr hdc, int x, int y, const position* clip);
+		virtual void				draw_background( uint_ptr hdc, int x, int y, const position* clip );
+		virtual const tchar_t*		get_style_property(const tchar_t* name, bool inherited, const tchar_t* def = 0);
+		virtual uint_ptr			get_font(font_metrics* fm = 0);
+		virtual int					get_font_size() const;
+		virtual void				get_text(tstring& text);
+		virtual void				parse_attributes();
+		virtual int					select(const css_selector& selector, bool apply_pseudo = true);
+		virtual int					select(const css_element_selector& selector, bool apply_pseudo = true);
+		virtual element::ptr		find_ancestor(const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0);
+		virtual bool				is_ancestor(const ptr &el) const;
+		virtual element::ptr		find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0);
+		virtual element::ptr		find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0);
+		virtual bool				is_first_child_inline(const element::ptr& el) const;
+		virtual bool				is_last_child_inline(const element::ptr& el);
+		virtual bool				have_inline_child() const;
+		virtual void				get_content_size(size& sz, int max_width);
+		virtual void				init();
+		virtual bool				is_floats_holder() const;
+		virtual int					get_floats_height(element_float el_float = float_none) const;
+		virtual int					get_left_floats_height() const;
+		virtual int					get_right_floats_height() const;
+		virtual int					get_line_left(int y);
+		virtual int					get_line_right(int y, int def_right);
+		virtual void				get_line_left_right(int y, int def_right, int& ln_left, int& ln_right);
+		virtual void				add_float(const ptr &el, int x, int y);
+		virtual void				update_floats(int dy, const ptr &parent);
+		virtual void				add_positioned(const ptr &el);
+		virtual int					find_next_line_top(int top, int width, int def_right);
+		virtual int					get_zindex() const;
+		virtual void				draw_stacking_context(uint_ptr hdc, int x, int y, const position* clip, bool with_positioned);
+		virtual void				draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex );
+		virtual bool				is_nth_child(const element::ptr& el, int num, int off, bool of_type) const;
+		virtual bool				is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const;
+		virtual bool				is_only_child(const element::ptr& el, bool of_type) const;
+		virtual bool				get_predefined_height(int& p_height) const;
+		virtual void				calc_document_size(litehtml::size& sz, int x = 0, int y = 0);
+		virtual void				get_redraw_box(litehtml::position& pos, int x = 0, int y = 0);
+		virtual void				add_style(const litehtml::style& st);
+		virtual element::ptr		get_element_by_point(int x, int y, int client_x, int client_y);
+		virtual element::ptr		get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex);
+		virtual const background*	get_background(bool own_only = false);
+	};
+
+	//////////////////////////////////////////////////////////////////////////
+	//							INLINE FUNCTIONS							//
+	//////////////////////////////////////////////////////////////////////////
+
+	inline int litehtml::element::right() const
+	{
+		return left() + width();
+	}
+
+	inline int litehtml::element::left() const
+	{
+		return m_pos.left() - margin_left() - m_padding.left - m_borders.left;
+	}
+
+	inline int litehtml::element::top() const
+	{
+		return m_pos.top() - margin_top() - m_padding.top - m_borders.top;
+	}
+
+	inline int litehtml::element::bottom() const
+	{
+		return top() + height();
+	}
+
+	inline int litehtml::element::height() const
+	{
+		return m_pos.height + margin_top() + margin_bottom() + m_padding.height() + m_borders.height();
+	}
+
+	inline int litehtml::element::width() const
+	{
+		return m_pos.width + margin_left() + margin_right() + m_padding.width() + m_borders.width();
+	}
+
+	inline int litehtml::element::content_margins_top() const
+	{
+		return margin_top() + m_padding.top + m_borders.top;
+	}
+
+	inline int litehtml::element::content_margins_bottom() const
+	{
+		return margin_bottom() + m_padding.bottom + m_borders.bottom;
+	}
+
+	inline int litehtml::element::content_margins_left() const
+	{
+		return margin_left() + m_padding.left + m_borders.left;
+	}
+
+	inline int litehtml::element::content_margins_right() const
+	{
+		return margin_right() + m_padding.right + m_borders.right;
+	}
+
+	inline int litehtml::element::content_margins_width() const
+	{
+		return content_margins_left() + content_margins_right();
+	}
+
+	inline int litehtml::element::content_margins_height() const
+	{
+		return content_margins_top() + content_margins_bottom();
+	}
+
+	inline litehtml::margins litehtml::element::get_paddings()	const
+	{
+		return m_padding;
+	}
+
+	inline litehtml::margins litehtml::element::get_borders()	const
+	{
+		return m_borders;
+	}
+
+	inline int litehtml::element::padding_top() const
+	{
+		return m_padding.top;
+	}
+
+	inline int litehtml::element::padding_bottom() const
+	{
+		return m_padding.bottom;
+	}
+
+	inline int litehtml::element::padding_left() const
+	{
+		return m_padding.left;
+	}
+
+	inline int litehtml::element::padding_right() const
+	{
+		return m_padding.right;
+	}
+
+	inline bool litehtml::element::in_normal_flow() const
+	{
+		if(get_element_position() != element_position_absolute && get_display() != display_none)
+		{
+			return true;
+		}
+		return false;
+	}
+
+	inline int litehtml::element::border_top() const
+	{
+		return m_borders.top;
+	}
+
+	inline int litehtml::element::border_bottom() const
+	{
+		return m_borders.bottom;
+	}
+
+	inline int litehtml::element::border_left() const
+	{
+		return m_borders.left;
+	}
+
+	inline int litehtml::element::border_right() const
+	{
+		return m_borders.right;
+	}
+
+	inline bool litehtml::element::skip()
+	{
+		return m_skip;
+	}
+
+	inline void litehtml::element::skip(bool val)
+	{
+		m_skip = val;
+	}
+
+	inline bool litehtml::element::have_parent() const
+	{
+		return !m_parent.expired();
+	}
+
+	inline element::ptr litehtml::element::parent() const
+	{
+		return m_parent.lock();
+	}
+
+	inline void litehtml::element::parent(element::ptr par)
+	{
+		m_parent = par;
+	}
+
+	inline int litehtml::element::margin_top() const
+	{
+		return m_margins.top;
+	}
+
+	inline int litehtml::element::margin_bottom() const
+	{
+		return m_margins.bottom;
+	}
+
+	inline int litehtml::element::margin_left() const
+	{
+		return m_margins.left;
+	}
+
+	inline int litehtml::element::margin_right() const
+	{
+		return m_margins.right;
+	}
+
+	inline litehtml::margins litehtml::element::get_margins() const
+	{
+		margins ret;
+		ret.left	= margin_left();
+		ret.right	= margin_right();
+		ret.top		= margin_top();
+		ret.bottom	= margin_bottom();
+
+		return ret;
+	}
+
+	inline bool litehtml::element::is_positioned()	const
+	{
+		return (get_element_position() > element_position_static);
+	}
+
+	inline bool litehtml::element::is_visible() const
+	{
+		return !(m_skip || get_display() == display_none || get_visibility() != visibility_visible);
+	}
+
+	inline position& litehtml::element::get_position()
+	{
+		return m_pos;
+	}
+
+	inline std::shared_ptr<document> element::get_document() const
+	{
+		return m_doc.lock();
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/html.cpp b/src/plugins/litehtml_viewer/litehtml/html.cpp
new file mode 100644
index 0000000..a11e2e4
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/html.cpp
@@ -0,0 +1,169 @@
+#include "html.h"
+#include "types.h"
+#include "html_tag.h"
+
+void litehtml::trim(tstring &s) 
+{
+	tstring::size_type pos = s.find_first_not_of(_t(" \n\r\t"));
+	if(pos != tstring::npos)
+	{
+		s.erase(s.begin(), s.begin() + pos);
+	}
+	pos = s.find_last_not_of(_t(" \n\r\t"));
+	if(pos != tstring::npos)
+	{
+		s.erase(s.begin() + pos + 1, s.end());
+	}
+}
+
+void litehtml::lcase(tstring &s) 
+{
+	for(tstring::iterator i = s.begin(); i != s.end(); i++)
+	{
+		(*i) = t_tolower(*i);
+	}
+}
+
+litehtml::tstring::size_type litehtml::find_close_bracket(const tstring &s, tstring::size_type off, tchar_t open_b, tchar_t close_b)
+{
+	int cnt = 0;
+	for(tstring::size_type i = off; i < s.length(); i++)
+	{
+		if(s[i] == open_b)
+		{
+			cnt++;
+		} else if(s[i] == close_b)
+		{
+			cnt--;
+			if(!cnt)
+			{
+				return i;
+			}
+		}
+	}
+	return tstring::npos;
+}
+
+int litehtml::value_index( const tstring& val, const tstring& strings, int defValue, tchar_t delim )
+{
+	if(val.empty() || strings.empty() || !delim)
+	{
+		return defValue;
+	}
+
+	int idx = 0;
+	tstring::size_type delim_start	= 0;
+	tstring::size_type delim_end	= strings.find(delim, delim_start);
+	tstring::size_type item_len		= 0;
+	while(true)
+	{
+		if(delim_end == tstring::npos)
+		{
+			item_len = strings.length() - delim_start;
+		} else
+		{
+			item_len = delim_end - delim_start;
+		}
+		if(item_len == val.length())
+		{
+			if(val == strings.substr(delim_start, item_len))
+			{
+				return idx;
+			}
+		}
+		idx++;
+		delim_start = delim_end;
+		if(delim_start == tstring::npos) break;
+		delim_start++;
+		if(delim_start == strings.length()) break;
+		delim_end = strings.find(delim, delim_start);
+	}
+	return defValue;
+}
+
+bool litehtml::value_in_list( const tstring& val, const tstring& strings, tchar_t delim )
+{
+	int idx = value_index(val, strings, -1, delim);
+	if(idx >= 0)
+	{
+		return true;
+	}
+	return false;
+}
+
+void litehtml::split_string(const tstring& str, string_vector& tokens, const tstring& delims, const tstring& delims_preserve, const tstring& quote)
+{
+	if(str.empty() || (delims.empty() && delims_preserve.empty()))
+	{
+		return;
+	}
+
+	tstring all_delims = delims + delims_preserve + quote;
+
+	tstring::size_type token_start	= 0;
+	tstring::size_type token_end	= str.find_first_of(all_delims, token_start);
+	tstring::size_type token_len	= 0;
+	tstring token;
+	while(true)
+	{
+		while( token_end != tstring::npos && quote.find_first_of(str[token_end]) != tstring::npos )
+		{
+			if(str[token_end] == _t('('))
+			{
+				token_end = find_close_bracket(str, token_end, _t('('), _t(')'));
+			} else if(str[token_end] == _t('['))
+			{
+				token_end = find_close_bracket(str, token_end, _t('['), _t(']'));
+			} else if(str[token_end] == _t('{'))
+			{
+				token_end = find_close_bracket(str, token_end, _t('{'), _t('}'));
+			} else
+			{
+				token_end = str.find_first_of(str[token_end], token_end + 1);
+			}
+			if(token_end != tstring::npos)
+			{
+				token_end = str.find_first_of(all_delims, token_end + 1);
+			}
+		}
+
+		if(token_end == tstring::npos)
+		{
+			token_len = tstring::npos;
+		} else
+		{
+			token_len = token_end - token_start;
+		}
+
+		token = str.substr(token_start, token_len);
+		if(!token.empty())
+		{
+			tokens.push_back( token );
+		}
+		if(token_end != tstring::npos && !delims_preserve.empty() && delims_preserve.find_first_of(str[token_end]) != tstring::npos)
+		{
+			tokens.push_back( str.substr(token_end, 1) );
+		}
+
+		token_start = token_end;
+		if(token_start == tstring::npos) break;
+		token_start++;
+		if(token_start == str.length()) break;
+		token_end = str.find_first_of(all_delims, token_start);
+	}
+}
+
+void litehtml::join_string(tstring& str, const string_vector& tokens, const tstring& delims)
+{
+	tstringstream ss;
+	for(size_t i=0; i<tokens.size(); ++i)
+	{
+		if(i != 0)
+		{
+			ss << delims;
+		}
+		ss << tokens[i];
+	}
+
+	str = ss.str();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/html.h b/src/plugins/litehtml_viewer/litehtml/html.h
new file mode 100644
index 0000000..31852c3
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/html.h
@@ -0,0 +1,92 @@
+#pragma once
+
+#include <stdlib.h>
+#include <string>
+#include <ctype.h>
+#include <vector>
+#include <map>
+#include <cstring>
+#include <algorithm>
+#include <sstream>
+#include "os_types.h"
+#include "types.h"
+#include "background.h"
+#include "borders.h"
+#include "html_tag.h"
+#include "web_color.h"
+#include "media_query.h"
+
+namespace litehtml
+{
+	struct list_marker
+	{
+		tstring			image;
+		const tchar_t*	baseurl;
+		list_style_type	marker_type;
+		web_color		color;
+		position		pos;
+	};
+
+	// call back interface to draw text, images and other elements
+	class document_container
+	{
+	public:
+		virtual litehtml::uint_ptr	create_font(const litehtml::tchar_t* faceName, int size, int weight, litehtml::font_style italic, unsigned int decoration, litehtml::font_metrics* fm) = 0;
+		virtual void				delete_font(litehtml::uint_ptr hFont) = 0;
+		virtual int					text_width(const litehtml::tchar_t* text, litehtml::uint_ptr hFont) = 0;
+		virtual void				draw_text(litehtml::uint_ptr hdc, const litehtml::tchar_t* text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos) = 0;
+		virtual int					pt_to_px(int pt) = 0;
+		virtual int					get_default_font_size() const = 0;
+		virtual const litehtml::tchar_t*	get_default_font_name() const = 0;
+		virtual void				draw_list_marker(litehtml::uint_ptr hdc, const litehtml::list_marker& marker) = 0;
+		virtual void				load_image(const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, bool redraw_on_ready) = 0;
+		virtual void				get_image_size(const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, litehtml::size& sz) = 0;
+		virtual void				draw_background(litehtml::uint_ptr hdc, const litehtml::background_paint& bg) = 0;
+		virtual void				draw_borders(litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root) = 0;
+
+		virtual	void				set_caption(const litehtml::tchar_t* caption) = 0;
+		virtual	void				set_base_url(const litehtml::tchar_t* base_url) = 0;
+		virtual void				link(const std::shared_ptr<litehtml::document>& doc, const litehtml::element::ptr& el) = 0;
+		virtual void				on_anchor_click(const litehtml::tchar_t* url, const litehtml::element::ptr& el) = 0;
+		virtual	void				set_cursor(const litehtml::tchar_t* cursor) = 0;
+		virtual	void				transform_text(litehtml::tstring& text, litehtml::text_transform tt) = 0;
+		virtual void				import_css(litehtml::tstring& text, const litehtml::tstring& url, litehtml::tstring& baseurl) = 0;
+		virtual void				set_clip(const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius, bool valid_x, bool valid_y) = 0;
+		virtual void				del_clip() = 0;
+		virtual void				get_client_rect(litehtml::position& client) const = 0;
+		virtual std::shared_ptr<litehtml::element>	create_element(const litehtml::tchar_t *tag_name,
+																	 const litehtml::string_map &attributes,
+																	 const std::shared_ptr<litehtml::document> &doc) = 0;
+
+		virtual void				get_media_features(litehtml::media_features& media) const = 0;
+		virtual void				get_language(litehtml::tstring& language, litehtml::tstring & culture) const = 0;
+	};
+
+	void trim(tstring &s);
+	void lcase(tstring &s);
+	int	 value_index(const tstring& val, const tstring& strings, int defValue = -1, tchar_t delim = _t(';'));
+	bool value_in_list(const tstring& val, const tstring& strings, tchar_t delim = _t(';'));
+	tstring::size_type find_close_bracket(const tstring &s, tstring::size_type off, tchar_t open_b = _t('('), tchar_t close_b = _t(')'));
+	void split_string(const tstring& str, string_vector& tokens, const tstring& delims, const tstring& delims_preserve = _t(""), const tstring& quote = _t("\""));
+	void join_string(tstring& str, const string_vector& tokens, const tstring& delims);
+
+	inline int round_f(float val)
+	{
+		int int_val = (int) val;
+		if(val - int_val >= 0.5)
+		{
+			int_val++;
+		}
+		return int_val;
+	}
+
+	inline int round_d(double val)
+	{
+		int int_val = (int) val;
+		if(val - int_val >= 0.5)
+		{
+			int_val++;
+		}
+		return int_val;
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/html_tag.cpp b/src/plugins/litehtml_viewer/litehtml/html_tag.cpp
new file mode 100644
index 0000000..40a76de
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/html_tag.cpp
@@ -0,0 +1,4663 @@
+#include "html.h"
+#include "html_tag.h"
+#include "document.h"
+#include "iterators.h"
+#include "stylesheet.h"
+#include "table.h"
+#include <algorithm>
+#include <locale>
+#include "el_before_after.h"
+
+litehtml::html_tag::html_tag(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
+{
+	m_box_sizing			= box_sizing_content_box;
+	m_z_index				= 0;
+	m_overflow				= overflow_visible;
+	m_box					= 0;
+	m_text_align			= text_align_left;
+	m_el_position			= element_position_static;
+	m_display				= display_inline;
+	m_vertical_align		= va_baseline;
+	m_list_style_type		= list_style_type_none;
+	m_list_style_position	= list_style_position_outside;
+	m_float					= float_none;
+	m_clear					= clear_none;
+	m_font					= 0;
+	m_font_size				= 0;
+	m_white_space			= white_space_normal;
+	m_lh_predefined			= false;
+	m_line_height			= 0;
+	m_visibility			= visibility_visible;
+	m_border_spacing_x		= 0;
+	m_border_spacing_y		= 0;
+	m_border_collapse		= border_collapse_separate;
+}
+
+litehtml::html_tag::~html_tag()
+{
+
+}
+
+bool litehtml::html_tag::appendChild(const element::ptr &el)
+{
+	if(el)
+	{
+		el->parent(shared_from_this());
+		m_children.push_back(el);
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::html_tag::removeChild(const element::ptr &el)
+{
+	if(el && el->parent() == shared_from_this())
+	{
+		el->parent(nullptr);
+		m_children.erase(std::remove(m_children.begin(), m_children.end(), el), m_children.end());
+		return true;
+	}
+	return false;
+}
+
+void litehtml::html_tag::clearRecursive()
+{
+	for(auto& el : m_children)
+	{
+		el->clearRecursive();
+		el->parent(nullptr);
+	}
+	m_children.clear();
+}
+
+
+const litehtml::tchar_t* litehtml::html_tag::get_tagName() const
+{
+	return m_tag.c_str();
+}
+
+void litehtml::html_tag::set_attr( const tchar_t* name, const tchar_t* val )
+{
+	if(name && val)
+	{
+		tstring s_val = name;
+		std::locale lc = std::locale::global(std::locale::classic());
+		for(size_t i = 0; i < s_val.length(); i++)
+		{
+			s_val[i] = std::tolower(s_val[i], lc);
+		}
+		m_attrs[s_val] = val;
+
+		if( t_strcasecmp( name, _t("class") ) == 0 )
+		{
+			m_class_values.resize( 0 );
+			split_string( val, m_class_values, _t(" ") );
+		}
+	}
+}
+
+const litehtml::tchar_t* litehtml::html_tag::get_attr( const tchar_t* name, const tchar_t* def )
+{
+	string_map::const_iterator attr = m_attrs.find(name);
+	if(attr != m_attrs.end())
+	{
+		return attr->second.c_str();
+	}
+	return def;
+}
+
+litehtml::elements_vector litehtml::html_tag::select_all( const tstring& selector )
+{
+	css_selector sel(media_query_list::ptr(0));
+	sel.parse(selector);
+	
+	return select_all(sel);
+}
+
+litehtml::elements_vector litehtml::html_tag::select_all( const css_selector& selector )
+{
+	litehtml::elements_vector res;
+	select_all(selector, res);
+	return res;
+}
+
+void litehtml::html_tag::select_all(const css_selector& selector, elements_vector& res)
+{
+	if(select(selector))
+	{
+		res.push_back(shared_from_this());
+	}
+	
+	for(auto& el : m_children)
+	{
+		el->select_all(selector, res);
+	}
+}
+
+
+litehtml::element::ptr litehtml::html_tag::select_one( const tstring& selector )
+{
+	css_selector sel(media_query_list::ptr(0));
+	sel.parse(selector);
+
+	return select_one(sel);
+}
+
+litehtml::element::ptr litehtml::html_tag::select_one( const css_selector& selector )
+{
+	if(select(selector))
+	{
+		return shared_from_this();
+	}
+
+	for(auto& el : m_children)
+	{
+		element::ptr res = el->select_one(selector);
+		if(res)
+		{
+			return res;
+		}
+	}
+	return 0;
+}
+
+void litehtml::html_tag::apply_stylesheet( const litehtml::css& stylesheet )
+{
+	remove_before_after();
+
+	for(const auto& sel : stylesheet.selectors())
+	{
+		int apply = select(*sel, false);
+
+		if(apply != select_no_match)
+		{
+			used_selector::ptr us = std::unique_ptr<used_selector>(new used_selector(sel, false));
+
+			if(sel->is_media_valid())
+			{
+				if(apply & select_match_pseudo_class)
+				{
+					if(select(*sel, true))
+					{
+						if(apply & select_match_with_after)
+						{
+							element::ptr el = get_element_after();
+							if(el)
+							{
+								el->add_style(*sel->m_style);
+							}
+						} else if(apply & select_match_with_before)
+						{
+							element::ptr el = get_element_before();
+							if(el)
+							{
+								el->add_style(*sel->m_style);
+							}
+						}
+						else
+						{
+							add_style(*sel->m_style);
+							us->m_used = true;
+						}
+					}
+				} else if(apply & select_match_with_after)
+				{
+					element::ptr el = get_element_after();
+					if(el)
+					{
+						el->add_style(*sel->m_style);
+					}
+				} else if(apply & select_match_with_before)
+				{
+					element::ptr el = get_element_before();
+					if(el)
+					{
+						el->add_style(*sel->m_style);
+					}
+				} else
+				{
+					add_style(*sel->m_style);
+					us->m_used = true;
+				}
+			}
+			m_used_styles.push_back(std::move(us));
+		}
+	}
+
+	for(auto& el : m_children)
+	{
+		if(el->get_display() != display_inline_text)
+		{
+			el->apply_stylesheet(stylesheet);
+		}
+	}
+}
+
+void litehtml::html_tag::get_content_size( size& sz, int max_width )
+{
+	sz.height	= 0;
+	if(m_display == display_block)
+	{
+		sz.width	= max_width;
+	} else
+	{
+		sz.width	= 0;
+	}
+}
+
+void litehtml::html_tag::draw( uint_ptr hdc, int x, int y, const position* clip )
+{
+	position pos = m_pos;
+	pos.x	+= x;
+	pos.y	+= y;
+
+	draw_background(hdc, x, y, clip);
+
+	if(m_display == display_list_item && m_list_style_type != list_style_type_none)
+	{
+		if(m_overflow > overflow_visible)
+		{
+			position border_box = pos;
+			border_box += m_padding;
+			border_box += m_borders;
+
+			border_radiuses bdr_radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
+
+			bdr_radius -= m_borders;
+			bdr_radius -= m_padding;
+
+			get_document()->container()->set_clip(pos, bdr_radius, true, true);
+		}
+
+		draw_list_marker(hdc, pos);
+
+		if(m_overflow > overflow_visible)
+		{
+			get_document()->container()->del_clip();
+		}
+	}
+}
+
+litehtml::uint_ptr litehtml::html_tag::get_font(font_metrics* fm)
+{
+	if(fm)
+	{
+		*fm = m_font_metrics;
+	}
+	return m_font;
+}
+
+const litehtml::tchar_t* litehtml::html_tag::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ )
+{
+	const tchar_t* ret = m_style.get_property(name);
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		if ( ( ret && !t_strcasecmp(ret, _t("inherit")) ) || (!ret && inherited) )
+		{
+			ret = el_parent->get_style_property(name, inherited, def);
+		}
+	}
+
+	if(!ret)
+	{
+		ret = def;
+	}
+
+	return ret;
+}
+
+void litehtml::html_tag::parse_styles(bool is_reparse)
+{
+	const tchar_t* style = get_attr(_t("style"));
+
+	if(style)
+	{
+		m_style.add(style, NULL);
+	}
+
+	init_font();
+	document::ptr doc = get_document();
+
+	m_el_position	= (element_position)	value_index(get_style_property(_t("position"),		false,	_t("static")),		element_position_strings,	element_position_fixed);
+	m_text_align	= (text_align)			value_index(get_style_property(_t("text-align"),		true,	_t("left")),		text_align_strings,			text_align_left);
+	m_overflow		= (overflow)			value_index(get_style_property(_t("overflow"),		false,	_t("visible")),		overflow_strings,			overflow_visible);
+	m_white_space	= (white_space)			value_index(get_style_property(_t("white-space"),	true,	_t("normal")),		white_space_strings,		white_space_normal);
+	m_display		= (style_display)		value_index(get_style_property(_t("display"),		false,	_t("inline")),		style_display_strings,		display_inline);
+	m_visibility	= (visibility)			value_index(get_style_property(_t("visibility"),	true,	_t("visible")),		visibility_strings,			visibility_visible);
+	m_box_sizing	= (box_sizing)			value_index(get_style_property(_t("box-sizing"),		false,	_t("content-box")),	box_sizing_strings,			box_sizing_content_box);
+
+	if(m_el_position != element_position_static)
+	{
+		const tchar_t* val = get_style_property(_t("z-index"), false, 0);
+		if(val)
+		{
+			m_z_index = t_atoi(val);
+		}
+	}
+
+	const tchar_t* va	= get_style_property(_t("vertical-align"), true,	_t("baseline"));
+	m_vertical_align = (vertical_align) value_index(va, vertical_align_strings, va_baseline);
+
+	const tchar_t* fl	= get_style_property(_t("float"), false,	_t("none"));
+	m_float = (element_float) value_index(fl, element_float_strings, float_none);
+
+	m_clear = (element_clear) value_index(get_style_property(_t("clear"), false, _t("none")), element_clear_strings, clear_none);
+
+	if (m_float != float_none)
+	{
+		// reset display in to block for floating elements
+		if (m_display != display_none)
+		{
+			m_display = display_block;
+		}
+	}
+	else if (m_display == display_table ||
+		m_display == display_table_caption ||
+		m_display == display_table_cell ||
+		m_display == display_table_column ||
+		m_display == display_table_column_group ||
+		m_display == display_table_footer_group ||
+		m_display == display_table_header_group ||
+		m_display == display_table_row ||
+		m_display == display_table_row_group)
+	{
+		doc->add_tabular(shared_from_this());
+	}
+	// fix inline boxes with absolute/fixed positions
+	else if (m_display != display_none && is_inline_box())
+	{
+		if (m_el_position == element_position_absolute || m_el_position == element_position_fixed)
+		{
+			m_display = display_block;
+		}
+	}
+
+	m_css_text_indent.fromString(	get_style_property(_t("text-indent"),	true,	_t("0")),	_t("0"));
+
+	m_css_width.fromString(			get_style_property(_t("width"),			false,	_t("auto")), _t("auto"));
+	m_css_height.fromString(		get_style_property(_t("height"),		false,	_t("auto")), _t("auto"));
+
+	doc->cvt_units(m_css_width, m_font_size);
+	doc->cvt_units(m_css_height, m_font_size);
+
+	m_css_min_width.fromString(		get_style_property(_t("min-width"),		false,	_t("0")));
+	m_css_min_height.fromString(	get_style_property(_t("min-height"),		false,	_t("0")));
+
+	m_css_max_width.fromString(		get_style_property(_t("max-width"),		false,	_t("none")),	_t("none"));
+	m_css_max_height.fromString(	get_style_property(_t("max-height"),		false,	_t("none")),	_t("none"));
+	
+	doc->cvt_units(m_css_min_width, m_font_size);
+	doc->cvt_units(m_css_min_height, m_font_size);
+
+	m_css_offsets.left.fromString(		get_style_property(_t("left"),				false,	_t("auto")), _t("auto"));
+	m_css_offsets.right.fromString(		get_style_property(_t("right"),				false,	_t("auto")), _t("auto"));
+	m_css_offsets.top.fromString(		get_style_property(_t("top"),				false,	_t("auto")), _t("auto"));
+	m_css_offsets.bottom.fromString(	get_style_property(_t("bottom"),			false,	_t("auto")), _t("auto"));
+
+	doc->cvt_units(m_css_offsets.left, m_font_size);
+	doc->cvt_units(m_css_offsets.right, m_font_size);
+	doc->cvt_units(m_css_offsets.top,		m_font_size);
+	doc->cvt_units(m_css_offsets.bottom,	m_font_size);
+
+	m_css_margins.left.fromString(		get_style_property(_t("margin-left"),		false,	_t("0")), _t("auto"));
+	m_css_margins.right.fromString(		get_style_property(_t("margin-right"),		false,	_t("0")), _t("auto"));
+	m_css_margins.top.fromString(		get_style_property(_t("margin-top"),			false,	_t("0")), _t("auto"));
+	m_css_margins.bottom.fromString(	get_style_property(_t("margin-bottom"),		false,	_t("0")), _t("auto"));
+
+	m_css_padding.left.fromString(		get_style_property(_t("padding-left"),		false,	_t("0")), _t(""));
+	m_css_padding.right.fromString(		get_style_property(_t("padding-right"),		false,	_t("0")), _t(""));
+	m_css_padding.top.fromString(		get_style_property(_t("padding-top"),		false,	_t("0")), _t(""));
+	m_css_padding.bottom.fromString(	get_style_property(_t("padding-bottom"),		false,	_t("0")), _t(""));
+
+	m_css_borders.left.width.fromString(	get_style_property(_t("border-left-width"),		false,	_t("medium")), border_width_strings);
+	m_css_borders.right.width.fromString(	get_style_property(_t("border-right-width"),		false,	_t("medium")), border_width_strings);
+	m_css_borders.top.width.fromString(		get_style_property(_t("border-top-width"),		false,	_t("medium")), border_width_strings);
+	m_css_borders.bottom.width.fromString(	get_style_property(_t("border-bottom-width"),	false,	_t("medium")), border_width_strings);
+
+	m_css_borders.left.color = web_color::from_string(get_style_property(_t("border-left-color"),	false,	_t("")));
+	m_css_borders.left.style = (border_style) value_index(get_style_property(_t("border-left-style"), false, _t("none")), border_style_strings, border_style_none);
+
+	m_css_borders.right.color = web_color::from_string(get_style_property(_t("border-right-color"),	false,	_t("")));
+	m_css_borders.right.style = (border_style) value_index(get_style_property(_t("border-right-style"), false, _t("none")), border_style_strings, border_style_none);
+
+	m_css_borders.top.color = web_color::from_string(get_style_property(_t("border-top-color"),	false,	_t("")));
+	m_css_borders.top.style = (border_style) value_index(get_style_property(_t("border-top-style"), false, _t("none")), border_style_strings, border_style_none);
+
+	m_css_borders.bottom.color = web_color::from_string(get_style_property(_t("border-bottom-color"),	false,	_t("")));
+	m_css_borders.bottom.style = (border_style) value_index(get_style_property(_t("border-bottom-style"), false, _t("none")), border_style_strings, border_style_none);
+
+	m_css_borders.radius.top_left_x.fromString(get_style_property(_t("border-top-left-radius-x"), false, _t("0")));
+	m_css_borders.radius.top_left_y.fromString(get_style_property(_t("border-top-left-radius-y"), false, _t("0")));
+
+	m_css_borders.radius.top_right_x.fromString(get_style_property(_t("border-top-right-radius-x"), false, _t("0")));
+	m_css_borders.radius.top_right_y.fromString(get_style_property(_t("border-top-right-radius-y"), false, _t("0")));
+
+	m_css_borders.radius.bottom_right_x.fromString(get_style_property(_t("border-bottom-right-radius-x"), false, _t("0")));
+	m_css_borders.radius.bottom_right_y.fromString(get_style_property(_t("border-bottom-right-radius-y"), false, _t("0")));
+
+	m_css_borders.radius.bottom_left_x.fromString(get_style_property(_t("border-bottom-left-radius-x"), false, _t("0")));
+	m_css_borders.radius.bottom_left_y.fromString(get_style_property(_t("border-bottom-left-radius-y"), false, _t("0")));
+
+	doc->cvt_units(m_css_borders.radius.bottom_left_x,			m_font_size);
+	doc->cvt_units(m_css_borders.radius.bottom_left_y,			m_font_size);
+	doc->cvt_units(m_css_borders.radius.bottom_right_x,			m_font_size);
+	doc->cvt_units(m_css_borders.radius.bottom_right_y,			m_font_size);
+	doc->cvt_units(m_css_borders.radius.top_left_x,				m_font_size);
+	doc->cvt_units(m_css_borders.radius.top_left_y,				m_font_size);
+	doc->cvt_units(m_css_borders.radius.top_right_x,				m_font_size);
+	doc->cvt_units(m_css_borders.radius.top_right_y,				m_font_size);
+
+	doc->cvt_units(m_css_text_indent,								m_font_size);
+
+	m_margins.left		= doc->cvt_units(m_css_margins.left,		m_font_size);
+	m_margins.right		= doc->cvt_units(m_css_margins.right,		m_font_size);
+	m_margins.top		= doc->cvt_units(m_css_margins.top,		m_font_size);
+	m_margins.bottom	= doc->cvt_units(m_css_margins.bottom,	m_font_size);
+
+	m_padding.left		= doc->cvt_units(m_css_padding.left,		m_font_size);
+	m_padding.right		= doc->cvt_units(m_css_padding.right,		m_font_size);
+	m_padding.top		= doc->cvt_units(m_css_padding.top,		m_font_size);
+	m_padding.bottom	= doc->cvt_units(m_css_padding.bottom,	m_font_size);
+
+	m_borders.left		= doc->cvt_units(m_css_borders.left.width,	m_font_size);
+	m_borders.right		= doc->cvt_units(m_css_borders.right.width,	m_font_size);
+	m_borders.top		= doc->cvt_units(m_css_borders.top.width,		m_font_size);
+	m_borders.bottom	= doc->cvt_units(m_css_borders.bottom.width,	m_font_size);
+
+	css_length line_height;
+	line_height.fromString(get_style_property(_t("line-height"),	true,	_t("normal")), _t("normal"));
+	if(line_height.is_predefined())
+	{
+		m_line_height = m_font_metrics.height;
+		m_lh_predefined = true;
+	} else if(line_height.units() == css_units_none)
+	{
+		m_line_height = (int) (line_height.val() * m_font_size);
+		m_lh_predefined = false;
+	} else
+	{
+		m_line_height =  doc->cvt_units(line_height,	m_font_size, m_font_size);
+		m_lh_predefined = false;
+	}
+
+
+	if(m_display == display_list_item)
+	{
+		const tchar_t* list_type = get_style_property(_t("list-style-type"), true, _t("disc"));
+		m_list_style_type = (list_style_type) value_index(list_type, list_style_type_strings, list_style_type_disc);
+
+		const tchar_t* list_pos = get_style_property(_t("list-style-position"), true, _t("outside"));
+		m_list_style_position = (list_style_position) value_index(list_pos, list_style_position_strings, list_style_position_outside);
+
+		const tchar_t* list_image = get_style_property(_t("list-style-image"), true, 0);
+		if(list_image && list_image[0])
+		{
+			tstring url;
+			css::parse_css_url(list_image, url);
+
+			const tchar_t* list_image_baseurl = get_style_property(_t("list-style-image-baseurl"), true, 0);
+			doc->container()->load_image(url.c_str(), list_image_baseurl, true);
+		}
+
+	}
+
+	parse_background();
+
+	if(!is_reparse)
+	{
+		for(auto& el : m_children)
+		{
+			el->parse_styles();
+		}
+	}
+}
+
+int litehtml::html_tag::render( int x, int y, int max_width, bool second_pass )
+{
+	if (m_display == display_table || m_display == display_inline_table)
+	{
+		return render_table(x, y, max_width, second_pass);
+	}
+
+	return render_box(x, y, max_width, second_pass);
+}
+
+bool litehtml::html_tag::is_white_space() const
+{
+	return false;
+}
+
+int litehtml::html_tag::get_font_size() const
+{
+	return m_font_size;
+}
+
+int litehtml::html_tag::get_base_line()
+{
+	if(is_replaced())
+	{
+		return 0;
+	}
+	int bl = 0;
+	if(!m_boxes.empty())
+	{
+		bl = m_boxes.back()->baseline() + content_margins_bottom();
+	}
+	return bl;
+}
+
+void litehtml::html_tag::init()
+{
+	if (m_display == display_table || m_display == display_inline_table)
+	{
+		if (m_grid)
+		{
+			m_grid->clear();
+		}
+		else
+		{
+			m_grid = std::unique_ptr<table_grid>(new table_grid());
+		}
+
+		go_inside_table 		table_selector;
+		table_rows_selector		row_selector;
+		table_cells_selector	cell_selector;
+
+		elements_iterator row_iter(shared_from_this(), &table_selector, &row_selector);
+
+		element::ptr row = row_iter.next(false);
+		while (row)
+		{
+			m_grid->begin_row(row);
+
+			elements_iterator cell_iter(row, &table_selector, &cell_selector);
+			element::ptr cell = cell_iter.next();
+			while (cell)
+			{
+				m_grid->add_cell(cell);
+
+				cell = cell_iter.next(false);
+			}
+			row = row_iter.next(false);
+		}
+
+		m_grid->finish();
+	}
+
+	for (auto& el : m_children)
+	{
+		el->init();
+	}
+}
+
+int litehtml::html_tag::select(const css_selector& selector, bool apply_pseudo)
+{
+	int right_res = select(selector.m_right, apply_pseudo);
+	if(right_res == select_no_match)
+	{
+		return select_no_match;
+	}
+	element::ptr el_parent = parent();
+	if(selector.m_left)
+	{
+		if (!el_parent)
+		{
+			return select_no_match;
+		}
+		switch(selector.m_combinator)
+		{
+		case combinator_descendant:
+			{
+				bool is_pseudo = false;
+				element::ptr res = find_ancestor(*selector.m_left, apply_pseudo, &is_pseudo);
+				if(!res)
+				{
+					return select_no_match;
+				} else
+				{
+					if(is_pseudo)
+					{
+						right_res |= select_match_pseudo_class;
+					}
+				}
+			}
+			break;
+		case combinator_child:
+			{
+				int res = el_parent->select(*selector.m_left, apply_pseudo);
+				if(res == select_no_match)
+				{
+					return select_no_match;
+				} else
+				{
+					if(right_res != select_match_pseudo_class)
+					{
+						right_res |= res;
+					}
+				}
+			}
+			break;
+		case combinator_adjacent_sibling:
+			{
+				bool is_pseudo = false;
+				element::ptr res = el_parent->find_adjacent_sibling(shared_from_this(), *selector.m_left, apply_pseudo, &is_pseudo);
+				if(!res)
+				{
+					return select_no_match;
+				} else
+				{
+					if(is_pseudo)
+					{
+						right_res |= select_match_pseudo_class;
+					}
+				}
+			}
+			break;
+		case combinator_general_sibling:
+			{
+				bool is_pseudo = false;
+				element::ptr res =  el_parent->find_sibling(shared_from_this(), *selector.m_left, apply_pseudo, &is_pseudo);
+				if(!res)
+				{
+					return select_no_match;
+				} else
+				{
+					if(is_pseudo)
+					{
+						right_res |= select_match_pseudo_class;
+					}
+				}
+			}
+			break;
+		default:
+			right_res = select_no_match;
+		}
+	}
+	return right_res;
+}
+
+int litehtml::html_tag::select(const css_element_selector& selector, bool apply_pseudo)
+{
+	if(!selector.m_tag.empty() && selector.m_tag != _t("*"))
+	{
+		if(selector.m_tag != m_tag)
+		{
+			return select_no_match;
+		}
+	}
+
+	int res = select_match;
+	element::ptr el_parent = parent();
+
+	for(css_attribute_selector::vector::const_iterator i = selector.m_attrs.begin(); i != selector.m_attrs.end(); i++)
+	{
+		const tchar_t* attr_value = get_attr(i->attribute.c_str());
+		switch(i->condition)
+		{
+		case select_exists:
+			if(!attr_value)
+			{
+				return select_no_match;
+			}
+			break;
+		case select_equal:
+			if(!attr_value)
+			{
+				return select_no_match;
+			} else 
+			{
+				if(i->attribute == _t("class"))
+				{
+					const string_vector & tokens1 = m_class_values;
+					const string_vector & tokens2 = i->class_val;
+					bool found = true;
+					for(string_vector::const_iterator str1 = tokens2.begin(); str1 != tokens2.end() && found; str1++)
+					{
+						bool f = false;
+						for(string_vector::const_iterator str2 = tokens1.begin(); str2 != tokens1.end() && !f; str2++)
+						{
+							if( !t_strcasecmp(str1->c_str(), str2->c_str()) )
+							{
+								f = true;
+							}
+						}
+						if(!f)
+						{
+							found = false;
+						}
+					}
+					if(!found)
+					{
+						return select_no_match;
+					}
+				} else
+				{
+					if( t_strcasecmp(i->val.c_str(), attr_value) )
+					{
+						return select_no_match;
+					}
+				}
+			}
+			break;
+		case select_contain_str:
+			if(!attr_value)
+			{
+				return select_no_match;
+			} else if(!t_strstr(attr_value, i->val.c_str()))
+			{
+				return select_no_match;
+			}
+			break;
+		case select_start_str:
+			if(!attr_value)
+			{
+				return select_no_match;
+			} else if(t_strncmp(attr_value, i->val.c_str(), i->val.length()))
+			{
+				return select_no_match;
+			}
+			break;
+		case select_end_str:
+			if(!attr_value)
+			{
+				return select_no_match;
+			} else if(t_strncmp(attr_value, i->val.c_str(), i->val.length()))
+			{
+				const tchar_t* s = attr_value + t_strlen(attr_value) - i->val.length() - 1;
+				if(s < attr_value)
+				{
+					return select_no_match;
+				}
+				if(i->val != s)
+				{
+					return select_no_match;
+				}
+			}
+			break;
+		case select_pseudo_element:
+			if(i->val == _t("after"))
+			{
+				res |= select_match_with_after;
+			} else if(i->val == _t("before"))
+			{
+				res |= select_match_with_before;
+			} else
+			{
+				return select_no_match;
+			}
+			break;
+		case select_pseudo_class:
+			if(apply_pseudo)
+			{
+				if (!el_parent) return select_no_match;
+
+				tstring selector_param;
+				tstring	selector_name;
+
+				tstring::size_type begin	= i->val.find_first_of(_t('('));
+				tstring::size_type end		= (begin == tstring::npos) ? tstring::npos : find_close_bracket(i->val, begin);
+				if(begin != tstring::npos && end != tstring::npos)
+				{
+					selector_param = i->val.substr(begin + 1, end - begin - 1);
+				}
+				if(begin != tstring::npos)
+				{
+					selector_name = i->val.substr(0, begin);
+					litehtml::trim(selector_name);
+				} else
+				{
+					selector_name = i->val;
+				}
+
+				int selector = value_index(selector_name.c_str(), pseudo_class_strings);
+				
+				switch(selector)
+				{
+				case pseudo_class_only_child:
+					if (!el_parent->is_only_child(shared_from_this(), false))
+					{
+						return select_no_match;
+					}
+					break;
+				case pseudo_class_only_of_type:
+					if (!el_parent->is_only_child(shared_from_this(), true))
+					{
+						return select_no_match;
+					}
+					break;
+				case pseudo_class_first_child:
+					if (!el_parent->is_nth_child(shared_from_this(), 0, 1, false))
+					{
+						return select_no_match;
+					}
+					break;
+				case pseudo_class_first_of_type:
+					if (!el_parent->is_nth_child(shared_from_this(), 0, 1, true))
+					{
+						return select_no_match;
+					}
+					break;
+				case pseudo_class_last_child:
+					if (!el_parent->is_nth_last_child(shared_from_this(), 0, 1, false))
+					{
+						return select_no_match;
+					}
+					break;
+				case pseudo_class_last_of_type:
+					if (!el_parent->is_nth_last_child(shared_from_this(), 0, 1, true))
+					{
+						return select_no_match;
+					}
+					break;
+				case pseudo_class_nth_child:
+				case pseudo_class_nth_of_type:
+				case pseudo_class_nth_last_child:
+				case pseudo_class_nth_last_of_type:
+					{
+						if(selector_param.empty()) return select_no_match;
+
+						int num = 0;
+						int off = 0;
+
+						parse_nth_child_params(selector_param, num, off);
+						if(!num && !off) return select_no_match;
+						switch(selector)
+						{
+						case pseudo_class_nth_child:
+							if (!el_parent->is_nth_child(shared_from_this(), num, off, false))
+							{
+								return select_no_match;
+							}
+							break;
+						case pseudo_class_nth_of_type:
+							if (!el_parent->is_nth_child(shared_from_this(), num, off, true))
+							{
+								return select_no_match;
+							}
+							break;
+						case pseudo_class_nth_last_child:
+							if (!el_parent->is_nth_last_child(shared_from_this(), num, off, false))
+							{
+								return select_no_match;
+							}
+							break;
+						case pseudo_class_nth_last_of_type:
+							if (!el_parent->is_nth_last_child(shared_from_this(), num, off, true))
+							{
+								return select_no_match;
+							}
+							break;
+						}
+
+					}
+					break;
+				case pseudo_class_not:
+					{
+						css_element_selector sel;
+						sel.parse(selector_param);
+						if(select(sel, apply_pseudo))
+						{
+							return select_no_match;
+						}
+					}
+					break;
+				case pseudo_class_lang:
+					{
+						trim( selector_param );
+
+						if( !get_document()->match_lang( selector_param ) )
+						{
+							return select_no_match;
+						}
+					}
+					break;
+				default:
+					if(std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), i->val) == m_pseudo_classes.end())
+					{
+						return select_no_match;
+					}
+					break;
+				}
+			} else
+			{
+				res |= select_match_pseudo_class;
+			}
+			break;
+		}
+	}
+	return res;
+}
+
+litehtml::element::ptr litehtml::html_tag::find_ancestor(const css_selector& selector, bool apply_pseudo, bool* is_pseudo)
+{
+	element::ptr el_parent = parent();
+	if (!el_parent)
+	{
+		return nullptr;
+	}
+	int res = el_parent->select(selector, apply_pseudo);
+	if(res != select_no_match)
+	{
+		if(is_pseudo)
+		{
+			if(res & select_match_pseudo_class)
+			{
+				*is_pseudo = true;
+			} else
+			{
+				*is_pseudo = false;
+			}
+		}
+		return el_parent;
+	}
+	return el_parent->find_ancestor(selector, apply_pseudo, is_pseudo);
+}
+
+int litehtml::html_tag::get_floats_height(element_float el_float) const
+{
+	if(is_floats_holder())
+	{
+		int h = 0;
+
+		bool process = false;
+
+		for(const auto& fb : m_floats_left)
+		{
+			process = false;
+			switch(el_float)
+			{
+			case float_none:
+				process = true;
+				break;
+			case float_left:
+				if (fb.clear_floats == clear_left || fb.clear_floats == clear_both)
+				{
+					process = true;
+				}
+				break;
+			case float_right:
+				if (fb.clear_floats == clear_right || fb.clear_floats == clear_both)
+				{
+					process = true;
+				}
+				break;
+			}
+			if(process)
+			{
+				if(el_float == float_none)
+				{
+					h = std::max(h, fb.pos.bottom());
+				} else
+				{
+					h = std::max(h, fb.pos.top());
+				}
+			}
+		}
+
+
+		for(const auto fb : m_floats_right)
+		{
+			process = false;
+			switch(el_float)
+			{
+			case float_none:
+				process = true;
+				break;
+			case float_left:
+				if (fb.clear_floats == clear_left || fb.clear_floats == clear_both)
+				{
+					process = true;
+				}
+				break;
+			case float_right:
+				if (fb.clear_floats == clear_right || fb.clear_floats == clear_both)
+				{
+					process = true;
+				}
+				break;
+			}
+			if(process)
+			{
+				if(el_float == float_none)
+				{
+					h = std::max(h, fb.pos.bottom());
+				} else
+				{
+					h = std::max(h, fb.pos.top());
+				}
+			}
+		}
+
+		return h;
+	}
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		int h = el_parent->get_floats_height(el_float);
+		return h - m_pos.y;
+	}
+	return 0;
+}
+
+int litehtml::html_tag::get_left_floats_height() const
+{
+	if(is_floats_holder())
+	{
+		int h = 0;
+		if(!m_floats_left.empty())
+		{
+			for (const auto& fb : m_floats_left)
+			{
+				h = std::max(h, fb.pos.bottom());
+			}
+		}
+		return h;
+	}
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		int h = el_parent->get_left_floats_height();
+		return h - m_pos.y;
+	}
+	return 0;
+}
+
+int litehtml::html_tag::get_right_floats_height() const
+{
+	if(is_floats_holder())
+	{
+		int h = 0;
+		if(!m_floats_right.empty())
+		{
+			for(const auto& fb : m_floats_right)
+			{
+				h = std::max(h, fb.pos.bottom());
+			}
+		}
+		return h;
+	}
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		int h = el_parent->get_right_floats_height();
+		return h - m_pos.y;
+	}
+	return 0;
+}
+
+int litehtml::html_tag::get_line_left( int y )
+{
+	if(is_floats_holder())
+	{
+		if(m_cahe_line_left.is_valid && m_cahe_line_left.hash == y)
+		{
+			return m_cahe_line_left.val;
+		}
+
+		int w = 0;
+		for(const auto& fb : m_floats_left)
+		{
+			if (y >= fb.pos.top() && y < fb.pos.bottom())
+			{
+				w = std::max(w, fb.pos.right());
+				if (w < fb.pos.right())
+				{
+					break;
+				}
+			}
+		}
+		m_cahe_line_left.set_value(y, w);
+		return w;
+	}
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		int w = el_parent->get_line_left(y + m_pos.y);
+		if (w < 0)
+		{
+			w = 0;
+		}
+		return w - (w ? m_pos.x : 0);
+	}
+	return 0;
+}
+
+int litehtml::html_tag::get_line_right( int y, int def_right )
+{
+	if(is_floats_holder())
+	{
+		if(m_cahe_line_right.is_valid && m_cahe_line_right.hash == y)
+		{
+			if(m_cahe_line_right.is_default)
+			{
+				return def_right;
+			} else
+			{
+				return std::min(m_cahe_line_right.val, def_right);
+			}
+		}
+
+		int w = def_right;
+		m_cahe_line_right.is_default = true;
+		for(const auto& fb : m_floats_right)
+		{
+			if(y >= fb.pos.top() && y < fb.pos.bottom())
+			{
+				w = std::min(w, fb.pos.left());
+				m_cahe_line_right.is_default = false;
+				if(w > fb.pos.left())
+				{
+					break;
+				}
+			}
+		}
+		m_cahe_line_right.set_value(y, w);
+		return w;
+	}
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		int w = el_parent->get_line_right(y + m_pos.y, def_right + m_pos.x);
+		return w - m_pos.x;
+	}
+	return 0;
+}
+
+
+void litehtml::html_tag::get_line_left_right( int y, int def_right, int& ln_left, int& ln_right )
+{
+	if(is_floats_holder())
+	{
+		ln_left		= get_line_left(y);
+		ln_right	= get_line_right(y, def_right);
+	} else
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			el_parent->get_line_left_right(y + m_pos.y, def_right + m_pos.x, ln_left, ln_right);
+		}
+		ln_right -= m_pos.x;
+		ln_left -= m_pos.x;
+
+		if(ln_left < 0)
+		{
+			ln_left = 0;
+		}
+	}
+}
+
+int litehtml::html_tag::fix_line_width( int max_width, element_float flt )
+{
+	int ret_width = 0;
+	if(!m_boxes.empty())
+	{
+		elements_vector els;
+		m_boxes.back()->get_elements(els);
+		bool was_cleared = false;
+		if(!els.empty() && els.front()->get_clear() != clear_none)
+		{
+			if(els.front()->get_clear() == clear_both)
+			{
+				was_cleared = true;
+			} else
+			{
+				if(	(flt == float_left	&& els.front()->get_clear() == clear_left) ||
+					(flt == float_right	&& els.front()->get_clear() == clear_right) )
+				{
+					was_cleared = true;
+				}
+			}
+		}
+
+		if(!was_cleared)
+		{
+			m_boxes.pop_back();
+
+			for(elements_vector::iterator i = els.begin(); i != els.end(); i++)
+			{
+				int rw = place_element((*i), max_width);
+				if(rw > ret_width)
+				{
+					ret_width = rw;
+				}
+			}
+		} else
+		{
+			int line_top = 0;
+			if(m_boxes.back()->get_type() == box_line)
+			{
+				line_top = m_boxes.back()->top();
+			} else
+			{
+				line_top = m_boxes.back()->bottom();
+			}
+
+			int line_left	= 0;
+			int line_right	= max_width;
+			get_line_left_right(line_top, max_width, line_left, line_right);
+
+			if(m_boxes.back()->get_type() == box_line)
+			{
+				if(m_boxes.size() == 1 && m_list_style_type != list_style_type_none && m_list_style_position == list_style_position_inside)
+				{
+					int sz_font = get_font_size();
+					line_left += sz_font;
+				}
+
+				if(m_css_text_indent.val() != 0)
+				{
+					bool line_box_found = false;
+					for(box::vector::iterator iter = m_boxes.begin(); iter < m_boxes.end(); iter++)
+					{
+						if((*iter)->get_type() == box_line)
+						{
+							line_box_found = true;
+							break;
+						}
+					}
+					if(!line_box_found)
+					{
+						line_left += m_css_text_indent.calc_percent(max_width);
+					}
+				}
+
+			}
+
+			elements_vector els;
+			m_boxes.back()->new_width(line_left, line_right, els);
+			for(auto& el : els)
+			{
+				int rw = place_element(el, max_width);
+				if(rw > ret_width)
+				{
+					ret_width = rw;
+				}
+			}
+		}
+	}
+
+	return ret_width;
+}
+
+void litehtml::html_tag::add_float(const element::ptr &el, int x, int y)
+{
+	if(is_floats_holder())
+	{
+		floated_box fb;
+		fb.pos.x		= el->left() + x;
+		fb.pos.y		= el->top()  + y;
+		fb.pos.width	= el->width();
+		fb.pos.height	= el->height();
+		fb.float_side	= el->get_float();
+		fb.clear_floats	= el->get_clear();
+		fb.el			= el;
+
+		if(fb.float_side == float_left)
+		{
+			if(m_floats_left.empty())
+			{
+				m_floats_left.push_back(fb);
+			} else
+			{
+				bool inserted = false;
+				for(floated_box::vector::iterator i = m_floats_left.begin(); i != m_floats_left.end(); i++)
+				{
+					if(fb.pos.right() > i->pos.right())
+					{
+						m_floats_left.insert(i, std::move(fb));
+						inserted = true;
+						break;
+					}
+				}
+				if(!inserted)
+				{
+					m_floats_left.push_back(std::move(fb));
+				}
+			}
+			m_cahe_line_left.invalidate();
+		} else if(fb.float_side == float_right)
+		{
+			if(m_floats_right.empty())
+			{
+				m_floats_right.push_back(std::move(fb));
+			} else
+			{
+				bool inserted = false;
+				for(floated_box::vector::iterator i = m_floats_right.begin(); i != m_floats_right.end(); i++)
+				{
+					if(fb.pos.left() < i->pos.left())
+					{
+						m_floats_right.insert(i, std::move(fb));
+						inserted = true;
+						break;
+					}
+				}
+				if(!inserted)
+				{
+					m_floats_right.push_back(fb);
+				}
+			}
+			m_cahe_line_right.invalidate();
+		}
+	} else
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			el_parent->add_float(el, x + m_pos.x, y + m_pos.y);
+		}
+	}
+}
+
+int litehtml::html_tag::find_next_line_top( int top, int width, int def_right )
+{
+	if(is_floats_holder())
+	{
+		int new_top = top;
+		int_vector points;
+
+		for(const auto& fb : m_floats_left)
+		{
+			if(fb.pos.top() >= top)
+			{
+				if(find(points.begin(), points.end(), fb.pos.top()) == points.end())
+				{
+					points.push_back(fb.pos.top());
+				}
+			}
+			if (fb.pos.bottom() >= top)
+			{
+				if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end())
+				{
+					points.push_back(fb.pos.bottom());
+				}
+			}
+		}
+
+		for (const auto& fb : m_floats_right)
+		{
+			if (fb.pos.top() >= top)
+			{
+				if (find(points.begin(), points.end(), fb.pos.top()) == points.end())
+				{
+					points.push_back(fb.pos.top());
+				}
+			}
+			if (fb.pos.bottom() >= top)
+			{
+				if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end())
+				{
+					points.push_back(fb.pos.bottom());
+				}
+			}
+		}
+
+		if(!points.empty())
+		{
+			sort(points.begin(), points.end(), std::less<int>( ));
+			new_top = points.back();
+
+			for(auto pt : points)
+			{
+				int pos_left	= 0;
+				int pos_right	= def_right;
+				get_line_left_right(pt, def_right, pos_left, pos_right);
+
+				if(pos_right - pos_left >= width)
+				{
+					new_top = pt;
+					break;
+				}
+			}
+		}
+		return new_top;
+	}
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		int new_top = el_parent->find_next_line_top(top + m_pos.y, width, def_right + m_pos.x);
+		return new_top - m_pos.y;
+	}
+	return 0;
+}
+
+void litehtml::html_tag::parse_background()
+{
+	// parse background-color
+	m_bg.m_color		= get_color(_t("background-color"), false, web_color(0, 0, 0, 0));
+
+	// parse background-position
+	const tchar_t* str = get_style_property(_t("background-position"), false, _t("0% 0%"));
+	if(str)
+	{
+		string_vector res;
+		split_string(str, res, _t(" \t"));
+		if(res.size() > 0)
+		{
+			if(res.size() == 1)
+			{
+				if( value_in_list(res[0].c_str(), _t("left;right;center")) )
+				{
+					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
+					m_bg.m_position.y.set_value(50, css_units_percentage);
+				} else if( value_in_list(res[0].c_str(), _t("top;bottom;center")) )
+				{
+					m_bg.m_position.y.fromString(res[0], _t("top;bottom;center"));
+					m_bg.m_position.x.set_value(50, css_units_percentage);
+				} else
+				{
+					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
+					m_bg.m_position.y.set_value(50, css_units_percentage);
+				}
+			} else
+			{
+				if(value_in_list(res[0].c_str(), _t("left;right")))
+				{
+					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
+					m_bg.m_position.y.fromString(res[1], _t("top;bottom;center"));
+				} else if(value_in_list(res[0].c_str(), _t("top;bottom")))
+				{
+					m_bg.m_position.x.fromString(res[1], _t("left;right;center"));
+					m_bg.m_position.y.fromString(res[0], _t("top;bottom;center"));
+				} else if(value_in_list(res[1].c_str(), _t("left;right")))
+				{
+					m_bg.m_position.x.fromString(res[1], _t("left;right;center"));
+					m_bg.m_position.y.fromString(res[0], _t("top;bottom;center"));
+				}else if(value_in_list(res[1].c_str(), _t("top;bottom")))
+				{
+					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
+					m_bg.m_position.y.fromString(res[1], _t("top;bottom;center"));
+				} else
+				{
+					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
+					m_bg.m_position.y.fromString(res[1], _t("top;bottom;center"));
+				}
+			}
+
+			if(m_bg.m_position.x.is_predefined())
+			{
+				switch(m_bg.m_position.x.predef())
+				{
+				case 0:
+					m_bg.m_position.x.set_value(0, css_units_percentage);
+					break;
+				case 1:
+					m_bg.m_position.x.set_value(100, css_units_percentage);
+					break;
+				case 2:
+					m_bg.m_position.x.set_value(50, css_units_percentage);
+					break;
+				}
+			}
+			if(m_bg.m_position.y.is_predefined())
+			{
+				switch(m_bg.m_position.y.predef())
+				{
+				case 0:
+					m_bg.m_position.y.set_value(0, css_units_percentage);
+					break;
+				case 1:
+					m_bg.m_position.y.set_value(100, css_units_percentage);
+					break;
+				case 2:
+					m_bg.m_position.y.set_value(50, css_units_percentage);
+					break;
+				}
+			}
+		} else
+		{
+			m_bg.m_position.x.set_value(0, css_units_percentage);
+			m_bg.m_position.y.set_value(0, css_units_percentage);
+		}
+	} else
+	{
+		m_bg.m_position.y.set_value(0, css_units_percentage);
+		m_bg.m_position.x.set_value(0, css_units_percentage);
+	}
+
+	str = get_style_property(_t("background-size"), false, _t("auto"));
+	if(str)
+	{
+		string_vector res;
+		split_string(str, res, _t(" \t"));
+		if(!res.empty())
+		{
+			m_bg.m_position.width.fromString(res[0], background_size_strings);
+			if(res.size() > 1)
+			{
+				m_bg.m_position.height.fromString(res[1], background_size_strings);
+			} else
+			{
+				m_bg.m_position.height.predef(background_size_auto);
+			}
+		} else
+		{
+			m_bg.m_position.width.predef(background_size_auto);
+			m_bg.m_position.height.predef(background_size_auto);
+		}
+	}
+
+	document::ptr doc = get_document();
+
+	doc->cvt_units(m_bg.m_position.x,		m_font_size);
+	doc->cvt_units(m_bg.m_position.y,		m_font_size);
+	doc->cvt_units(m_bg.m_position.width,	m_font_size);
+	doc->cvt_units(m_bg.m_position.height,	m_font_size);
+
+	// parse background_attachment
+	m_bg.m_attachment = (background_attachment) value_index(
+		get_style_property(_t("background-attachment"), false, _t("scroll")), 
+		background_attachment_strings, 
+		background_attachment_scroll);
+
+	// parse background_attachment
+	m_bg.m_repeat = (background_repeat) value_index(
+		get_style_property(_t("background-repeat"), false, _t("repeat")), 
+		background_repeat_strings, 
+		background_repeat_repeat);
+
+	// parse background_clip
+	m_bg.m_clip = (background_box) value_index(
+		get_style_property(_t("background-clip"), false, _t("border-box")), 
+		background_box_strings, 
+		background_box_border);
+
+	// parse background_origin
+	m_bg.m_origin = (background_box) value_index(
+		get_style_property(_t("background-origin"), false, _t("padding-box")), 
+		background_box_strings, 
+		background_box_content);
+
+	// parse background-image
+	css::parse_css_url(get_style_property(_t("background-image"), false, _t("")), m_bg.m_image);
+	m_bg.m_baseurl = get_style_property(_t("background-image-baseurl"), false, _t(""));
+
+	if(!m_bg.m_image.empty())
+	{
+		doc->container()->load_image(m_bg.m_image.c_str(), m_bg.m_baseurl.empty() ? 0 : m_bg.m_baseurl.c_str(), true);
+	}
+}
+
+void litehtml::html_tag::add_positioned(const element::ptr &el)
+{
+	if (m_el_position != element_position_static || (!have_parent()))
+	{
+		m_positioned.push_back(el);
+	} else
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			el_parent->add_positioned(el);
+		}
+	}
+}
+
+void litehtml::html_tag::calc_outlines( int parent_width )
+{
+	m_padding.left	= m_css_padding.left.calc_percent(parent_width);
+	m_padding.right	= m_css_padding.right.calc_percent(parent_width);
+
+	m_borders.left	= m_css_borders.left.width.calc_percent(parent_width);
+	m_borders.right	= m_css_borders.right.width.calc_percent(parent_width);
+
+	m_margins.left	= m_css_margins.left.calc_percent(parent_width);
+	m_margins.right	= m_css_margins.right.calc_percent(parent_width);
+
+	m_margins.top		= m_css_margins.top.calc_percent(parent_width);
+	m_margins.bottom	= m_css_margins.bottom.calc_percent(parent_width);
+
+	m_padding.top		= m_css_padding.top.calc_percent(parent_width);
+	m_padding.bottom	= m_css_padding.bottom.calc_percent(parent_width);
+}
+
+void litehtml::html_tag::calc_auto_margins(int parent_width)
+{
+	if (get_element_position() != element_position_absolute && (m_display == display_block || m_display == display_table))
+	{
+		if (m_css_margins.left.is_predefined() && m_css_margins.right.is_predefined())
+		{
+			int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right;
+			if (el_width <= parent_width)
+			{
+				m_margins.left = (parent_width - el_width) / 2;
+				m_margins.right = (parent_width - el_width) - m_margins.left;
+			}
+			else
+			{
+				m_margins.left = 0;
+				m_margins.right = 0;
+			}
+		}
+		else if (m_css_margins.left.is_predefined() && !m_css_margins.right.is_predefined())
+		{
+			int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right + m_margins.right;
+			m_margins.left = parent_width - el_width;
+			if (m_margins.left < 0) m_margins.left = 0;
+		}
+		else if (!m_css_margins.left.is_predefined() && m_css_margins.right.is_predefined())
+		{
+			int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right + m_margins.left;
+			m_margins.right = parent_width - el_width;
+			if (m_margins.right < 0) m_margins.right = 0;
+		}
+	}
+}
+
+void litehtml::html_tag::parse_attributes()
+{
+	for(auto& el : m_children)
+	{
+		el->parse_attributes();
+	}
+}
+
+void litehtml::html_tag::get_text( tstring& text )
+{
+	for (auto& el : m_children)
+	{
+		el->get_text(text);
+	}
+}
+
+bool litehtml::html_tag::is_body()  const
+{
+	return false;
+}
+
+void litehtml::html_tag::set_data( const tchar_t* data )
+{
+
+}
+
+void litehtml::html_tag::get_inline_boxes( position::vector& boxes )
+{
+	litehtml::box* old_box = 0;
+	position pos;
+	for(auto& el : m_children)
+	{
+		if(!el->skip())
+		{
+			if(el->m_box)
+			{
+				if(el->m_box != old_box)
+				{
+					if(old_box)
+					{
+						if(boxes.empty())
+						{
+							pos.x		-= m_padding.left + m_borders.left;
+							pos.width	+= m_padding.left + m_borders.left;
+						}
+						boxes.push_back(pos);
+					}
+					old_box		= el->m_box;
+					pos.x		= el->left() + el->margin_left();
+					pos.y		= el->top() - m_padding.top - m_borders.top;
+					pos.width	= 0;
+					pos.height	= 0;
+				}
+				pos.width	= el->right() - pos.x - el->margin_right() - el->margin_left();
+				pos.height	= std::max(pos.height, el->height() + m_padding.top + m_padding.bottom + m_borders.top + m_borders.bottom);
+			} else if(el->get_display() == display_inline)
+			{
+				position::vector sub_boxes;
+				el->get_inline_boxes(sub_boxes);
+				if(!sub_boxes.empty())
+				{
+					sub_boxes.rbegin()->width += el->margin_right();
+					if(boxes.empty())
+					{
+						if(m_padding.left + m_borders.left > 0)
+						{
+							position padding_box = (*sub_boxes.begin());
+							padding_box.x		-= m_padding.left + m_borders.left + el->margin_left();
+							padding_box.width	= m_padding.left + m_borders.left + el->margin_left();
+							boxes.push_back(padding_box);
+						}
+					}
+
+					sub_boxes.rbegin()->width += el->margin_right();
+
+					boxes.insert(boxes.end(), sub_boxes.begin(), sub_boxes.end());
+				}
+			}
+		}
+	}
+	if(pos.width || pos.height)
+	{
+		if(boxes.empty())
+		{
+			pos.x		-= m_padding.left + m_borders.left;
+			pos.width	+= m_padding.left + m_borders.left;
+		}
+		boxes.push_back(pos);
+	}
+	if(!boxes.empty())
+	{
+		if(m_padding.right + m_borders.right > 0)
+		{
+			boxes.back().width += m_padding.right + m_borders.right;
+		}
+	}
+}
+
+bool litehtml::html_tag::on_mouse_over()
+{
+	bool ret = false;
+
+	element::ptr el = shared_from_this();
+	while(el)
+	{
+		if(el->set_pseudo_class(_t("hover"), true))
+		{
+			ret = true;
+		}
+		el = el->parent();
+	}
+
+	return ret;
+}
+
+bool litehtml::html_tag::find_styles_changes( position::vector& redraw_boxes, int x, int y )
+{
+	if(m_display == display_inline_text)
+	{
+		return false;
+	}
+
+	bool ret = false;
+	bool apply = false;
+	for (used_selector::vector::iterator iter = m_used_styles.begin(); iter != m_used_styles.end() && !apply; iter++)
+	{
+		if((*iter)->m_selector->is_media_valid())
+		{
+			int res = select(*((*iter)->m_selector), true);
+			if( (res == select_no_match && (*iter)->m_used) || (res == select_match && !(*iter)->m_used) )
+			{
+				apply = true;
+			}
+		}
+	}
+
+	if(apply)
+	{
+		if(m_display == display_inline ||  m_display == display_table_row)
+		{
+			position::vector boxes;
+			get_inline_boxes(boxes);
+			for(position::vector::iterator pos = boxes.begin(); pos != boxes.end(); pos++)
+			{
+				pos->x	+= x;
+				pos->y	+= y;
+				redraw_boxes.push_back(*pos);
+			}
+		} else
+		{
+			position pos = m_pos;
+			if(m_el_position != element_position_fixed)
+			{
+				pos.x += x;
+				pos.y += y;
+			}
+			pos += m_padding;
+			pos += m_borders;
+			redraw_boxes.push_back(pos);
+		}
+
+		ret = true;
+		refresh_styles();
+		parse_styles();
+	}
+	for (auto& el : m_children)
+	{
+		if(!el->skip())
+		{
+			if(m_el_position != element_position_fixed)
+			{
+				if(el->find_styles_changes(redraw_boxes, x + m_pos.x, y + m_pos.y))
+				{
+					ret = true;
+				}
+			} else
+			{
+				if(el->find_styles_changes(redraw_boxes, m_pos.x, m_pos.y))
+				{
+					ret = true;
+				}
+			}
+		}
+	}
+	return ret;
+}
+
+bool litehtml::html_tag::on_mouse_leave()
+{
+	bool ret = false;
+
+	element::ptr el = shared_from_this();
+	while(el)
+	{
+		if(el->set_pseudo_class(_t("hover"), false))
+		{
+			ret = true;
+		}
+		if(el->set_pseudo_class(_t("active"), false))
+		{
+			ret = true;
+		}
+		el = el->parent();
+	}
+
+	return ret;
+}
+
+bool litehtml::html_tag::on_lbutton_down()
+{
+    bool ret = false;
+
+	element::ptr el = shared_from_this();
+    while (el)
+    {
+        if (el->set_pseudo_class(_t("active"), true))
+        {
+            ret = true;
+        }
+        el = el->parent();
+    }
+
+    return ret;
+}
+
+bool litehtml::html_tag::on_lbutton_up()
+{
+	bool ret = false;
+
+	element::ptr el = shared_from_this();
+    while (el)
+    {
+        if (el->set_pseudo_class(_t("active"), false))
+        {
+            ret = true;
+        }
+        el = el->parent();
+    }
+
+    on_click();
+
+	return ret;
+}
+
+void litehtml::html_tag::on_click()
+{
+	if (have_parent())
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			el_parent->on_click();
+		}
+	}
+}
+
+const litehtml::tchar_t* litehtml::html_tag::get_cursor()
+{
+	return get_style_property(_t("cursor"), true, 0);
+}
+
+static const int font_size_table[8][7] =
+{
+	{ 9,    9,     9,     9,    11,    14,    18},
+	{ 9,    9,     9,    10,    12,    15,    20},
+	{ 9,    9,     9,    11,    13,    17,    22},
+	{ 9,    9,    10,    12,    14,    18,    24},
+	{ 9,    9,    10,    13,    16,    20,    26},
+	{ 9,    9,    11,    14,    17,    21,    28},
+	{ 9,   10,    12,    15,    17,    23,    30},
+	{ 9,   10,    13,    16,    18,    24,    32}
+};
+
+
+void litehtml::html_tag::init_font()
+{
+	// initialize font size
+	const tchar_t* str = get_style_property(_t("font-size"), false, 0);
+
+	int parent_sz = 0;
+	int doc_font_size = get_document()->container()->get_default_font_size();
+	element::ptr el_parent = parent();
+	if (el_parent)
+	{
+		parent_sz = el_parent->get_font_size();
+	} else
+	{
+		parent_sz = doc_font_size;
+	}
+
+
+	if(!str)
+	{
+		m_font_size = parent_sz;
+	} else
+	{
+		m_font_size = parent_sz;
+
+		css_length sz;
+		sz.fromString(str, font_size_strings);
+		if(sz.is_predefined())
+		{
+			int idx_in_table = doc_font_size - 9;
+			if(idx_in_table >= 0 && idx_in_table <= 7)
+			{
+				if(sz.predef() >= fontSize_xx_small && sz.predef() <= fontSize_xx_large)
+				{
+					m_font_size = font_size_table[idx_in_table][sz.predef()];
+				} else
+				{
+					m_font_size = doc_font_size;
+				}
+			} else			
+			{
+				switch(sz.predef())
+				{
+				case fontSize_xx_small:
+					m_font_size = doc_font_size * 3 / 5;
+					break;
+				case fontSize_x_small:
+					m_font_size = doc_font_size * 3 / 4;
+					break;
+				case fontSize_small:
+					m_font_size = doc_font_size * 8 / 9;
+					break;
+				case fontSize_large:
+					m_font_size = doc_font_size * 6 / 5;
+					break;
+				case fontSize_x_large:
+					m_font_size = doc_font_size * 3 / 2;
+					break;
+				case fontSize_xx_large:
+					m_font_size = doc_font_size * 2;
+					break;
+				default:
+					m_font_size = doc_font_size;
+					break;
+				}
+			}
+		} else
+		{
+			if(sz.units() == css_units_percentage)
+			{
+				m_font_size = sz.calc_percent(parent_sz);
+			} else if(sz.units() == css_units_none)
+			{
+				m_font_size = parent_sz;
+			} else
+			{
+				m_font_size = get_document()->cvt_units(sz, parent_sz);
+			}
+		}
+	}
+
+	// initialize font
+	const tchar_t* name			= get_style_property(_t("font-family"),		true,	_t("inherit"));
+	const tchar_t* weight		= get_style_property(_t("font-weight"),		true,	_t("normal"));
+	const tchar_t* style		= get_style_property(_t("font-style"),		true,	_t("normal"));
+	const tchar_t* decoration	= get_style_property(_t("text-decoration"),	true,	_t("none"));
+
+	m_font = get_document()->get_font(name, m_font_size, weight, style, decoration, &m_font_metrics);
+}
+
+bool litehtml::html_tag::is_break() const
+{
+	return false;
+}
+
+void litehtml::html_tag::set_tagName( const tchar_t* tag )
+{
+	tstring s_val = tag;
+	std::locale lc = std::locale::global(std::locale::classic());
+	for(size_t i = 0; i < s_val.length(); i++)
+	{
+		s_val[i] = std::tolower(s_val[i], lc);
+	}
+	m_tag = s_val;
+}
+
+void litehtml::html_tag::draw_background( uint_ptr hdc, int x, int y, const position* clip )
+{
+	position pos = m_pos;
+	pos.x	+= x;
+	pos.y	+= y;
+
+	position el_pos = pos;
+	el_pos += m_padding;
+	el_pos += m_borders;
+
+	if(m_display != display_inline && m_display != display_table_row)
+	{
+		if(el_pos.does_intersect(clip))
+		{
+			const background* bg = get_background();
+			if(bg)
+			{
+				background_paint bg_paint;
+				init_background_paint(pos, bg_paint, bg);
+
+				get_document()->container()->draw_background(hdc, bg_paint);
+			}
+			position border_box = pos;
+			border_box += m_padding;
+			border_box += m_borders;
+
+			borders bdr = m_css_borders;
+			bdr.radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
+
+			get_document()->container()->draw_borders(hdc, bdr, border_box, have_parent() ? false : true);
+		}
+	} else
+	{
+		const background* bg = get_background();
+
+		position::vector boxes;
+		get_inline_boxes(boxes);
+
+		background_paint bg_paint;
+		position content_box;
+
+		for(position::vector::iterator box = boxes.begin(); box != boxes.end(); box++)
+		{
+			box->x	+= x;
+			box->y	+= y;
+
+			if(box->does_intersect(clip))
+			{
+				content_box = *box;
+				content_box -= m_borders;
+				content_box -= m_padding;
+
+				if(bg)
+				{
+					init_background_paint(content_box, bg_paint, bg);
+				}
+
+				css_borders bdr;
+
+				// set left borders radius for the first box
+				if(box == boxes.begin())
+				{
+					bdr.radius.bottom_left_x	= m_css_borders.radius.bottom_left_x;
+					bdr.radius.bottom_left_y	= m_css_borders.radius.bottom_left_y;
+					bdr.radius.top_left_x		= m_css_borders.radius.top_left_x;
+					bdr.radius.top_left_y		= m_css_borders.radius.top_left_y;
+				}
+
+				// set right borders radius for the last box
+				if(box == boxes.end() - 1)
+				{
+					bdr.radius.bottom_right_x	= m_css_borders.radius.bottom_right_x;
+					bdr.radius.bottom_right_y	= m_css_borders.radius.bottom_right_y;
+					bdr.radius.top_right_x		= m_css_borders.radius.top_right_x;
+					bdr.radius.top_right_y		= m_css_borders.radius.top_right_y;
+				}
+
+				
+				bdr.top		= m_css_borders.top;
+				bdr.bottom	= m_css_borders.bottom;
+				if(box == boxes.begin())
+				{
+					bdr.left	= m_css_borders.left;
+				}
+				if(box == boxes.end() - 1)
+				{
+					bdr.right	= m_css_borders.right;
+				}
+
+
+				if(bg)
+				{
+					bg_paint.border_radius = bdr.radius.calc_percents(bg_paint.border_box.width, bg_paint.border_box.width);
+					get_document()->container()->draw_background(hdc, bg_paint);
+				}
+				borders b = bdr;
+				b.radius = bdr.radius.calc_percents(box->width, box->height);
+				get_document()->container()->draw_borders(hdc, b, *box, false);
+			}
+		}
+	}
+}
+
+int litehtml::html_tag::render_inline(const element::ptr &container, int max_width)
+{
+	int ret_width = 0;
+	int rw = 0;
+
+	white_space ws = get_white_space();
+	bool skip_spaces = false;
+	if (ws == white_space_normal ||
+		ws == white_space_nowrap ||
+		ws == white_space_pre_line)
+	{
+		skip_spaces = true;
+	}
+	bool was_space = false;
+
+	for (auto& el : m_children)
+	{
+		// skip spaces to make rendering a bit faster
+		if (skip_spaces)
+		{
+			if (el->is_white_space())
+			{
+				if (was_space)
+				{
+					el->skip(true);
+					continue;
+				}
+				else
+				{
+					was_space = true;
+				}
+			}
+			else
+			{
+				was_space = false;
+			}
+		}
+
+		rw = container->place_element( el, max_width );
+		if(rw > ret_width)
+		{
+			ret_width = rw;
+		}
+	}
+	return ret_width;
+}
+
+int litehtml::html_tag::place_element(const element::ptr &el, int max_width)
+{
+	if(el->get_display() == display_none) return 0;
+
+	if(el->get_display() == display_inline)
+	{
+		return el->render_inline(shared_from_this(), max_width);
+	}
+
+	element_position el_position = el->get_element_position();
+
+	if(el_position == element_position_absolute || el_position == element_position_fixed)
+	{
+		int line_top = 0;
+		if(!m_boxes.empty())
+		{
+			if(m_boxes.back()->get_type() == box_line)
+			{
+				line_top = m_boxes.back()->top();
+				if(!m_boxes.back()->is_empty())
+				{
+					line_top += line_height();
+				}
+			} else
+			{
+				line_top = m_boxes.back()->bottom();
+			}
+		}
+
+		el->render(0, line_top, max_width);
+		el->m_pos.x	+= el->content_margins_left();
+		el->m_pos.y	+= el->content_margins_top();
+
+		return 0;
+	}
+
+	int ret_width = 0;
+
+	switch(el->get_float())
+	{
+	case float_left:
+		{
+			int line_top = 0;
+			if(!m_boxes.empty())
+			{
+				if(m_boxes.back()->get_type() == box_line)
+				{
+					line_top = m_boxes.back()->top();
+				} else
+				{
+					line_top = m_boxes.back()->bottom();
+				}
+			}
+			line_top		= get_cleared_top(el, line_top);
+			int line_left	= 0;
+			int line_right	= max_width;
+			get_line_left_right(line_top, max_width, line_left, line_right);
+
+			el->render(line_left, line_top, line_right);
+			if(el->right() > line_right)
+			{
+				int new_top = find_next_line_top(el->top(), el->width(), max_width);
+				el->m_pos.x = get_line_left(new_top) + el->content_margins_left();
+				el->m_pos.y = new_top + el->content_margins_top();
+			}
+			add_float(el, 0, 0);
+			ret_width = fix_line_width(max_width, float_left);
+			if(!ret_width)
+			{
+				ret_width = el->right();
+			}
+		}
+		break;
+	case float_right:
+		{
+			int line_top = 0;
+			if(!m_boxes.empty())
+			{
+				if(m_boxes.back()->get_type() == box_line)
+				{
+					line_top = m_boxes.back()->top();
+				} else
+				{
+					line_top = m_boxes.back()->bottom();
+				}
+			}
+			line_top		= get_cleared_top(el, line_top);
+			int line_left	= 0;
+			int line_right	= max_width;
+			get_line_left_right(line_top, max_width, line_left, line_right);
+
+			el->render(0, line_top, line_right);
+
+			if(line_left + el->width() > line_right)
+			{
+				int new_top = find_next_line_top(el->top(), el->width(), max_width);
+				el->m_pos.x = get_line_right(new_top, max_width) - el->width() + el->content_margins_left();
+				el->m_pos.y = new_top + el->content_margins_top();
+			} else
+			{
+				el->m_pos.x = line_right - el->width() + el->content_margins_left();
+			}
+			add_float(el, 0, 0);
+			ret_width = fix_line_width(max_width, float_right);
+
+			if(!ret_width)
+			{
+				line_left	= 0;
+				line_right	= max_width;
+				get_line_left_right(line_top, max_width, line_left, line_right);
+
+				ret_width = ret_width + (max_width - line_right);
+			}
+		}
+		break;
+	default:
+		{
+			line_context line_ctx;
+			line_ctx.top = 0;
+			if (!m_boxes.empty())
+			{
+				line_ctx.top = m_boxes.back()->top();
+			}
+			line_ctx.left = 0;
+			line_ctx.right = max_width;
+			line_ctx.fix_top();
+			get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
+
+			switch(el->get_display())
+			{
+			case display_inline_block:
+				ret_width = el->render(line_ctx.left, line_ctx.top, line_ctx.right);
+				break;
+			case display_block:		
+				if(el->is_replaced() || el->is_floats_holder())
+				{
+					element::ptr el_parent = el->parent();
+					el->m_pos.width = el->get_css_width().calc_percent(line_ctx.right - line_ctx.left);
+					el->m_pos.height = el->get_css_height().calc_percent(el_parent ? el_parent->m_pos.height : 0);
+				}
+				el->calc_outlines(line_ctx.right - line_ctx.left);
+				break;
+			case display_inline_text:
+				{
+					litehtml::size sz;
+					el->get_content_size(sz, line_ctx.right);
+					el->m_pos = sz;
+				}
+				break;
+			default:
+				ret_width = 0;
+				break;
+			}
+
+			bool add_box = true;
+			if(!m_boxes.empty())
+			{
+				if(m_boxes.back()->can_hold(el, m_white_space))
+				{
+					add_box = false;
+				}
+			}
+			if(add_box)
+			{
+				new_box(el, max_width, line_ctx);
+			} else if(!m_boxes.empty())
+			{
+				line_ctx.top = m_boxes.back()->top();
+			}
+
+			if (line_ctx.top != line_ctx.calculatedTop)
+			{
+				line_ctx.left = 0;
+				line_ctx.right = max_width;
+				line_ctx.fix_top();
+				get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
+			}
+
+			if(!el->is_inline_box())
+			{
+				if(m_boxes.size() == 1)
+				{
+					if(collapse_top_margin())
+					{
+						int shift = el->margin_top();
+						if(shift >= 0)
+						{
+							line_ctx.top -= shift;
+							m_boxes.back()->y_shift(-shift);
+						}
+					}
+				} else
+				{
+					int shift = 0;
+					int prev_margin = m_boxes[m_boxes.size() - 2]->bottom_margin();
+
+					if(prev_margin > el->margin_top())
+					{
+						shift = el->margin_top();
+					} else
+					{
+						shift = prev_margin;
+					}
+					if(shift >= 0)
+					{
+						line_ctx.top -= shift;
+						m_boxes.back()->y_shift(-shift);
+					}
+				}
+			}
+
+			switch(el->get_display())
+			{
+			case display_table:
+			case display_list_item:
+				ret_width = el->render(line_ctx.left, line_ctx.top, line_ctx.width());
+				break;
+			case display_block:
+			case display_table_cell:
+			case display_table_caption:
+			case display_table_row:
+				if(el->is_replaced() || el->is_floats_holder())
+				{
+					ret_width = el->render(line_ctx.left, line_ctx.top, line_ctx.width()) + line_ctx.left + (max_width - line_ctx.right);
+				} else
+				{
+					ret_width = el->render(0, line_ctx.top, max_width);
+				}
+				break;
+			default:
+				ret_width = 0;
+				break;
+			}
+
+			m_boxes.back()->add_element(el);
+
+			if(el->is_inline_box() && !el->skip())
+			{
+				ret_width = el->right() + (max_width - line_ctx.right);
+			}
+		}
+		break;
+	}
+
+	return ret_width;
+}
+
+bool litehtml::html_tag::set_pseudo_class( const tchar_t* pclass, bool add )
+{
+	bool ret = false;
+	if(add)
+	{
+		if(std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), pclass) == m_pseudo_classes.end())
+		{
+			m_pseudo_classes.push_back(pclass);
+			ret = true;
+		}
+	} else
+	{
+		string_vector::iterator pi = std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), pclass);
+		if(pi != m_pseudo_classes.end())
+		{
+			m_pseudo_classes.erase(pi);
+			ret = true;
+		}
+	}
+	return ret;
+}
+
+bool litehtml::html_tag::set_class( const tchar_t* pclass, bool add )
+{
+	string_vector classes;
+	bool changed = false;
+
+	split_string( pclass, classes, _t(" ") );
+
+	if(add)
+	{
+		for( auto & _class : classes  )
+		{
+			if(std::find(m_class_values.begin(), m_class_values.end(), _class) == m_class_values.end())
+			{
+				m_class_values.push_back( std::move( _class ) );
+				changed = true;
+			}
+		}
+	} else
+	{
+		for( const auto & _class : classes )
+		{
+			auto end = std::remove(m_class_values.begin(), m_class_values.end(), _class);
+
+			if(end != m_class_values.end())
+			{
+				m_class_values.erase(end, m_class_values.end());
+				changed = true;
+			}
+		}
+	}
+
+	if( changed )
+	{
+		tstring class_string;
+		join_string(class_string, m_class_values, _t(" "));
+		set_attr(_t("class"), class_string.c_str());
+
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+
+}
+
+int litehtml::html_tag::line_height() const
+{
+	return m_line_height;
+}
+
+bool litehtml::html_tag::is_replaced() const
+{
+	return false;
+}
+
+int litehtml::html_tag::finish_last_box(bool end_of_render)
+{
+	int line_top = 0;
+
+	if(!m_boxes.empty())
+	{
+		m_boxes.back()->finish(end_of_render);
+
+		if(m_boxes.back()->is_empty())
+		{
+			line_top = m_boxes.back()->top();
+			m_boxes.pop_back();
+		}
+
+		if(!m_boxes.empty())
+		{
+			line_top = m_boxes.back()->bottom();
+		}
+	}
+	return line_top;
+}
+
+int litehtml::html_tag::new_box(const element::ptr &el, int max_width, line_context& line_ctx)
+{
+	line_ctx.top = get_cleared_top(el, finish_last_box());
+
+	line_ctx.left = 0;
+	line_ctx.right = max_width;
+	line_ctx.fix_top();
+	get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
+
+	if(el->is_inline_box() || el->is_floats_holder())
+	{
+		if (el->width() > line_ctx.right - line_ctx.left)
+		{
+			line_ctx.top = find_next_line_top(line_ctx.top, el->width(), max_width);
+			line_ctx.left = 0;
+			line_ctx.right = max_width;
+			line_ctx.fix_top();
+			get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
+		}
+	}
+
+	int first_line_margin = 0;
+	if(m_boxes.empty() && m_list_style_type != list_style_type_none && m_list_style_position == list_style_position_inside)
+	{
+		int sz_font = get_font_size();
+		first_line_margin = sz_font;
+	}
+
+	if(el->is_inline_box())
+	{
+		int text_indent = 0;
+		if(m_css_text_indent.val() != 0)
+		{
+			bool line_box_found = false;
+			for(box::vector::iterator iter = m_boxes.begin(); iter != m_boxes.end(); iter++)
+			{
+				if((*iter)->get_type() == box_line)
+				{
+					line_box_found = true;
+					break;
+				}
+			}
+			if(!line_box_found)
+			{
+				text_indent = m_css_text_indent.calc_percent(max_width);
+			}
+		}
+
+		font_metrics fm;
+		get_font(&fm);
+		m_boxes.emplace_back(std::unique_ptr<line_box>(new line_box(line_ctx.top, line_ctx.left + first_line_margin + text_indent, line_ctx.right, line_height(), fm, m_text_align)));
+	} else
+	{
+		m_boxes.emplace_back(std::unique_ptr<block_box>(new block_box(line_ctx.top, line_ctx.left, line_ctx.right)));
+	}
+
+	return line_ctx.top;
+}
+
+int litehtml::html_tag::get_cleared_top(const element::ptr &el, int line_top) const
+{
+	switch(el->get_clear())
+	{
+	case clear_left:
+		{
+			int fh = get_left_floats_height();
+			if(fh && fh > line_top)
+			{
+				line_top = fh;
+			}
+		}
+		break;
+	case clear_right:
+		{
+			int fh = get_right_floats_height();
+			if(fh && fh > line_top)
+			{
+				line_top = fh;
+			}
+		}
+		break;
+	case clear_both:
+		{
+			int fh = get_floats_height();
+			if(fh && fh > line_top)
+			{
+				line_top = fh;
+			}
+		}
+		break;
+	default:
+		if(el->get_float() != float_none)
+		{
+			int fh = get_floats_height(el->get_float());
+			if(fh && fh > line_top)
+			{
+				line_top = fh;
+			}
+		}
+		break;
+	}
+	return line_top;
+}
+
+litehtml::style_display litehtml::html_tag::get_display() const
+{
+	return m_display;
+}
+
+litehtml::element_float litehtml::html_tag::get_float() const
+{
+	return m_float;
+}
+
+bool litehtml::html_tag::is_floats_holder() const
+{
+	if(	m_display == display_inline_block || 
+		m_display == display_table_cell || 
+		!have_parent() ||
+		is_body() || 
+		m_float != float_none ||
+		m_el_position == element_position_absolute ||
+		m_el_position == element_position_fixed ||
+		m_overflow > overflow_visible)
+	{
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::html_tag::is_first_child_inline(const element::ptr& el) const
+{
+	if(!m_children.empty())
+	{
+		for (const auto& this_el : m_children)
+		{
+			if (!this_el->is_white_space())
+			{
+				if (el == this_el)
+				{
+					return true;
+				}
+				if (this_el->get_display() == display_inline)
+				{
+					if (this_el->have_inline_child())
+					{
+						return false;
+					}
+				} else
+				{
+					return false;
+				}
+			}
+		}
+	}
+	return false;
+}
+
+bool litehtml::html_tag::is_last_child_inline(const element::ptr& el)
+{
+	if(!m_children.empty())
+	{
+		for (auto this_el = m_children.rbegin(); this_el < m_children.rend(); ++this_el)
+		{
+			if (!(*this_el)->is_white_space())
+			{
+				if (el == (*this_el))
+				{
+					return true;
+				}
+				if ((*this_el)->get_display() == display_inline)
+				{
+					if ((*this_el)->have_inline_child())
+					{
+						return false;
+					}
+				} else
+				{
+					return false;
+				}
+			}
+		}
+	}
+	return false;
+}
+
+litehtml::white_space litehtml::html_tag::get_white_space() const
+{
+	return m_white_space;
+}
+
+litehtml::vertical_align litehtml::html_tag::get_vertical_align() const
+{
+	return m_vertical_align;
+}
+
+litehtml::css_length litehtml::html_tag::get_css_left() const
+{
+	return m_css_offsets.left;
+}
+
+litehtml::css_length litehtml::html_tag::get_css_right() const
+{
+	return m_css_offsets.right;
+}
+
+litehtml::css_length litehtml::html_tag::get_css_top() const
+{
+	return m_css_offsets.top;
+}
+
+litehtml::css_length litehtml::html_tag::get_css_bottom() const
+{
+	return m_css_offsets.bottom;
+}
+
+
+litehtml::css_offsets litehtml::html_tag::get_css_offsets() const
+{
+	return m_css_offsets;
+}
+
+litehtml::element_clear litehtml::html_tag::get_clear() const
+{
+	return m_clear;
+}
+
+litehtml::css_length litehtml::html_tag::get_css_width() const
+{
+	return m_css_width;
+}
+
+litehtml::css_length litehtml::html_tag::get_css_height() const
+{
+	return m_css_height;
+}
+
+size_t litehtml::html_tag::get_children_count() const
+{
+	return m_children.size();
+}
+
+litehtml::element::ptr litehtml::html_tag::get_child( int idx ) const
+{
+	return m_children[idx];
+}
+
+void litehtml::html_tag::set_css_width( css_length& w )
+{
+	m_css_width = w;
+}
+
+void litehtml::html_tag::apply_vertical_align()
+{
+	if(!m_boxes.empty())
+	{
+		int add = 0;
+		int content_height	= m_boxes.back()->bottom();
+
+		if(m_pos.height > content_height)
+		{
+			switch(m_vertical_align)
+			{
+			case va_middle:
+				add = (m_pos.height - content_height) / 2;
+				break;
+			case va_bottom:
+				add = m_pos.height - content_height;
+				break;
+			default:
+				add = 0;
+				break;
+			}
+		}
+
+		if(add)
+		{
+			for(size_t i = 0; i < m_boxes.size(); i++)
+			{
+				m_boxes[i]->y_shift(add);
+			}
+		}
+	}
+}
+
+litehtml::element_position litehtml::html_tag::get_element_position(css_offsets* offsets) const
+{
+	if(offsets && m_el_position != element_position_static)
+	{
+		*offsets = m_css_offsets;
+	}
+	return m_el_position;
+}
+
+void litehtml::html_tag::init_background_paint(position pos, background_paint &bg_paint, const background* bg)
+{
+	if(!bg) return;
+
+	bg_paint = *bg;
+	position content_box	= pos;
+	position padding_box	= pos;
+	padding_box += m_padding;
+	position border_box		= padding_box;
+	border_box += m_borders;
+
+	switch(bg->m_clip)
+	{
+	case litehtml::background_box_padding:
+		bg_paint.clip_box = padding_box;
+		break;
+	case litehtml::background_box_content:
+		bg_paint.clip_box = content_box;
+		break;
+	default:
+		bg_paint.clip_box = border_box;
+		break;
+	}
+
+	switch(bg->m_origin)
+	{
+	case litehtml::background_box_border:
+		bg_paint.origin_box = border_box;
+		break;
+	case litehtml::background_box_content:
+		bg_paint.origin_box = content_box;
+		break;
+	default:
+		bg_paint.origin_box = padding_box;
+		break;
+	}
+
+	if(!bg_paint.image.empty())
+	{
+		get_document()->container()->get_image_size(bg_paint.image.c_str(), bg_paint.baseurl.c_str(), bg_paint.image_size);
+		if(bg_paint.image_size.width && bg_paint.image_size.height)
+		{
+			litehtml::size img_new_sz = bg_paint.image_size;
+			double img_ar_width		= (double) bg_paint.image_size.width / (double) bg_paint.image_size.height;
+			double img_ar_height	= (double) bg_paint.image_size.height / (double) bg_paint.image_size.width;
+
+
+			if(bg->m_position.width.is_predefined())
+			{
+				switch(bg->m_position.width.predef())
+				{
+				case litehtml::background_size_contain:
+					if( (int) ((double) bg_paint.origin_box.width * img_ar_height) <= bg_paint.origin_box.height )
+					{
+						img_new_sz.width = bg_paint.origin_box.width;
+						img_new_sz.height	= (int) ((double) bg_paint.origin_box.width * img_ar_height);
+					} else
+					{
+						img_new_sz.height = bg_paint.origin_box.height;
+						img_new_sz.width	= (int) ((double) bg_paint.origin_box.height * img_ar_width);
+					}
+					break;
+				case litehtml::background_size_cover:
+					if( (int) ((double) bg_paint.origin_box.width * img_ar_height) >= bg_paint.origin_box.height )
+					{
+						img_new_sz.width = bg_paint.origin_box.width;
+						img_new_sz.height	= (int) ((double) bg_paint.origin_box.width * img_ar_height);
+					} else
+					{
+						img_new_sz.height = bg_paint.origin_box.height;
+						img_new_sz.width	= (int) ((double) bg_paint.origin_box.height * img_ar_width);
+					}
+					break;
+					break;
+				case litehtml::background_size_auto:
+					if(!bg->m_position.height.is_predefined())
+					{
+						img_new_sz.height	= bg->m_position.height.calc_percent(bg_paint.origin_box.height);
+						img_new_sz.width	= (int) ((double) img_new_sz.height * img_ar_width);
+					}
+					break;
+				}
+			} else
+			{
+				img_new_sz.width = bg->m_position.width.calc_percent(bg_paint.origin_box.width);
+				if(bg->m_position.height.is_predefined())
+				{
+					img_new_sz.height = (int) ((double) img_new_sz.width * img_ar_height);
+				} else
+				{
+					img_new_sz.height = bg->m_position.height.calc_percent(bg_paint.origin_box.height);
+				}
+			}
+
+			bg_paint.image_size = img_new_sz;
+			bg_paint.position_x = bg_paint.origin_box.x + (int) bg->m_position.x.calc_percent(bg_paint.origin_box.width - bg_paint.image_size.width);
+			bg_paint.position_y = bg_paint.origin_box.y + (int) bg->m_position.y.calc_percent(bg_paint.origin_box.height - bg_paint.image_size.height);
+		}
+
+	}
+	bg_paint.border_radius	= m_css_borders.radius.calc_percents(border_box.width, border_box.height);;
+	bg_paint.border_box		= border_box;
+	bg_paint.is_root		= have_parent() ? false : true;
+}
+
+litehtml::visibility litehtml::html_tag::get_visibility() const
+{
+	return m_visibility;
+}
+
+void litehtml::html_tag::draw_list_marker( uint_ptr hdc, const position &pos )
+{
+	list_marker lm;
+
+	const tchar_t* list_image = get_style_property(_t("list-style-image"), true, 0);
+	size img_size;
+	if(list_image)
+	{
+		css::parse_css_url(list_image, lm.image);
+		lm.baseurl = get_style_property(_t("list-style-image-baseurl"), true, 0);
+		get_document()->container()->get_image_size(lm.image.c_str(), lm.baseurl, img_size);
+	} else
+	{
+		lm.baseurl = 0;
+	}
+
+
+	int ln_height	= line_height();
+	int sz_font		= get_font_size();
+	lm.pos.x		= pos.x;
+	lm.pos.width	= sz_font	- sz_font * 2 / 3;
+	lm.pos.height	= sz_font	- sz_font * 2 / 3;
+	lm.pos.y		= pos.y		+ ln_height / 2 - lm.pos.height / 2;
+
+	if(img_size.width && img_size.height)
+	{
+		if(lm.pos.y + img_size.height > pos.y + pos.height)
+		{
+			lm.pos.y = pos.y + pos.height - img_size.height;
+		}
+		if(img_size.width > lm.pos.width)
+		{
+			lm.pos.x -= img_size.width - lm.pos.width;
+		}
+
+		lm.pos.width	= img_size.width;
+		lm.pos.height	= img_size.height;
+	}
+	if(m_list_style_position == list_style_position_outside)
+	{
+		lm.pos.x -= sz_font;
+	}
+
+	lm.color = get_color(_t("color"), true, web_color(0, 0, 0));
+	lm.marker_type = m_list_style_type;
+	get_document()->container()->draw_list_marker(hdc, lm);
+}
+
+void litehtml::html_tag::draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex )
+{
+	if (m_display == display_table || m_display == display_inline_table)
+	{
+		draw_children_table(hdc, x, y, clip, flag, zindex);
+	}
+	else
+	{
+		draw_children_box(hdc, x, y, clip, flag, zindex);
+	}
+}
+
+bool litehtml::html_tag::fetch_positioned()
+{
+	bool ret = false;
+
+	m_positioned.clear();
+
+	litehtml::element_position el_pos;
+
+	for(auto& el : m_children)
+	{
+		el_pos = el->get_element_position();
+		if (el_pos != element_position_static)
+		{
+			add_positioned(el);
+		}
+		if (!ret && (el_pos == element_position_absolute || el_pos == element_position_fixed))
+		{
+			ret = true;
+		}
+		if(el->fetch_positioned())
+		{
+			ret = true;
+		}
+	}
+	return ret;
+}
+
+int litehtml::html_tag::get_zindex() const
+{
+	return m_z_index;
+}
+
+void litehtml::html_tag::render_positioned(render_type rt)
+{
+	position wnd_position;
+	get_document()->container()->get_client_rect(wnd_position);
+
+	element_position el_position;
+	bool process;
+	for (auto& el : m_positioned)
+	{
+		el_position = el->get_element_position();
+
+		process = false;
+		if(el->get_display() != display_none)
+		{
+			if(el_position == element_position_absolute)
+			{
+				if(rt != render_fixed_only)
+				{
+					process = true;
+				}
+			} else if(el_position == element_position_fixed)
+			{
+				if(rt != render_no_fixed)
+				{
+					process = true;
+				}
+			}
+		}
+
+		if(process)
+		{
+			int parent_height	= 0;
+			int parent_width	= 0;
+			int client_x		= 0;
+			int client_y		= 0;
+			if(el_position == element_position_fixed)
+			{
+				parent_height	= wnd_position.height;
+				parent_width	= wnd_position.width;
+				client_x		= wnd_position.left();
+				client_y		= wnd_position.top();
+			} else
+			{
+				element::ptr el_parent = el->parent();
+				if(el_parent)
+				{
+					parent_height	= el_parent->height();
+					parent_width	= el_parent->width();
+				}
+			}
+
+			css_length	css_left	= el->get_css_left();
+			css_length	css_right	= el->get_css_right();
+			css_length	css_top		= el->get_css_top();
+			css_length	css_bottom	= el->get_css_bottom();
+
+			bool need_render = false;
+
+			css_length el_w = el->get_css_width();
+			css_length el_h = el->get_css_height();
+
+            int new_width = -1;
+            int new_height = -1;
+			if(el_w.units() == css_units_percentage && parent_width)
+			{
+                new_width = el_w.calc_percent(parent_width);
+                if(el->m_pos.width != new_width)
+				{
+					need_render = true;
+                    el->m_pos.width = new_width;
+				}
+			}
+
+			if(el_h.units() == css_units_percentage && parent_height)
+			{
+                new_height = el_h.calc_percent(parent_height);
+                if(el->m_pos.height != new_height)
+				{
+					need_render = true;
+                    el->m_pos.height = new_height;
+				}
+			}
+
+			bool cvt_x = false;
+			bool cvt_y = false;
+
+			if(el_position == element_position_fixed)
+			{
+				if(!css_left.is_predefined() || !css_right.is_predefined())
+				{
+					if(!css_left.is_predefined() && css_right.is_predefined())
+					{
+						el->m_pos.x = css_left.calc_percent(parent_width) + el->content_margins_left();
+					} else if(css_left.is_predefined() && !css_right.is_predefined())
+					{
+						el->m_pos.x = parent_width - css_right.calc_percent(parent_width) - el->m_pos.width - el->content_margins_right();
+					} else
+					{
+						el->m_pos.x		= css_left.calc_percent(parent_width) + el->content_margins_left();
+						el->m_pos.width	= parent_width - css_left.calc_percent(parent_width) - css_right.calc_percent(parent_width) - (el->content_margins_left() + el->content_margins_right());
+						need_render = true;
+					}
+				}
+
+				if(!css_top.is_predefined() || !css_bottom.is_predefined())
+				{
+					if(!css_top.is_predefined() && css_bottom.is_predefined())
+					{
+						el->m_pos.y = css_top.calc_percent(parent_height) + el->content_margins_top();
+					} else if(css_top.is_predefined() && !css_bottom.is_predefined())
+					{
+						el->m_pos.y = parent_height - css_bottom.calc_percent(parent_height) - el->m_pos.height - el->content_margins_bottom();
+					} else
+					{
+						el->m_pos.y			= css_top.calc_percent(parent_height) + el->content_margins_top();
+						el->m_pos.height	= parent_height - css_top.calc_percent(parent_height) - css_bottom.calc_percent(parent_height) - (el->content_margins_top() + el->content_margins_bottom());
+						need_render = true;
+					}
+				}
+			} else 
+			{
+				if(!css_left.is_predefined() || !css_right.is_predefined())
+				{
+					if(!css_left.is_predefined() && css_right.is_predefined())
+					{
+						el->m_pos.x = css_left.calc_percent(parent_width) + el->content_margins_left() - m_padding.left;
+					} else if(css_left.is_predefined() && !css_right.is_predefined())
+					{
+						el->m_pos.x = m_pos.width + m_padding.right - css_right.calc_percent(parent_width) - el->m_pos.width - el->content_margins_right();
+					} else
+					{
+						el->m_pos.x		= css_left.calc_percent(parent_width) + el->content_margins_left() - m_padding.left;
+						el->m_pos.width	= m_pos.width + m_padding.left + m_padding.right - css_left.calc_percent(parent_width) - css_right.calc_percent(parent_width) - (el->content_margins_left() + el->content_margins_right());
+                        if (new_width != -1)
+                        {
+                            el->m_pos.x += (el->m_pos.width - new_width) / 2;
+                            el->m_pos.width = new_width;
+                        }
+                        need_render = true;
+					}
+					cvt_x = true;
+				}
+
+				if(!css_top.is_predefined() || !css_bottom.is_predefined())
+				{
+					if(!css_top.is_predefined() && css_bottom.is_predefined())
+					{
+						el->m_pos.y = css_top.calc_percent(parent_height) + el->content_margins_top() - m_padding.top;
+					} else if(css_top.is_predefined() && !css_bottom.is_predefined())
+					{
+						el->m_pos.y = m_pos.height + m_padding.bottom - css_bottom.calc_percent(parent_height) - el->m_pos.height - el->content_margins_bottom();
+					} else
+					{
+						el->m_pos.y			= css_top.calc_percent(parent_height) + el->content_margins_top() - m_padding.top;
+						el->m_pos.height	= m_pos.height + m_padding.top + m_padding.bottom - css_top.calc_percent(parent_height) - css_bottom.calc_percent(parent_height) - (el->content_margins_top() + el->content_margins_bottom());
+                        if (new_height != -1)
+                        {
+                            el->m_pos.y += (el->m_pos.height - new_height) / 2;
+                            el->m_pos.height = new_height;
+                        }
+                        need_render = true;
+					}
+					cvt_y = true;
+				}
+			}
+
+			if(cvt_x || cvt_y)
+			{
+				int offset_x = 0;
+				int offset_y = 0;
+				element::ptr cur_el = el->parent();
+				element::ptr this_el = shared_from_this();
+				while(cur_el && cur_el != this_el)
+				{
+					offset_x += cur_el->m_pos.x;
+					offset_y += cur_el->m_pos.y;
+					cur_el = cur_el->parent();
+				}
+				if(cvt_x)	el->m_pos.x -= offset_x;
+				if(cvt_y)	el->m_pos.y -= offset_y;
+			}
+
+			if(need_render)
+			{
+				position pos = el->m_pos;
+				el->render(el->left(), el->top(), el->width(), true);
+				el->m_pos = pos;
+			}
+
+			if(el_position == element_position_fixed)
+			{
+				position fixed_pos;
+				el->get_redraw_box(fixed_pos);
+				get_document()->add_fixed_box(fixed_pos);
+			}
+		}
+
+		el->render_positioned();
+	}
+
+	if(!m_positioned.empty())
+	{
+		std::stable_sort(m_positioned.begin(), m_positioned.end(), [](const litehtml::element::ptr& _Left, const litehtml::element::ptr& _Right)
+		{
+			return (_Left->get_zindex() < _Right->get_zindex());
+		});
+	}
+}
+
+void litehtml::html_tag::draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned )
+{
+	if(!is_visible()) return;
+
+	std::map<int, bool> zindexes;
+	if(with_positioned)
+	{
+		for(elements_vector::iterator i = m_positioned.begin(); i != m_positioned.end(); i++)
+		{
+			zindexes[(*i)->get_zindex()];
+		}
+
+		for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end(); idx++)
+		{
+			if(idx->first < 0)
+			{
+				draw_children(hdc, x, y, clip, draw_positioned, idx->first);
+			}
+		}
+	}
+	draw_children(hdc, x, y, clip, draw_block, 0);
+	draw_children(hdc, x, y, clip, draw_floats, 0);
+	draw_children(hdc, x, y, clip, draw_inlines, 0);
+	if(with_positioned)
+	{
+		for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end(); idx++)
+		{
+			if(idx->first == 0)
+			{
+				draw_children(hdc, x, y, clip, draw_positioned, idx->first);
+			}
+		}
+
+		for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end(); idx++)
+		{
+			if(idx->first > 0)
+			{
+				draw_children(hdc, x, y, clip, draw_positioned, idx->first);
+			}
+		}
+	}
+}
+
+litehtml::overflow litehtml::html_tag::get_overflow() const
+{
+	return m_overflow;
+}
+
+bool litehtml::html_tag::is_nth_child(const element::ptr& el, int num, int off, bool of_type) const
+{
+	int idx = 1;
+	for(const auto& child : m_children)
+	{
+		if(child->get_display() != display_inline_text)
+		{
+			if( (!of_type) || (of_type && !t_strcmp(el->get_tagName(), child->get_tagName())) )
+			{
+				if(el == child)
+				{
+					if(num != 0)
+					{
+						if((idx - off) >= 0 && (idx - off) % num == 0)
+						{
+							return true;
+						}
+
+					} else if(idx == off)
+					{
+						return true;
+					}
+					return false;
+				}
+				idx++;
+			}
+			if(el == child) break;
+		}
+	}
+	return false;
+}
+
+bool litehtml::html_tag::is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const
+{
+	int idx = 1;
+	for(elements_vector::const_reverse_iterator child = m_children.rbegin(); child != m_children.rend(); child++)
+	{
+		if((*child)->get_display() != display_inline_text)
+		{
+			if( !of_type || (of_type && !t_strcmp(el->get_tagName(), (*child)->get_tagName())) )
+			{
+				if(el == (*child))
+				{
+					if(num != 0)
+					{
+						if((idx - off) >= 0 && (idx - off) % num == 0)
+						{
+							return true;
+						}
+
+					} else if(idx == off)
+					{
+						return true;
+					}
+					return false;
+				}
+				idx++;
+			}
+			if(el == (*child)) break;
+		}
+	}
+	return false;
+}
+
+void litehtml::html_tag::parse_nth_child_params( tstring param, int &num, int &off )
+{
+	if(param == _t("odd"))
+	{
+		num = 2;
+		off = 1;
+	} else if(param == _t("even"))
+	{
+		num = 2;
+		off = 0;
+	} else
+	{
+		string_vector tokens;
+		split_string(param, tokens, _t(" n"), _t("n"));
+
+		tstring s_num;
+		tstring s_off;
+
+		tstring s_int;
+		for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+		{
+			if((*tok) == _t("n"))
+			{
+				s_num = s_int;
+				s_int.clear();
+			} else
+			{
+				s_int += (*tok);
+			}
+		}
+		s_off = s_int;
+
+		num = t_atoi(s_num.c_str());
+		off = t_atoi(s_off.c_str());
+	}
+}
+
+void litehtml::html_tag::calc_document_size( litehtml::size& sz, int x /*= 0*/, int y /*= 0*/ )
+{
+	if(is_visible() && m_el_position != element_position_fixed)
+	{
+		element::calc_document_size(sz, x, y);
+
+		if(m_overflow == overflow_visible)
+		{
+			for(auto& el : m_children)
+			{
+				el->calc_document_size(sz, x + m_pos.x, y + m_pos.y);
+			}
+		}
+
+		// root element (<html>) must to cover entire window
+		if(!have_parent())
+		{
+			position client_pos;
+			get_document()->container()->get_client_rect(client_pos);
+			m_pos.height = std::max(sz.height, client_pos.height) - content_margins_top() - content_margins_bottom();
+			m_pos.width	 = std::max(sz.width, client_pos.width) - content_margins_left() - content_margins_right();
+		}
+	}
+}
+
+
+void litehtml::html_tag::get_redraw_box(litehtml::position& pos, int x /*= 0*/, int y /*= 0*/)
+{
+	if(is_visible())
+	{
+		element::get_redraw_box(pos, x, y);
+
+		if(m_overflow == overflow_visible)
+		{
+			for(auto& el : m_children)
+			{
+				if(el->get_element_position() != element_position_fixed)
+				{
+					el->get_redraw_box(pos, x + m_pos.x, y + m_pos.y);
+				}
+			}
+		}
+	}
+}
+
+litehtml::element::ptr litehtml::html_tag::find_adjacent_sibling( const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/ )
+{
+	element::ptr ret;
+	for(auto& e : m_children)
+	{
+		if(e->get_display() != display_inline_text)
+		{
+			if(e == el)
+			{
+				if(ret)
+				{
+					int res = ret->select(selector, apply_pseudo);
+					if(res != select_no_match)
+					{
+						if(is_pseudo)
+						{
+							if(res & select_match_pseudo_class)
+							{
+								*is_pseudo = true;
+							} else
+							{
+								*is_pseudo = false;
+							}
+						}
+						return ret;
+					}
+				}
+				return 0;
+			} else
+			{
+				ret = e;
+			}
+		}
+	}
+	return 0;
+}
+
+litehtml::element::ptr litehtml::html_tag::find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/)
+{
+	element::ptr ret = 0;
+	for(auto& e : m_children)
+	{
+		if(e->get_display() != display_inline_text)
+		{
+			if(e == el)
+			{
+				return ret;
+			} else if(!ret)
+			{
+				int res = e->select(selector, apply_pseudo);
+				if(res != select_no_match)
+				{
+					if(is_pseudo)
+					{
+						if(res & select_match_pseudo_class)
+						{
+							*is_pseudo = true;
+						} else
+						{
+							*is_pseudo = false;
+						}
+					}
+					ret = e;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+bool litehtml::html_tag::is_only_child(const element::ptr& el, bool of_type) const
+{
+	int child_count = 0;
+	for(const auto& child : m_children)
+	{
+		if(child->get_display() != display_inline_text)
+		{
+			if( !of_type || (of_type && !t_strcmp(el->get_tagName(), child->get_tagName())) )
+			{
+				child_count++;
+			}
+			if(child_count > 1) break;
+		}
+	}
+	if(child_count > 1)
+	{
+		return false;
+	}
+	return true;
+}
+
+void litehtml::html_tag::update_floats(int dy, const element::ptr &parent)
+{
+	if(is_floats_holder())
+	{
+		bool reset_cache = false;
+		for(floated_box::vector::reverse_iterator fb = m_floats_left.rbegin(); fb != m_floats_left.rend(); fb++)
+		{
+			if(fb->el->is_ancestor(parent))
+			{
+				reset_cache	= true;
+				fb->pos.y	+= dy;
+			}
+		}
+		if(reset_cache)
+		{
+			m_cahe_line_left.invalidate();
+		}
+		reset_cache = false;
+		for(floated_box::vector::reverse_iterator fb = m_floats_right.rbegin(); fb != m_floats_right.rend(); fb++)
+		{
+			if(fb->el->is_ancestor(parent))
+			{
+				reset_cache	= true;
+				fb->pos.y	+= dy;
+			}
+		}
+		if(reset_cache)
+		{
+			m_cahe_line_right.invalidate();
+		}
+	} else
+	{
+		element::ptr el_parent = this->parent();
+		if (el_parent)
+		{
+			el_parent->update_floats(dy, parent);
+		}
+	}
+}
+
+void litehtml::html_tag::remove_before_after()
+{
+	if(!m_children.empty())
+	{
+		if( !t_strcmp(m_children.front()->get_tagName(), _t("::before")) )
+		{
+			m_children.erase(m_children.begin());
+		}
+	}
+	if(!m_children.empty())
+	{
+		if( !t_strcmp(m_children.back()->get_tagName(), _t("::after")) )
+		{
+			m_children.erase(m_children.end() - 1);
+		}
+	}
+}
+
+litehtml::element::ptr litehtml::html_tag::get_element_before()
+{
+	if(!m_children.empty())
+	{
+		if( !t_strcmp(m_children.front()->get_tagName(), _t("::before")) )
+		{
+			return m_children.front();
+		}
+	}
+	element::ptr el = std::make_shared<el_before>(get_document());
+	el->parent(shared_from_this());
+	m_children.insert(m_children.begin(), el);
+	return el;
+}
+
+litehtml::element::ptr litehtml::html_tag::get_element_after()
+{
+	if(!m_children.empty())
+	{
+		if( !t_strcmp(m_children.back()->get_tagName(), _t("::after")) )
+		{
+			return m_children.back();
+		}
+	}
+	element::ptr el = std::make_shared<el_after>(get_document());
+	appendChild(el);
+	return el;
+}
+
+void litehtml::html_tag::add_style( const litehtml::style& st )
+{
+	m_style.combine(st);
+}
+
+bool litehtml::html_tag::have_inline_child() const
+{
+	if(!m_children.empty())
+	{
+		for(const auto& el : m_children)
+		{
+			if(!el->is_white_space())
+			{
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+void litehtml::html_tag::refresh_styles()
+{
+	remove_before_after();
+
+	for (auto& el : m_children)
+	{
+		if(el->get_display() != display_inline_text)
+		{
+			el->refresh_styles();
+		}
+	}
+
+	m_style.clear();
+
+	for (auto& usel : m_used_styles)
+	{
+		usel->m_used = false;
+
+		if(usel->m_selector->is_media_valid())
+		{
+			int apply = select(*usel->m_selector, false);
+
+			if(apply != select_no_match)
+			{
+				if(apply & select_match_pseudo_class)
+				{
+					if(select(*usel->m_selector, true))
+					{
+						if(apply & select_match_with_after)
+						{
+							element::ptr el = get_element_after();
+							if(el)
+							{
+								el->add_style(*usel->m_selector->m_style);
+							}
+						} else if(apply & select_match_with_before)
+						{
+							element::ptr el = get_element_before();
+							if(el)
+							{
+								el->add_style(*usel->m_selector->m_style);
+							}
+						}
+						else
+						{
+							add_style(*usel->m_selector->m_style);
+							usel->m_used = true;
+						}
+					}
+				} else if(apply & select_match_with_after)
+				{
+					element::ptr el = get_element_after();
+					if(el)
+					{
+						el->add_style(*usel->m_selector->m_style);
+					}
+				} else if(apply & select_match_with_before)
+				{
+					element::ptr el = get_element_before();
+					if(el)
+					{
+						el->add_style(*usel->m_selector->m_style);
+					}
+				} else
+				{
+					add_style(*usel->m_selector->m_style);
+					usel->m_used = true;
+				}
+			}
+		}
+	}
+}
+
+litehtml::element::ptr litehtml::html_tag::get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex)
+{
+	element::ptr ret = 0;
+
+	if(m_overflow > overflow_visible)
+	{
+		if(!m_pos.is_point_inside(x, y))
+		{
+			return ret;
+		}
+	}
+
+	position pos = m_pos;
+	pos.x	= x - pos.x;
+	pos.y	= y - pos.y;
+
+	for(elements_vector::reverse_iterator i = m_children.rbegin(); i != m_children.rend() && !ret; i++)
+	{
+		element::ptr el = (*i);
+
+		if(el->is_visible() && el->get_display() != display_inline_text)
+		{
+			switch(flag)
+			{
+			case draw_positioned:
+				if(el->is_positioned() && el->get_zindex() == zindex)
+				{
+					if(el->get_element_position() == element_position_fixed)
+					{
+						ret = el->get_element_by_point(client_x, client_y, client_x, client_y);
+						if(!ret && (*i)->is_point_inside(client_x, client_y))
+						{
+							ret = (*i);
+						}
+					} else
+					{
+						ret = el->get_element_by_point(pos.x, pos.y, client_x, client_y);
+						if(!ret && (*i)->is_point_inside(pos.x, pos.y))
+						{
+							ret = (*i);
+						}
+					}
+					el = 0;
+				}
+				break;
+			case draw_block:
+				if(!el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
+				{
+					if(el->is_point_inside(pos.x, pos.y))
+					{
+						ret = el;
+					}
+				}
+				break;
+			case draw_floats:
+				if(el->get_float() != float_none && !el->is_positioned())
+				{
+					ret = el->get_element_by_point(pos.x, pos.y, client_x, client_y);
+
+					if(!ret && (*i)->is_point_inside(pos.x, pos.y))
+					{
+						ret = (*i);
+					}
+					el = 0;
+				}
+				break;
+			case draw_inlines:
+				if(el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
+				{
+					if(el->get_display() == display_inline_block)
+					{
+						ret = el->get_element_by_point(pos.x, pos.y, client_x, client_y);
+						el = 0;
+					}
+					if(!ret && (*i)->is_point_inside(pos.x, pos.y))
+					{
+						ret = (*i);
+					}
+				}
+				break;
+			default:
+				break;
+			}
+
+			if(el && !el->is_positioned())
+			{
+				if(flag == draw_positioned)
+				{
+					element::ptr child = el->get_child_by_point(pos.x, pos.y, client_x, client_y, flag, zindex);
+					if(child)
+					{
+						ret = child;
+					}
+				} else
+				{
+					if(	el->get_float() == float_none &&
+						el->get_display() != display_inline_block)
+					{
+						element::ptr child = el->get_child_by_point(pos.x, pos.y, client_x, client_y, flag, zindex);
+						if(child)
+						{
+							ret = child;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	return ret;
+}
+
+litehtml::element::ptr litehtml::html_tag::get_element_by_point(int x, int y, int client_x, int client_y)
+{
+	if(!is_visible()) return 0;
+
+	element::ptr ret;
+
+	std::map<int, bool> zindexes;
+
+	for(elements_vector::iterator i = m_positioned.begin(); i != m_positioned.end(); i++)
+	{
+		zindexes[(*i)->get_zindex()];
+	}
+
+	for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end() && !ret; idx++)
+	{
+		if(idx->first > 0)
+		{
+			ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, idx->first);
+		}
+	}
+	if(ret) return ret;
+
+	for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end() && !ret; idx++)
+	{
+		if(idx->first == 0)
+		{
+			ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, idx->first);
+		}
+	}
+	if(ret) return ret;
+
+	ret = get_child_by_point(x, y, client_x, client_y, draw_inlines, 0);
+	if(ret) return ret;
+
+	ret = get_child_by_point(x, y, client_x, client_y, draw_floats, 0);
+	if(ret) return ret;
+
+	ret = get_child_by_point(x, y, client_x, client_y, draw_block, 0);
+	if(ret) return ret;
+
+
+	for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end() && !ret; idx++)
+	{
+		if(idx->first < 0)
+		{
+			ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, idx->first);
+		}
+	}
+	if(ret) return ret;
+
+	if(m_el_position == element_position_fixed)
+	{
+		if(is_point_inside(client_x, client_y))
+		{
+			ret = shared_from_this();
+		}
+	} else
+	{
+		if(is_point_inside(x, y))
+		{
+			ret = shared_from_this();
+		}
+	}
+
+	return ret;
+}
+
+const litehtml::background* litehtml::html_tag::get_background(bool own_only)
+{
+	if(own_only)
+	{
+		// return own background with check for empty one
+		if(m_bg.m_image.empty() && !m_bg.m_color.alpha)
+		{
+			return 0;
+		}
+		return &m_bg;
+	}
+
+	if(m_bg.m_image.empty() && !m_bg.m_color.alpha)
+	{
+		// if this is root element (<html>) try to get background from body
+		if (!have_parent())
+		{
+			for (const auto& el : m_children)
+			{
+				if( el->is_body() )
+				{
+					// return own body background
+					return el->get_background(true);
+				}
+			}
+		}
+		return 0;
+	}
+	
+	if(is_body())
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			if (!el_parent->get_background(true))
+			{
+				// parent of body will draw background for body
+				return 0;
+			}
+		}
+	}
+
+	return &m_bg;
+}
+
+int litehtml::html_tag::render_box(int x, int y, int max_width, bool second_pass /*= false*/)
+{
+	int parent_width = max_width;
+
+	calc_outlines(parent_width);
+
+	m_pos.clear();
+	m_pos.move_to(x, y);
+
+	m_pos.x += content_margins_left();
+	m_pos.y += content_margins_top();
+
+	int ret_width = 0;
+
+	def_value<int>	block_width(0);
+
+	if (m_display != display_table_cell && !m_css_width.is_predefined())
+	{
+		int w = calc_width(parent_width);
+		
+		if (m_box_sizing == box_sizing_border_box)
+		{
+			w -= m_padding.width() + m_borders.width();
+		}
+		ret_width = max_width = block_width = w;
+	}
+	else
+	{
+		if (max_width)
+		{
+			max_width -= content_margins_left() + content_margins_right();
+		}
+	}
+
+	// check for max-width (on the first pass only)
+	if (!m_css_max_width.is_predefined() && !second_pass)
+	{
+		int mw = get_document()->cvt_units(m_css_max_width, m_font_size, parent_width);
+		if (m_box_sizing == box_sizing_border_box)
+		{
+			mw -= m_padding.left + m_borders.left + m_padding.right + m_borders.right;
+		}
+		if (max_width > mw)
+		{
+			max_width = mw;
+		}
+	}
+
+	m_floats_left.clear();
+	m_floats_right.clear();
+	m_boxes.clear();
+	m_cahe_line_left.invalidate();
+	m_cahe_line_right.invalidate();
+
+	element_position el_position;
+
+	int block_height = 0;
+
+	m_pos.height = 0;
+
+	if (get_predefined_height(block_height))
+	{
+		m_pos.height = block_height;
+	}
+
+	white_space ws = get_white_space();
+	bool skip_spaces = false;
+	if (ws == white_space_normal ||
+		ws == white_space_nowrap ||
+		ws == white_space_pre_line)
+	{
+		skip_spaces = true;
+	}
+
+	bool was_space = false;
+
+	for (auto el : m_children)
+	{
+		// we don't need process absolute and fixed positioned element on the second pass
+		if (second_pass)
+		{
+			el_position = el->get_element_position();
+			if ((el_position == element_position_absolute || el_position == element_position_fixed)) continue;
+		}
+
+		// skip spaces to make rendering a bit faster
+		if (skip_spaces)
+		{
+			if (el->is_white_space())
+			{
+				if (was_space)
+				{
+					el->skip(true);
+					continue;
+				}
+				else
+				{
+					was_space = true;
+				}
+			}
+			else
+			{
+				was_space = false;
+			}
+		}
+
+		// place element into rendering flow
+		int rw = place_element(el, max_width);
+		if (rw > ret_width)
+		{
+			ret_width = rw;
+		}
+	}
+
+	finish_last_box(true);
+
+	if (block_width.is_default() && is_inline_box())
+	{
+		m_pos.width = ret_width;
+	}
+	else
+	{
+		m_pos.width = max_width;
+	}
+	calc_auto_margins(parent_width);
+
+	if (!m_boxes.empty())
+	{
+		if (collapse_top_margin())
+		{
+			int old_top = m_margins.top;
+			m_margins.top = std::max(m_boxes.front()->top_margin(), m_margins.top);
+			if (m_margins.top != old_top)
+			{
+				update_floats(m_margins.top - old_top, shared_from_this());
+			}
+		}
+		if (collapse_bottom_margin())
+		{
+			m_margins.bottom = std::max(m_boxes.back()->bottom_margin(), m_margins.bottom);
+			m_pos.height = m_boxes.back()->bottom() - m_boxes.back()->bottom_margin();
+		}
+		else
+		{
+			m_pos.height = m_boxes.back()->bottom();
+		}
+	}
+
+	// add the floats height to the block height
+	if (is_floats_holder())
+	{
+		int floats_height = get_floats_height();
+		if (floats_height > m_pos.height)
+		{
+			m_pos.height = floats_height;
+		}
+	}
+
+	// calculate the final position
+
+	m_pos.move_to(x, y);
+	m_pos.x += content_margins_left();
+	m_pos.y += content_margins_top();
+
+	if (get_predefined_height(block_height))
+	{
+		m_pos.height = block_height;
+	}
+
+	int min_height = 0;
+	if (!m_css_min_height.is_predefined() && m_css_min_height.units() == css_units_percentage)
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			if (el_parent->get_predefined_height(block_height))
+			{
+				min_height = m_css_min_height.calc_percent(block_height);
+			}
+		}
+	}
+	else
+	{
+		min_height = (int)m_css_min_height.val();
+	}
+	if (min_height != 0 && m_box_sizing == box_sizing_border_box)
+	{
+		min_height -= m_padding.top + m_borders.top + m_padding.bottom + m_borders.bottom;
+		if (min_height < 0) min_height = 0;
+	}
+
+	if (m_display == display_list_item)
+	{
+		const tchar_t* list_image = get_style_property(_t("list-style-image"), true, 0);
+		if (list_image)
+		{
+			tstring url;
+			css::parse_css_url(list_image, url);
+
+			size sz;
+			const tchar_t* list_image_baseurl = get_style_property(_t("list-style-image-baseurl"), true, 0);
+			get_document()->container()->get_image_size(url.c_str(), list_image_baseurl, sz);
+			if (min_height < sz.height)
+			{
+				min_height = sz.height;
+			}
+		}
+
+	}
+
+	if (min_height > m_pos.height)
+	{
+		m_pos.height = min_height;
+	}
+
+	int min_width = m_css_min_width.calc_percent(parent_width);
+
+	if (min_width != 0 && m_box_sizing == box_sizing_border_box)
+	{
+		min_width -= m_padding.left + m_borders.left + m_padding.right + m_borders.right;
+		if (min_width < 0) min_width = 0;
+	}
+
+	if (min_width != 0)
+	{
+		if (min_width > m_pos.width)
+		{
+			m_pos.width = min_width;
+		}
+		if (min_width > ret_width)
+		{
+			ret_width = min_width;
+		}
+	}
+
+	ret_width += content_margins_left() + content_margins_right();
+
+	// re-render with new width
+	if (ret_width < max_width && !second_pass && have_parent())
+	{
+		if (m_display == display_inline_block ||
+			m_css_width.is_predefined() &&
+			(m_float != float_none ||
+			m_display == display_table ||
+			m_el_position == element_position_absolute ||
+			m_el_position == element_position_fixed
+			)
+			)
+		{
+			render(x, y, ret_width, true);
+			m_pos.width = ret_width - (content_margins_left() + content_margins_right());
+		}
+	}
+
+	if (is_floats_holder() && !second_pass)
+	{
+		for (const auto& fb : m_floats_left)
+		{
+			fb.el->apply_relative_shift(fb.el->parent()->calc_width(m_pos.width));
+		}
+	}
+
+
+	return ret_width;
+}
+
+int litehtml::html_tag::render_table(int x, int y, int max_width, bool second_pass /*= false*/)
+{
+	if (!m_grid) return 0;
+
+	int parent_width = max_width;
+
+	calc_outlines(parent_width);
+
+	m_pos.clear();
+	m_pos.move_to(x, y);
+
+	m_pos.x += content_margins_left();
+	m_pos.y += content_margins_top();
+
+	def_value<int>	block_width(0);
+
+	if (!m_css_width.is_predefined())
+	{
+		max_width = block_width = calc_width(parent_width) - m_padding.width() - m_borders.width();
+	}
+	else
+	{
+		if (max_width)
+		{
+			max_width -= content_margins_left() + content_margins_right();
+		}
+	}
+
+	// Calculate table spacing
+	int table_width_spacing = 0;
+	if (m_border_collapse == border_collapse_separate)
+	{
+		table_width_spacing = m_border_spacing_x * (m_grid->cols_count() + 1);
+	}
+	else
+	{
+		table_width_spacing = 0;
+
+		if (m_grid->cols_count())
+		{
+			table_width_spacing -= std::min(border_left(), m_grid->column(0).border_left);
+			table_width_spacing -= std::min(border_right(), m_grid->column(m_grid->cols_count() - 1).border_right);
+		}
+
+		for (int col = 1; col < m_grid->cols_count(); col++)
+		{
+			table_width_spacing -= std::min(m_grid->column(col).border_left, m_grid->column(col - 1).border_right);
+		}
+	}
+
+
+	// Calculate the minimum content width (MCW) of each cell: the formatted content may span any number of lines but may not overflow the cell box. 
+	// If the specified 'width' (W) of the cell is greater than MCW, W is the minimum cell width. A value of 'auto' means that MCW is the minimum 
+	// cell width.
+	// 
+	// Also, calculate the "maximum" cell width of each cell: formatting the content without breaking lines other than where explicit line breaks occur.
+
+	if (m_grid->cols_count() == 1 && !block_width.is_default())
+	{
+		for (int row = 0; row < m_grid->rows_count(); row++)
+		{
+			table_cell* cell = m_grid->cell(0, row);
+			if (cell && cell->el)
+			{
+				cell->min_width = cell->max_width = cell->el->render(0, 0, max_width - table_width_spacing);
+				cell->el->m_pos.width = cell->min_width - cell->el->content_margins_left() - cell->el->content_margins_right();
+			}
+		}
+	}
+	else
+	{
+		for (int row = 0; row < m_grid->rows_count(); row++)
+		{
+			for (int col = 0; col < m_grid->cols_count(); col++)
+			{
+				table_cell* cell = m_grid->cell(col, row);
+				if (cell && cell->el)
+				{
+					if (!m_grid->column(col).css_width.is_predefined() && m_grid->column(col).css_width.units() != css_units_percentage)
+					{
+						int css_w = m_grid->column(col).css_width.calc_percent(block_width);
+						int el_w = cell->el->render(0, 0, css_w);
+						cell->min_width = cell->max_width = std::max(css_w, el_w);
+						cell->el->m_pos.width = cell->min_width - cell->el->content_margins_left() - cell->el->content_margins_right();
+					}
+					else
+					{
+						// calculate minimum content width
+						cell->min_width = cell->el->render(0, 0, 1);
+						// calculate maximum content width
+						cell->max_width = cell->el->render(0, 0, max_width - table_width_spacing);
+					}
+				}
+			}
+		}
+	}
+
+	// For each column, determine a maximum and minimum column width from the cells that span only that column. 
+	// The minimum is that required by the cell with the largest minimum cell width (or the column 'width', whichever is larger). 
+	// The maximum is that required by the cell with the largest maximum cell width (or the column 'width', whichever is larger).
+
+	for (int col = 0; col < m_grid->cols_count(); col++)
+	{
+		m_grid->column(col).max_width = 0;
+		m_grid->column(col).min_width = 0;
+		for (int row = 0; row < m_grid->rows_count(); row++)
+		{
+			if (m_grid->cell(col, row)->colspan <= 1)
+			{
+				m_grid->column(col).max_width = std::max(m_grid->column(col).max_width, m_grid->cell(col, row)->max_width);
+				m_grid->column(col).min_width = std::max(m_grid->column(col).min_width, m_grid->cell(col, row)->min_width);
+			}
+		}
+	}
+
+	// For each cell that spans more than one column, increase the minimum widths of the columns it spans so that together, 
+	// they are at least as wide as the cell. Do the same for the maximum widths. 
+	// If possible, widen all spanned columns by approximately the same amount.
+
+	for (int col = 0; col < m_grid->cols_count(); col++)
+	{
+		for (int row = 0; row < m_grid->rows_count(); row++)
+		{
+			if (m_grid->cell(col, row)->colspan > 1)
+			{
+				int max_total_width = m_grid->column(col).max_width;
+				int min_total_width = m_grid->column(col).min_width;
+				for (int col2 = col + 1; col2 < col + m_grid->cell(col, row)->colspan; col2++)
+				{
+					max_total_width += m_grid->column(col2).max_width;
+					min_total_width += m_grid->column(col2).min_width;
+				}
+				if (min_total_width < m_grid->cell(col, row)->min_width)
+				{
+					m_grid->distribute_min_width(m_grid->cell(col, row)->min_width - min_total_width, col, col + m_grid->cell(col, row)->colspan - 1);
+				}
+				if (max_total_width < m_grid->cell(col, row)->max_width)
+				{
+					m_grid->distribute_max_width(m_grid->cell(col, row)->max_width - max_total_width, col, col + m_grid->cell(col, row)->colspan - 1);
+				}
+			}
+		}
+	}
+
+	// If the 'table' or 'inline-table' element's 'width' property has a computed value (W) other than 'auto', the used width is the 
+	// greater of W, CAPMIN, and the minimum width required by all the columns plus cell spacing or borders (MIN). 
+	// If the used width is greater than MIN, the extra width should be distributed over the columns.
+	//
+	// If the 'table' or 'inline-table' element has 'width: auto', the used width is the greater of the table's containing block width, 
+	// CAPMIN, and MIN. However, if either CAPMIN or the maximum width required by the columns plus cell spacing or borders (MAX) is 
+	// less than that of the containing block, use max(MAX, CAPMIN).
+
+
+	int table_width = 0;
+	int min_table_width = 0;
+	int max_table_width = 0;
+
+	if (!block_width.is_default())
+	{
+		table_width = m_grid->calc_table_width(block_width - table_width_spacing, false, min_table_width, max_table_width);
+	}
+	else
+	{
+		table_width = m_grid->calc_table_width(max_width - table_width_spacing, true, min_table_width, max_table_width);
+	}
+
+	min_table_width += table_width_spacing;
+	max_table_width += table_width_spacing;
+	table_width += table_width_spacing;
+	m_grid->calc_horizontal_positions(m_borders, m_border_collapse, m_border_spacing_x);
+
+	bool row_span_found = false;
+
+	// render cells with computed width
+	for (int row = 0; row < m_grid->rows_count(); row++)
+	{
+		m_grid->row(row).height = 0;
+		for (int col = 0; col < m_grid->cols_count(); col++)
+		{
+			table_cell* cell = m_grid->cell(col, row);
+			if (cell->el)
+			{
+				int span_col = col + cell->colspan - 1;
+				if (span_col >= m_grid->cols_count())
+				{
+					span_col = m_grid->cols_count() - 1;
+				}
+				int cell_width = m_grid->column(span_col).right - m_grid->column(col).left;
+
+				if (cell->el->m_pos.width != cell_width - cell->el->content_margins_left() - cell->el->content_margins_right())
+				{
+					cell->el->render(m_grid->column(col).left, 0, cell_width);
+					cell->el->m_pos.width = cell_width - cell->el->content_margins_left() - cell->el->content_margins_right();
+				}
+				else
+				{
+					cell->el->m_pos.x = m_grid->column(col).left + cell->el->content_margins_left();
+				}
+
+				if (cell->rowspan <= 1)
+				{
+					m_grid->row(row).height = std::max(m_grid->row(row).height, cell->el->height());
+				}
+				else
+				{
+					row_span_found = true;
+				}
+
+			}
+		}
+	}
+
+	if (row_span_found)
+	{
+		for (int col = 0; col < m_grid->cols_count(); col++)
+		{
+			for (int row = 0; row < m_grid->rows_count(); row++)
+			{
+				table_cell* cell = m_grid->cell(col, row);
+				if (cell->el)
+				{
+					int span_row = row + cell->rowspan - 1;
+					if (span_row >= m_grid->rows_count())
+					{
+						span_row = m_grid->rows_count() - 1;
+					}
+					if (span_row != row)
+					{
+						int h = 0;
+						for (int i = row; i <= span_row; i++)
+						{
+							h += m_grid->row(i).height;
+						}
+						if (h < cell->el->height())
+						{
+							m_grid->row(span_row).height += cell->el->height() - h;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	// Calculate vertical table spacing
+	int table_height_spacing = 0;
+	if (m_border_collapse == border_collapse_separate)
+	{
+		table_height_spacing = m_border_spacing_y * (m_grid->rows_count() + 1);
+	}
+	else
+	{
+		table_height_spacing = 0;
+
+		if (m_grid->rows_count())
+		{
+			table_height_spacing -= std::min(border_top(), m_grid->row(0).border_top);
+			table_height_spacing -= std::min(border_bottom(), m_grid->row(m_grid->rows_count() - 1).border_bottom);
+		}
+
+		for (int row = 1; row < m_grid->rows_count(); row++)
+		{
+			table_height_spacing -= std::min(m_grid->row(row).border_top, m_grid->row(row - 1).border_bottom);
+		}
+	}
+
+
+	// calculate block height
+	int block_height = 0;
+	if (get_predefined_height(block_height))
+	{
+		block_height -= m_padding.height() + m_borders.height();
+	}
+
+	// calculate minimum height from m_css_min_height
+	int min_height = 0;
+	if (!m_css_min_height.is_predefined() && m_css_min_height.units() == css_units_percentage)
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			int parent_height = 0;
+			if (el_parent->get_predefined_height(parent_height))
+			{
+				min_height = m_css_min_height.calc_percent(parent_height);
+			}
+		}
+	}
+	else
+	{
+		min_height = (int)m_css_min_height.val();
+	}
+
+	int extra_row_height = 0;
+	int minimum_table_height = std::max(block_height, min_height);
+
+	m_grid->calc_rows_height(minimum_table_height - table_height_spacing, m_border_spacing_y);
+	m_grid->calc_vertical_positions(m_borders, m_border_collapse, m_border_spacing_y);
+
+	int table_height = 0;
+
+	// place cells vertically
+	for (int col = 0; col < m_grid->cols_count(); col++)
+	{
+		for (int row = 0; row < m_grid->rows_count(); row++)
+		{
+			table_cell* cell = m_grid->cell(col, row);
+			if (cell->el)
+			{
+				int span_row = row + cell->rowspan - 1;
+				if (span_row >= m_grid->rows_count())
+				{
+					span_row = m_grid->rows_count() - 1;
+				}
+				cell->el->m_pos.y = m_grid->row(row).top + cell->el->content_margins_top();
+				cell->el->m_pos.height = m_grid->row(span_row).bottom - m_grid->row(row).top - cell->el->content_margins_top() - cell->el->content_margins_bottom();
+				table_height = std::max(table_height, m_grid->row(span_row).bottom);
+				cell->el->apply_vertical_align();
+			}
+		}
+	}
+
+	if (m_border_collapse == border_collapse_collapse)
+	{
+		if (m_grid->rows_count())
+		{
+			table_height -= std::min(border_bottom(), m_grid->row(m_grid->rows_count() - 1).border_bottom);
+		}
+	}
+	else
+	{
+		table_height += m_border_spacing_y;
+	}
+
+	m_pos.width = table_width;
+
+	calc_auto_margins(parent_width);
+
+	m_pos.move_to(x, y);
+	m_pos.x += content_margins_left();
+	m_pos.y += content_margins_top();
+	m_pos.width = table_width;
+	m_pos.height = table_height;
+
+	return max_table_width;
+}
+
+void litehtml::html_tag::draw_children_box(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex)
+{
+	position pos = m_pos;
+	pos.x += x;
+	pos.y += y;
+
+	document::ptr doc = get_document();
+
+	if (m_overflow > overflow_visible)
+	{
+		position border_box = pos;
+		border_box += m_padding;
+		border_box += m_borders;
+
+		border_radiuses bdr_radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
+
+		bdr_radius -= m_borders;
+		bdr_radius -= m_padding;
+
+		doc->container()->set_clip(pos, bdr_radius, true, true);
+	}
+
+	position browser_wnd;
+	doc->container()->get_client_rect(browser_wnd);
+
+	element::ptr el;
+	for (auto& item : m_children)
+	{
+		el = item;
+		if (el->is_visible())
+		{
+			switch (flag)
+			{
+			case draw_positioned:
+				if (el->is_positioned() && el->get_zindex() == zindex)
+				{
+					if (el->get_element_position() == element_position_fixed)
+					{
+						el->draw(hdc, browser_wnd.x, browser_wnd.y, clip);
+						el->draw_stacking_context(hdc, browser_wnd.x, browser_wnd.y, clip, true);
+					}
+					else
+					{
+						el->draw(hdc, pos.x, pos.y, clip);
+						el->draw_stacking_context(hdc, pos.x, pos.y, clip, true);
+					}
+					el = 0;
+				}
+				break;
+			case draw_block:
+				if (!el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
+				{
+					el->draw(hdc, pos.x, pos.y, clip);
+				}
+				break;
+			case draw_floats:
+				if (el->get_float() != float_none && !el->is_positioned())
+				{
+					el->draw(hdc, pos.x, pos.y, clip);
+					el->draw_stacking_context(hdc, pos.x, pos.y, clip, false);
+					el = 0;
+				}
+				break;
+			case draw_inlines:
+				if (el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
+				{
+					el->draw(hdc, pos.x, pos.y, clip);
+					if (el->get_display() == display_inline_block)
+					{
+						el->draw_stacking_context(hdc, pos.x, pos.y, clip, false);
+						el = 0;
+					}
+				}
+				break;
+			default:
+				break;
+			}
+
+			if (el)
+			{
+				if (flag == draw_positioned)
+				{
+					if (!el->is_positioned())
+					{
+						el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
+					}
+				}
+				else
+				{
+					if (el->get_float() == float_none &&
+						el->get_display() != display_inline_block &&
+						!el->is_positioned())
+					{
+						el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
+					}
+				}
+			}
+		}
+	}
+
+	if (m_overflow > overflow_visible)
+	{
+		doc->container()->del_clip();
+	}
+}
+
+void litehtml::html_tag::draw_children_table(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex)
+{
+	if (!m_grid) return;
+
+	position pos = m_pos;
+	pos.x += x;
+	pos.y += y;
+	for (int row = 0; row < m_grid->rows_count(); row++)
+	{
+		if (flag == draw_block)
+		{
+			m_grid->row(row).el_row->draw_background(hdc, pos.x, pos.y, clip);
+		}
+		for (int col = 0; col < m_grid->cols_count(); col++)
+		{
+			table_cell* cell = m_grid->cell(col, row);
+			if (cell->el)
+			{
+				if (flag == draw_block)
+				{
+					cell->el->draw(hdc, pos.x, pos.y, clip);
+				}
+				cell->el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
+			}
+		}
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/html_tag.h b/src/plugins/litehtml_viewer/litehtml/html_tag.h
new file mode 100644
index 0000000..f03bb62
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/html_tag.h
@@ -0,0 +1,246 @@
+#pragma once
+
+#include "element.h"
+#include "style.h"
+#include "background.h"
+#include "css_margins.h"
+#include "borders.h"
+#include "css_selector.h"
+#include "stylesheet.h"
+#include "box.h"
+#include "table.h"
+
+namespace litehtml
+{
+	struct line_context
+	{
+		int calculatedTop;
+		int top;
+		int left;
+		int right;
+
+		int width()
+		{
+			return right - left;
+		}
+		void fix_top()
+		{
+			calculatedTop = top;
+		}
+	};
+
+	class html_tag : public element
+	{
+		friend class elements_iterator;
+		friend class el_table;
+		friend class table_grid;
+		friend class block_box;
+		friend class line_box;
+	public:
+		typedef std::shared_ptr<litehtml::html_tag>	ptr;
+	protected:
+		box::vector				m_boxes;
+		string_vector			m_class_values;
+		tstring					m_tag;
+		litehtml::style			m_style;
+		string_map				m_attrs;
+		vertical_align			m_vertical_align;
+		text_align				m_text_align;
+		style_display			m_display;
+		list_style_type			m_list_style_type;
+		list_style_position		m_list_style_position;
+		white_space				m_white_space;
+		element_float			m_float;
+		element_clear			m_clear;
+		floated_box::vector		m_floats_left;
+		floated_box::vector		m_floats_right;
+		elements_vector			m_positioned;
+		background				m_bg;
+		element_position		m_el_position;
+		int						m_line_height;
+		bool					m_lh_predefined;
+		string_vector			m_pseudo_classes;
+		used_selector::vector	m_used_styles;		
+		
+		uint_ptr				m_font;
+		int						m_font_size;
+		font_metrics			m_font_metrics;
+
+		css_margins				m_css_margins;
+		css_margins				m_css_padding;
+		css_borders				m_css_borders;
+		css_length				m_css_width;
+		css_length				m_css_height;
+		css_length				m_css_min_width;
+		css_length				m_css_min_height;
+		css_length				m_css_max_width;
+		css_length				m_css_max_height;
+		css_offsets				m_css_offsets;
+		css_length				m_css_text_indent;
+
+		overflow				m_overflow;
+		visibility				m_visibility;
+		int						m_z_index;
+		box_sizing				m_box_sizing;
+
+		int_int_cache			m_cahe_line_left;
+		int_int_cache			m_cahe_line_right;
+
+		// data for table rendering
+		std::unique_ptr<table_grid>	m_grid;
+		css_length				m_css_border_spacing_x;
+		css_length				m_css_border_spacing_y;
+		int						m_border_spacing_x;
+		int						m_border_spacing_y;
+		border_collapse			m_border_collapse;
+
+		virtual void			select_all(const css_selector& selector, elements_vector& res);
+
+	public:
+		html_tag(const std::shared_ptr<litehtml::document>& doc);
+		virtual ~html_tag();
+
+		/* render functions */
+
+		virtual int					render(int x, int y, int max_width, bool second_pass = false) override;
+
+		virtual int					render_inline(const element::ptr &container, int max_width) override;
+		virtual int					place_element(const element::ptr &el, int max_width) override;
+		virtual bool				fetch_positioned() override;
+		virtual void				render_positioned(render_type rt = render_all) override;
+
+		int							new_box(const element::ptr &el, int max_width, line_context& line_ctx);
+
+		int							get_cleared_top(const element::ptr &el, int line_top) const;
+		int							finish_last_box(bool end_of_render = false);
+
+		virtual bool				appendChild(const element::ptr &el) override;
+		virtual bool				removeChild(const element::ptr &el) override;
+		virtual void				clearRecursive() override;
+		virtual const tchar_t*		get_tagName() const override;
+		virtual void				set_tagName(const tchar_t* tag) override;
+		virtual void				set_data(const tchar_t* data) override;
+		virtual element_float		get_float() const override;
+		virtual vertical_align		get_vertical_align() const override;
+		virtual css_length			get_css_left() const override;
+		virtual css_length			get_css_right() const override;
+		virtual css_length			get_css_top() const override;
+		virtual css_length			get_css_bottom() const override;
+		virtual css_length			get_css_width() const override;
+		virtual css_offsets			get_css_offsets() const override;
+		virtual void				set_css_width(css_length& w) override;
+		virtual css_length			get_css_height() const override;
+		virtual element_clear		get_clear() const override;
+		virtual size_t				get_children_count() const override;
+		virtual element::ptr		get_child(int idx) const override;
+		virtual element_position	get_element_position(css_offsets* offsets = 0) const override;
+		virtual overflow			get_overflow() const override;
+
+		virtual void				set_attr(const tchar_t* name, const tchar_t* val) override;
+		virtual const tchar_t*		get_attr(const tchar_t* name, const tchar_t* def = 0) override;
+		virtual void				apply_stylesheet(const litehtml::css& stylesheet) override;
+		virtual void				refresh_styles() override;
+
+		virtual bool				is_white_space() const override;
+		virtual bool				is_body() const override;
+		virtual bool				is_break() const override;
+		virtual int					get_base_line() override;
+		virtual bool				on_mouse_over() override;
+		virtual bool				on_mouse_leave() override;
+		virtual bool				on_lbutton_down() override;
+		virtual bool				on_lbutton_up() override;
+		virtual void				on_click() override;
+		virtual bool				find_styles_changes(position::vector& redraw_boxes, int x, int y) override;
+		virtual const tchar_t*		get_cursor() override;
+		virtual void				init_font() override;
+		virtual bool				set_pseudo_class(const tchar_t* pclass, bool add) override;
+		virtual bool				set_class(const tchar_t* pclass, bool add) override;
+		virtual bool				is_replaced() const override;
+		virtual int					line_height() const override;
+		virtual white_space			get_white_space() const override;
+		virtual style_display		get_display() const override;
+		virtual visibility			get_visibility() const override;
+		virtual void				parse_styles(bool is_reparse = false) override;
+		virtual void				draw(uint_ptr hdc, int x, int y, const position* clip) override;
+		virtual void				draw_background(uint_ptr hdc, int x, int y, const position* clip) override;
+
+		virtual const tchar_t*		get_style_property(const tchar_t* name, bool inherited, const tchar_t* def = 0) override;
+		virtual uint_ptr			get_font(font_metrics* fm = 0) override;
+		virtual int					get_font_size() const override;
+
+		elements_vector&			children();
+		virtual void				calc_outlines(int parent_width) override;
+		virtual void				calc_auto_margins(int parent_width) override;
+
+		virtual int					select(const css_selector& selector, bool apply_pseudo = true) override;
+		virtual int					select(const css_element_selector& selector, bool apply_pseudo = true) override;
+
+		virtual elements_vector		select_all(const tstring& selector) override;
+		virtual elements_vector		select_all(const css_selector& selector) override;
+
+		virtual element::ptr		select_one(const tstring& selector) override;
+		virtual element::ptr		select_one(const css_selector& selector) override;
+
+		virtual element::ptr		find_ancestor(const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0) override;
+		virtual element::ptr		find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0) override;
+		virtual element::ptr		find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0) override;
+		virtual void				get_text(tstring& text) override;
+		virtual void				parse_attributes() override;
+
+		virtual bool				is_first_child_inline(const element::ptr& el) const override;
+		virtual bool				is_last_child_inline(const element::ptr& el) override;
+		virtual bool				have_inline_child() const override;
+		virtual void				get_content_size(size& sz, int max_width) override;
+		virtual void				init() override;
+		virtual void				get_inline_boxes(position::vector& boxes) override;
+		virtual bool				is_floats_holder() const override;
+		virtual int					get_floats_height(element_float el_float = float_none) const override;
+		virtual int					get_left_floats_height() const override;
+		virtual int					get_right_floats_height() const override;
+		virtual int					get_line_left(int y) override;
+		virtual int					get_line_right(int y, int def_right) override;
+		virtual void				get_line_left_right(int y, int def_right, int& ln_left, int& ln_right) override;
+		virtual void				add_float(const element::ptr &el, int x, int y) override;
+		virtual void				update_floats(int dy, const element::ptr &parent) override;
+		virtual void				add_positioned(const element::ptr &el) override;
+		virtual int					find_next_line_top(int top, int width, int def_right) override;
+		virtual void				apply_vertical_align() override;
+		virtual void				draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override;
+		virtual int					get_zindex() const override;
+		virtual void				draw_stacking_context(uint_ptr hdc, int x, int y, const position* clip, bool with_positioned) override;
+		virtual void				calc_document_size(litehtml::size& sz, int x = 0, int y = 0) override;
+		virtual void				get_redraw_box(litehtml::position& pos, int x = 0, int y = 0) override;
+		virtual void				add_style(const litehtml::style& st) override;
+		virtual element::ptr		get_element_by_point(int x, int y, int client_x, int client_y) override;
+		virtual element::ptr		get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex) override;
+
+		virtual bool				is_nth_child(const element::ptr& el, int num, int off, bool of_type) const override;
+		virtual bool				is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const override;
+		virtual bool				is_only_child(const element::ptr& el, bool of_type) const override;
+		virtual const background*	get_background(bool own_only = false) override;
+
+	protected:
+		void						draw_children_box(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex);
+		void						draw_children_table(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex);
+		int							render_box(int x, int y, int max_width, bool second_pass = false);
+		int							render_table(int x, int y, int max_width, bool second_pass = false);
+		int							fix_line_width(int max_width, element_float flt);
+		void						parse_background();
+		void						init_background_paint( position pos, background_paint &bg_paint, const background* bg );
+		void						draw_list_marker( uint_ptr hdc, const position &pos );
+		void						parse_nth_child_params( tstring param, int &num, int &off );
+		void						remove_before_after();
+		litehtml::element::ptr		get_element_before();
+		litehtml::element::ptr		get_element_after();
+	};
+
+	/************************************************************************/
+	/*                        Inline Functions                              */
+	/************************************************************************/
+
+	inline elements_vector& litehtml::html_tag::children()
+	{
+		return m_children;
+	}
+}
+
diff --git a/src/plugins/litehtml_viewer/litehtml/iterators.cpp b/src/plugins/litehtml_viewer/litehtml/iterators.cpp
new file mode 100644
index 0000000..3459f5c
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/iterators.cpp
@@ -0,0 +1,94 @@
+#include "html.h"
+#include "iterators.h"
+#include "html_tag.h"
+
+litehtml::element::ptr litehtml::elements_iterator::next(bool ret_parent)
+{
+	next_idx();
+
+	while(m_idx < (int) m_el->get_children_count())
+	{
+		element::ptr el = m_el->get_child(m_idx);
+		if(	el->get_children_count() && m_go_inside && m_go_inside->select(el) )
+		{
+			stack_item si;
+			si.idx		= m_idx;
+			si.el		= m_el;
+			m_stack.push_back(si);
+			m_el		= el;
+			m_idx		= -1;
+			if(ret_parent)
+			{
+				return el;
+			}
+			next_idx();
+		} else
+		{
+			if( !m_select || (m_select && m_select->select(m_el->get_child(m_idx))) )
+			{
+				return m_el->get_child(m_idx);
+			} else
+			{
+				next_idx();
+			}
+		}
+	}
+
+	return 0;
+}
+
+void litehtml::elements_iterator::next_idx()
+{
+	m_idx++;
+	while(m_idx >= (int) m_el->get_children_count() && m_stack.size())
+	{
+		stack_item si = m_stack.back();
+		m_stack.pop_back();
+		m_idx	= si.idx;
+		m_el	= si.el;
+		m_idx++;
+		continue;
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+
+bool litehtml::go_inside_inline::select(const element::ptr& el)
+{
+	if(el->get_display() == display_inline || el->get_display() == display_inline_text)
+	{
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::go_inside_table::select(const element::ptr& el)
+{
+	if(	el->get_display() == display_table_row_group ||
+		el->get_display() == display_table_header_group ||
+		el->get_display() == display_table_footer_group)
+	{
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::table_rows_selector::select(const element::ptr& el)
+{
+	if(	el->get_display() == display_table_row)
+	{
+		return true;
+	}
+	return false;
+}
+
+bool litehtml::table_cells_selector::select(const element::ptr& el)
+{
+	if(	el->get_display() == display_table_cell)
+	{
+		return true;
+	}
+	return false;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/iterators.h b/src/plugins/litehtml_viewer/litehtml/iterators.h
new file mode 100644
index 0000000..df60dc5
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/iterators.h
@@ -0,0 +1,87 @@
+#pragma once
+
+#include "types.h"
+
+namespace litehtml
+{
+	class element;
+
+	class iterator_selector
+	{
+	public:
+		virtual bool select(const element::ptr& el) = 0;
+	};
+
+	class elements_iterator
+	{
+	private:
+		struct stack_item
+		{
+			int				idx;
+			element::ptr	el;
+			stack_item()
+			{
+
+			}
+			stack_item(const stack_item& val)
+			{
+				idx = val.idx;
+				el = val.el;
+			}
+			stack_item(stack_item&& val)
+			{
+				idx = val.idx;
+				el = std::move(val.el);
+			}
+		};
+
+		std::vector<stack_item>		m_stack;
+		element::ptr				m_el;
+		int							m_idx;
+		iterator_selector*			m_go_inside;
+		iterator_selector*			m_select;
+	public:
+
+		elements_iterator(const element::ptr& el, iterator_selector* go_inside, iterator_selector* select)
+		{ 
+			m_el			= el;
+			m_idx			= -1; 
+			m_go_inside		= go_inside;
+			m_select		= select;
+		}
+
+		~elements_iterator()
+		{
+
+		}
+
+		element::ptr next(bool ret_parent = true);
+	
+	private:
+		void next_idx();
+	};
+
+	class go_inside_inline : public iterator_selector
+	{
+	public:
+		virtual bool select(const element::ptr& el);
+	};
+
+	class go_inside_table : public iterator_selector
+	{
+	public:
+		virtual bool select(const element::ptr& el);
+	};
+
+	class table_rows_selector : public iterator_selector
+	{
+	public:
+		virtual bool select(const element::ptr& el);
+	};
+
+	class table_cells_selector : public iterator_selector
+	{
+	public:
+		virtual bool select(const element::ptr& el);
+	};
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/litehtml.h b/src/plugins/litehtml_viewer/litehtml/litehtml.h
new file mode 100644
index 0000000..02e5b8d
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/litehtml.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "litehtml/os_types.h"
+#include "litehtml/types.h"
+#include "litehtml/html.h"
+#include "litehtml/element.h"
+#include "litehtml/document.h"
+#include "litehtml/context.h"
+#include "litehtml/element.h"
+
diff --git a/src/plugins/litehtml_viewer/litehtml/media_query.cpp b/src/plugins/litehtml_viewer/litehtml/media_query.cpp
new file mode 100644
index 0000000..6cc66da
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/media_query.cpp
@@ -0,0 +1,432 @@
+#include "html.h"
+#include "media_query.h"
+#include "document.h"
+
+
+litehtml::media_query::media_query()
+{
+	m_media_type	= media_type_all;
+	m_not			= false;
+}
+
+litehtml::media_query::media_query( const media_query& val )
+{
+	m_not			= val.m_not;
+	m_expressions	= val.m_expressions;
+	m_media_type	= val.m_media_type;
+}
+
+litehtml::media_query::ptr litehtml::media_query::create_from_string(const tstring& str, const std::shared_ptr<document>& doc)
+{
+	media_query::ptr query = std::make_shared<media_query>();
+
+	string_vector tokens;
+	split_string(str, tokens, _t(" \t\r\n"), _t(""), _t("("));
+
+	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+	{
+		if((*tok) == _t("not"))
+		{
+			query->m_not = true;
+		} else if(tok->at(0) == _t('('))
+		{
+			tok->erase(0, 1);
+			if(tok->at(tok->length() - 1) == _t(')'))
+			{
+				tok->erase(tok->length() - 1, 1);
+			}
+			media_query_expression expr;
+			string_vector expr_tokens;
+			split_string((*tok), expr_tokens, _t(":"));
+			if(!expr_tokens.empty())
+			{
+				trim(expr_tokens[0]);
+				expr.feature = (media_feature) value_index(expr_tokens[0], media_feature_strings, media_feature_none);
+				if(expr.feature != media_feature_none)
+				{
+					if(expr_tokens.size() == 1)
+					{
+						expr.check_as_bool = true;
+					} else
+					{
+						trim(expr_tokens[1]);
+						expr.check_as_bool = false;
+						if(expr.feature == media_feature_orientation)
+						{
+							expr.val = value_index(expr_tokens[1], media_orientation_strings, media_orientation_landscape);
+						} else
+						{
+							tstring::size_type slash_pos = expr_tokens[1].find(_t('/'));
+							if( slash_pos != tstring::npos )
+							{
+								tstring val1 = expr_tokens[1].substr(0, slash_pos);
+								tstring val2 = expr_tokens[1].substr(slash_pos + 1);
+								trim(val1);
+								trim(val2);
+								expr.val = t_atoi(val1.c_str());
+								expr.val2 = t_atoi(val2.c_str());
+							} else
+							{
+								css_length length;
+								length.fromString(expr_tokens[1]);
+								if(length.units() == css_units_dpcm)
+								{
+									expr.val = (int) (length.val() * 2.54);
+								} else if(length.units() == css_units_dpi)
+								{
+									expr.val = (int) (length.val() * 2.54);
+								} else
+								{
+									if(doc)
+									{
+										doc->cvt_units(length, doc->container()->get_default_font_size());
+									}
+									expr.val = (int) length.val();
+								}
+							}
+						}
+					}
+					query->m_expressions.push_back(expr);
+				}
+			}
+		} else
+		{
+			query->m_media_type = (media_type) value_index((*tok), media_type_strings, media_type_all);
+
+		}
+	}
+
+	return query;
+}
+
+bool litehtml::media_query::check( const media_features& features ) const
+{
+	bool res = false;
+	if(m_media_type == media_type_all || m_media_type == features.type)
+	{
+		res = true;
+		for(media_query_expression::vector::const_iterator expr = m_expressions.begin(); expr != m_expressions.end() && res; expr++)
+		{
+			if(!expr->check(features))
+			{
+				res = false;
+			}
+		}
+	}
+
+	if(m_not)
+	{
+		res = !res;
+	}
+
+	return res;
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+litehtml::media_query_list::ptr litehtml::media_query_list::create_from_string(const tstring& str, const std::shared_ptr<document>& doc)
+{
+	media_query_list::ptr list = std::make_shared<media_query_list>();
+
+	string_vector tokens;
+	split_string(str, tokens, _t(","));
+
+	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+	{
+		trim(*tok);
+		lcase(*tok);
+
+		litehtml::media_query::ptr query = media_query::create_from_string(*tok, doc);
+		if(query)
+		{
+			list->m_queries.push_back(query);
+		}
+	}
+	if(list->m_queries.empty())
+	{
+		list = 0;
+	}
+
+	return list;
+}
+
+bool litehtml::media_query_list::apply_media_features( const media_features& features )
+{
+	bool apply = false;
+	
+	for(media_query::vector::iterator iter = m_queries.begin(); iter != m_queries.end() && !apply; iter++)
+	{
+		if((*iter)->check(features))
+		{
+			apply = true;
+		}
+	}
+
+	bool ret = (apply != m_is_used);
+	m_is_used = apply;
+	return ret;
+}
+
+bool litehtml::media_query_expression::check( const media_features& features ) const
+{
+	switch(feature)
+	{
+	case media_feature_width:
+		if(check_as_bool)
+		{
+			return (features.width != 0);
+		} else if(features.width == val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_min_width:
+		if(features.width >= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_max_width:
+		if(features.width <= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_height:
+		if(check_as_bool)
+		{
+			return (features.height != 0);
+		} else if(features.height == val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_min_height:
+		if(features.height >= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_max_height:
+		if(features.height <= val)
+		{
+			return true;
+		}
+		break;
+
+	case media_feature_device_width:
+		if(check_as_bool)
+		{
+			return (features.device_width != 0);
+		} else if(features.device_width == val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_min_device_width:
+		if(features.device_width >= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_max_device_width:
+		if(features.device_width <= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_device_height:
+		if(check_as_bool)
+		{
+			return (features.device_height != 0);
+		} else if(features.device_height == val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_min_device_height:
+		if(features.device_height <= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_max_device_height:
+		if(features.device_height <= val)
+		{
+			return true;
+		}
+		break;
+
+	case media_feature_orientation:
+		if(features.height >= features.width)
+		{
+			if(val == media_orientation_portrait)
+			{
+				return true;
+			}
+		} else
+		{
+			if(val == media_orientation_landscape)
+			{
+				return true;
+			}
+		}
+		break;
+	case media_feature_aspect_ratio:
+		if(features.height && val2)
+		{
+			int ratio_this = round_d( (double) val / (double) val2 * 100 );
+			int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 );
+			if(ratio_this == ratio_feat)
+			{
+				return true;
+			}
+		}
+		break;
+	case media_feature_min_aspect_ratio:
+		if(features.height && val2)
+		{
+			int ratio_this = round_d( (double) val / (double) val2 * 100 );
+			int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 );
+			if(ratio_feat >= ratio_this)
+			{
+				return true;
+			}
+		}
+		break;
+	case media_feature_max_aspect_ratio:
+		if(features.height && val2)
+		{
+			int ratio_this = round_d( (double) val / (double) val2 * 100 );
+			int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 );
+			if(ratio_feat <= ratio_this)
+			{
+				return true;
+			}
+		}
+		break;
+
+	case media_feature_device_aspect_ratio:
+		if(features.device_height && val2)
+		{
+			int ratio_this = round_d( (double) val / (double) val2 * 100 );
+			int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 );
+			if(ratio_feat == ratio_this)
+			{
+				return true;
+			}
+		}
+		break;
+	case media_feature_min_device_aspect_ratio:
+		if(features.device_height && val2)
+		{
+			int ratio_this = round_d( (double) val / (double) val2 * 100 );
+			int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 );
+			if(ratio_feat >= ratio_this)
+			{
+				return true;
+			}
+		}
+		break;
+	case media_feature_max_device_aspect_ratio:
+		if(features.device_height && val2)
+		{
+			int ratio_this = round_d( (double) val / (double) val2 * 100 );
+			int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 );
+			if(ratio_feat <= ratio_this)
+			{
+				return true;
+			}
+		}
+		break;
+
+	case media_feature_color:
+		if(check_as_bool)
+		{
+			return (features.color != 0);
+		} else if(features.color == val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_min_color:
+		if(features.color >= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_max_color:
+		if(features.color <= val)
+		{
+			return true;
+		}
+		break;
+
+	case media_feature_color_index:
+		if(check_as_bool)
+		{
+			return (features.color_index != 0);
+		} else if(features.color_index == val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_min_color_index:
+		if(features.color_index >= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_max_color_index:
+		if(features.color_index <= val)
+		{
+			return true;
+		}
+		break;
+
+	case media_feature_monochrome:
+		if(check_as_bool)
+		{
+			return (features.monochrome != 0);
+		} else if(features.monochrome == val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_min_monochrome:
+		if(features.monochrome >= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_max_monochrome:
+		if(features.monochrome <= val)
+		{
+			return true;
+		}
+		break;
+
+	case media_feature_resolution:
+		if(features.resolution == val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_min_resolution:
+		if(features.resolution >= val)
+		{
+			return true;
+		}
+		break;
+	case media_feature_max_resolution:
+		if(features.resolution <= val)
+		{
+			return true;
+		}
+		break;
+	default:
+		return false;
+	}
+
+	return false;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/media_query.h b/src/plugins/litehtml_viewer/litehtml/media_query.h
new file mode 100644
index 0000000..52c7f3f
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/media_query.h
@@ -0,0 +1,74 @@
+#pragma once
+
+namespace litehtml
+{
+	struct media_query_expression
+	{
+		typedef std::vector<media_query_expression>	vector;
+		media_feature	feature;
+		int				val;
+		int				val2;
+		bool			check_as_bool;
+		
+		media_query_expression()
+		{
+			check_as_bool	= false;
+			feature			= media_feature_none;
+			val				= 0;
+			val2			= 0;
+		}
+
+		bool check(const media_features& features) const;
+	};
+
+	class media_query
+	{
+	public:
+		typedef std::shared_ptr<media_query>	ptr;
+		typedef std::vector<media_query::ptr>	vector;
+	private:
+		media_query_expression::vector	m_expressions;
+		bool							m_not;
+		media_type						m_media_type;
+	public:
+		media_query();
+		media_query(const media_query& val);
+
+		static media_query::ptr create_from_string(const tstring& str, const std::shared_ptr<document>& doc);
+		bool check(const media_features& features) const;
+	};
+
+	class media_query_list
+	{
+	public:
+		typedef std::shared_ptr<media_query_list>	ptr;
+		typedef std::vector<media_query_list::ptr>	vector;
+	private:
+		media_query::vector	m_queries;
+		bool				m_is_used;
+	public:
+		media_query_list();
+		media_query_list(const media_query_list& val);
+
+		static media_query_list::ptr create_from_string(const tstring& str, const std::shared_ptr<document>& doc);
+		bool is_used() const;
+		bool apply_media_features(const media_features& features);	// returns true if the m_is_used changed
+	};
+
+	inline media_query_list::media_query_list(const media_query_list& val)
+	{
+		m_is_used	= val.m_is_used;
+		m_queries	= val.m_queries;
+	}
+
+	inline media_query_list::media_query_list()
+	{
+		m_is_used = false;
+	}
+
+	inline bool media_query_list::is_used() const
+	{
+		return m_is_used;
+	}
+
+}
\ No newline at end of file
diff --git a/src/plugins/litehtml_viewer/litehtml/os_types.h b/src/plugins/litehtml_viewer/litehtml/os_types.h
new file mode 100644
index 0000000..4fb638f
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/os_types.h
@@ -0,0 +1,83 @@
+#pragma once
+
+namespace litehtml
+{
+#if defined( WIN32 ) || defined( WINCE )
+
+#ifndef LITEHTML_UTF8
+
+	typedef std::wstring		tstring;
+	typedef wchar_t				tchar_t;
+	typedef std::wstringstream	tstringstream;
+
+	#define _t(quote)			L##quote
+
+	#define t_strlen			wcslen
+	#define t_strcmp			wcscmp
+	#define t_strncmp			wcsncmp
+	#define t_strcasecmp		_wcsicmp
+	#define t_strncasecmp		_wcsnicmp
+	#define t_strtol			wcstol
+	#define t_atoi				_wtoi
+	#define t_strtod			wcstod
+	#define t_itoa(value, buffer, size, radix)	_itow_s(value, buffer, size, radix)
+	#define t_strstr			wcsstr
+	#define t_tolower			towlower
+	#define t_isdigit			iswdigit
+
+#else
+
+	typedef std::string			tstring;
+	typedef char				tchar_t;
+	typedef std::stringstream	tstringstream;
+
+	#define _t(quote)			quote
+
+	#define t_strlen			strlen
+	#define t_strcmp			strcmp
+	#define t_strncmp			strncmp
+	#define t_strcasecmp		_stricmp
+	#define t_strncasecmp		_strnicmp
+	#define t_strtol			strtol
+	#define t_atoi				atoi
+	#define t_strtod			strtod
+	#define t_itoa(value, buffer, size, radix)	_itoa_s(value, buffer, size, radix)
+	#define t_strstr			strstr
+	#define t_tolower			tolower
+	#define t_isdigit			isdigit
+
+#endif
+
+	#ifdef _WIN64
+		typedef unsigned __int64 uint_ptr;
+	#else
+		typedef unsigned int	uint_ptr;
+	#endif
+
+#else
+	#define LITEHTML_UTF8
+
+	typedef std::string			tstring;
+	typedef char				tchar_t;
+	typedef void*				uint_ptr;
+	typedef std::stringstream	tstringstream;
+
+	#define _t(quote)			quote
+
+	#define t_strlen			strlen
+	#define t_strcmp			strcmp
+	#define t_strncmp			strncmp
+
+	#define t_strcasecmp		strcasecmp
+	#define t_strncasecmp		strncasecmp
+	#define t_itoa(value, buffer, size, radix)	snprintf(buffer, size, "%d", value)
+
+	#define t_strtol			strtol
+	#define t_atoi				atoi
+	#define t_strtod			strtod
+	#define t_strstr			strstr
+	#define t_tolower			tolower
+	#define t_isdigit			isdigit
+
+#endif
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/style.cpp b/src/plugins/litehtml_viewer/litehtml/style.cpp
new file mode 100644
index 0000000..60b8738
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/style.cpp
@@ -0,0 +1,654 @@
+#include "html.h"
+#include "style.h"
+#include <functional>
+#include <algorithm>
+#ifndef WINCE
+#include <locale>
+#endif
+
+litehtml::string_map litehtml::style::m_valid_values =
+{
+	{ _t("white-space"), white_space_strings }
+};
+
+litehtml::style::style()
+{
+}
+
+litehtml::style::style( const style& val )
+{
+	m_properties = val.m_properties;
+}
+
+litehtml::style::~style()
+{
+
+}
+
+void litehtml::style::parse( const tchar_t* txt, const tchar_t* baseurl )
+{
+	std::vector<tstring> properties;
+	split_string(txt, properties, _t(";"));
+
+	for(std::vector<tstring>::const_iterator i = properties.begin(); i != properties.end(); i++)
+	{
+		parse_property(*i, baseurl);
+	}
+}
+
+void litehtml::style::parse_property( const tstring& txt, const tchar_t* baseurl )
+{
+	tstring::size_type pos = txt.find_first_of(_t(":"));
+	if(pos != tstring::npos)
+	{
+		tstring name	= txt.substr(0, pos);
+		tstring val	= txt.substr(pos + 1);
+
+		trim(name);
+		trim(val);
+
+		lcase(name);
+
+		if(!name.empty() && !val.empty())
+		{
+			string_vector vals;
+			split_string(val, vals, _t("!"));
+			if(vals.size() == 1)
+			{
+				add_property(name.c_str(), val.c_str(), baseurl, false);
+			} else if(vals.size() > 1)
+			{
+				trim(vals[0]);
+				lcase(vals[1]);
+				if(vals[1] == _t("important"))
+				{
+					add_property(name.c_str(), vals[0].c_str(), baseurl, true);
+				} else
+				{
+					add_property(name.c_str(), vals[0].c_str(), baseurl, false);
+				}
+			}
+		}
+	}
+}
+
+void litehtml::style::combine( const litehtml::style& src )
+{
+	for(props_map::const_iterator i = src.m_properties.begin(); i != src.m_properties.end(); i++)
+	{
+		add_parsed_property(i->first.c_str(), i->second.m_value.c_str(), i->second.m_important);
+	}
+}
+
+void litehtml::style::add_property( const tchar_t* name, const tchar_t* val, const tchar_t* baseurl, bool important )
+{
+	if(!name || !val)
+	{
+		return;
+	}
+
+	// Add baseurl for background image 
+	if(	!t_strcmp(name, _t("background-image")))
+	{
+		add_parsed_property(name, val, important);
+		if(baseurl)
+		{
+			add_parsed_property(_t("background-image-baseurl"), baseurl, important);
+		}
+	} else
+
+	// Parse border spacing properties 
+	if(	!t_strcmp(name, _t("border-spacing")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "));
+		if(tokens.size() == 1)
+		{
+			add_property(_t("-litehtml-border-spacing-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("-litehtml-border-spacing-y"), tokens[0].c_str(), baseurl, important);
+		} else if(tokens.size() == 2)
+		{
+			add_property(_t("-litehtml-border-spacing-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("-litehtml-border-spacing-y"), tokens[1].c_str(), baseurl, important);
+		}
+	} else
+
+	// Parse borders shorthand properties 
+
+	if(	!t_strcmp(name, _t("border")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "), _t(""), _t("("));
+		int idx;
+		tstring str;
+		for(string_vector::const_iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+		{
+			idx = value_index(tok->c_str(), border_style_strings, -1);
+			if(idx >= 0)
+			{
+				add_property(_t("border-left-style"), tok->c_str(), baseurl, important);
+				add_property(_t("border-right-style"), tok->c_str(), baseurl, important);
+				add_property(_t("border-top-style"), tok->c_str(), baseurl, important);
+				add_property(_t("border-bottom-style"), tok->c_str(), baseurl, important);
+			} else
+			{
+				if(web_color::is_color(tok->c_str()))
+				{
+					add_property(_t("border-left-color"), tok->c_str(), baseurl, important);
+					add_property(_t("border-right-color"), tok->c_str(), baseurl, important);
+					add_property(_t("border-top-color"), tok->c_str(), baseurl, important);
+					add_property(_t("border-bottom-color"), tok->c_str(), baseurl, important);
+				} else
+				{
+					add_property(_t("border-left-width"), tok->c_str(), baseurl, important);
+					add_property(_t("border-right-width"), tok->c_str(), baseurl, important);
+					add_property(_t("border-top-width"), tok->c_str(), baseurl, important);
+					add_property(_t("border-bottom-width"), tok->c_str(), baseurl, important);
+				}
+			}
+		}
+	} else if(	!t_strcmp(name, _t("border-left"))	||
+		!t_strcmp(name, _t("border-right"))	||
+		!t_strcmp(name, _t("border-top"))	||
+		!t_strcmp(name, _t("border-bottom")) )
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "), _t(""), _t("("));
+		int idx;
+		tstring str;
+		for(string_vector::const_iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+		{
+			idx = value_index(tok->c_str(), border_style_strings, -1);
+			if(idx >= 0)
+			{
+				str = name;
+				str += _t("-style");
+				add_property(str.c_str(), tok->c_str(), baseurl, important);
+			} else
+			{
+				if(web_color::is_color(tok->c_str()))
+				{
+					str = name;
+					str += _t("-color");
+					add_property(str.c_str(), tok->c_str(), baseurl, important);
+				} else
+				{
+					str = name;
+					str += _t("-width");
+					add_property(str.c_str(), tok->c_str(), baseurl, important);
+				}
+			}
+		}
+	} else 
+
+	// Parse border radius shorthand properties 
+	if(!t_strcmp(name, _t("border-bottom-left-radius")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "));
+		if(tokens.size() >= 2)
+		{
+			add_property(_t("border-bottom-left-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-y"), tokens[1].c_str(), baseurl, important);
+		} else if(tokens.size() == 1)
+		{
+			add_property(_t("border-bottom-left-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-y"), tokens[0].c_str(), baseurl, important);
+		}
+
+	} else if(!t_strcmp(name, _t("border-bottom-right-radius")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "));
+		if(tokens.size() >= 2)
+		{
+			add_property(_t("border-bottom-right-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-y"), tokens[1].c_str(), baseurl, important);
+		} else if(tokens.size() == 1)
+		{
+			add_property(_t("border-bottom-right-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-y"), tokens[0].c_str(), baseurl, important);
+		}
+
+	} else if(!t_strcmp(name, _t("border-top-right-radius")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "));
+		if(tokens.size() >= 2)
+		{
+			add_property(_t("border-top-right-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-y"), tokens[1].c_str(), baseurl, important);
+		} else if(tokens.size() == 1)
+		{
+			add_property(_t("border-top-right-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-y"), tokens[0].c_str(), baseurl, important);
+		}
+
+	} else if(!t_strcmp(name, _t("border-top-left-radius")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "));
+		if(tokens.size() >= 2)
+		{
+			add_property(_t("border-top-left-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-left-radius-y"), tokens[1].c_str(), baseurl, important);
+		} else if(tokens.size() == 1)
+		{
+			add_property(_t("border-top-left-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-left-radius-y"), tokens[0].c_str(), baseurl, important);
+		}
+
+	} else 
+
+	// Parse border-radius shorthand properties 
+	if(!t_strcmp(name, _t("border-radius")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t("/"));
+		if(tokens.size() == 1)
+		{
+			add_property(_t("border-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-radius-y"), tokens[0].c_str(), baseurl, important);
+		} else if(tokens.size() >= 2)
+		{
+			add_property(_t("border-radius-x"), tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-radius-y"), tokens[1].c_str(), baseurl, important);
+		}
+	} else if(!t_strcmp(name, _t("border-radius-x")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "));
+		if(tokens.size() == 1)
+		{
+			add_property(_t("border-top-left-radius-x"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-x"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-x"),	tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-x"),	tokens[0].c_str(), baseurl, important);
+		} else if(tokens.size() == 2)
+		{
+			add_property(_t("border-top-left-radius-x"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-x"),		tokens[1].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-x"),	tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-x"),	tokens[1].c_str(), baseurl, important);
+		} else if(tokens.size() == 3)
+		{
+			add_property(_t("border-top-left-radius-x"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-x"),		tokens[1].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-x"),	tokens[2].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-x"),	tokens[1].c_str(), baseurl, important);
+		} else if(tokens.size() == 4)
+		{
+			add_property(_t("border-top-left-radius-x"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-x"),		tokens[1].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-x"),	tokens[2].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-x"),	tokens[3].c_str(), baseurl, important);
+		}
+	} else if(!t_strcmp(name, _t("border-radius-y")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "));
+		if(tokens.size() == 1)
+		{
+			add_property(_t("border-top-left-radius-y"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-y"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-y"),	tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-y"),	tokens[0].c_str(), baseurl, important);
+		} else if(tokens.size() == 2)
+		{
+			add_property(_t("border-top-left-radius-y"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-y"),		tokens[1].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-y"),	tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-y"),	tokens[1].c_str(), baseurl, important);
+		} else if(tokens.size() == 3)
+		{
+			add_property(_t("border-top-left-radius-y"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-y"),		tokens[1].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-y"),	tokens[2].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-y"),	tokens[1].c_str(), baseurl, important);
+		} else if(tokens.size() == 4)
+		{
+			add_property(_t("border-top-left-radius-y"),		tokens[0].c_str(), baseurl, important);
+			add_property(_t("border-top-right-radius-y"),		tokens[1].c_str(), baseurl, important);
+			add_property(_t("border-bottom-right-radius-y"),	tokens[2].c_str(), baseurl, important);
+			add_property(_t("border-bottom-left-radius-y"),	tokens[3].c_str(), baseurl, important);
+		}
+	}
+	
+
+	// Parse list-style shorthand properties 
+	if(!t_strcmp(name, _t("list-style")))
+	{
+		add_parsed_property(_t("list-style-type"),			_t("disc"),		important);
+		add_parsed_property(_t("list-style-position"),		_t("outside"),	important);
+		add_parsed_property(_t("list-style-image"),			_t(""),			important);
+		add_parsed_property(_t("list-style-image-baseurl"),	_t(""),			important);
+
+		string_vector tokens;
+		split_string(val, tokens, _t(" "), _t(""), _t("("));
+		for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+		{
+			int idx = value_index(tok->c_str(), list_style_type_strings, -1);
+			if(idx >= 0)
+			{
+				add_parsed_property(_t("list-style-type"), *tok, important);
+			} else
+			{
+				idx = value_index(tok->c_str(), list_style_position_strings, -1);
+				if(idx >= 0)
+				{
+					add_parsed_property(_t("list-style-position"), *tok, important);
+				} else if(!t_strncmp(val, _t("url"), 3))
+				{
+					add_parsed_property(_t("list-style-image"), *tok, important);
+					if(baseurl)
+					{
+						add_parsed_property(_t("list-style-image-baseurl"), baseurl, important);
+					}
+				}
+			}
+		}
+	} else 
+
+	// Add baseurl for background image 
+	if(	!t_strcmp(name, _t("list-style-image")))
+	{
+		add_parsed_property(name, val, important);
+		if(baseurl)
+		{
+			add_parsed_property(_t("list-style-image-baseurl"), baseurl, important);
+		}
+	} else
+		
+	// Parse background shorthand properties 
+	if(!t_strcmp(name, _t("background")))
+	{
+		parse_short_background(val, baseurl, important);
+
+	} else 
+		
+	// Parse margin and padding shorthand properties 
+	if(!t_strcmp(name, _t("margin")) || !t_strcmp(name, _t("padding")))
+	{
+		string_vector tokens;
+		split_string(val, tokens, _t(" "));
+		if(tokens.size() >= 4)
+		{
+			add_parsed_property(tstring(name) + _t("-top"),		tokens[0], important);
+			add_parsed_property(tstring(name) + _t("-right"),		tokens[1], important);
+			add_parsed_property(tstring(name) + _t("-bottom"),	tokens[2], important);
+			add_parsed_property(tstring(name) + _t("-left"),		tokens[3], important);
+		} else if(tokens.size() == 3)
+		{
+			add_parsed_property(tstring(name) + _t("-top"),		tokens[0], important);
+			add_parsed_property(tstring(name) + _t("-right"),		tokens[1], important);
+			add_parsed_property(tstring(name) + _t("-left"),		tokens[1], important);
+			add_parsed_property(tstring(name) + _t("-bottom"),	tokens[2], important);
+		} else if(tokens.size() == 2)
+		{
+			add_parsed_property(tstring(name) + _t("-top"),		tokens[0], important);
+			add_parsed_property(tstring(name) + _t("-bottom"),	tokens[0], important);
+			add_parsed_property(tstring(name) + _t("-right"),		tokens[1], important);
+			add_parsed_property(tstring(name) + _t("-left"),		tokens[1], important);
+		} else if(tokens.size() == 1)
+		{
+			add_parsed_property(tstring(name) + _t("-top"),		tokens[0], important);
+			add_parsed_property(tstring(name) + _t("-bottom"),	tokens[0], important);
+			add_parsed_property(tstring(name) + _t("-right"),		tokens[0], important);
+			add_parsed_property(tstring(name) + _t("-left"),		tokens[0], important);
+		}
+	} else 
+		
+		
+	// Parse border-* shorthand properties 
+	if(	!t_strcmp(name, _t("border-left")) || 
+		!t_strcmp(name, _t("border-right")) ||
+		!t_strcmp(name, _t("border-top"))  || 
+		!t_strcmp(name, _t("border-bottom")))
+	{
+		parse_short_border(name, val, important);
+	} else 
+		
+	// Parse border-width/style/color shorthand properties 
+	if(	!t_strcmp(name, _t("border-width")) ||
+		!t_strcmp(name, _t("border-style"))  ||
+		!t_strcmp(name, _t("border-color")) )
+	{
+		string_vector nametokens;
+		split_string(name, nametokens, _t("-"));
+
+		string_vector tokens;
+		split_string(val, tokens, _t(" "));
+		if(tokens.size() >= 4)
+		{
+			add_parsed_property(nametokens[0] + _t("-top-")		+ nametokens[1],	tokens[0], important);
+			add_parsed_property(nametokens[0] + _t("-right-")	+ nametokens[1],	tokens[1], important);
+			add_parsed_property(nametokens[0] + _t("-bottom-")	+ nametokens[1],	tokens[2], important);
+			add_parsed_property(nametokens[0] + _t("-left-")	+ nametokens[1],	tokens[3], important);
+		} else if(tokens.size() == 3)
+		{
+			add_parsed_property(nametokens[0] + _t("-top-")		+ nametokens[1],	tokens[0], important);
+			add_parsed_property(nametokens[0] + _t("-right-")	+ nametokens[1],	tokens[1], important);
+			add_parsed_property(nametokens[0] + _t("-left-")	+ nametokens[1],	tokens[1], important);
+			add_parsed_property(nametokens[0] + _t("-bottom-")	+ nametokens[1],	tokens[2], important);
+		} else if(tokens.size() == 2)
+		{
+			add_parsed_property(nametokens[0] + _t("-top-")		+ nametokens[1],	tokens[0], important);
+			add_parsed_property(nametokens[0] + _t("-bottom-")	+ nametokens[1],	tokens[0], important);
+			add_parsed_property(nametokens[0] + _t("-right-")	+ nametokens[1],	tokens[1], important);
+			add_parsed_property(nametokens[0] + _t("-left-")	+ nametokens[1],	tokens[1], important);
+		} else if(tokens.size() == 1)
+		{
+			add_parsed_property(nametokens[0] + _t("-top-")		+ nametokens[1],	tokens[0], important);
+			add_parsed_property(nametokens[0] + _t("-bottom-")	+ nametokens[1],	tokens[0], important);
+			add_parsed_property(nametokens[0] + _t("-right-")	+ nametokens[1],	tokens[0], important);
+			add_parsed_property(nametokens[0] + _t("-left-")	+ nametokens[1],	tokens[0], important);
+		}
+	} else 
+		
+	// Parse font shorthand properties 
+	if(!t_strcmp(name, _t("font")))
+	{
+		parse_short_font(val, important);
+	} else 
+	{
+		add_parsed_property(name, val, important);
+	}
+}
+
+void litehtml::style::parse_short_border( const tstring& prefix, const tstring& val, bool important )
+{
+	string_vector tokens;
+	split_string(val, tokens, _t(" "), _t(""), _t("("));
+	if(tokens.size() >= 3)
+	{
+		add_parsed_property(prefix + _t("-width"),	tokens[0], important);
+		add_parsed_property(prefix + _t("-style"),	tokens[1], important);
+		add_parsed_property(prefix + _t("-color"),	tokens[2], important);
+	} else if(tokens.size() == 2)
+	{
+		if(iswdigit(tokens[0][0]) || value_index(val.c_str(), border_width_strings) >= 0)
+		{
+			add_parsed_property(prefix + _t("-width"),	tokens[0], important);
+			add_parsed_property(prefix + _t("-style"),	tokens[1], important);
+		} else
+		{
+			add_parsed_property(prefix + _t("-style"),	tokens[0], important);
+			add_parsed_property(prefix + _t("-color"),	tokens[1], important);
+		}
+	}
+}
+
+void litehtml::style::parse_short_background( const tstring& val, const tchar_t* baseurl, bool important )
+{
+	add_parsed_property(_t("background-color"),			_t("transparent"),	important);
+	add_parsed_property(_t("background-image"),			_t(""),				important);
+	add_parsed_property(_t("background-image-baseurl"), _t(""),				important);
+	add_parsed_property(_t("background-repeat"),		_t("repeat"),		important);
+	add_parsed_property(_t("background-origin"),		_t("padding-box"),	important);
+	add_parsed_property(_t("background-clip"),			_t("border-box"),	important);
+	add_parsed_property(_t("background-attachment"),	_t("scroll"),		important);
+
+	if(val == _t("none"))
+	{
+		return;
+	}
+
+	string_vector tokens;
+	split_string(val, tokens, _t(" "), _t(""), _t("("));
+	bool origin_found = false;
+	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+	{
+		if(web_color::is_color(tok->c_str()))
+		{
+			add_parsed_property(_t("background-color"), *tok, important);
+		} else if(tok->substr(0, 3) == _t("url"))
+		{
+			add_parsed_property(_t("background-image"), *tok, important);
+			if(baseurl)
+			{
+				add_parsed_property(_t("background-image-baseurl"), baseurl, important);
+			}
+
+		} else if( value_in_list(tok->c_str(), background_repeat_strings) )
+		{
+			add_parsed_property(_t("background-repeat"), *tok, important);
+		} else if( value_in_list(tok->c_str(), background_attachment_strings) )
+		{
+			add_parsed_property(_t("background-attachment"), *tok, important);
+		} else if( value_in_list(tok->c_str(), background_box_strings) )
+		{
+			if(!origin_found)
+			{
+				add_parsed_property(_t("background-origin"), *tok, important);
+				origin_found = true;
+			} else
+			{
+				add_parsed_property(_t("background-clip"),*tok, important);
+			}
+		} else if(	value_in_list(tok->c_str(), _t("left;right;top;bottom;center")) ||
+					iswdigit((*tok)[0]) ||
+					(*tok)[0] == _t('-')	||
+					(*tok)[0] == _t('.')	||
+					(*tok)[0] == _t('+'))
+		{
+			if(m_properties.find(_t("background-position")) != m_properties.end())
+			{
+				m_properties[_t("background-position")].m_value = m_properties[_t("background-position")].m_value + _t(" ") + *tok;
+			} else
+			{
+				add_parsed_property(_t("background-position"), *tok, important);
+			}
+		}
+	}
+}
+
+void litehtml::style::parse_short_font( const tstring& val, bool important )
+{
+	add_parsed_property(_t("font-style"),	_t("normal"),	important);
+	add_parsed_property(_t("font-variant"),	_t("normal"),	important);
+	add_parsed_property(_t("font-weight"),	_t("normal"),	important);
+	add_parsed_property(_t("font-size"),		_t("medium"),	important);
+	add_parsed_property(_t("line-height"),	_t("normal"),	important);
+
+	string_vector tokens;
+	split_string(val, tokens, _t(" "), _t(""), _t("\""));
+
+	int idx = 0;
+	bool was_normal = false;
+	bool is_family = false;
+	tstring font_family;
+	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+	{
+		idx = value_index(tok->c_str(), font_style_strings);
+		if(!is_family)
+		{
+			if(idx >= 0)
+			{
+				if(idx == 0 && !was_normal)
+				{
+					add_parsed_property(_t("font-weight"),		*tok, important);
+					add_parsed_property(_t("font-variant"),		*tok, important);
+					add_parsed_property(_t("font-style"),		*tok, important);
+				} else
+				{
+					add_parsed_property(_t("font-style"),		*tok, important);
+				}
+			} else
+			{
+				if(value_in_list(tok->c_str(), font_weight_strings))
+				{
+					add_parsed_property(_t("font-weight"),		*tok, important);
+				} else
+				{
+					if(value_in_list(tok->c_str(), font_variant_strings))
+					{
+						add_parsed_property(_t("font-variant"),	*tok, important);
+					} else if( iswdigit((*tok)[0]) )
+					{
+						string_vector szlh;
+						split_string(*tok, szlh, _t("/"));
+
+						if(szlh.size() == 1)
+						{
+							add_parsed_property(_t("font-size"),	szlh[0], important);
+						} else	if(szlh.size() >= 2)
+						{
+							add_parsed_property(_t("font-size"),	szlh[0], important);
+							add_parsed_property(_t("line-height"),	szlh[1], important);
+						}
+					} else
+					{
+						is_family = true;
+						font_family += *tok;
+					}
+				}
+			}
+		} else
+		{
+			font_family += *tok;
+		}
+	}
+	add_parsed_property(_t("font-family"), font_family, important);
+}
+
+void litehtml::style::add_parsed_property( const tstring& name, const tstring& val, bool important )
+{
+	bool is_valid = true;
+	string_map::iterator vals = m_valid_values.find(name);
+	if (vals != m_valid_values.end())
+	{
+		if (!value_in_list(val, vals->second))
+		{
+			is_valid = false;
+		}
+	}
+
+	if (is_valid)
+	{
+		props_map::iterator prop = m_properties.find(name);
+		if (prop != m_properties.end())
+		{
+			if (!prop->second.m_important || (important && prop->second.m_important))
+			{
+				prop->second.m_value = val;
+				prop->second.m_important = important;
+			}
+		}
+		else
+		{
+			m_properties[name] = property_value(val.c_str(), important);
+		}
+	}
+}
+
+void litehtml::style::remove_property( const tstring& name, bool important )
+{
+	props_map::iterator prop = m_properties.find(name);
+	if(prop != m_properties.end())
+	{
+		if( !prop->second.m_important || (important && prop->second.m_important) )
+		{
+			m_properties.erase(prop);
+		}
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/style.h b/src/plugins/litehtml_viewer/litehtml/style.h
new file mode 100644
index 0000000..bf05772
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/style.h
@@ -0,0 +1,91 @@
+#pragma once
+#include "attributes.h"
+#include <string>
+
+namespace litehtml
+{
+	class property_value
+	{
+	public:
+		tstring	m_value;
+		bool			m_important;
+
+		property_value()
+		{
+			m_important = false;
+		}
+		property_value(const tchar_t* val, bool imp)
+		{
+			m_important = imp;
+			m_value		= val;
+		}
+		property_value(const property_value& val)
+		{
+			m_value		= val.m_value;
+			m_important	= val.m_important;
+		}
+
+		property_value& operator=(const property_value& val)
+		{
+			m_value		= val.m_value;
+			m_important	= val.m_important;
+			return *this;
+		}
+	};
+
+	typedef std::map<tstring, property_value>	props_map;
+
+	class style
+	{
+	public:
+		typedef std::shared_ptr<style>		ptr;
+		typedef std::vector<style::ptr>		vector;
+	private:
+		props_map			m_properties;
+		static string_map	m_valid_values;
+	public:
+		style();
+		style(const style& val);
+		virtual ~style();
+
+		void operator=(const style& val)
+		{
+			m_properties = val.m_properties;
+		}
+
+		void add(const tchar_t* txt, const tchar_t* baseurl)
+		{
+			parse(txt, baseurl);
+		}
+
+		void add_property(const tchar_t* name, const tchar_t* val, const tchar_t* baseurl, bool important);
+
+		const tchar_t* get_property(const tchar_t* name) const
+		{
+			if(name)
+			{
+				props_map::const_iterator f = m_properties.find(name);
+				if(f != m_properties.end())
+				{
+					return f->second.m_value.c_str();
+				}
+			}
+			return 0;
+		}
+
+		void combine(const litehtml::style& src);
+		void clear()
+		{
+			m_properties.clear();
+		}
+
+	private:
+		void parse_property(const tstring& txt, const tchar_t* baseurl);
+		void parse(const tchar_t* txt, const tchar_t* baseurl);
+		void parse_short_border(const tstring& prefix, const tstring& val, bool important);
+		void parse_short_background(const tstring& val, const tchar_t* baseurl, bool important);
+		void parse_short_font(const tstring& val, bool important);
+		void add_parsed_property(const tstring& name, const tstring& val, bool important);
+		void remove_property(const tstring& name, bool important);
+	};
+}
\ No newline at end of file
diff --git a/src/plugins/litehtml_viewer/litehtml/stylesheet.cpp b/src/plugins/litehtml_viewer/litehtml/stylesheet.cpp
new file mode 100644
index 0000000..7f0a2be
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/stylesheet.cpp
@@ -0,0 +1,219 @@
+#include "html.h"
+#include "stylesheet.h"
+#include <algorithm>
+#include "document.h"
+
+
+void litehtml::css::parse_stylesheet(const tchar_t* str, const tchar_t* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media)
+{
+	tstring text = str;
+
+	// remove comments
+	tstring::size_type c_start = text.find(_t("/*"));
+	while(c_start != tstring::npos)
+	{
+		tstring::size_type c_end = text.find(_t("*/"), c_start + 2);
+		text.erase(c_start, c_end - c_start + 2);
+		c_start = text.find(_t("/*"));
+	}
+
+	tstring::size_type pos = text.find_first_not_of(_t(" \n\r\t"));
+	while(pos != tstring::npos)
+	{
+		while(pos != tstring::npos && text[pos] == _t('@'))
+		{
+			tstring::size_type sPos = pos;
+			pos = text.find_first_of(_t("{"), pos);
+			if(pos != tstring::npos && text[pos] == _t('{'))
+			{
+				pos = find_close_bracket(text, pos, _t('{'), _t('}'));
+			}
+			if(pos != tstring::npos)
+			{
+				parse_atrule(text.substr(sPos, pos - sPos + 1), baseurl, doc, media);
+			} else
+			{
+				parse_atrule(text.substr(sPos), baseurl, doc, media);
+			}
+
+			if(pos != tstring::npos)
+			{
+				pos = text.find_first_not_of(_t(" \n\r\t"), pos + 1);
+			}
+		}
+
+		if(pos == tstring::npos)
+		{
+			break;
+		}
+
+		tstring::size_type style_start = text.find(_t("{"), pos);
+		tstring::size_type style_end	= text.find(_t("}"), pos);
+		if(style_start != tstring::npos && style_end != tstring::npos)
+		{
+			style::ptr st = std::make_shared<style>();
+			st->add(text.substr(style_start + 1, style_end - style_start - 1).c_str(), baseurl);
+
+			parse_selectors(text.substr(pos, style_start - pos), st, media);
+
+			if(media && doc)
+			{
+				doc->add_media_list(media);
+			}
+
+			pos = style_end + 1;
+		} else
+		{
+			pos = tstring::npos;
+		}
+
+		if(pos != tstring::npos)
+		{
+			pos = text.find_first_not_of(_t(" \n\r\t"), pos);
+		}
+	}
+}
+
+void litehtml::css::parse_css_url( const tstring& str, tstring& url )
+{
+	url = _t("");
+	size_t pos1 = str.find(_t('('));
+	size_t pos2 = str.find(_t(')'));
+	if(pos1 != tstring::npos && pos2 != tstring::npos)
+	{
+		url = str.substr(pos1 + 1, pos2 - pos1 - 1);
+		if(url.length())
+		{
+			if(url[0] == _t('\'') || url[0] == _t('"'))
+			{
+				url.erase(0, 1);
+			}
+		}
+		if(url.length())
+		{
+			if(url[url.length() - 1] == _t('\'') || url[url.length() - 1] == _t('"'))
+			{
+				url.erase(url.length() - 1, 1);
+			}
+		}
+	}
+}
+
+bool litehtml::css::parse_selectors( const tstring& txt, const litehtml::style::ptr& styles, const media_query_list::ptr& media )
+{
+	tstring selector = txt;
+	trim(selector);
+	string_vector tokens;
+	split_string(selector, tokens, _t(","));
+
+	bool added_something = false;
+
+	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+	{
+		css_selector::ptr selector = std::make_shared<css_selector>(media);
+		selector->m_style = styles;
+		trim(*tok);
+		if(selector->parse(*tok))
+		{
+			selector->calc_specificity();
+			add_selector(selector);
+			added_something = true;
+		}
+	}
+
+	return added_something;
+}
+
+void litehtml::css::sort_selectors()
+{
+	std::sort(m_selectors.begin(), m_selectors.end(),
+		 [](const css_selector::ptr& v1, const css_selector::ptr& v2)
+		 {
+			 return (*v1) < (*v2);
+		 }
+	);
+}
+
+void litehtml::css::parse_atrule(const tstring& text, const tchar_t* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media)
+{
+	if(text.substr(0, 7) == _t("@import"))
+	{
+		int sPos = 7;
+		tstring iStr;
+		iStr = text.substr(sPos);
+		if(iStr[iStr.length() - 1] == _t(';'))
+		{
+			iStr.erase(iStr.length() - 1);
+		}
+		trim(iStr);
+		string_vector tokens;
+		split_string(iStr, tokens, _t(" "), _t(""), _t("(\""));
+		if(!tokens.empty())
+		{
+			tstring url;
+			parse_css_url(tokens.front(), url);
+			if(url.empty())
+			{
+				url = tokens.front();
+			}
+			tokens.erase(tokens.begin());
+			if(doc)
+			{
+				document_container* doc_cont = doc->container();
+				if(doc_cont)
+				{
+					tstring css_text;
+					tstring css_baseurl;
+					if(baseurl)
+					{
+						css_baseurl = baseurl;
+					}
+					doc_cont->import_css(css_text, url, css_baseurl);
+					if(!css_text.empty())
+					{
+						media_query_list::ptr new_media = media;
+						if(!tokens.empty())
+						{
+							tstring media_str;
+							for(string_vector::iterator iter = tokens.begin(); iter != tokens.end(); iter++)
+							{
+								if(iter != tokens.begin())
+								{
+									media_str += _t(" ");
+								}
+								media_str += (*iter);
+							}
+							new_media = media_query_list::create_from_string(media_str, doc);
+							if(!new_media)
+							{
+								new_media = media;
+							}
+						}
+						parse_stylesheet(css_text.c_str(), css_baseurl.c_str(), doc, new_media);
+					}
+				}
+			}
+		}
+	} else if(text.substr(0, 6) == _t("@media"))
+	{
+		tstring::size_type b1 = text.find_first_of(_t('{'));
+		tstring::size_type b2 = text.find_last_of(_t('}'));
+		if(b1 != tstring::npos)
+		{
+			tstring media_type = text.substr(6, b1 - 6);
+			trim(media_type);
+			media_query_list::ptr new_media = media_query_list::create_from_string(media_type, doc);
+
+			tstring media_style;
+			if(b2 != tstring::npos)
+			{
+				media_style = text.substr(b1 + 1, b2 - b1 - 1);
+			} else
+			{
+				media_style = text.substr(b1 + 1);
+			}
+
+			parse_stylesheet(media_style.c_str(), baseurl, doc, new_media);
+		}
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/stylesheet.h b/src/plugins/litehtml_viewer/litehtml/stylesheet.h
new file mode 100644
index 0000000..04536c3
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/stylesheet.h
@@ -0,0 +1,50 @@
+#pragma once
+#include "style.h"
+#include "css_selector.h"
+
+namespace litehtml
+{
+	class document_container;
+
+	class css
+	{
+		css_selector::vector	m_selectors;
+	public:
+		css()
+		{
+
+		}
+		
+		~css()
+		{
+
+		}
+
+		const css_selector::vector& selectors() const
+		{
+			return m_selectors;
+		}
+
+		void clear()
+		{
+			m_selectors.clear();
+		}
+
+		void	parse_stylesheet(const tchar_t* str, const tchar_t* baseurl, const std::shared_ptr <document>& doc, const media_query_list::ptr& media);
+		void	sort_selectors();
+		static void	parse_css_url(const tstring& str, tstring& url);
+
+	private:
+		void	parse_atrule(const tstring& text, const tchar_t* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media);
+		void	add_selector(css_selector::ptr selector);
+		bool	parse_selectors(const tstring& txt, const litehtml::style::ptr& styles, const media_query_list::ptr& media);
+
+	};
+
+	inline void litehtml::css::add_selector( css_selector::ptr selector )
+	{
+		selector->m_order = (int) m_selectors.size();
+		m_selectors.push_back(selector);
+	}
+
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/table.cpp b/src/plugins/litehtml_viewer/litehtml/table.cpp
new file mode 100644
index 0000000..23d1e9a
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/table.cpp
@@ -0,0 +1,566 @@
+#include "html.h"
+#include "table.h"
+#include "html_tag.h"
+
+void litehtml::table_grid::add_cell(element::ptr& el)
+{
+	table_cell cell;
+	cell.el = el;
+	cell.colspan	= t_atoi(el->get_attr(_t("colspan"), _t("1")));
+	cell.rowspan	= t_atoi(el->get_attr(_t("rowspan"), _t("1")));
+	cell.borders	= el->get_borders();
+
+	while( is_rowspanned( (int) m_cells.size() - 1, (int) m_cells.back().size() ) )
+	{
+		m_cells.back().push_back(table_cell());
+	}
+
+	m_cells.back().push_back(cell);
+	for(int i = 1; i < cell.colspan; i++)
+	{
+		table_cell empty_cell;
+		m_cells.back().push_back(empty_cell);
+	}
+}
+
+
+void litehtml::table_grid::begin_row(element::ptr& row)
+{
+	std::vector<table_cell> r;
+	m_cells.push_back(r);
+	
+	m_rows.push_back(table_row(0, row));
+
+}
+
+
+bool litehtml::table_grid::is_rowspanned( int r, int c )
+{
+	for(int row = r - 1; row >= 0; row--)
+	{
+		if(c < (int) m_cells[row].size())
+		{
+			if(m_cells[row][c].rowspan > 1)
+			{
+				if(m_cells[row][c].rowspan >= r - row + 1)
+				{
+					return true;
+				}
+			}
+		}
+	}
+	return false;
+}
+
+void litehtml::table_grid::finish()
+{
+	m_rows_count	= (int) m_cells.size();
+	m_cols_count	= 0;
+	for(int i = 0; i < (int) m_cells.size(); i++)
+	{
+		m_cols_count = std::max(m_cols_count, (int) m_cells[i].size());
+	}
+	for(int i = 0; i < (int) m_cells.size(); i++)
+	{
+		for(int j = (int) m_cells[i].size(); j < m_cols_count; j++)
+		{
+			table_cell empty_cell;
+			m_cells[i].push_back(empty_cell);
+		}
+	}
+
+	m_columns.clear();
+	for(int i = 0; i < m_cols_count; i++)
+	{
+		m_columns.push_back(table_column(0, 0));
+	}
+
+	for(int col = 0; col < m_cols_count; col++)
+	{
+		for(int row = 0; row < m_rows_count; row++)
+		{
+			if(cell(col, row)->el)
+			{
+				// find minimum left border width
+				if(m_columns[col].border_left)
+				{
+					m_columns[col].border_left = std::min(m_columns[col].border_left, cell(col, row)->borders.left);
+				} else
+				{
+					m_columns[col].border_left = cell(col, row)->borders.left;
+				}
+				// find minimum right border width
+				if(m_columns[col].border_right)
+				{
+					m_columns[col].border_right = std::min(m_columns[col].border_right, cell(col, row)->borders.right);
+				} else
+				{
+					m_columns[col].border_right = cell(col, row)->borders.right;
+				}
+				// find minimum top border width
+				if(m_rows[row].border_top)
+				{
+					m_rows[row].border_top = std::min(m_rows[row].border_top, cell(col, row)->borders.top);
+				} else
+				{
+					m_rows[row].border_top = cell(col, row)->borders.top;
+				}
+				// find minimum bottom border width
+				if(m_rows[row].border_bottom)
+				{
+					m_rows[row].border_bottom = std::min(m_rows[row].border_bottom, cell(col, row)->borders.bottom);
+				} else
+				{
+					m_rows[row].border_bottom = cell(col, row)->borders.bottom;
+				}
+			}
+
+			if(cell(col, row)->el && cell(col, row)->colspan <= 1)
+			{
+				if (!cell(col, row)->el->get_css_width().is_predefined() && m_columns[col].css_width.is_predefined())
+				{
+					m_columns[col].css_width = cell(col, row)->el->get_css_width();
+				}
+			}
+		}
+	}
+
+	for(int col = 0; col < m_cols_count; col++)
+	{
+		for(int row = 0; row < m_rows_count; row++)
+		{
+			if(cell(col, row)->el)
+			{
+				cell(col, row)->el->set_css_width(m_columns[col].css_width);
+			}
+		}
+	}
+}
+
+litehtml::table_cell* litehtml::table_grid::cell( int t_col, int t_row )
+{
+	if(t_col >= 0 && t_col < m_cols_count && t_row >= 0 && t_row < m_rows_count)
+	{
+		return &m_cells[t_row][t_col];
+	}
+	return 0;
+}
+
+void litehtml::table_grid::distribute_max_width( int width, int start, int end )
+{
+	table_column_accessor_max_width selector;
+	distribute_width(width, start, end, &selector);
+}
+
+void litehtml::table_grid::distribute_min_width( int width, int start, int end )
+{
+	table_column_accessor_min_width selector;
+	distribute_width(width, start, end, &selector);
+}
+
+void litehtml::table_grid::distribute_width( int width, int start, int end, table_column_accessor* acc )
+{
+	if(!(start >= 0 && start < m_cols_count && end >= 0 && end < m_cols_count))
+	{
+		return;
+	}
+
+	int cols_width = 0;
+	for(int col = start; col <= end; col++)
+	{
+		cols_width		+= m_columns[col].max_width;
+	}
+
+	int add = width / (end - start + 1);
+	int added_width = 0;
+	for(int col = start; col <= end; col++)
+	{
+		if(cols_width)
+		{
+			add = round_f( (float) width * ((float) m_columns[col].max_width / (float) cols_width) );
+		}
+		added_width += add;
+		acc->get(m_columns[col]) += add;
+	}
+	if(added_width < width)
+	{
+		acc->get(m_columns[start]) += width - added_width;
+	}
+}
+
+void litehtml::table_grid::distribute_width( int width, int start, int end )
+{
+	if(!(start >= 0 && start < m_cols_count && end >= 0 && end < m_cols_count))
+	{
+		return;
+	}
+
+	std::vector<table_column*> distribute_columns;
+
+	for(int step = 0; step < 3; step++)
+	{
+		distribute_columns.clear();
+
+		switch(step)
+		{
+		case 0:
+			{
+				// distribute between the columns with width == auto
+				for(int col = start; col <= end; col++)
+				{
+					if(m_columns[col].css_width.is_predefined())
+					{
+						distribute_columns.push_back(&m_columns[col]);
+					}
+				}
+			}
+			break;
+		case 1:
+			{
+				// distribute between the columns with percents
+				for(int col = start; col <= end; col++)
+				{
+					if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
+					{
+						distribute_columns.push_back(&m_columns[col]);
+					}
+				}
+			}
+			break;
+		case 2:
+			{
+				//well distribute between all columns
+				for(int col = start; col <= end; col++)
+				{
+					distribute_columns.push_back(&m_columns[col]);
+				}
+			}
+			break;
+		}
+
+		int added_width = 0;
+
+		if(!distribute_columns.empty() || step == 2)
+		{
+			int cols_width = 0;
+			for(std::vector<table_column*>::iterator col = distribute_columns.begin(); col != distribute_columns.end(); col++)
+			{
+				cols_width += (*col)->max_width - (*col)->min_width;
+			}
+
+			if(cols_width)
+			{
+				int add = width / (int) distribute_columns.size();
+				for(std::vector<table_column*>::iterator col = distribute_columns.begin(); col != distribute_columns.end(); col++)
+				{
+					add = round_f( (float) width * ((float) ((*col)->max_width - (*col)->min_width) / (float) cols_width) );
+					if((*col)->width + add >= (*col)->min_width)
+					{
+						(*col)->width	+= add;
+						added_width		+= add;
+					} else
+					{
+						added_width	+= ((*col)->width - (*col)->min_width) * (add / abs(add));
+						(*col)->width = (*col)->min_width;
+					}
+				}
+				if(added_width < width && step)
+				{
+					distribute_columns.front()->width += width - added_width;
+					added_width = width;
+				}
+			} else
+			{
+				distribute_columns.back()->width += width;
+				added_width = width;
+			}
+		}
+
+		if(added_width == width)
+		{
+			break;
+		} else
+		{
+			width -= added_width;
+		}
+	}
+}
+
+int litehtml::table_grid::calc_table_width(int block_width, bool is_auto, int& min_table_width, int& max_table_width)
+{
+	//int table_width = 0;
+
+	min_table_width = 0; // MIN
+	max_table_width = 0; // MAX
+
+	int cur_width = 0;
+	int max_w = 0;
+	int min_w = 0;
+
+	for(int col = 0; col < m_cols_count; col++)
+	{
+		min_table_width += m_columns[col].min_width;
+		max_table_width += m_columns[col].max_width;
+
+		if(!m_columns[col].css_width.is_predefined())
+		{
+			m_columns[col].width = m_columns[col].css_width.calc_percent(block_width);
+			m_columns[col].width = std::max(m_columns[col].width, m_columns[col].min_width);
+		} else
+		{
+			m_columns[col].width = m_columns[col].min_width;
+			max_w += m_columns[col].max_width;
+			min_w += m_columns[col].min_width;
+		}
+
+		cur_width += m_columns[col].width;
+	}
+
+	if(cur_width == block_width)
+	{
+		return cur_width;
+	}
+
+	if(cur_width < block_width)
+	{
+		if(cur_width - min_w + max_w <= block_width)
+		{
+			cur_width = 0;
+			for(int col = 0; col < m_cols_count; col++)
+			{
+				if(m_columns[col].css_width.is_predefined())
+				{
+					m_columns[col].width = m_columns[col].max_width;
+				}
+				cur_width += m_columns[col].width;
+			}
+			if(cur_width == block_width || is_auto)
+			{
+				return cur_width;
+			}
+		}
+		distribute_width(block_width - cur_width, 0, m_cols_count - 1);
+		cur_width = 0;
+		for(int col = 0; col < m_cols_count; col++)
+		{
+			cur_width += m_columns[col].width;
+		}
+	} else
+	{
+		int fixed_width = 0;
+		float percent = 0;
+		for(int col = 0; col < m_cols_count; col++)
+		{
+			if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
+			{
+				percent += m_columns[col].css_width.val();
+			} else
+			{
+				fixed_width += m_columns[col].width;
+			}
+		}
+		float scale = (float) (100.0 / percent);
+		cur_width = 0;
+		for(int col = 0; col < m_cols_count; col++)
+		{
+			if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
+			{
+				css_length w;
+				w.set_value(m_columns[col].css_width.val() * scale, css_units_percentage);
+				m_columns[col].width = w.calc_percent(block_width - fixed_width);
+				if(m_columns[col].width < m_columns[col].min_width)
+				{
+					m_columns[col].width = m_columns[col].min_width;
+				}
+			}
+			cur_width += m_columns[col].width;
+		}
+	}
+	return cur_width;
+}
+
+void litehtml::table_grid::clear()
+{
+	m_rows_count	= 0;
+	m_cols_count	= 0;
+	m_cells.clear();
+	m_columns.clear();
+	m_rows.clear();
+}
+
+void litehtml::table_grid::calc_horizontal_positions( margins& table_borders, border_collapse bc, int bdr_space_x)
+{
+	if(bc == border_collapse_separate)
+	{
+		int left = bdr_space_x;
+		for(int i = 0; i < m_cols_count; i++)
+		{
+			m_columns[i].left	= left;
+			m_columns[i].right	= m_columns[i].left + m_columns[i].width;
+			left = m_columns[i].right + bdr_space_x;
+		}
+	} else
+	{
+		int left = 0;
+		if(m_cols_count)
+		{
+			left -= std::min(table_borders.left, m_columns[0].border_left);
+		}
+		for(int i = 0; i < m_cols_count; i++)
+		{
+			if(i > 0)
+			{
+				left -= std::min(m_columns[i - 1].border_right, m_columns[i].border_left);
+			}
+
+			m_columns[i].left	= left;
+			m_columns[i].right	= m_columns[i].left + m_columns[i].width;
+			left = m_columns[i].right;
+		}
+	}
+}
+
+void litehtml::table_grid::calc_vertical_positions( margins& table_borders, border_collapse bc, int bdr_space_y )
+{
+	if(bc == border_collapse_separate)
+	{
+		int top = bdr_space_y;
+		for(int i = 0; i < m_rows_count; i++)
+		{
+			m_rows[i].top		= top;
+			m_rows[i].bottom	= m_rows[i].top + m_rows[i].height;
+			top = m_rows[i].bottom + bdr_space_y;
+		}
+	} else
+	{
+		int top = 0;
+		if(m_rows_count)
+		{
+			top -= std::min(table_borders.top, m_rows[0].border_top);
+		}
+		for(int i = 0; i < m_rows_count; i++)
+		{
+			if(i > 0)
+			{
+				top -= std::min(m_rows[i - 1].border_bottom, m_rows[i].border_top);
+			}
+
+			m_rows[i].top		= top;
+			m_rows[i].bottom	= m_rows[i].top + m_rows[i].height;
+			top = m_rows[i].bottom;
+		}
+	}
+}
+
+void litehtml::table_grid::calc_rows_height(int blockHeight, int borderSpacingY)
+{
+	int min_table_height = 0;
+
+	// compute vertical size inferred by cells
+	for (auto& row : m_rows)
+	{
+		if (!row.css_height.is_predefined())
+		{
+			if (row.css_height.units() != css_units_percentage)
+			{
+				if (row.height < (int)row.css_height.val())
+				{
+					row.height = (int)row.css_height.val();
+				}
+			}
+		}
+		row.min_height = row.height;
+		min_table_height += row.height;
+	}
+
+	//min_table_height += borderSpacingY * ((int) m_rows.size() + 1);
+
+	if (blockHeight > min_table_height)
+	{
+		int extra_height = blockHeight - min_table_height;
+		int auto_count = 0; // number of rows with height=auto
+		for (auto& row : m_rows)
+		{
+			if (!row.css_height.is_predefined() && row.css_height.units() == css_units_percentage)
+			{
+				row.height = row.css_height.calc_percent(blockHeight);
+				if (row.height < row.min_height)
+				{
+					row.height = row.min_height;
+				}
+
+				extra_height -= row.height - row.min_height;
+
+				if (extra_height <= 0) break;
+			}
+			else if (row.css_height.is_predefined())
+			{
+				auto_count++;
+			}
+		}
+		if (extra_height > 0)
+		{
+			if (auto_count)
+			{
+				// distribute height to the rows with height=auto
+				int extra_row_height = (int)(extra_height / auto_count);
+				for (auto& row : m_rows)
+				{
+					if (row.css_height.is_predefined())
+					{
+						row.height += extra_row_height;
+					}
+				}
+			}
+			else
+			{
+				// We don't have rows with height=auto, so distribute height to all rows
+				if (!m_rows.empty())
+				{
+					int extra_row_height = (int)(extra_height / m_rows.size());
+					for (auto& row : m_rows)
+					{
+						row.height += extra_row_height;
+					}
+				}
+			}
+		}
+		else if (extra_height < 0)
+		{
+			extra_height = -extra_height;
+			for (auto row = m_rows.rbegin(); row < m_rows.rend() && extra_height > 0; row++)
+			{
+				if (row->height > row->min_height)
+				{
+					if (row->height - extra_height >= row->min_height)
+					{
+						row->height -= extra_height;
+						extra_height = 0;
+					}
+					else
+					{
+						extra_height -= row->height - row->min_height;
+						row->height = row->min_height;
+					}
+				}
+			}
+		}
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+int& litehtml::table_column_accessor_max_width::get( table_column& col )
+{
+	return col.max_width;
+}
+
+int& litehtml::table_column_accessor_min_width::get( table_column& col )
+{
+	return col.min_width;
+}
+
+int& litehtml::table_column_accessor_width::get( table_column& col )
+{
+	return col.width;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/table.h b/src/plugins/litehtml_viewer/litehtml/table.h
new file mode 100644
index 0000000..6f23b97
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/table.h
@@ -0,0 +1,238 @@
+#pragma once
+
+namespace litehtml
+{
+	struct table_row
+	{
+		typedef std::vector<table_row>	vector;
+
+		int				height;
+		int				border_top;
+		int				border_bottom;
+		element::ptr	el_row;
+		int				top;
+		int				bottom;
+		css_length		css_height;
+		int				min_height;
+
+		table_row()
+		{
+			min_height		= 0;
+			top				= 0;
+			bottom			= 0;
+			border_bottom	= 0;
+			border_top		= 0;
+			height			= 0;
+			el_row			= nullptr;
+			css_height.predef(0);
+		}
+
+		table_row(int h, element::ptr& row)
+		{
+			min_height		= 0;
+			height			= h;
+			el_row			= row;
+			border_bottom	= 0;
+			border_top		= 0;
+			top				= 0;
+			bottom			= 0;
+			if (row)
+			{
+				css_height = row->get_css_height();
+			}
+		}
+
+		table_row(const table_row& val)
+		{
+			min_height = val.min_height;
+			top = val.top;
+			bottom = val.bottom;
+			border_bottom = val.border_bottom;
+			border_top = val.border_top;
+			height = val.height;
+			css_height = val.css_height;
+			el_row = val.el_row;
+		}
+
+		table_row(table_row&& val)
+		{
+			min_height = val.min_height;
+			top = val.top;
+			bottom = val.bottom;
+			border_bottom = val.border_bottom;
+			border_top = val.border_top;
+			height = val.height;
+			css_height = val.css_height;
+			el_row = std::move(val.el_row);
+		}
+	};
+
+	struct table_column
+	{
+		typedef std::vector<table_column>	vector;
+		
+		int			min_width;
+		int			max_width;
+		int			width;
+		css_length	css_width;
+		int			border_left;
+		int			border_right;
+		int			left;
+		int			right;
+
+		table_column()
+		{
+			left			= 0;
+			right			= 0;
+			border_left		= 0;
+			border_right	= 0;
+			min_width		= 0;
+			max_width		= 0;
+			width			= 0;
+			css_width.predef(0);
+		}
+
+		table_column(int min_w, int max_w)
+		{
+			left			= 0;
+			right			= 0;
+			border_left		= 0;
+			border_right	= 0;
+			max_width		= max_w;
+			min_width		= min_w;
+			width			= 0;
+			css_width.predef(0);
+		}
+
+		table_column(const table_column& val)
+		{
+			left			= val.left;
+			right			= val.right;
+			border_left		= val.border_left;
+			border_right	= val.border_right;
+			max_width		= val.max_width;
+			min_width		= val.min_width;
+			width			= val.width;
+			css_width		= val.css_width;
+		}
+	};
+
+	class table_column_accessor
+	{
+	public:
+		virtual int& get(table_column& col) = 0;
+	};
+
+	class table_column_accessor_max_width : public table_column_accessor
+	{
+	public:
+		virtual int& get(table_column& col);
+	};
+
+	class table_column_accessor_min_width : public table_column_accessor
+	{
+	public:
+		virtual int& get(table_column& col);
+	};
+
+	class table_column_accessor_width : public table_column_accessor
+	{
+	public:
+		virtual int& get(table_column& col);
+	};
+
+	struct table_cell
+	{
+		element::ptr	el;
+		int				colspan;
+		int				rowspan;
+		int				min_width;
+		int				min_height;
+		int				max_width;
+		int				max_height;
+		int				width;
+		int				height;
+		margins			borders;
+
+		table_cell()
+		{
+			min_width		= 0;
+			min_height		= 0;
+			max_width		= 0;
+			max_height		= 0;
+			width			= 0;
+			height			= 0;
+			colspan			= 1;
+			rowspan			= 1;
+			el				= nullptr;
+		}
+
+		table_cell(const table_cell& val)
+		{
+			el				= val.el;
+			colspan			= val.colspan;
+			rowspan			= val.rowspan;
+			width			= val.width;
+			height			= val.height;
+			min_width		= val.min_width;
+			min_height		= val.min_height;
+			max_width		= val.max_width;
+			max_height		= val.max_height;
+			borders			= val.borders;
+		}
+
+		table_cell(const table_cell&& val)
+		{
+			el = std::move(val.el);
+			colspan = val.colspan;
+			rowspan = val.rowspan;
+			width = val.width;
+			height = val.height;
+			min_width = val.min_width;
+			min_height = val.min_height;
+			max_width = val.max_width;
+			max_height = val.max_height;
+			borders = val.borders;
+		}
+	};
+
+	class table_grid
+	{
+	public:
+		typedef std::vector< std::vector<table_cell> >	rows;
+	private:
+		int						m_rows_count;
+		int						m_cols_count;
+		rows					m_cells;
+		table_column::vector	m_columns;
+		table_row::vector		m_rows;
+	public:
+
+		table_grid()
+		{
+			m_rows_count	= 0;
+			m_cols_count	= 0;
+		}
+
+		void			clear();
+		void			begin_row(element::ptr& row);
+		void			add_cell(element::ptr& el);
+		bool			is_rowspanned(int r, int c);
+		void			finish();
+		table_cell*		cell(int t_col, int t_row);
+		table_column&	column(int c)	{ return m_columns[c];	}
+		table_row&		row(int r)		{ return m_rows[r];		}
+
+		int				rows_count()	{ return m_rows_count;	}
+		int				cols_count()	{ return m_cols_count;	}
+
+		void			distribute_max_width(int width, int start, int end);
+		void			distribute_min_width(int width, int start, int end);
+		void			distribute_width(int width, int start, int end);
+		void			distribute_width(int width, int start, int end, table_column_accessor* acc);
+		int				calc_table_width(int block_width, bool is_auto, int& min_table_width, int& max_table_width);
+		void			calc_horizontal_positions(margins& table_borders, border_collapse bc, int bdr_space_x);
+		void			calc_vertical_positions(margins& table_borders, border_collapse bc, int bdr_space_y);
+		void			calc_rows_height(int blockHeight, int borderSpacingY);
+	};
+}
\ No newline at end of file
diff --git a/src/plugins/litehtml_viewer/litehtml/types.h b/src/plugins/litehtml_viewer/litehtml/types.h
new file mode 100644
index 0000000..bb292a4
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/types.h
@@ -0,0 +1,733 @@
+#pragma once
+
+#include <stdlib.h>
+#include <memory>
+#include <map>
+#include <vector>
+
+namespace litehtml
+{
+	class document;
+	class element;
+
+	typedef std::map<litehtml::tstring, litehtml::tstring>			string_map;
+	typedef std::vector< std::shared_ptr<litehtml::element> >		elements_vector;
+	typedef std::vector<int>										int_vector;
+	typedef std::vector<litehtml::tstring>							string_vector;
+
+	const unsigned int font_decoration_none			= 0x00;
+	const unsigned int font_decoration_underline	= 0x01;
+	const unsigned int font_decoration_linethrough	= 0x02;
+	const unsigned int font_decoration_overline		= 0x04;
+
+	typedef unsigned char	byte;
+	typedef unsigned int	ucode_t;
+
+	struct margins
+	{
+		int	left;
+		int	right;
+		int top;
+		int bottom;
+
+		margins()
+		{
+			left = right = top = bottom = 0;
+		}
+
+		int width()		const	{ return left + right; } 
+		int height()	const	{ return top + bottom; } 
+	};
+
+	struct size
+	{
+		int		width;
+		int		height;
+
+		size()
+		{
+			width	= 0;
+			height	= 0;
+		}
+	};
+
+	struct position
+	{
+		typedef std::vector<position>	vector;
+
+		int	x;
+		int	y;
+		int	width;
+		int	height;
+
+		position()
+		{
+			x = y = width = height = 0;
+		}
+
+		position(int x, int y, int width, int height)
+		{
+			this->x			= x;
+			this->y			= y;
+			this->width		= width;
+			this->height	= height;
+		}
+
+		int right()		const		{ return x + width;		}
+		int bottom()	const		{ return y + height;	}
+		int left()		const		{ return x;				}
+		int top()		const		{ return y;				}
+
+		void operator+=(const margins& mg)
+		{
+			x		-= mg.left;
+			y		-= mg.top;
+			width	+= mg.left + mg.right;
+			height	+= mg.top + mg.bottom;
+		}
+		void operator-=(const margins& mg)
+		{
+			x		+= mg.left;
+			y		+= mg.top;
+			width	-= mg.left + mg.right;
+			height	-= mg.top + mg.bottom;
+		}
+
+		void clear()
+		{
+			x = y = width = height = 0;
+		}
+
+		void operator=(const size& sz)
+		{
+			width	= sz.width;
+			height	= sz.height;
+		}
+
+		void move_to(int x, int y)
+		{
+			this->x = x;
+			this->y = y;
+		}
+
+		bool does_intersect(const position* val) const
+		{
+			if(!val) return true;
+
+			return (
+				left()			<= val->right()		&& 
+				right()			>= val->left()		&& 
+				bottom()		>= val->top()		&& 
+				top()			<= val->bottom()	)
+				|| (
+				val->left()		<= right()			&& 
+				val->right()	>= left()			&& 
+				val->bottom()	>= top()			&& 
+				val->top()		<= bottom()			);
+		}
+
+		bool empty() const
+		{
+			if(!width && !height)
+			{
+				return true;
+			}
+			return false;
+		}
+
+		bool is_point_inside(int x, int y) const
+		{
+			if(x >= left() && x <= right() && y >= top() && y <= bottom())
+			{
+				return true;
+			}
+			return false;
+		}
+	};
+
+	struct font_metrics
+	{
+		int		height;
+		int		ascent;
+		int		descent;
+		int		x_height;
+		bool	draw_spaces;
+
+		font_metrics()
+		{
+			height			= 0;
+			ascent			= 0;
+			descent			= 0;
+			x_height		= 0;
+			draw_spaces		= true;
+		}
+		int base_line()	{ return descent; }
+	};
+
+	struct font_item
+	{
+		uint_ptr		font;
+		font_metrics	metrics;
+	};
+
+	typedef std::map<tstring, font_item>	fonts_map;
+
+	enum draw_flag
+	{
+		draw_root,
+		draw_block,
+		draw_floats,
+		draw_inlines,
+		draw_positioned,
+	};
+
+#define  style_display_strings		_t("none;block;inline;inline-block;inline-table;list-item;table;table-caption;table-cell;table-column;table-column-group;table-footer-group;table-header-group;table-row;table-row-group")
+
+	enum style_display
+	{
+		display_none,
+		display_block,
+		display_inline,
+		display_inline_block,
+		display_inline_table,
+		display_list_item,
+		display_table,
+		display_table_caption,
+		display_table_cell,
+		display_table_column,
+		display_table_column_group,
+		display_table_footer_group,
+		display_table_header_group,
+		display_table_row,
+		display_table_row_group,
+		display_inline_text,
+	};
+
+	enum style_border
+	{
+		borderNope,
+		borderNone,
+		borderHidden,
+		borderDotted,
+		borderDashed,
+		borderSolid,
+		borderDouble
+	};
+
+#define  font_size_strings		_t("xx-small;x-small;small;medium;large;x-large;xx-large;smaller;larger")
+
+	enum font_size
+	{
+		fontSize_xx_small,
+		fontSize_x_small,
+		fontSize_small,
+		fontSize_medium,
+		fontSize_large,
+		fontSize_x_large,
+		fontSize_xx_large,
+		fontSize_smaller,
+		fontSize_larger,
+	};
+
+#define  font_style_strings		_t("normal;italic")
+
+	enum font_style
+	{
+		fontStyleNormal,
+		fontStyleItalic
+	};
+
+#define  font_variant_strings		_t("normal;small-caps")
+
+	enum font_variant
+	{
+		font_variant_normal,
+		font_variant_italic
+	};
+
+#define  font_weight_strings	_t("normal;bold;bolder;lighter100;200;300;400;500;600;700")
+
+	enum font_weight
+	{
+		fontWeightNormal,
+		fontWeightBold,
+		fontWeightBolder,
+		fontWeightLighter,
+		fontWeight100,
+		fontWeight200,
+		fontWeight300,
+		fontWeight400,
+		fontWeight500,
+		fontWeight600,
+		fontWeight700
+	};
+
+#define  list_style_type_strings	_t("none;circle;disc;square;armenian;cjk-ideographic;decimal;decimal-leading-zero;georgian;hebrew;hiragana;hiragana-iroha;katakana;katakana-iroha;lower-alpha;lower-greek;lower-latin;lower-roman;upper-alpha;upper-latin;upper-roman")
+
+	enum list_style_type
+	{
+		list_style_type_none,
+		list_style_type_circle,
+		list_style_type_disc,
+		list_style_type_square,
+		list_style_type_armenian,
+		list_style_type_cjk_ideographic,
+		list_style_type_decimal,
+		list_style_type_decimal_leading_zero,
+		list_style_type_georgian,
+		list_style_type_hebrew,
+		list_style_type_hiragana,
+		list_style_type_hiragana_iroha,
+		list_style_type_katakana,
+		list_style_type_katakana_iroha,
+		list_style_type_lower_alpha,
+		list_style_type_lower_greek,
+		list_style_type_lower_latin,
+		list_style_type_lower_roman,
+		list_style_type_upper_alpha,
+		list_style_type_upper_latin,
+		list_style_type_upper_roman,
+	};
+
+#define  list_style_position_strings	_t("inside;outside")
+
+	enum list_style_position
+	{
+		list_style_position_inside,
+		list_style_position_outside
+	};
+
+#define  vertical_align_strings	_t("baseline;sub;super;top;text-top;middle;bottom;text-bottom")
+
+	enum vertical_align
+	{
+		va_baseline,
+		va_sub,
+		va_super,
+		va_top,
+		va_text_top,
+		va_middle,
+		va_bottom,
+		va_text_bottom
+	};
+
+#define  border_width_strings	_t("thin;medium;thick")
+
+	enum border_width
+	{
+		border_width_thin,
+		border_width_medium,
+		border_width_thick
+	};
+
+#define  border_style_strings	_t("none;hidden;dotted;dashed;solid;double;groove;ridge;inset;outset")
+
+	enum border_style
+	{
+		border_style_none,
+		border_style_hidden,
+		border_style_dotted,
+		border_style_dashed,
+		border_style_solid,
+		border_style_double,
+		border_style_groove,
+		border_style_ridge,
+		border_style_inset,
+		border_style_outset
+	};
+
+#define  element_float_strings	_t("none;left;right")
+
+	enum element_float
+	{
+		float_none,
+		float_left,
+		float_right
+	};
+
+#define  element_clear_strings	_t("none;left;right;both")
+
+	enum element_clear
+	{
+		clear_none,
+		clear_left,
+		clear_right,
+		clear_both
+	};
+
+#define  css_units_strings	_t("none;%;in;cm;mm;em;ex;pt;pc;px;dpi;dpcm;vw;vh;vmin;vmax")
+
+	enum css_units
+	{
+		css_units_none,
+		css_units_percentage,
+		css_units_in,
+		css_units_cm,
+		css_units_mm,
+		css_units_em,
+		css_units_ex,
+		css_units_pt,
+		css_units_pc,
+		css_units_px,
+		css_units_dpi,
+		css_units_dpcm,
+		css_units_vw,
+		css_units_vh,
+		css_units_vmin,
+		css_units_vmax,
+	};
+
+#define  background_attachment_strings	_t("scroll;fixed")
+
+	enum background_attachment
+	{
+		background_attachment_scroll,
+		background_attachment_fixed
+	};
+
+#define  background_repeat_strings	_t("repeat;repeat-x;repeat-y;no-repeat")
+
+	enum background_repeat
+	{
+		background_repeat_repeat,
+		background_repeat_repeat_x,
+		background_repeat_repeat_y,
+		background_repeat_no_repeat
+	};
+
+#define  background_box_strings	_t("border-box;padding-box;content-box")
+
+	enum background_box
+	{
+		background_box_border,
+		background_box_padding,
+		background_box_content
+	};
+
+#define element_position_strings	_t("static;relative;absolute;fixed")
+
+	enum element_position
+	{
+		element_position_static,
+		element_position_relative,
+		element_position_absolute,
+		element_position_fixed,
+	};
+
+#define text_align_strings		_t("left;right;center;justify")
+
+	enum text_align
+	{
+		text_align_left,
+		text_align_right,
+		text_align_center,
+		text_align_justify
+	};
+
+#define text_transform_strings		_t("none;capitalize;uppercase;lowercase")
+
+	enum text_transform
+	{
+		text_transform_none,
+		text_transform_capitalize,
+		text_transform_uppercase,
+		text_transform_lowercase
+	};
+
+#define white_space_strings		_t("normal;nowrap;pre;pre-line;pre-wrap")
+
+	enum white_space
+	{
+		white_space_normal,
+		white_space_nowrap,
+		white_space_pre,
+		white_space_pre_line,
+		white_space_pre_wrap
+	};
+
+#define overflow_strings		_t("visible;hidden;scroll;auto;no-display;no-content")
+
+	enum overflow
+	{
+		overflow_visible,
+		overflow_hidden,
+		overflow_scroll,
+		overflow_auto,
+		overflow_no_display,
+		overflow_no_content
+	};
+
+#define background_size_strings		_t("auto;cover;contain")
+
+	enum background_size
+	{
+		background_size_auto,
+		background_size_cover,
+		background_size_contain,
+	};
+
+#define visibility_strings			_t("visible;hidden;collapse")
+
+	enum visibility
+	{
+		visibility_visible,
+		visibility_hidden,
+		visibility_collapse,
+	};
+
+#define border_collapse_strings		_t("collapse;separate")
+
+	enum border_collapse
+	{
+		border_collapse_collapse,
+		border_collapse_separate,
+	};
+
+
+#define pseudo_class_strings		_t("only-child;only-of-type;first-child;first-of-type;last-child;last-of-type;nth-child;nth-of-type;nth-last-child;nth-last-of-type;not;lang")
+
+	enum pseudo_class
+	{
+		pseudo_class_only_child,
+		pseudo_class_only_of_type,
+		pseudo_class_first_child,
+		pseudo_class_first_of_type,
+		pseudo_class_last_child,
+		pseudo_class_last_of_type,
+		pseudo_class_nth_child,
+		pseudo_class_nth_of_type,
+		pseudo_class_nth_last_child,
+		pseudo_class_nth_last_of_type,
+		pseudo_class_not,
+		pseudo_class_lang,
+	};
+
+#define content_property_string		_t("none;normal;open-quote;close-quote;no-open-quote;no-close-quote")
+
+	enum content_property
+	{
+		content_property_none,
+		content_property_normal,
+		content_property_open_quote,
+		content_property_close_quote,
+		content_property_no_open_quote,
+		content_property_no_close_quote,
+	};
+
+
+	struct floated_box
+	{
+		typedef std::vector<floated_box>	vector;
+
+		position		pos;
+		element_float	float_side;
+		element_clear	clear_floats;
+		std::shared_ptr<element>	el;
+
+		floated_box() = default;
+		floated_box(const floated_box& val)
+		{
+			pos = val.pos;
+			float_side = val.float_side;
+			clear_floats = val.clear_floats;
+			el = val.el;
+		}
+		floated_box& operator=(const floated_box& val)
+		{
+			pos = val.pos;
+			float_side = val.float_side;
+			clear_floats = val.clear_floats;
+			el = val.el;
+			return *this;
+		}
+		floated_box(floated_box&& val)
+		{
+			pos = val.pos;
+			float_side = val.float_side;
+			clear_floats = val.clear_floats;
+			el = std::move(val.el);
+		}
+		void operator=(floated_box&& val)
+		{
+			pos = val.pos;
+			float_side = val.float_side;
+			clear_floats = val.clear_floats;
+			el = std::move(val.el);
+		}
+	};
+
+	struct int_int_cache
+	{
+		int		hash;
+		int		val;
+		bool	is_valid;
+		bool	is_default;
+
+		int_int_cache()
+		{
+			hash		= 0;
+			val			= 0;
+			is_valid	= false;
+			is_default	= false;
+		}
+		void invalidate()
+		{
+			is_valid	= false;
+			is_default	= false;
+		}
+		void set_value(int vHash, int vVal)
+		{
+			hash		= vHash;
+			val			= vVal;
+			is_valid	= true;
+		}
+	};
+
+	enum select_result
+	{
+		select_no_match				= 0x00,
+		select_match				= 0x01,
+		select_match_pseudo_class	= 0x02,
+		select_match_with_before	= 0x10,
+		select_match_with_after		= 0x20,
+	};
+
+	template<class T>
+	class def_value
+	{
+		T		m_val;
+		bool	m_is_default;
+	public:
+		def_value(T def_val)
+		{
+			m_is_default	= true;
+			m_val			= def_val;
+		}
+		void reset(T def_val)
+		{
+			m_is_default	= true;
+			m_val			= def_val;
+		}
+		bool is_default()
+		{
+			return m_is_default;
+		}
+		T operator=(T new_val)
+		{
+			m_val			= new_val;
+			m_is_default	= false;
+			return m_val;
+		}
+		operator T()
+		{
+			return m_val;
+		}
+	};
+
+
+#define media_orientation_strings		_t("portrait;landscape")
+
+	enum media_orientation
+	{
+		media_orientation_portrait,
+		media_orientation_landscape,
+	};
+
+#define media_feature_strings		_t("none;width;min-width;max-width;height;min-height;max-height;device-width;min-device-width;max-device-width;device-height;min-device-height;max-device-height;orientation;aspect-ratio;min-aspect-ratio;max-aspect-ratio;device-aspect-ratio;min-device-aspect-ratio;max-device-aspect-ratio;color;min-color;max-color;color-index;min-color-index;max-color-index;monochrome;min-monochrome;max-monochrome;resolution;min-resolution;max-resolution")
+
+	enum media_feature
+	{
+		media_feature_none,
+
+		media_feature_width,
+		media_feature_min_width,
+		media_feature_max_width,
+
+		media_feature_height,
+		media_feature_min_height,
+		media_feature_max_height,
+
+		media_feature_device_width,
+		media_feature_min_device_width,
+		media_feature_max_device_width,
+
+		media_feature_device_height,
+		media_feature_min_device_height,
+		media_feature_max_device_height,
+
+		media_feature_orientation,
+
+		media_feature_aspect_ratio,
+		media_feature_min_aspect_ratio,
+		media_feature_max_aspect_ratio,
+
+		media_feature_device_aspect_ratio,
+		media_feature_min_device_aspect_ratio,
+		media_feature_max_device_aspect_ratio,
+
+		media_feature_color,
+		media_feature_min_color,
+		media_feature_max_color,
+
+		media_feature_color_index,
+		media_feature_min_color_index,
+		media_feature_max_color_index,
+
+		media_feature_monochrome,
+		media_feature_min_monochrome,
+		media_feature_max_monochrome,
+
+		media_feature_resolution,
+		media_feature_min_resolution,
+		media_feature_max_resolution,
+	};
+
+#define box_sizing_strings		_t("content-box;border-box")
+
+	enum box_sizing
+	{
+		box_sizing_content_box,
+		box_sizing_border_box,
+	};
+
+
+#define media_type_strings		_t("none;all;screen;print;braille;embossed;handheld;projection;speech;tty;tv")
+
+	enum media_type
+	{
+		media_type_none,
+		media_type_all,
+		media_type_screen,
+		media_type_print,
+		media_type_braille,
+		media_type_embossed,
+		media_type_handheld,
+		media_type_projection,
+		media_type_speech,
+		media_type_tty,
+		media_type_tv,
+	};
+
+	struct media_features
+	{
+		media_type	type;
+		int			width;			// (pixels) For continuous media, this is the width of the viewport including the size of a rendered scroll bar (if any). For paged media, this is the width of the page box.
+		int			height;			// (pixels) The height of the targeted display area of the output device. For continuous media, this is the height of the viewport including the size of a rendered scroll bar (if any). For paged media, this is the height of the page box.
+		int			device_width;	// (pixels) The width of the rendering surface of the output device. For continuous media, this is the width of the screen. For paged media, this is the width of the page sheet size.
+		int			device_height;	// (pixels) The height of the rendering surface of the output device. For continuous media, this is the height of the screen. For paged media, this is the height of the page sheet size.
+		int			color;			// The number of bits per color component of the output device. If the device is not a color device, the value is zero.
+		int			color_index;	// The number of entries in the color lookup table of the output device. If the device does not use a color lookup table, the value is zero.
+		int			monochrome;		// The number of bits per pixel in a monochrome frame buffer. If the device is not a monochrome device, the output device value will be 0.
+		int			resolution;		// The resolution of the output device (in DPI)
+	};
+
+	enum render_type
+	{
+		render_all,
+		render_no_fixed,
+		render_fixed_only,
+	};
+
+	// List of the Void Elements (can't have any contents)
+	const litehtml::tchar_t* const void_elements = _t("area;base;br;col;command;embed;hr;img;input;keygen;link;meta;param;source;track;wbr");
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/utf8_strings.cpp b/src/plugins/litehtml_viewer/litehtml/utf8_strings.cpp
new file mode 100644
index 0000000..fcb18c8
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/utf8_strings.cpp
@@ -0,0 +1,97 @@
+#include "html.h"
+#include "utf8_strings.h"
+
+
+litehtml::utf8_to_wchar::utf8_to_wchar(const char* val)
+{
+	m_utf8 = (const byte*) val;
+	while (true)
+	{
+		ucode_t wch = get_char();
+		if (!wch) break;
+		m_str += wch;
+	}
+}
+
+litehtml::ucode_t litehtml::utf8_to_wchar::get_char()
+{
+	ucode_t b1 = getb();
+
+	if (!b1)
+	{
+		return 0;
+	}
+
+	// Determine whether we are dealing
+	// with a one-, two-, three-, or four-
+	// byte sequence.
+	if ((b1 & 0x80) == 0)
+	{
+		// 1-byte sequence: 000000000xxxxxxx = 0xxxxxxx
+		return b1;
+	}
+	else if ((b1 & 0xe0) == 0xc0)
+	{
+		// 2-byte sequence: 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
+		ucode_t r = (b1 & 0x1f) << 6;
+		r |= get_next_utf8(getb());
+		return r;
+	}
+	else if ((b1 & 0xf0) == 0xe0)
+	{
+		// 3-byte sequence: zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
+		ucode_t r = (b1 & 0x0f) << 12;
+		r |= get_next_utf8(getb()) << 6;
+		r |= get_next_utf8(getb());
+		return r;
+	}
+	else if ((b1 & 0xf8) == 0xf0)
+	{
+		// 4-byte sequence: 11101110wwwwzzzzyy + 110111yyyyxxxxxx
+		//     = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
+		// (uuuuu = wwww + 1)
+		int b2 = get_next_utf8(getb());
+		int b3 = get_next_utf8(getb());
+		int b4 = get_next_utf8(getb());
+		return ((b1 & 7) << 18) | ((b2 & 0x3f) << 12) |
+			((b3 & 0x3f) << 6) | (b4 & 0x3f);
+	}
+
+	//bad start for UTF-8 multi-byte sequence
+	return '?';
+}
+
+litehtml::wchar_to_utf8::wchar_to_utf8(const wchar_t* val)
+{
+	unsigned int code;
+	for (int i = 0; val[i]; i++)
+	{
+		code = val[i];
+		if (code <= 0x7F)
+		{
+			m_str += (char)code;
+		}
+		else if (code <= 0x7FF)
+		{
+			m_str += (code >> 6) + 192;
+			m_str += (code & 63) + 128;
+		}
+		else if (0xd800 <= code && code <= 0xdfff)
+		{
+			//invalid block of utf8
+		}
+		else if (code <= 0xFFFF)
+		{
+			m_str += (code >> 12) + 224;
+			m_str += ((code >> 6) & 63) + 128;
+			m_str += (code & 63) + 128;
+		}
+		else if (code <= 0x10FFFF)
+		{
+			m_str += (code >> 18) + 240;
+			m_str += ((code >> 12) & 63) + 128;
+			m_str += ((code >> 6) & 63) + 128;
+			m_str += (code & 63) + 128;
+		}
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/utf8_strings.h b/src/plugins/litehtml_viewer/litehtml/utf8_strings.h
new file mode 100644
index 0000000..c932ed5
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/utf8_strings.h
@@ -0,0 +1,48 @@
+#pragma once
+
+namespace litehtml
+{
+	class utf8_to_wchar
+	{
+		const byte* m_utf8;
+		std::wstring m_str;
+	public:
+		utf8_to_wchar(const char* val);
+		operator const wchar_t*() const
+		{
+			return m_str.c_str();
+		}
+	private:
+		ucode_t getb()
+		{
+			if (!(*m_utf8)) return 0;
+			return *m_utf8++;
+		}
+		ucode_t get_next_utf8(ucode_t val)
+		{
+			return (val & 0x3f);
+		}
+		ucode_t get_char();
+	};
+
+	class wchar_to_utf8
+	{
+		std::string m_str;
+	public:
+		wchar_to_utf8(const wchar_t* val);
+		operator const char*() const
+		{
+			return m_str.c_str();
+		}
+	};
+
+#ifdef LITEHTML_UTF8
+#define litehtml_from_utf8(str)		str
+#define litehtml_to_utf8(str)		str
+#define litehtml_from_wchar(str)	wchar_to_utf8(str)
+#else
+#define litehtml_from_utf8(str)		utf8_to_wchar(str)
+#define litehtml_from_wchar(str)	str
+#define litehtml_to_utf8(str)		wchar_to_utf8(str)
+#endif
+}
\ No newline at end of file
diff --git a/src/plugins/litehtml_viewer/litehtml/web_color.cpp b/src/plugins/litehtml_viewer/litehtml/web_color.cpp
new file mode 100644
index 0000000..814765d
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/web_color.cpp
@@ -0,0 +1,251 @@
+#include "html.h"
+#include "web_color.h"
+#include <string.h>
+
+litehtml::def_color litehtml::g_def_colors[] = 
+{
+	{_t("transparent"),_t("rgba(0, 0, 0, 0)")},
+	{_t("AliceBlue"),_t("#F0F8FF")},
+	{_t("AntiqueWhite"),_t("#FAEBD7")},
+	{_t("Aqua"),_t("#00FFFF")},
+	{_t("Aquamarine"),_t("#7FFFD4")},
+	{_t("Azure"),_t("#F0FFFF")},
+	{_t("Beige"),_t("#F5F5DC")},
+	{_t("Bisque"),_t("#FFE4C4")},
+	{_t("Black"),_t("#000000")},
+	{_t("BlanchedAlmond"),_t("#FFEBCD")},
+	{_t("Blue"),_t("#0000FF")},
+	{_t("BlueViolet"),_t("#8A2BE2")},
+	{_t("Brown"),_t("#A52A2A")},
+	{_t("BurlyWood"),_t("#DEB887")},
+	{_t("CadetBlue"),_t("#5F9EA0")},
+	{_t("Chartreuse"),_t("#7FFF00")},
+	{_t("Chocolate"),_t("#D2691E")},
+	{_t("Coral"),_t("#FF7F50")},
+	{_t("CornflowerBlue"),_t("#6495ED")},
+	{_t("Cornsilk"),_t("#FFF8DC")},
+	{_t("Crimson"),_t("#DC143C")},
+	{_t("Cyan"),_t("#00FFFF")},
+	{_t("DarkBlue"),_t("#00008B")},
+	{_t("DarkCyan"),_t("#008B8B")},
+	{_t("DarkGoldenRod"),_t("#B8860B")},
+	{_t("DarkGray"),_t("#A9A9A9")},
+	{_t("DarkGrey"),_t("#A9A9A9")},
+	{_t("DarkGreen"),_t("#006400")},
+	{_t("DarkKhaki"),_t("#BDB76B")},
+	{_t("DarkMagenta"),_t("#8B008B")},
+	{_t("DarkOliveGreen"),_t("#556B2F")},
+	{_t("Darkorange"),_t("#FF8C00")},
+	{_t("DarkOrchid"),_t("#9932CC")},
+	{_t("DarkRed"),_t("#8B0000")},
+	{_t("DarkSalmon"),_t("#E9967A")},
+	{_t("DarkSeaGreen"),_t("#8FBC8F")},
+	{_t("DarkSlateBlue"),_t("#483D8B")},
+	{_t("DarkSlateGray"),_t("#2F4F4F")},
+	{_t("DarkSlateGrey"),_t("#2F4F4F")},
+	{_t("DarkTurquoise"),_t("#00CED1")},
+	{_t("DarkViolet"),_t("#9400D3")},
+	{_t("DeepPink"),_t("#FF1493")},
+	{_t("DeepSkyBlue"),_t("#00BFFF")},
+	{_t("DimGray"),_t("#696969")},
+	{_t("DimGrey"),_t("#696969")},
+	{_t("DodgerBlue"),_t("#1E90FF")},
+	{_t("FireBrick"),_t("#B22222")},
+	{_t("FloralWhite"),_t("#FFFAF0")},
+	{_t("ForestGreen"),_t("#228B22")},
+	{_t("Fuchsia"),_t("#FF00FF")},
+	{_t("Gainsboro"),_t("#DCDCDC")},
+	{_t("GhostWhite"),_t("#F8F8FF")},
+	{_t("Gold"),_t("#FFD700")},
+	{_t("GoldenRod"),_t("#DAA520")},
+	{_t("Gray"),_t("#808080")},
+	{_t("Grey"),_t("#808080")},
+	{_t("Green"),_t("#008000")},
+	{_t("GreenYellow"),_t("#ADFF2F")},
+	{_t("HoneyDew"),_t("#F0FFF0")},
+	{_t("HotPink"),_t("#FF69B4")},
+	{_t("Ivory"),_t("#FFFFF0")},
+	{_t("Khaki"),_t("#F0E68C")},
+	{_t("Lavender"),_t("#E6E6FA")},
+	{_t("LavenderBlush"),_t("#FFF0F5")},
+	{_t("LawnGreen"),_t("#7CFC00")},
+	{_t("LemonChiffon"),_t("#FFFACD")},
+	{_t("LightBlue"),_t("#ADD8E6")},
+	{_t("LightCoral"),_t("#F08080")},
+	{_t("LightCyan"),_t("#E0FFFF")},
+	{_t("LightGoldenRodYellow"),_t("#FAFAD2")},
+	{_t("LightGray"),_t("#D3D3D3")},
+	{_t("LightGrey"),_t("#D3D3D3")},
+	{_t("LightGreen"),_t("#90EE90")},
+	{_t("LightPink"),_t("#FFB6C1")},
+	{_t("LightSalmon"),_t("#FFA07A")},
+	{_t("LightSeaGreen"),_t("#20B2AA")},
+	{_t("LightSkyBlue"),_t("#87CEFA")},
+	{_t("LightSlateGray"),_t("#778899")},
+	{_t("LightSlateGrey"),_t("#778899")},
+	{_t("LightSteelBlue"),_t("#B0C4DE")},
+	{_t("LightYellow"),_t("#FFFFE0")},
+	{_t("Lime"),_t("#00FF00")},
+	{_t("LimeGreen"),_t("#32CD32")},
+	{_t("Linen"),_t("#FAF0E6")},
+	{_t("Magenta"),_t("#FF00FF")},
+	{_t("Maroon"),_t("#800000")},
+	{_t("MediumAquaMarine"),_t("#66CDAA")},
+	{_t("MediumBlue"),_t("#0000CD")},
+	{_t("MediumOrchid"),_t("#BA55D3")},
+	{_t("MediumPurple"),_t("#9370D8")},
+	{_t("MediumSeaGreen"),_t("#3CB371")},
+	{_t("MediumSlateBlue"),_t("#7B68EE")},
+	{_t("MediumSpringGreen"),_t("#00FA9A")},
+	{_t("MediumTurquoise"),_t("#48D1CC")},
+	{_t("MediumVioletRed"),_t("#C71585")},
+	{_t("MidnightBlue"),_t("#191970")},
+	{_t("MintCream"),_t("#F5FFFA")},
+	{_t("MistyRose"),_t("#FFE4E1")},
+	{_t("Moccasin"),_t("#FFE4B5")},
+	{_t("NavajoWhite"),_t("#FFDEAD")},
+	{_t("Navy"),_t("#000080")},
+	{_t("OldLace"),_t("#FDF5E6")},
+	{_t("Olive"),_t("#808000")},
+	{_t("OliveDrab"),_t("#6B8E23")},
+	{_t("Orange"),_t("#FFA500")},
+	{_t("OrangeRed"),_t("#FF4500")},
+	{_t("Orchid"),_t("#DA70D6")},
+	{_t("PaleGoldenRod"),_t("#EEE8AA")},
+	{_t("PaleGreen"),_t("#98FB98")},
+	{_t("PaleTurquoise"),_t("#AFEEEE")},
+	{_t("PaleVioletRed"),_t("#D87093")},
+	{_t("PapayaWhip"),_t("#FFEFD5")},
+	{_t("PeachPuff"),_t("#FFDAB9")},
+	{_t("Peru"),_t("#CD853F")},
+	{_t("Pink"),_t("#FFC0CB")},
+	{_t("Plum"),_t("#DDA0DD")},
+	{_t("PowderBlue"),_t("#B0E0E6")},
+	{_t("Purple"),_t("#800080")},
+	{_t("Red"),_t("#FF0000")},
+	{_t("RosyBrown"),_t("#BC8F8F")},
+	{_t("RoyalBlue"),_t("#4169E1")},
+	{_t("SaddleBrown"),_t("#8B4513")},
+	{_t("Salmon"),_t("#FA8072")},
+	{_t("SandyBrown"),_t("#F4A460")},
+	{_t("SeaGreen"),_t("#2E8B57")},
+	{_t("SeaShell"),_t("#FFF5EE")},
+	{_t("Sienna"),_t("#A0522D")},
+	{_t("Silver"),_t("#C0C0C0")},
+	{_t("SkyBlue"),_t("#87CEEB")},
+	{_t("SlateBlue"),_t("#6A5ACD")},
+	{_t("SlateGray"),_t("#708090")},
+	{_t("SlateGrey"),_t("#708090")},
+	{_t("Snow"),_t("#FFFAFA")},
+	{_t("SpringGreen"),_t("#00FF7F")},
+	{_t("SteelBlue"),_t("#4682B4")},
+	{_t("Tan"),_t("#D2B48C")},
+	{_t("Teal"),_t("#008080")},
+	{_t("Thistle"),_t("#D8BFD8")},
+	{_t("Tomato"),_t("#FF6347")},
+	{_t("Turquoise"),_t("#40E0D0")},
+	{_t("Violet"),_t("#EE82EE")},
+	{_t("Wheat"),_t("#F5DEB3")},
+	{_t("White"),_t("#FFFFFF")},
+	{_t("WhiteSmoke"),_t("#F5F5F5")},
+	{_t("Yellow"),_t("#FFFF00")},
+	{_t("YellowGreen"),_t("#9ACD32")},
+	{0,0}
+};
+
+
+litehtml::web_color litehtml::web_color::from_string( const tchar_t* str )
+{
+	if(!str)
+	{
+		return web_color(0, 0, 0);
+	}
+	if(str[0] == _t('#'))
+	{
+		tstring red		= _t("");
+		tstring green		= _t("");
+		tstring blue		= _t("");
+		if(t_strlen(str + 1) == 3)
+		{
+			red		+= str[1];
+			red		+= str[1];
+			green	+= str[2];
+			green	+= str[2];
+			blue	+= str[3];
+			blue	+= str[3];
+		} else if(t_strlen(str + 1) == 6)
+		{
+			red		+= str[1];
+			red		+= str[2];
+			green	+= str[3];
+			green	+= str[4];
+			blue	+= str[5];
+			blue	+= str[6];
+		}
+		tchar_t* sss = 0;
+		web_color clr;
+		clr.red		= (byte) t_strtol(red.c_str(),	&sss, 16);
+		clr.green	= (byte) t_strtol(green.c_str(),	&sss, 16);
+		clr.blue	= (byte) t_strtol(blue.c_str(),	&sss, 16);
+		return clr;
+	} else if(!t_strncmp(str, _t("rgb"), 3))
+	{
+		tstring s = str;
+
+		tstring::size_type pos = s.find_first_of(_t("("));
+		if(pos != tstring::npos)
+		{
+			s.erase(s.begin(), s.begin() + pos + 1);
+		}
+		pos = s.find_last_of(_t(")"));
+		if(pos != tstring::npos)
+		{
+			s.erase(s.begin() + pos, s.end());
+		}
+
+		std::vector<tstring> tokens;
+		split_string(s, tokens, _t(", \t"));
+
+		web_color clr;
+
+		if(tokens.size() >= 1)	clr.red		= (byte) t_atoi(tokens[0].c_str());
+		if(tokens.size() >= 2)	clr.green	= (byte) t_atoi(tokens[1].c_str());
+		if(tokens.size() >= 3)	clr.blue	= (byte) t_atoi(tokens[2].c_str());
+		if(tokens.size() >= 4)	clr.alpha	= (byte) (t_strtod(tokens[3].c_str(), 0) * 255.0);
+
+		return clr;
+	} else
+	{
+		const tchar_t* rgb = resolve_name(str);
+		if(rgb)
+		{
+			return from_string(rgb);
+		}
+	}
+	return web_color(0, 0, 0);
+}
+
+const litehtml::tchar_t* litehtml::web_color::resolve_name( const tchar_t* name )
+{
+	for(int i=0; g_def_colors[i].name; i++)
+	{
+		if(!t_strcasecmp(name, g_def_colors[i].name))
+		{
+			return g_def_colors[i].rgb;
+		}
+	}
+	return 0;
+}
+
+bool litehtml::web_color::is_color( const tchar_t* str )
+{
+	if(!t_strncasecmp(str, _t("rgb"), 3) || str[0] == _t('#'))
+	{
+		return true;
+	}
+	if(resolve_name(str))
+	{
+		return true;
+	}
+	return false;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/web_color.h b/src/plugins/litehtml_viewer/litehtml/web_color.h
new file mode 100644
index 0000000..8d4829f
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/web_color.h
@@ -0,0 +1,56 @@
+#pragma once
+
+namespace litehtml
+{
+	struct def_color
+	{
+		const tchar_t*	name;
+		const tchar_t*	rgb;
+	};
+
+	extern def_color g_def_colors[];
+
+	struct web_color
+	{
+		byte    blue;
+		byte    green;
+		byte    red;
+		byte    alpha;
+
+		web_color(byte r, byte g, byte b, byte a = 255)
+		{
+			blue	= b;
+			green	= g;
+			red		= r;
+			alpha	= a;
+		}
+
+		web_color()
+		{
+			blue	= 0;
+			green	= 0;
+			red		= 0;
+			alpha	= 0xFF;
+		}
+
+		web_color(const web_color& val)
+		{
+			blue	= val.blue;
+			green	= val.green;
+			red		= val.red;
+			alpha	= val.alpha;
+		}
+
+		web_color& operator=(const web_color& val)
+		{
+			blue	= val.blue;
+			green	= val.green;
+			red		= val.red;
+			alpha	= val.alpha;
+			return *this;
+		}
+		static web_color		from_string(const tchar_t* str);
+		static const tchar_t*	resolve_name(const tchar_t* name);
+		static bool				is_color(const tchar_t* str);
+	};
+}
\ No newline at end of file
diff --git a/src/plugins/litehtml_viewer/plugin.c b/src/plugins/litehtml_viewer/plugin.c
new file mode 100644
index 0000000..3b0dc93
--- /dev/null
+++ b/src/plugins/litehtml_viewer/plugin.c
@@ -0,0 +1,79 @@
+/*
+ * 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 at 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 <glib/gi18n.h>
+
+#include <mimeview.h>
+#include <plugin.h>
+
+extern MimeViewerFactory lh_viewer_factory;
+
+gint plugin_init(gchar **error)
+{
+	debug_print("LH: plugin_init\n");
+	mimeview_register_viewer_factory(&lh_viewer_factory);
+	return 0;
+}
+
+gboolean plugin_done(void)
+{
+	debug_print("LH: plugin_done\n");
+	mimeview_unregister_viewer_factory(&lh_viewer_factory);
+	return TRUE;
+}
+
+const gchar *plugin_name(void)
+{
+	return "LiteHTML viewer";
+}
+
+const gchar *plugin_desc(void)
+{
+	return "[description goes here]";
+}
+
+const gchar *plugin_type(void)
+{
+	return "GTK2";
+}
+
+const gchar *plugin_licence(void)
+{
+	return "GPL3";
+}
+
+const gchar *plugin_version(void)
+{
+	return "0.1";
+}
+
+struct PluginFeature *plugin_provides(void)
+{
+	static struct PluginFeature features[] = {
+		{ PLUGIN_MIMEVIEWER, "text/html" },
+		{ PLUGIN_NOTHING, NULL }
+	};
+
+	return features;
+}
diff --git a/src/plugins/litehtml_viewer/plugin.def b/src/plugins/litehtml_viewer/plugin.def
new file mode 100644
index 0000000..8916a5d
--- /dev/null
+++ b/src/plugins/litehtml_viewer/plugin.def
@@ -0,0 +1,10 @@
+EXPORTS
+        plugin_desc
+        plugin_done
+        plugin_init
+        plugin_licence
+        plugin_name
+        plugin_type
+	plugin_provides
+        plugin_version
+
diff --git a/src/plugins/litehtml_viewer/version.rc b/src/plugins/litehtml_viewer/version.rc
new file mode 100644
index 0000000..e54fb10
--- /dev/null
+++ b/src/plugins/litehtml_viewer/version.rc
@@ -0,0 +1,36 @@
+1 VERSIONINFO
+ FILEVERSION 0, 0, 0, 0
+ PRODUCTVERSION 0, 0, 0, 0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "000004b0"
+        BEGIN
+            VALUE "FileDescription", "Claws Mail Fancy Plugin\0"
+            VALUE "FileVersion", "0.0.0.0\0"
+            VALUE "ProductVersion", "0.0.0.0 Win32\0"
+            VALUE "LegalCopyright", "GPL / © 1999-2017 Hiroyuki Yamamoto & The Claws Mail Team\0"
+            VALUE "CompanyName", "GNU / Free Software Foundation\0"
+            VALUE "ProductName", "Claws Mail\0"
+//            VALUE "Comments", "\0"
+//            VALUE "InternalName", "\0"
+//            VALUE "LegalTrademarks", "\0"
+//            VALUE "OriginalFilename", "\0"
+//            VALUE "PrivateBuild", "\0"
+//            VALUE "SpecialBuild", "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x0, 1200
+    END
+END

commit d38ab508ad6133ddaa9524318bd9fef6fd2a1846
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sat May 4 02:52:32 2019 +0200

    Make Enter key in mbox export dialog's file entry start the export

diff --git a/src/export.c b/src/export.c
index 4e1d4c1..045fa87 100644
--- a/src/export.c
+++ b/src/export.c
@@ -159,6 +159,7 @@ static void export_create(void)
 	gtk_table_attach(GTK_TABLE(table), file_entry, 1, 2, 1, 2,
 			 (GtkAttachOptions) (GTK_EXPAND|GTK_SHRINK|GTK_FILL),
 			 (GtkAttachOptions) (0), 0, 0);
+	gtk_entry_set_activates_default(GTK_ENTRY(file_entry), TRUE);
 
 	src_button = gtkut_get_browse_directory_btn(_("_Browse"));
 	gtk_table_attach(GTK_TABLE(table), src_button, 2, 3, 0, 1,

commit e035ca4f0844b022399f82d323e3839c2f577e9a
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Wed May 1 12:44:20 2019 +0200

    Fix CID 1444847 - Uninitialized variables in sock_close()

diff --git a/src/common/socket.c b/src/common/socket.c
index ad740b5..4dac820 100644
--- a/src/common/socket.c
+++ b/src/common/socket.c
@@ -1488,7 +1488,7 @@ Single-byte send() and recv().
 
 gint sock_close(SockInfo *sock, gboolean close_fd)
 {
-	gint ret;
+	gint ret = 0;
 
 	if (!sock)
 		return 0;

commit 14b89d30c8ad53fb734a84a9696a71d46479b021
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Apr 30 23:03:03 2019 +0200

    Fix a memory corruption bug in RSSyl's feed_item_copy()

diff --git a/src/plugins/rssyl/libfeed/feeditem.c b/src/plugins/rssyl/libfeed/feeditem.c
index 340cbf5..8d9faaa 100644
--- a/src/plugins/rssyl/libfeed/feeditem.c
+++ b/src/plugins/rssyl/libfeed/feeditem.c
@@ -344,7 +344,7 @@ FeedItem *feed_item_copy(FeedItem *item)
 	nitem->comments_url = g_strdup(item->comments_url);
 	nitem->parent_id = g_strdup(item->parent_id);
 
-	nitem->enclosure = g_memdup(item->enclosure, sizeof(FeedItemEnclosure));
+	nitem->enclosure = feed_item_enclosure_copy(item->enclosure);
 
 	nitem->date_published = item->date_published;
 	nitem->date_modified = item->date_modified;
diff --git a/src/plugins/rssyl/libfeed/feeditemenclosure.c b/src/plugins/rssyl/libfeed/feeditemenclosure.c
index 183cfb5..7f55961 100644
--- a/src/plugins/rssyl/libfeed/feeditemenclosure.c
+++ b/src/plugins/rssyl/libfeed/feeditemenclosure.c
@@ -98,3 +98,12 @@ void feed_item_enclosure_set_size(FeedItemEnclosure *enclosure, gulong size)
 
 	enclosure->size = size;
 }
+
+FeedItemEnclosure *feed_item_enclosure_copy(FeedItemEnclosure *enclosure)
+{
+	if (enclosure == NULL)
+		return NULL;
+
+	return feed_item_enclosure_new(enclosure->url, enclosure->type,
+			enclosure->size);
+}
diff --git a/src/plugins/rssyl/libfeed/feeditemenclosure.h b/src/plugins/rssyl/libfeed/feeditemenclosure.h
index ba4d127..69e9eff 100644
--- a/src/plugins/rssyl/libfeed/feeditemenclosure.h
+++ b/src/plugins/rssyl/libfeed/feeditemenclosure.h
@@ -40,4 +40,6 @@ void feed_item_enclosure_set_type(FeedItemEnclosure *enclosure, gchar *type);
 gulong feed_item_enclosure_get_size(FeedItemEnclosure *enclosure);
 void feed_item_enclosure_set_size(FeedItemEnclosure *enclosure, gulong size);
 
+FeedItemEnclosure *feed_item_enclosure_copy(FeedItemEnclosure *enclosure);
+
 #endif /* __FEEDITEMENCLOSURE_H */

commit 4f3a94b969648c6cd7703053ddcbd05fcb3d6c9a
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Apr 30 23:02:18 2019 +0200

    Fix parsing items with empty bodies from on-disk RSSyl items

diff --git a/src/plugins/rssyl/parse822.c b/src/plugins/rssyl/parse822.c
index 1c89c77..51cb313 100644
--- a/src/plugins/rssyl/parse822.c
+++ b/src/plugins/rssyl/parse822.c
@@ -198,6 +198,7 @@ FeedItem *rssyl_parse_folder_item_file(gchar *path)
 			if( !strcmp(lines[i], RSSYL_TEXT_START) ) {
 				debug_print("RSSyl: Leading html tag found at line %d\n", i);
 				past_html_tag = TRUE;
+				body = g_string_new("");
 				i++;
 				continue;
 			}
@@ -208,12 +209,9 @@ FeedItem *rssyl_parse_folder_item_file(gchar *path)
 					continue;
 				}
 
-				if (body) {
+				if (body->len > 0)
 					body = g_string_append_c(body, '\n');
-					body = g_string_append(body, lines[i]);
-				} else {
-					body = g_string_new(lines[i]);
-				}
+				body = g_string_append(body, lines[i]);
 
 				i++;
 			}
@@ -224,7 +222,7 @@ FeedItem *rssyl_parse_folder_item_file(gchar *path)
 	}
 
 	if (body != NULL ) {
-		if (past_endhtml_tag && body->str != NULL && body->len > 0)
+		if (past_html_tag && past_endhtml_tag && body->str != NULL)
 			feed_item_set_text(item, body->str);
 		g_string_free(body, TRUE);
 	}
diff --git a/src/plugins/rssyl/rssyl_add_item.c b/src/plugins/rssyl/rssyl_add_item.c
index d22e1dd..c40c9cd 100644
--- a/src/plugins/rssyl/rssyl_add_item.c
+++ b/src/plugins/rssyl/rssyl_add_item.c
@@ -542,7 +542,8 @@ void rssyl_add_item(RFolderItem *ritem, FeedItem *feed_item)
 			(heading ? heading : ""),
 			(tmpurl ? tmpurl : ""),
 			(tmpurl ? tmpurl : "n/a"),
-			(text ? text : ""), (text ? "\n" : "") );
+			(text ? text : ""),
+			(text && strlen(text) > 0 ? "\n" : "") );
 
 	g_free(meta_charset);
 	g_free(baseurl);

commit 81379996cd48fdb4115189ed394d470697089dd4
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sun Apr 28 23:22:00 2019 +0200

    Remove unnecessary debug output from previous commit

diff --git a/src/plugins/rssyl/parse822.c b/src/plugins/rssyl/parse822.c
index 0553de6..1c89c77 100644
--- a/src/plugins/rssyl/parse822.c
+++ b/src/plugins/rssyl/parse822.c
@@ -205,15 +205,13 @@ FeedItem *rssyl_parse_folder_item_file(gchar *path)
 				if( !strcmp(lines[i], RSSYL_TEXT_END) ) {
 					debug_print("RSSyl: Trailing html tag found at line %d\n", i);
 					past_endhtml_tag = TRUE;
-					i++;
 					continue;
 				}
 
 				if (body) {
-					debug_print("appending '%s'\n", lines[i]);
+					body = g_string_append_c(body, '\n');
 					body = g_string_append(body, lines[i]);
 				} else {
-					debug_print("creating new with '%s'\n", lines[i]);
 					body = g_string_new(lines[i]);
 				}
 

commit ce6fa72069affbe12945f396fba10deec6bd064a
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sun Apr 28 23:13:32 2019 +0200

    Simplify item body parsing in rssyl_parse_folder_item_file()
    
    This possibly fixes a memory corruption issue, too.

diff --git a/src/plugins/rssyl/parse822.c b/src/plugins/rssyl/parse822.c
index 4732afa..0553de6 100644
--- a/src/plugins/rssyl/parse822.c
+++ b/src/plugins/rssyl/parse822.c
@@ -55,6 +55,7 @@ FeedItem *rssyl_parse_folder_item_file(gchar *path)
 	FeedItem *item;
 	RFeedCtx *ctx;
 	gint i = 0;
+	GString *body = NULL;
 	gboolean parsing_headers = TRUE, past_html_tag = FALSE, past_endhtml_tag = FALSE;
 	gboolean started_author = FALSE, started_subject = FALSE;
 	gboolean started_link = FALSE, started_clink = FALSE, got_original_title = FALSE;
@@ -207,26 +208,29 @@ FeedItem *rssyl_parse_folder_item_file(gchar *path)
 					i++;
 					continue;
 				}
-				if( feed_item_get_text(item) != NULL ) {
-					gint e_len, n_len;
-					e_len = strlen(item->text);
-					n_len = strlen(lines[i]);
-					item->text = g_realloc(item->text, e_len + n_len + 2);
-					*(item->text+e_len) = '\n';
-					strcpy(item->text+e_len+1, lines[i]);
-					*(item->text+e_len+n_len+1) = '\0';
+
+				if (body) {
+					debug_print("appending '%s'\n", lines[i]);
+					body = g_string_append(body, lines[i]);
 				} else {
-					item->text = g_strdup(lines[i]);
+					debug_print("creating new with '%s'\n", lines[i]);
+					body = g_string_new(lines[i]);
 				}
+
 				i++;
 			}
 
-			if( lines[i] == NULL )
-				return item;
 		}
 
 		i++;
 	}
+
+	if (body != NULL ) {
+		if (past_endhtml_tag && body->str != NULL && body->len > 0)
+			feed_item_set_text(item, body->str);
+		g_string_free(body, TRUE);
+	}
+
 	g_free(lines);
 	g_free(contents);
 	return item;

commit 59ca7ef79b2d22e033b8971f706b4618b71bdbd7
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri Apr 26 08:16:08 2019 +0200

    Fix a syntax error in sock_close() causing windows build to fail

diff --git a/src/common/socket.c b/src/common/socket.c
index c5814d7..ad740b5 100644
--- a/src/common/socket.c
+++ b/src/common/socket.c
@@ -1509,8 +1509,8 @@ gint sock_close(SockInfo *sock, gboolean close_fd)
 		ret = closesocket(sock->sock);
 #else
 		ret = fd_close(sock->sock);
-	}
 #endif
+	}
 
 	g_free(sock->canonical_name);
 	g_free(sock->hostname);

commit ff5ef90b73a3ca7b806455b218efde1fdbc69c58
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri Apr 26 00:28:58 2019 +0200

    Free a memory leak in libetpan-backed server connections
    
    We create a connection using our sock_connect() and let
    libetpan take over managing it. However, libetpan only
    needs the socket file descriptor, so we need to get rid
    of the rest of the returned SockInfo struct.

diff --git a/src/common/session.c b/src/common/session.c
index a6f19ea..2da8e16 100644
--- a/src/common/session.c
+++ b/src/common/session.c
@@ -388,7 +388,7 @@ static gint session_close(Session *session)
 	}
 
 	if (session->sock) {
-		sock_close(session->sock);
+		sock_close(session->sock, TRUE);
 		session->sock = NULL;
 		session->state = SESSION_DISCONNECTED;
 		debug_print("session (%p): closed\n", session);
diff --git a/src/common/socket.c b/src/common/socket.c
index fdc1589..c5814d7 100644
--- a/src/common/socket.c
+++ b/src/common/socket.c
@@ -1486,7 +1486,7 @@ Single-byte send() and recv().
 	return bp - buf;
 }
 
-gint sock_close(SockInfo *sock)
+gint sock_close(SockInfo *sock, gboolean close_fd)
 {
 	gint ret;
 
@@ -1503,11 +1503,13 @@ gint sock_close(SockInfo *sock)
 		g_source_remove(sock->g_source);
 	sock->g_source = 0;
 #endif
+	if (close_fd) {
 #ifdef G_OS_WIN32
-	shutdown(sock->sock, 1); /* complete transfer before close */
-	ret = closesocket(sock->sock);
+		shutdown(sock->sock, 1); /* complete transfer before close */
+		ret = closesocket(sock->sock);
 #else
-	ret = fd_close(sock->sock); 
+		ret = fd_close(sock->sock);
+	}
 #endif
 
 	g_free(sock->canonical_name);
diff --git a/src/common/socket.h b/src/common/socket.h
index 005f5a0..a1b17e5 100644
--- a/src/common/socket.h
+++ b/src/common/socket.h
@@ -108,7 +108,7 @@ gint sock_connect_async_cancel		(gint id);
 gint sock_read		(SockInfo *sock, gchar *buf, gint len);
 gint sock_write		(SockInfo *sock, const gchar *buf, gint len);
 gint sock_write_all	(SockInfo *sock, const gchar *buf, gint len);
-gint sock_close		(SockInfo *sock);
+gint sock_close		(SockInfo *sock, gboolean close_fd);
 
 /* Functions to directly work on FD.  They are needed for pipes */
 gint fd_connect_unix	(const gchar *path);
diff --git a/src/etpan/imap-thread.c b/src/etpan/imap-thread.c
index b68e303..eeccac7 100644
--- a/src/etpan/imap-thread.c
+++ b/src/etpan/imap-thread.c
@@ -78,17 +78,22 @@ static int do_mailimap_socket_connect(mailimap * imap, const char * server,
 		return MAILIMAP_ERROR_CONNECTION_REFUSED;
 
 	if (proxy_connect(sock, server, port, proxy_info) < 0) {
-		sock_close(sock);
+		sock_close(sock, TRUE);
 		return MAILIMAP_ERROR_CONNECTION_REFUSED;
 	}
 
 	stream = mailstream_socket_open_timeout(sock->sock,
 			imap->imap_timeout);
 	if (stream == NULL) {
-		sock_close(sock);
+		sock_close(sock, TRUE);
 		return MAILIMAP_ERROR_MEMORY;
 	}
 
+	/* Libetpan now has the socket fd, and we're not interested in
+	 * rest of the SockInfo struct. Let's free it, while not touching
+	 * the socket itself. */
+	sock_close(sock, FALSE);
+
 	return mailimap_connect(imap, stream);
 }
 
@@ -119,17 +124,22 @@ static int do_mailimap_ssl_connect_with_callback(mailimap * imap, const char * s
 	if (proxy_connect(sock, server, port, proxy_info) < 0) {
 		debug_print("Can not make proxy connection via %s:%d\n",
 				proxy_info->proxy_host, proxy_info->proxy_port);
-		sock_close(sock);
+		sock_close(sock, TRUE);
 		return MAILIMAP_ERROR_CONNECTION_REFUSED;
 	}
 
 	stream = mailstream_ssl_open_with_callback_timeout(sock->sock,
 			imap->imap_timeout, callback, data);
 	if (stream == NULL) {
-		sock_close(sock);
+		sock_close(sock, TRUE);
 		return MAILIMAP_ERROR_SSL;
 	}
 
+	/* Libetpan now has the socket fd, and we're not interested in
+	 * rest of the SockInfo struct. Let's free it, while not touching
+	 * the socket itself. */
+	sock_close(sock, FALSE);
+
 	return mailimap_connect(imap, stream);
 }
 
diff --git a/src/etpan/nntp-thread.c b/src/etpan/nntp-thread.c
index bf67cd0..5f5b31b 100644
--- a/src/etpan/nntp-thread.c
+++ b/src/etpan/nntp-thread.c
@@ -78,17 +78,22 @@ static int do_newsnntp_socket_connect(newsnntp * imap, const char * server,
 		return NEWSNNTP_ERROR_CONNECTION_REFUSED;
 
 	if (proxy_connect(sock, server, port, proxy_info) < 0) {
-		sock_close(sock);
+		sock_close(sock, TRUE);
 		return NEWSNNTP_ERROR_CONNECTION_REFUSED;
 	}
 
 	stream = mailstream_socket_open_timeout(sock->sock,
 			imap->nntp_timeout);
 	if (stream == NULL) {
-		sock_close(sock);
+		sock_close(sock, TRUE);
 		return NEWSNNTP_ERROR_MEMORY;
 	}
 
+	/* Libetpan now has the socket fd, and we're not interested in
+	 * rest of the SockInfo struct. Let's free it, while not touching
+	 * the socket itself. */
+	sock_close(sock, FALSE);
+
 	return newsnntp_connect(imap, stream);
 }
 
@@ -114,17 +119,22 @@ static int do_newsnntp_ssl_connect_with_callback(newsnntp * imap, const char * s
 		return NEWSNNTP_ERROR_CONNECTION_REFUSED;
 
 	if (proxy_connect(sock, server, port, proxy_info) < 0) {
-		sock_close(sock);
+		sock_close(sock, TRUE);
 		return NEWSNNTP_ERROR_CONNECTION_REFUSED;
 	}
 
 	stream = mailstream_ssl_open_with_callback_timeout(sock->sock,
 			imap->nntp_timeout, callback, data);
 	if (stream == NULL) {
-		sock_close(sock);
+		sock_close(sock, TRUE);
 		return NEWSNNTP_ERROR_SSL;
 	}
 
+	/* Libetpan now has the socket fd, and we're not interested in
+	 * rest of the SockInfo struct. Let's free it, while not touching
+	 * the socket itself. */
+	sock_close(sock, FALSE);
+
 	return newsnntp_connect(imap, stream);
 }
 
diff --git a/src/plugins/notification/notification_lcdproc.c b/src/plugins/notification/notification_lcdproc.c
index 874caa7..0f131d1 100644
--- a/src/plugins/notification/notification_lcdproc.c
+++ b/src/plugins/notification/notification_lcdproc.c
@@ -61,7 +61,7 @@ void notification_lcdproc_connect(void)
   if(sock == NULL || sock->state == CONN_FAILED) {
     debug_print("Could not connect to LCDd\n");
     if(sock && sock->state == CONN_FAILED) {
-      sock_close(sock);
+      sock_close(sock, TRUE);
       sock = NULL;
     }
     return;
@@ -116,7 +116,7 @@ void notification_lcdproc_disconnect(void)
 #ifndef G_OS_WIN32
     shutdown(sock->sock, SHUT_RDWR);
 #endif
-    sock_close(sock);
+    sock_close(sock, TRUE);
     sock = NULL;
   }
 }

commit 95d249d866ea6dd069537df07ee5c3f76fcd5b20
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Thu Apr 25 23:59:40 2019 +0200

    Fix memory leaks in imap_handle_error()

diff --git a/src/imap.c b/src/imap.c
index db6770a..8d8876b 100644
--- a/src/imap.c
+++ b/src/imap.c
@@ -600,9 +600,15 @@ static gboolean is_fatal(int libetpan_errcode)
 	}
 }
 
+#define MY_LOG_WARNING(concat_cmd, ...) \
+	msg = concat_cmd; \
+	log_warning(LOG_PROTOCOL, msg, __VA_ARGS__); \
+	g_free(msg);
+
 static void imap_handle_error(Session *session, const gchar *server, int libetpan_errcode)
 {
 	const gchar *session_server = (session ? session->server : NULL);
+	gchar *msg;
 
 	if (session_server == NULL)
 		session_server = server;
@@ -613,135 +619,135 @@ static void imap_handle_error(Session *session, const gchar *server, int libetpa
 	case MAILIMAP_NO_ERROR:
 		return;
 	case MAILIMAP_NO_ERROR_AUTHENTICATED:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("authenticated"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("authenticated"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_NO_ERROR_NON_AUTHENTICATED:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("not authenticated"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("not authenticated"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_BAD_STATE:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("bad state"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("bad state"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_STREAM:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("stream error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("stream error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_PARSE:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("parse error "
-					    "(very probably non-RFC compliance from the server)"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("parse error "
+					    "(very probably non-RFC compliance from the server)"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_CONNECTION_REFUSED:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("connection refused"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("connection refused"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_MEMORY:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("memory error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("memory error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_FATAL:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("fatal error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("fatal error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_PROTOCOL:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("protocol error "
-					    "(very probably non-RFC compliance from the server)"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("protocol error "
+					    "(very probably non-RFC compliance from the server)"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_DONT_ACCEPT_CONNECTION:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("connection not accepted"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("connection not accepted"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_APPEND:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("APPEND error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("APPEND error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_NOOP:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("NOOP error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("NOOP error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_LOGOUT:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("LOGOUT error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("LOGOUT error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_CAPABILITY:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("CAPABILITY error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("CAPABILITY error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_CHECK:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("CHECK error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("CHECK error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_CLOSE:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("CLOSE error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("CLOSE error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_EXPUNGE:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("EXPUNGE error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("EXPUNGE error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_COPY:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("COPY error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("COPY error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_UID_COPY:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("UID COPY error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("UID COPY error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_CREATE:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("CREATE error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("CREATE error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_DELETE:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("DELETE error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("DELETE error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_EXAMINE:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("EXAMINE error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("EXAMINE error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_FETCH:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("FETCH error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("FETCH error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_UID_FETCH:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("UID FETCH error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("UID FETCH error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_LIST:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("LIST error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("LIST error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_LOGIN:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("LOGIN error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("LOGIN error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_LSUB:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("LSUB error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("LSUB error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_RENAME:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("RENAME error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("RENAME error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_SEARCH:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("SEARCH error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("SEARCH error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_UID_SEARCH:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("UID SEARCH error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("UID SEARCH error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_SELECT:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("SELECT error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("SELECT error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_STATUS:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("STATUS error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("STATUS error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_STORE:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("STORE error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("STORE error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_UID_STORE:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("UID STORE error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("UID STORE error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_SUBSCRIBE:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("SUBSCRIBE error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("SUBSCRIBE error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_UNSUBSCRIBE:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("UNSUBSCRIBE error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("UNSUBSCRIBE error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_STARTTLS:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("STARTTLS error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("STARTTLS error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_INVAL:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("INVAL error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("INVAL error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_EXTENSION:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("EXTENSION error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("EXTENSION error"), "\n", NULL), session_server)
 		break;
 	case MAILIMAP_ERROR_SASL:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("SASL error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("SASL error"), "\n", NULL), session_server)
 		break;
 #ifdef USE_GNUTLS
 	case MAILIMAP_ERROR_SSL:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("SSL/TLS error"), "\n", NULL), session_server);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("SSL/TLS error"), "\n", NULL), session_server)
 		break;
 #endif
 	default:
-		log_warning(LOG_PROTOCOL, g_strconcat(_("IMAP error on %s:"), " ", _("Unknown error [%d]"), "\n", NULL),
-			session_server, libetpan_errcode);
+		MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("Unknown error [%d]"), "\n", NULL),
+			session_server, libetpan_errcode)
 		break;
 	}
 
@@ -753,6 +759,8 @@ static void imap_handle_error(Session *session, const gchar *server, int libetpa
 	}
 }
 
+#undef MY_LOG_WARNING
+
 static Folder *imap_folder_new(const gchar *name, const gchar *path)
 {
 	Folder *folder;

commit b10324dea0905d1f014d51bf064628a41280fda1
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Thu Apr 25 23:49:47 2019 +0200

    Fix a memory leak in sc_session_manager_connect()

diff --git a/src/main.c b/src/main.c
index f3a54a2..25357a2 100644
--- a/src/main.c
+++ b/src/main.c
@@ -641,6 +641,16 @@ static void sc_session_manager_connect(MainWindow *mainwin)
 				NULL, &client_id,
 				256, error_string_ret);
 
+		/* From https://www.x.org/releases/X11R7.7/doc/libSM/SMlib.txt:
+		 * If SmcOpenConnection succeeds, it returns an opaque connection
+		 * pointer of type SmcConn and the client_id_ret argument contains
+		 * the client ID to be used for this session. The client_id_ret
+		 * should be freed with a call to free when no longer needed. On
+		 * failure, SmcOpenConnection returns NULL, and the reason for
+		 * failure is returned in error_string_ret. */
+		if (mainwin->smc_conn != NULL)
+			g_free(client_id);
+
 		if (error_string_ret[0] || mainwin->smc_conn == NULL)
 			g_warning ("While connecting to session manager: %s.",
 				error_string_ret);

commit 3b4a311d506acffb87e0c057825dee7c91b7ed0c
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Thu Apr 25 22:20:06 2019 +0200

    Fix a runaway string read in procmime_decode_content()
    
    We initialize output buffer for g_base64_decode_step()
    to zeroes, so that we can later call strlen() on it
    safely.
    We also allocate one byte more than we write, so that
    the trailing zero byte is guaranteed to be there.

diff --git a/src/procmime.c b/src/procmime.c
index 84d9d07..fdc17ff 100644
--- a/src/procmime.c
+++ b/src/procmime.c
@@ -366,7 +366,7 @@ gboolean procmime_decode_content(MimeInfo *mimeinfo)
 		if (flowed)
 			FLUSH_LASTLINE();
 	} else if (encoding == ENC_BASE64) {
-		gchar outbuf[BUFFSIZE];
+		gchar outbuf[BUFFSIZE + 1];
 		gint len, inlen, inread;
 		gboolean got_error = FALSE;
 		gboolean uncanonicalize = FALSE;
@@ -390,6 +390,7 @@ gboolean procmime_decode_content(MimeInfo *mimeinfo)
 
 		while ((inlen = MIN(readend - ftell(infp), sizeof(buf))) > 0 && !err) {
 			inread = claws_fread(buf, 1, inlen, infp);
+			memset(outbuf, 0, sizeof(buf));
 			len = g_base64_decode_step(buf, inlen, outbuf, &state, &save);
 			if (uncanonicalize == TRUE && strlen(outbuf) < len && starting) {
 				uncanonicalize = FALSE;

commit b629b57eb9d511fe15e1b418e7ed674e0764a65a
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Thu Apr 25 21:38:10 2019 +0200

    Fix a memory leak in rssyl_add_item()

diff --git a/src/plugins/rssyl/rssyl.c b/src/plugins/rssyl/rssyl.c
index 410b536..e6cc6e3 100644
--- a/src/plugins/rssyl/rssyl.c
+++ b/src/plugins/rssyl/rssyl.c
@@ -811,7 +811,7 @@ static gint rssyl_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
 	return dest->last_num;
 }
 
-static gint rssyl_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
+gint rssyl_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
 		MsgFlags *flags)
 {
 	GSList file_list;
diff --git a/src/plugins/rssyl/rssyl_add_item.c b/src/plugins/rssyl/rssyl_add_item.c
index 2bff270..d22e1dd 100644
--- a/src/plugins/rssyl/rssyl_add_item.c
+++ b/src/plugins/rssyl/rssyl_add_item.c
@@ -46,6 +46,9 @@
 #include "rssyl_parse_feed.h"
 #include "strutils.h"
 
+gint rssyl_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
+		MsgFlags *flags);
+
 /* rssyl_cb_feed_compare()
  *
  * GCompareFunc function called by glib2's g_slist_find_custom().
@@ -560,10 +563,15 @@ void rssyl_add_item(RFolderItem *ritem, FeedItem *feed_item)
 	flags->perm_flags = MSG_NEW | MSG_UNREAD;
 	flags->tmp_flags = 0;
 
-	d = folder_item_add_msg(&ritem->item, template, flags, TRUE);
-	g_free(template);
+	d = rssyl_add_msg(ritem->item.folder, &ritem->item, template, flags);
+
 	g_free(flags);
 
+	if (claws_unlink(template) < 0)
+		FILE_OP_ERROR(template, "unlink");
+
+	g_free(template);
+
 	ctx = g_new0(RFeedCtx, 1);
 	ctx->path = (gpointer)g_strdup_printf("%s%c%d", dirname,
 			G_DIR_SEPARATOR, d);
@@ -583,5 +591,5 @@ void rssyl_add_item(RFolderItem *ritem, FeedItem *feed_item)
 		}
 	}
 
-	debug_print("RSSyl: folder_item_add_msg(): %d\n", d);
+	debug_print("RSSyl: rssyl_add_msg(): %d\n", d);
 }

commit cab9f7c7a3ec9134197188dbeacb1b2b9e6c19ec
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Thu Apr 25 01:10:36 2019 +0200

    Fix a memory leak in sgpgme_sigstat_info_short()

diff --git a/src/plugins/pgpcore/sgpgme.c b/src/plugins/pgpcore/sgpgme.c
index 79c0c92..3d056e9 100644
--- a/src/plugins/pgpcore/sgpgme.c
+++ b/src/plugins/pgpcore/sgpgme.c
@@ -310,6 +310,10 @@ gchar *sgpgme_sigstat_info_short(gpgme_ctx_t ctx, gpgme_verify_result_t status)
 	if (result == NULL)
 		result = g_strdup(_("Error"));
 	g_free(uname);
+
+	if (key)
+		gpgme_key_release(key);
+
 	return result;
 }
 

commit b17dda3046b44e615747ad59fbcc7b5c75053fd1
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Thu Apr 25 01:04:59 2019 +0200

    Fix a memory leak in icon_list_append_icon()

diff --git a/src/mimeview.c b/src/mimeview.c
index 92b8e61..71d07b7 100644
--- a/src/mimeview.c
+++ b/src/mimeview.c
@@ -2629,8 +2629,12 @@ static void icon_list_append_icon (MimeView *mimeview, MimeInfo *mimeinfo)
 		g_free(escaped);
 	}
 	if (sigshort && *sigshort) {
-		tiptmp = g_strjoin("\n", tip, g_markup_escape_text(sigshort, -1), NULL);
+		gchar *sigshort_escaped =
+			g_markup_escape_text(sigshort, -1);
+
+		tiptmp = g_strjoin("\n", tip, sigshort_escaped, NULL);
 		g_free(tip);
+		g_free(sigshort_escaped);
 		tip = tiptmp;
 	}
 	g_free(sigshort);

commit a73b1eec22aeb59262113ba7044081349da446db
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Thu Apr 25 00:13:35 2019 +0200

    Fix a long-standing use-after-free in mainwin_actions_execute()
    
    message_actions_execute() eventually calls summary_show()
    to redisplay current folder in summaryview.
    This causes a summary_clear(), which frees all MsgInfos
    from the local linked list in mainwin_actions_execute().
    This list is then used to restore summaryview selection, but
    at this point, all its members point to already freed memory.
    
    We solve this by increasing each MsgInfo's reference count,
    so that they do not get freed, and we free them after we're
    done with them.
    
    Note: procmsg_msginfo_free() should probably be renamed to
    procmsg_msginfo_unref()

diff --git a/src/action.c b/src/action.c
index 56783c1..dda5dc7 100644
--- a/src/action.c
+++ b/src/action.c
@@ -620,6 +620,13 @@ static void mainwin_actions_execute_cb(GtkWidget *widget, gpointer data)
 	mainwin_actions_execute(mainwin, action_nb, NULL);
 }
 
+static void _free_msginfos(gpointer data, gpointer user_data)
+{
+	MsgInfo *msginfo = (MsgInfo *)data;
+
+	procmsg_msginfo_free(&msginfo);
+}
+
 static void mainwin_actions_execute(MainWindow *mainwin, guint action_nb,
 				       GtkWidget *widget)
 {
@@ -628,6 +635,7 @@ static void mainwin_actions_execute(MainWindow *mainwin, guint action_nb,
 	msg_list = summary_get_selected_msg_list(mainwin->summaryview);
 	message_actions_execute(mainwin->messageview, action_nb, msg_list);
 	summary_select_by_msg_list(mainwin->summaryview, msg_list);
+	g_slist_foreach(msg_list, _free_msginfos, NULL);
 	g_slist_free(msg_list);
 }
 
diff --git a/src/summaryview.c b/src/summaryview.c
index 00ec6b3..d9d1afe 100644
--- a/src/summaryview.c
+++ b/src/summaryview.c
@@ -1784,7 +1784,8 @@ GSList *summary_get_selected_msg_list(SummaryView *summaryview)
 	for (cur = GTK_CMCLIST(summaryview->ctree)->selection; cur != NULL && cur->data != NULL;
 	     cur = cur->next) {
 		msginfo = GTKUT_CTREE_NODE_GET_ROW_DATA(cur->data);
-		mlist = g_slist_prepend(mlist, msginfo);
+		mlist = g_slist_prepend(mlist,
+				procmsg_msginfo_new_ref(msginfo));
 	}
 
 	mlist = g_slist_reverse(mlist);

commit 0ae08c27c278560b157259b62b09fb8244e96e53
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Wed Apr 24 07:57:47 2019 +0200

    Fix a blatant textbook case of use-after-free in rssyl_update_feed()

diff --git a/src/plugins/rssyl/rssyl_update_feed.c b/src/plugins/rssyl/rssyl_update_feed.c
index e0ad115..31b4228 100644
--- a/src/plugins/rssyl/rssyl_update_feed.c
+++ b/src/plugins/rssyl/rssyl_update_feed.c
@@ -256,7 +256,7 @@ gboolean rssyl_update_feed(RFolderItem *ritem, RSSylVerboseFlags verbose)
 		g_free(ctx->error);
 		g_free(ctx);
 		STATUSBAR_POP(mainwin);
-		return ctx->success;
+		return FALSE;
 	}
 
 	rssyl_deleted_update(ritem);

commit fe13430b1687828b6b8c22672ea626dbd4812302
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Wed Apr 24 00:03:27 2019 +0200

    Fix memory leak in smime_sign() and forgotten removal of a temporary file in smime_encrypt()

diff --git a/src/plugins/smime/smime.c b/src/plugins/smime/smime.c
index f0cd96f..fd50f1e 100644
--- a/src/plugins/smime/smime.c
+++ b/src/plugins/smime/smime.c
@@ -691,6 +691,7 @@ gboolean smime_sign(MimeInfo *mimeinfo, PrefsAccount *account, const gchar *from
 	g_hash_table_insert(newinfo->dispositionparameters, g_strdup("filename"),
 			    g_strdup("smime.p7s"));
 	newinfo->data.mem = g_malloc(len + 1);
+	newinfo->tmp = TRUE;
 	g_memmove(newinfo->data.mem, real_content, len);
 	newinfo->data.mem[len] = '\0';
 	newinfo->encoding_type = ENC_BASE64;
@@ -869,6 +870,7 @@ gboolean smime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
 
 	encmultipart->content = MIMECONTENT_FILE;
 	encmultipart->data.filename = tmpfile;
+	encmultipart->tmp = TRUE;
 	procmime_encode_content(encmultipart, ENC_BASE64);
 
 	g_free(enccontent);

commit a534a94ff6a02d7e7a2e1a6f8e8463e40ae19dd9
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Apr 23 23:58:22 2019 +0200

    Fix memory leaks in pgpmime_sign() and pgpmime_encrypt()

diff --git a/src/plugins/pgpmime/pgpmime.c b/src/plugins/pgpmime/pgpmime.c
index 5633e0f..bd64439 100644
--- a/src/plugins/pgpmime/pgpmime.c
+++ b/src/plugins/pgpmime/pgpmime.c
@@ -601,6 +601,7 @@ gboolean pgpmime_sign(MimeInfo *mimeinfo, PrefsAccount *account, const gchar *fr
 	newinfo->data.mem = g_malloc(len + 1);
 	g_memmove(newinfo->data.mem, sigcontent, len);
 	newinfo->data.mem[len] = '\0';
+	newinfo->tmp = TRUE;
 	g_node_append(sigmultipart->node, newinfo->node);
 
 	g_free(sigcontent);
@@ -736,6 +737,7 @@ gboolean pgpmime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
 	newinfo->subtype = g_strdup("pgp-encrypted");
 	newinfo->content = MIMECONTENT_MEM;
 	newinfo->data.mem = g_strdup("Version: 1\n");
+	newinfo->tmp = TRUE;
 	g_node_append(encmultipart->node, newinfo->node);
 
 	newinfo = procmime_mimeinfo_new();
@@ -743,6 +745,7 @@ gboolean pgpmime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
 	newinfo->subtype = g_strdup("octet-stream");
 	newinfo->content = MIMECONTENT_MEM;
 	newinfo->data.mem = g_malloc(len + 1);
+	newinfo->tmp = TRUE;
 	g_memmove(newinfo->data.mem, enccontent, len);
 	newinfo->data.mem[len] = '\0';
 	g_node_append(encmultipart->node, newinfo->node);

commit 4a51eec45e2a45ff531874cd8972f2786cba8e23
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Apr 23 23:46:43 2019 +0200

    Fix a memory leak in rssyl_rename_folder()

diff --git a/src/plugins/rssyl/rssyl.c b/src/plugins/rssyl/rssyl.c
index fdd1816..410b536 100644
--- a/src/plugins/rssyl/rssyl.c
+++ b/src/plugins/rssyl/rssyl.c
@@ -591,6 +591,7 @@ static gint rssyl_rename_folder(Folder *folder, FolderItem *item,
 	dirname = g_path_get_dirname(oldpath);
 	basenewpath = g_strdelimit(g_strdup(name), G_DIR_SEPARATOR_S, '_');
 	newpath = g_strconcat(dirname, G_DIR_SEPARATOR_S, basenewpath, NULL);
+	g_free(dirname);
 	g_free(basenewpath);
 
 	if( g_rename(oldpath, newpath) < 0 ) {

commit bfc55f7a4e6fe27aa9fa3086dc5930bad52943bb
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Apr 23 22:31:31 2019 +0200

    Fix a memory leak in rssyl_add_item()

diff --git a/src/plugins/rssyl/rssyl_add_item.c b/src/plugins/rssyl/rssyl_add_item.c
index 4123008..2bff270 100644
--- a/src/plugins/rssyl/rssyl_add_item.c
+++ b/src/plugins/rssyl/rssyl_add_item.c
@@ -379,6 +379,7 @@ void rssyl_add_item(RFolderItem *ritem, FeedItem *feed_item)
 						atoi(pathbasename));
 		g_free(pathbasename);
 		oldperm_flags = msginfo->flags.perm_flags;
+		procmsg_msginfo_free(&msginfo);
 
 		ritem->items = g_slist_remove(ritem->items, old_item);
 		if (g_unlink(ctx->path) != 0) {
@@ -575,9 +576,11 @@ void rssyl_add_item(RFolderItem *ritem, FeedItem *feed_item)
 	 * doesn't want to see it unread because of the change. */
 	if (dif != EXISTS_NEW) {
 		if (!(oldperm_flags & MSG_UNREAD) && (ritem->silent_update == 2
-				|| (ritem->silent_update == 1 && dif == EXISTS_CHANGED_TEXTONLY)))
-			procmsg_msginfo_unset_flags(
-					folder_item_get_msginfo((FolderItem *)ritem, d), MSG_NEW | MSG_UNREAD, 0);
+				|| (ritem->silent_update == 1 && dif == EXISTS_CHANGED_TEXTONLY))) {
+			msginfo = folder_item_get_msginfo((FolderItem *)ritem, d);
+			procmsg_msginfo_unset_flags(msginfo, MSG_NEW | MSG_UNREAD, 0);
+			procmsg_msginfo_free(&msginfo);
+		}
 	}
 
 	debug_print("RSSyl: folder_item_add_msg(): %d\n", d);

commit 6a99577ab05c39eec8674af6c7786b5e1fd4b6a2
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Mon Apr 22 12:58:59 2019 +0200

    Fix a memory leak in rssyl_deleted_expire()

diff --git a/src/plugins/rssyl/rssyl_deleted.c b/src/plugins/rssyl/rssyl_deleted.c
index a264365..5d1bbfc 100644
--- a/src/plugins/rssyl/rssyl_deleted.c
+++ b/src/plugins/rssyl/rssyl_deleted.c
@@ -370,8 +370,9 @@ void rssyl_deleted_expire(RFolderItem *ritem, Feed *feed)
 			debug_print("RSSyl: (DELETED) removing '%s' from list\n", ditem->title);
 			d2 = d->next;
 			ritem->deleted_items = g_slist_remove_link(ritem->deleted_items, d);
+			_free_deleted_item(ditem, NULL);
+			g_slist_free(d);
 			d = d2;
-			continue;
 		} else {
 			d = d->next;
 		}

commit 70eebdd11a9e2fa542425768cbffa1b5c57888f9
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Mon Apr 22 11:37:27 2019 +0200

    Fix memory leak in RSSyl's feed_item_free()

diff --git a/src/plugins/rssyl/libfeed/feeditem.c b/src/plugins/rssyl/libfeed/feeditem.c
index a85852e..340cbf5 100644
--- a/src/plugins/rssyl/libfeed/feeditem.c
+++ b/src/plugins/rssyl/libfeed/feeditem.c
@@ -80,7 +80,7 @@ void feed_item_free(FeedItem *item)
 	g_free(item->data);
 	g_free(item->comments_url);
 	g_free(item->parent_id);
-	g_free(item->enclosure);
+	feed_item_enclosure_free(item->enclosure);
 
 	g_free(item->sourcetitle);
 	g_free(item->sourceid);

commit 9b490d06142246b6dda2bf36484ff4e5a6bfec00
Author: Paul <paul at claws-mail.org>
Date:   Sun Apr 21 11:44:00 2019 +0100

    fix bug 4167, 'Max line length exceeded when forwarding mail'

diff --git a/src/compose.c b/src/compose.c
index e5f9062..efe08b1 100644
--- a/src/compose.c
+++ b/src/compose.c
@@ -1,6 +1,6 @@
 /*
  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2018 the Claws Mail team and Hiroyuki Yamamoto
+ * Copyright (C) 1999-2019 the Claws Mail team and Hiroyuki Yamamoto
  *
  * 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
@@ -6471,7 +6471,7 @@ static int compose_add_attachments(Compose *compose, MimeInfo *parent)
 		if (mimepart->type == MIMETYPE_MESSAGE
 		    || mimepart->type == MIMETYPE_MULTIPART)
 			ainfo->encoding = ENC_BINARY;
-		else if (compose->use_signing) {
+		else if (compose->use_signing || compose->fwdinfo != NULL) {
 			if (ainfo->encoding == ENC_7BIT)
 				ainfo->encoding = ENC_QUOTED_PRINTABLE;
 			else if (ainfo->encoding == ENC_8BIT)

commit b524c3fadd2e9213f39582233cc258b7159e79db
Author: Paul <paul at claws-mail.org>
Date:   Sun Mar 24 13:38:58 2019 +0000

    recognise model/* mime type
    
    fixes bug 4188, 'STL file is sent not as an attachment but as its base64
    representation in plaintext'

diff --git a/src/procmime.c b/src/procmime.c
index cb5e77e..84d9d07 100644
--- a/src/procmime.c
+++ b/src/procmime.c
@@ -1363,6 +1363,7 @@ static struct TypeTable mime_type_table[] = {
 	{"image", MIMETYPE_IMAGE},
 	{"audio", MIMETYPE_AUDIO},
 	{"video", MIMETYPE_VIDEO},
+	{"model", MIMETYPE_MODEL},
 	{"application", MIMETYPE_APPLICATION},
 	{"message", MIMETYPE_MESSAGE},
 	{"multipart", MIMETYPE_MULTIPART},
diff --git a/src/procmime.h b/src/procmime.h
index b21dc94..ac73447 100644
--- a/src/procmime.h
+++ b/src/procmime.h
@@ -48,6 +48,7 @@ typedef enum
 	MIMETYPE_APPLICATION,
 	MIMETYPE_MESSAGE,
 	MIMETYPE_MULTIPART,
+	MIMETYPE_MODEL,
 	MIMETYPE_UNKNOWN
 } MimeMediaType;
 

commit 509ed390092c95640ccf71460be8594931b54edb
Author: Ricardo Mones <ricardo at mones.org>
Date:   Wed Mar 13 22:46:59 2019 +0100

    Fix segfault using gdata plugin in German locales
    
    Reported as Debian bug #923980

diff --git a/po/de.po b/po/de.po
index f6c56c7..a58d7d7 100644
--- a/po/de.po
+++ b/po/de.po
@@ -10405,7 +10405,7 @@ msgstr "GData-Plugin: Fehler beim Erneuern der Autorisierung: %s\n"
 
 #: src/plugins/gdata/cm_gdata_contacts.c:506
 msgid "GData plugin: Authorization refresh successful\n"
-msgstr "GData-Plugin: Erneuern der Autorisierung erfolgreich: %s\n"
+msgstr "GData-Plugin: Erneuern der Autorisierung erfolgreich\n"
 
 #: src/plugins/gdata/cm_gdata_contacts.c:566
 #, c-format

commit ddfa3c24f186ce768680dd4b97433752a27a1210
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Wed Mar 13 21:58:56 2019 +0100

    Remove mgu_free_list() and mgu_free_dlist()
    
    We depend on glib 2.28, which has g_slist_free_full()
    and g_list_free_full(), which we can use instead.

diff --git a/src/addressbook.c b/src/addressbook.c
index cbc4030..14dee50 100644
--- a/src/addressbook.c
+++ b/src/addressbook.c
@@ -2389,7 +2389,7 @@ static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
 	if( ! addrselect_test_empty( _addressSelect_ ) ) {
 		listAddress = addrselect_build_list( _addressSelect_ );
 		compose_new_with_list( NULL, listAddress );
-		mgu_free_dlist( listAddress );
+		g_list_free_full( listAddress, g_free );
 		listAddress = NULL;
 	}
 }
diff --git a/src/addrharvest.c b/src/addrharvest.c
index 32e46f9..5e6cbeb 100644
--- a/src/addrharvest.c
+++ b/src/addrharvest.c
@@ -731,7 +731,7 @@ static gint addrharvest_readfile(
 		}
 
 		buf = mgu_list_coalesce( list );
-		mgu_free_list( list );
+		g_slist_free_full( list, g_free );
 
 		if(( p = strchr( buf, ':' ) ) != NULL ) {
 			addr = p + 1;
@@ -891,7 +891,7 @@ gint addrharvest_harvest(
 	else {
 		addrharvest_harvest_list( harvester, cache, listHdr, msgList );
 	}
-	mgu_free_dlist( listHdr );
+	g_list_free_full( listHdr, g_free );
 
 #ifndef USE_ALT_ADDRBOOK
 	/* Mark cache */
diff --git a/src/addrindex.c b/src/addrindex.c
index dff2c93..d44924c 100644
--- a/src/addrindex.c
+++ b/src/addrindex.c
@@ -1295,7 +1295,7 @@ static void addrindex_parse_ldap_attrlist( XMLFile *file, LdapControl *ctl ) {
 		rc = xml_parse_next_tag( file );
 		if( rc != 0 ) {
 			/* Terminate prematurely */
-			mgu_free_dlist( list );
+			g_list_free_full( list, g_free );
 			list = NULL;
 			return;
 		}
diff --git a/src/common/mgutils.c b/src/common/mgutils.c
index 8b90eab..9bdb2b1 100644
--- a/src/common/mgutils.c
+++ b/src/common/mgutils.c
@@ -58,32 +58,6 @@ void mgu_print_dlist( GList *list, FILE *stream ) {
 }
 
 /*
-* Free linked list of character strings.
-*/
-void mgu_free_list( GSList *list ) {
-	GSList *node = list;
-	while( node ) {
-		g_free( node->data );
-		node->data = NULL;
-		node = g_slist_next( node );
-	}
-	g_slist_free( list );
-}
-
-/*
-* Free linked list of character strings.
-*/
-void mgu_free_dlist( GList *list ) {
-	GList *node = list;
-	while( node ) {
-		g_free( node->data );
-		node->data = NULL;
-		node = g_list_next( node );
-	}
-	g_list_free( list );
-}
-
-/*
 * Coalesce linked list of characaters into one long string.
 */
 gchar *mgu_list_coalesce( GSList *list ) {
diff --git a/src/common/mgutils.h b/src/common/mgutils.h
index f589458..90c5d80 100644
--- a/src/common/mgutils.h
+++ b/src/common/mgutils.h
@@ -43,8 +43,6 @@
 /* Function prototypes */
 void mgu_print_list		( GSList *list, FILE *stream );
 void mgu_print_dlist		( GList *list, FILE *stream );
-void mgu_free_list		( GSList *list );
-void mgu_free_dlist		( GList *list );
 gchar *mgu_list_coalesce	( GSList *list );
 gchar *mgu_replace_string	( gchar *str, const gchar *value );
 gchar *mgu_email_check_empty	( gchar *address );
diff --git a/src/editjpilot.c b/src/editjpilot.c
index db1b46e..56fab21 100644
--- a/src/editjpilot.c
+++ b/src/editjpilot.c
@@ -123,7 +123,7 @@ static void edit_jpilot_fill_check_box( JPilotFile *jpf ) {
 			done = TRUE;
 		}
 	}
-	mgu_free_dlist( customLbl );
+	g_list_free_full( customLbl, g_free );
 	customLbl = NULL;
 }
 
diff --git a/src/editldap.c b/src/editldap.c
index dcea407..cd73e9f 100644
--- a/src/editldap.c
+++ b/src/editldap.c
@@ -254,7 +254,7 @@ static void edit_ldap_server_check( void ) {
 					}
 					node = g_list_next( node );
 				}
-				mgu_free_dlist( baseDN );
+				g_list_free_full( baseDN, g_free );
 				baseDN = node = NULL;
 				flg = TRUE;
 			} else {
diff --git a/src/editldap_basedn.c b/src/editldap_basedn.c
index 3a01737..5d830db 100644
--- a/src/editldap_basedn.c
+++ b/src/editldap_basedn.c
@@ -311,7 +311,7 @@ static void edit_ldap_bdn_load_data(
 				if (gtk_tree_model_get_iter_first(model, &iter))
 					gtk_tree_selection_select_iter(sel, &iter);
 
-				mgu_free_dlist( baseDN );
+				g_list_free_full( baseDN, g_free );
 				baseDN = node = NULL;
 			}
 			ldapedit_basedn_bad_server = FALSE;
diff --git a/src/jpilot.c b/src/jpilot.c
index 7b37c37..9923d76 100644
--- a/src/jpilot.c
+++ b/src/jpilot.c
@@ -256,7 +256,7 @@ void jpilot_clear_custom_labels( JPilotFile *pilotFile ) {
 	cm_return_if_fail( pilotFile != NULL );
 
 	/* Release custom labels */
-	mgu_free_dlist( pilotFile->customLabels );
+	g_list_free_full( pilotFile->customLabels, g_free );
 	pilotFile->customLabels = NULL;
 
 	/* Release indexes */
@@ -1079,7 +1079,7 @@ static void jpilot_parse_label( JPilotFile *pilotFile, gchar *labelEntry, ItemPe
 			addrcache_person_add_email( pilotFile->addressCache, person, email );
 			node = g_list_next( node );
 		}
-		mgu_free_dlist( list );
+		g_list_free_full( list, g_free );
 		list = NULL;
 	}
 }
diff --git a/src/ldapctrl.c b/src/ldapctrl.c
index 4cb929e..bdba4ff 100644
--- a/src/ldapctrl.c
+++ b/src/ldapctrl.c
@@ -241,7 +241,7 @@ GList *ldapctl_get_criteria_list( const LdapControl* ctl ) {
  */
 void ldapctl_criteria_list_clear( LdapControl *ctl ) {
 	cm_return_if_fail( ctl != NULL );
-	mgu_free_dlist( ctl->listCriteria );
+	g_list_free_full( ctl->listCriteria, g_free );
 	ctl->listCriteria = NULL;
 }
 
diff --git a/src/ldapquery.c b/src/ldapquery.c
index 2e96831..f799599 100644
--- a/src/ldapquery.c
+++ b/src/ldapquery.c
@@ -370,11 +370,11 @@ static void ldapqry_free_lists(
 		GSList *listLast, GSList *listDisplay, GSList *other_attrs )
 {
 	GSList *cur = other_attrs;
-	mgu_free_list( listName );
-	mgu_free_list( listAddr );
-	mgu_free_list( listFirst );
-	mgu_free_list( listLast );
-	mgu_free_list( listDisplay );
+	g_slist_free_full( listName, g_free );
+	g_slist_free_full( listAddr, g_free );
+	g_slist_free_full( listFirst, g_free );
+	g_slist_free_full( listLast, g_free );
+	g_slist_free_full( listDisplay, g_free );
 	for(;cur; cur = cur->next)
 		addritem_free_attribute((UserAttribute *)cur->data);
 	g_slist_free(other_attrs);
@@ -625,7 +625,7 @@ static GList *ldapqry_process_single_entry(
 				addritem_attrib_set_value( attrib, attvalue );
 				other_attrs = g_slist_prepend(other_attrs, attrib);
 			}
-			mgu_free_list(attlist);
+			g_slist_free_full(attlist, g_free);
 		}
 		/* Free memory used to store attribute */
 		ldap_memfree( attribute );
diff --git a/src/ldif.c b/src/ldif.c
index d2b19ef..086ab0b 100644
--- a/src/ldif.c
+++ b/src/ldif.c
@@ -651,7 +651,7 @@ static void ldif_read_file( LdifFile *ldifFile, AddressCache *cache ) {
 				ldif_build_items( ldifFile, rec, cache );
 				ldif_clear_rec( rec );
 				g_free( lastTag );
-				mgu_free_list( listValue );
+				g_slist_free_full( listValue, g_free );
 				g_free(fullValue);
 				lastTag = NULL;
 				listValue = NULL;
@@ -696,7 +696,7 @@ static void ldif_read_file( LdifFile *ldifFile, AddressCache *cache ) {
 								rec, lastTag, fullValue,
 								hashField );
 							g_free( lastTag );
-							mgu_free_list( listValue );
+							g_slist_free_full( listValue, g_free );
 							lastTag = NULL;
 							listValue = NULL;
 						}
@@ -719,7 +719,7 @@ static void ldif_read_file( LdifFile *ldifFile, AddressCache *cache ) {
 	ldif_clear_rec( rec );
 	g_free( rec );
 	g_free( lastTag );
-	mgu_free_list( listValue );
+	g_slist_free_full( listValue, g_free );
 }
 
 /**
@@ -854,7 +854,7 @@ static void ldif_read_tag_list( LdifFile *ldifFile ) {
 				ldif_hash_add_list(
 					ldifFile->hashFields, listTags );
 			}
-			mgu_free_list( listTags );
+			g_slist_free_full( listTags, g_free );
 			listTags = NULL;
 			flagMail = FALSE;
 		}
@@ -891,7 +891,7 @@ static void ldif_read_tag_list( LdifFile *ldifFile ) {
 	}
 
 	/* Release data */
-	mgu_free_list( listTags );
+	g_slist_free_full( listTags, g_free );
 	listTags = NULL;
 }
 
diff --git a/src/mutt.c b/src/mutt.c
index c6224c8..0747cf5 100644
--- a/src/mutt.c
+++ b/src/mutt.c
@@ -416,7 +416,7 @@ static void mutt_build_items( MuttFile *muttFile, AddressCache *cache, gchar *li
 	list = mgu_parse_string( line,  3, &tCount );
 	if( tCount < 3 ) {
 		if( list ) {
-			mgu_free_dlist( list );
+			g_list_free_full( list, g_free );
 			list = NULL;
 		}
 		return;
@@ -438,7 +438,7 @@ static void mutt_build_items( MuttFile *muttFile, AddressCache *cache, gchar *li
 		mutt_build_address( muttFile, cache, aliasName, addrList, aCount );
 	}
 
-	mgu_free_dlist( list );
+	g_list_free_full( list, g_free );
 	list = NULL;
 
 }
@@ -479,7 +479,7 @@ static void mutt_read_file( MuttFile *muttFile, AddressCache *cache ) {
 			}
 			g_free( lineValue );
 			lineValue = NULL;
-			mgu_free_list( listValue );
+			g_slist_free_full( listValue, g_free );
 			listValue = NULL;
 		}
 		lastCont = flagCont;
@@ -492,7 +492,7 @@ static void mutt_read_file( MuttFile *muttFile, AddressCache *cache ) {
 	}
 
 	/* Release data */
-	mgu_free_list( listValue );
+	g_slist_free_full( listValue, g_free );
 	listValue = NULL;
 }
 
diff --git a/src/pine.c b/src/pine.c
index 19e2525..1e5df3d 100644
--- a/src/pine.c
+++ b/src/pine.c
@@ -576,7 +576,7 @@ static void pine_read_file( PineFile *pineFile, AddressCache *cache ) {
 				}
 				g_free( lineValue );
 				lineValue = NULL;
-				mgu_free_list( listValue );
+				g_slist_free_full( listValue, g_free );
 				listValue = NULL;
 			}
 			if( line != NULL ) {
@@ -591,7 +591,7 @@ static void pine_read_file( PineFile *pineFile, AddressCache *cache ) {
 	}
 
 	/* Release data */
-	mgu_free_list( listValue );
+	g_slist_free_full( listValue, g_free );
 	listValue = NULL;
 }
 
diff --git a/src/vcard.c b/src/vcard.c
index df417a8..463f4a3 100644
--- a/src/vcard.c
+++ b/src/vcard.c
@@ -248,10 +248,10 @@ static gchar *vcard_get_line( VCardFile *cardFile ) {
 * Free linked lists of character strings.
 */
 static void vcard_free_lists( GSList *listName, GSList *listAddr, GSList *listRem, GSList* listID ) {
-	mgu_free_list( listName );
-	mgu_free_list( listAddr );
-	mgu_free_list( listRem );
-	mgu_free_list( listID );
+	g_slist_free_full( listName, g_free );
+	g_slist_free_full( listAddr, g_free );
+	g_slist_free_full( listRem, g_free );
+	g_slist_free_full( listID, g_free );
 }
 
 /*
@@ -275,7 +275,7 @@ static gchar *vcard_read_qp( VCardFile *cardFile, char *tagvalue ) {
 	line = mgu_list_coalesce( listQP );
 
 	/* Clean up */
-	mgu_free_list( listQP );
+	g_slist_free_full( listQP, g_free );
 	listQP = NULL;
 	return line;
 }

commit 59fdc07ddeff92ab869956e142de8716c973330e
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Wed Mar 13 21:39:28 2019 +0100

    Remove functions mgu_*_test_unq_nc()
    
    Only one of them was being used, only once, and
    it was replaced by a straightforward call to
    g_list_find_custom().

diff --git a/src/common/mgutils.c b/src/common/mgutils.c
index 941fc26..8b90eab 100644
--- a/src/common/mgutils.c
+++ b/src/common/mgutils.c
@@ -317,53 +317,5 @@ gchar *mgu_slist_longest_entry( GSList *list ) {
 }	
 
 /*
- * Test whether string appears in list of strings, ignoring case. NULL or empty
- * strings will be ignored.
- * Enter: list List to process.
- *        str  String to test.
- * Return: TRUE if string is unique.
- */
-gboolean mgu_slist_test_unq_nc( GSList *list, gchar *str ) {
-	GSList *node;
-
-	if( str ) {
-		if( strlen( str ) > 0 ) {
-			node = list;
-			while( node ) {
-				if( g_utf8_collate( str, node->data ) == 0 )
-					return FALSE;
-				node = g_slist_next( node );
-			}
-			return TRUE;
-		}
-	}
-	return FALSE;
-}
-
-/*
- * Test whether string appears in list of strings, ignoring case. NULL or empty
- * strings will be ignored.
- * Enter: list List to process.
- *        str  String to test.
- * Return: TRUE if string is unique.
- */
-gboolean mgu_list_test_unq_nc( GList *list, gchar *str ) {
-	GList *node;
-
-	if( str ) {
-		if( strlen( str ) > 0 ) {
-			node = list;
-			while( node ) {
-				if( g_utf8_collate( str, node->data ) == 0 )
-					return FALSE;
-				node = g_list_next( node );
-			}
-			return TRUE;
-		}
-	}
-	return FALSE;
-}
-
-/*
 * End of Source.
 */
diff --git a/src/common/mgutils.h b/src/common/mgutils.h
index 6e944c2..f589458 100644
--- a/src/common/mgutils.h
+++ b/src/common/mgutils.h
@@ -53,8 +53,6 @@ GList *mgu_parse_string		( gchar *line, const gint maxTokens,
 void mgu_str_unescape		( gchar *str );
 void mgu_str_ltc2space		( gchar *str, gchar chlead, gchar chtail );
 gchar *mgu_slist_longest_entry	( GSList *list );
-gboolean mgu_slist_test_unq_nc	( GSList *list, gchar *str );
-gboolean mgu_list_test_unq_nc	( GList *list, gchar *str );
 
 #endif /* __MGUTILS_H__ */
 
diff --git a/src/ldapctrl.c b/src/ldapctrl.c
index 2a67c62..4cb929e 100644
--- a/src/ldapctrl.c
+++ b/src/ldapctrl.c
@@ -254,7 +254,8 @@ void ldapctl_criteria_list_clear( LdapControl *ctl ) {
 void ldapctl_criteria_list_add( LdapControl *ctl, gchar *attr ) {
 	cm_return_if_fail( ctl != NULL );
 	if( attr != NULL ) {
-		if( mgu_list_test_unq_nc( ctl->listCriteria, attr ) ) {
+		if( !g_list_find_custom( ctl->listCriteria, attr,
+					(GCompareFunc)g_utf8_collate ) ) {
 			debug_print("adding to criteria list: %s\n", attr);
 			ctl->listCriteria = g_list_append(
 				ctl->listCriteria, g_strdup( attr ) );

commit fd2dcd76f62fcb3baa34a427b712937d0fccb1a7
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Wed Mar 13 20:55:36 2019 +0100

    Remove mgu_clear_list() function
    
    Its remaining uses were unnecessary, because in each
    case, the list was being freed immediately afterwards,
    without freeing the data. This function only set the
    list items' data pointer to NULL, which served no
    purpose here.

diff --git a/src/addressbook.c b/src/addressbook.c
index 2454a13..cbc4030 100644
--- a/src/addressbook.c
+++ b/src/addressbook.c
@@ -3777,7 +3777,6 @@ static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemF
 		addressbook_folder_load_one_person( clist, cur->data, atci, atciMail );
 	}
 	/* Free up the list */
-	mgu_clear_list( items );
 	g_list_free( items );
 }
 
@@ -3855,7 +3854,6 @@ static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFo
 		gtk_sctree_sort_node(clist, NULL);
 	}
 	/* Free up the list */
-	mgu_clear_list( items );
 	g_list_free( items );
 }
 
@@ -5254,7 +5252,6 @@ static void addrbookctl_build_ifselect( void ) {
 	g_free( selectStr );
 
 	/* Replace existing list */
-	mgu_clear_list( _addressIFaceSelection_ );
 	g_list_free( _addressIFaceSelection_ );
 	_addressIFaceSelection_ = newList;
 	newList = NULL;
diff --git a/src/addrindex.c b/src/addrindex.c
index 62d4aa9..dff2c93 100644
--- a/src/addrindex.c
+++ b/src/addrindex.c
@@ -2960,8 +2960,8 @@ gboolean addrindex_load_completion(
 					nodeM = g_list_next( nodeM );
 				}
 			}
-			/* Free up the list */
-			mgu_clear_list( items );
+			/* Free up the list (but not the data inside the
+			 * individual list items) */
 			g_list_free( items );
 
 			return TRUE;
diff --git a/src/addritem.c b/src/addritem.c
index cb76257..832a139 100644
--- a/src/addritem.c
+++ b/src/addritem.c
@@ -688,7 +688,6 @@ void addritem_free_item_group( ItemGroup *group ) {
 	g_free( ADDRITEM_ID(group) );
 	g_free( ADDRITEM_NAME(group) );
 	g_free( group->remarks );
-	mgu_clear_list( group->listEMail );
 	g_list_free( group->listEMail );
 
 	ADDRITEM_TYPE(group) = ITEMTYPE_NONE;
@@ -864,7 +863,6 @@ void addritem_free_item_folder( ItemFolder *folder ) {
 	g_free( ADDRITEM_ID(folder) );
 	g_free( ADDRITEM_NAME(folder) );
 	g_free( folder->remarks );
-	mgu_clear_list( folder->listItems );
 	g_list_free( folder->listItems );
 
 	ADDRITEM_TYPE(folder) = ITEMTYPE_NONE;
diff --git a/src/common/mgutils.c b/src/common/mgutils.c
index e15207b..941fc26 100644
--- a/src/common/mgutils.c
+++ b/src/common/mgutils.c
@@ -134,18 +134,6 @@ gchar *mgu_replace_string( gchar *str, const gchar *value ) {
 }
 
 /*
-* Clear a linked list by setting node data pointers to NULL. Note that
-* items are not freed.
-*/
-void mgu_clear_list( GList *list ) {
-	GList *node = list;
-	while( node ) {
-		node->data = NULL;
-		node = g_list_next( node );
-	}
-}
-
-/*
 * Test and reformat an email address.
 * Enter:  address.
 * Return: Address, or NULL if address is empty.
diff --git a/src/common/mgutils.h b/src/common/mgutils.h
index 15555362..6e944c2 100644
--- a/src/common/mgutils.h
+++ b/src/common/mgutils.h
@@ -47,7 +47,6 @@ void mgu_free_list		( GSList *list );
 void mgu_free_dlist		( GList *list );
 gchar *mgu_list_coalesce	( GSList *list );
 gchar *mgu_replace_string	( gchar *str, const gchar *value );
-void mgu_clear_list		( GList *list );
 gchar *mgu_email_check_empty	( gchar *address );
 GList *mgu_parse_string		( gchar *line, const gint maxTokens,
 				  gint *tokenCnt );

commit 92074af6a19075e9865bfb573013b8ca48da73a2
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Wed Mar 13 20:54:20 2019 +0100

    Fix two small memory leaks in addressbook code
    
    In each case, the GList structure itself was not
    being freed.

diff --git a/src/addrbook.c b/src/addrbook.c
index 8087996..296af5d 100644
--- a/src/addrbook.c
+++ b/src/addrbook.c
@@ -1606,7 +1606,7 @@ static void addrbook_build_avail_email_vis(gpointer key, gpointer value,
 /**
  * Return link list of available email items that have not already been linked
  * to groups. Note that the list contains references to items and should be
- * <code>g_free()</code> when done. Do <b>*NOT*</b> attempt to used the
+ * <code>g_list_free()</code> when done. Do <b>*NOT*</b> attempt to used the
  * <code>addrbook_free_xxx()<code> functions... this will destroy the
  * addressbook data!
  *
@@ -1672,8 +1672,7 @@ void addrbook_update_group_list(AddressBookFile *book, ItemGroup *group,
 	/* Remember old list */
 	oldData = group->listEMail;
 	group->listEMail = listEMail;
-	mgu_clear_list(oldData);
-	oldData = NULL;
+	g_list_free(oldData);
 }
 
 /**
diff --git a/src/editgroup.c b/src/editgroup.c
index cfc7a9d..f864d50 100644
--- a/src/editgroup.c
+++ b/src/editgroup.c
@@ -505,8 +505,7 @@ ItemGroup *addressbook_edit_group( AddressBookFile *abf, ItemFolder *parent, Ite
 
 	listEMail = addrbook_get_available_email_list( abf, group );
 	edit_group_load_clist( groupeditdlg.clist_avail, listEMail );
-	mgu_clear_list( listEMail );
-	listEMail = NULL;
+	g_list_free( listEMail );
 	gtk_cmclist_select_row( groupeditdlg.clist_group, 0, 0 );
 	gtk_cmclist_select_row( groupeditdlg.clist_avail, 0, 0 );
 

commit c992286253f10e928362583d2fd2676e6c48f405
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Wed Mar 13 20:19:59 2019 +0100

    Fix a memory leak in Pine address book support
    
    Also removed mgu_clear_slist(), since it is not
    used anywhere anymore.

diff --git a/src/common/mgutils.c b/src/common/mgutils.c
index cbb5761..e15207b 100644
--- a/src/common/mgutils.c
+++ b/src/common/mgutils.c
@@ -137,18 +137,6 @@ gchar *mgu_replace_string( gchar *str, const gchar *value ) {
 * Clear a linked list by setting node data pointers to NULL. Note that
 * items are not freed.
 */
-void mgu_clear_slist( GSList *list ) {
-	GSList *node = list;
-	while( node ) {
-		node->data = NULL;
-		node = g_slist_next( node );
-	}
-}
-
-/*
-* Clear a linked list by setting node data pointers to NULL. Note that
-* items are not freed.
-*/
 void mgu_clear_list( GList *list ) {
 	GList *node = list;
 	while( node ) {
diff --git a/src/common/mgutils.h b/src/common/mgutils.h
index 574c980..15555362 100644
--- a/src/common/mgutils.h
+++ b/src/common/mgutils.h
@@ -47,7 +47,6 @@ void mgu_free_list		( GSList *list );
 void mgu_free_dlist		( GList *list );
 gchar *mgu_list_coalesce	( GSList *list );
 gchar *mgu_replace_string	( gchar *str, const gchar *value );
-void mgu_clear_slist		( GSList *list );
 void mgu_clear_list		( GList *list );
 gchar *mgu_email_check_empty	( gchar *address );
 GList *mgu_parse_string		( gchar *line, const gint maxTokens,
diff --git a/src/pine.c b/src/pine.c
index 20944d0..19e2525 100644
--- a/src/pine.c
+++ b/src/pine.c
@@ -195,10 +195,8 @@ static void pine_free_rec( Pine_ParsedRec *rec ) {
 		g_free( rec->address );
 		g_free( rec->fcc );
 		g_free( rec->comments );
-		mgu_clear_slist( rec->listName );
-		mgu_clear_slist( rec->listAddr );
-		g_slist_free( rec->listName );
-		g_slist_free( rec->listAddr );
+		g_slist_free_full( rec->listName, g_free );
+		g_slist_free_full( rec->listAddr, g_free );
 		rec->nickName = NULL;
 		rec->name = NULL;
 		rec->address = NULL;

commit 65af7e84abf09b87e60efb7714e1326b8bc01fe7
Author: wwp <subscript at free.fr>
Date:   Mon Mar 11 11:33:10 2019 +0100

    Make Fancy plugin's download-link feature following redirections.

diff --git a/src/plugins/fancy/fancy_viewer.c b/src/plugins/fancy/fancy_viewer.c
index 0f49d6d..c9da66d 100644
--- a/src/plugins/fancy/fancy_viewer.c
+++ b/src/plugins/fancy/fancy_viewer.c
@@ -696,6 +696,7 @@ static void *download_file_curl (void *data)
 		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, download_file_curl_write_cb);
 		curl_easy_setopt(curl, CURLOPT_WRITEDATA, viewer);
 		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+		curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
 		res = curl_easy_perform(curl);
 		curl_easy_cleanup(curl);
 

commit 2aa6fdce4045d93cce4082ece711c8cc047b8fde
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sun Mar 10 20:27:34 2019 +0100

    Fix buf #4166: corrupted double-linked list

diff --git a/src/action.c b/src/action.c
index 30b893b..56783c1 100644
--- a/src/action.c
+++ b/src/action.c
@@ -1096,7 +1096,6 @@ static gint wait_for_children(Children *children)
 		free_children(children);
 	} else if (!children->output) {
 		gtk_widget_destroy(children->dialog);
-		children->dialog = NULL;
 	}
 
 	return FALSE;

commit d8761d2da6c6dcadff995348383afea0c127b19e
Author: wwp <subscript at free.fr>
Date:   Sun Mar 10 09:06:50 2019 +0100

    Stop proceeding if file-save-as has been cancelled.

diff --git a/src/plugins/fancy/fancy_viewer.c b/src/plugins/fancy/fancy_viewer.c
index c9df4f7..0f49d6d 100644
--- a/src/plugins/fancy/fancy_viewer.c
+++ b/src/plugins/fancy/fancy_viewer.c
@@ -721,6 +721,10 @@ static void download_file_cb(GtkWidget *widget, FancyViewer *viewer)
 	gchar *filename = g_utf8_strchr(link, -1, g_utf8_get_char("/"));
 	filename = g_strconcat(g_get_home_dir(), filename, NULL);
 	gchar *fname = filesel_select_file_save(_("Save as"), filename);
+	if (!fname) {
+		g_free(filename);
+		return;
+	}
 
 	if (viewer->curlfile) viewer->curlfile = NULL;
 	if (viewer->stream) viewer->stream = NULL;

commit fb775752ebf03a505c17f0674d73b220dc41a97c
Author: wwp <subscript at free.fr>
Date:   Sun Mar 10 09:05:33 2019 +0100

    Do not throw an error when cancelling 'Save email as...'.

diff --git a/src/summaryview.c b/src/summaryview.c
index fa498b3..00ec6b3 100644
--- a/src/summaryview.c
+++ b/src/summaryview.c
@@ -4996,6 +4996,7 @@ void summary_save_as(SummaryView *summaryview)
 		dest = g_strconcat(prefs_common.attach_save_dir, G_DIR_SEPARATOR_S,
 				   dest, NULL);
 	dest = filesel_select_file_save(_("Save as"), dest);
+	if (!dest) return;
 
 	if (is_file_exist(dest)) {
 		aval = alertpanel(_("Append or Overwrite"),

commit b38dbc64cb0dc06386314646f6def1a8b1495723
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sat Mar 9 21:51:29 2019 +0100

    Add missing config.h include to utils.h
    
    It should be there, since we refer to a lot of HAVE_
    macros defined in config.h

diff --git a/src/common/utils.h b/src/common/utils.h
index 09db918..47563b2 100644
--- a/src/common/utils.h
+++ b/src/common/utils.h
@@ -25,6 +25,7 @@
 
 #ifdef HAVE_CONFIG_H
 #include "claws-features.h"
+#include "config.h"
 #endif
 
 #ifdef HAVE_BACKTRACE

commit 52b0e21c190fa02e9b5dde7cd95f8c9ee339288c
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sat Mar 9 21:22:34 2019 +0100

    Add a forgotten fclose() call
    
    Fixes CID 1443021.

diff --git a/src/procmime.c b/src/procmime.c
index 7777901..cb5e77e 100644
--- a/src/procmime.c
+++ b/src/procmime.c
@@ -2731,7 +2731,12 @@ void *procmime_get_part_as_string(MimeInfo *mimeinfo,
 	length = mimeinfo->length;
 
 	data = g_malloc(null_terminate ? length + 1 : length);
-	cm_return_val_if_fail(data != NULL, NULL);
+	if (data == NULL) {
+		g_warning("Could not allocate %d bytes for procmime_get_part_as_string.\n",
+				(null_terminate ? length + 1 : length));
+		claws_fclose(infp);
+		return NULL;
+	}
 
 	readlength = claws_fread(data, length, 1, infp);
 	if (readlength <= 0) {

commit 78547fd63e16a76d656e668c17b7ae8975c46e12
Author: Paul <paul at claws-mail.org>
Date:   Thu Mar 7 07:20:36 2019 +0000

    fix build with gdk-pixbuf 2.26

diff --git a/src/image_viewer.c b/src/image_viewer.c
index da2ab90..0e8d785 100644
--- a/src/image_viewer.c
+++ b/src/image_viewer.c
@@ -88,7 +88,7 @@ static void image_viewer_load_image(ImageViewer *imageviewer)
 		return;
 	}
 
-#if GDK_PIXBUF_CHECK_VERSION(2, 28, 0)
+#if GDK_PIXBUF_MINOR >= 28
 	animation = gdk_pixbuf_animation_new_from_stream(stream, NULL, &error);
 #else
 	pixbuf = gdk_pixbuf_new_from_stream(stream, NULL, &error);
@@ -101,7 +101,7 @@ static void image_viewer_load_image(ImageViewer *imageviewer)
 		return;
 	}
 
-#if GDK_PIXBUF_CHECK_VERSION(2, 28, 0)
+#if GDK_PIXBUF_MINOR >= 28
 	if (gdk_pixbuf_animation_is_static_image(animation)
 	    || imageviewer->resize_img) {
 		pixbuf = gdk_pixbuf_animation_get_static_image(animation);

commit 08697167f45960f875d22f82e77bd5b633b8e5a0
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Wed Mar 6 18:11:03 2019 +0100

    Restore compatibility with gdk-pixbuf version 2.26

diff --git a/configure.ac b/configure.ac
index 995ff74..597b1d1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -430,7 +430,7 @@ dnl ** common code **
 dnl *****************
 
 dnl check for glib
-PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.28 gmodule-2.0 >= 2.28 gobject-2.0 >= 2.28 gthread-2.0 >= 2.28)
+PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.28 gmodule-2.0 >= 2.28 gobject-2.0 >= 2.28 gthread-2.0 >= 2.28])
 
 GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0`
 AC_SUBST(GLIB_GENMARSHAL)
@@ -438,6 +438,8 @@ AC_SUBST(GLIB_GENMARSHAL)
 AC_SUBST(GLIB_CFLAGS)
 AC_SUBST(GLIB_LIBS)
 
+PKG_CHECK_MODULES(GDK_PIXBUF, [gdk-pixbuf-2.0 >= 2.26])
+
 dnl Check for bind_textdomain_codeset, including -lintl if GLib brings it in.
 syl_save_LIBS=$LIBS
 LIBS="$LIBS $GTK_LIBS"
diff --git a/src/image_viewer.c b/src/image_viewer.c
index 2541527..da2ab90 100644
--- a/src/image_viewer.c
+++ b/src/image_viewer.c
@@ -88,7 +88,11 @@ static void image_viewer_load_image(ImageViewer *imageviewer)
 		return;
 	}
 
+#if GDK_PIXBUF_CHECK_VERSION(2, 28, 0)
 	animation = gdk_pixbuf_animation_new_from_stream(stream, NULL, &error);
+#else
+	pixbuf = gdk_pixbuf_new_from_stream(stream, NULL, &error);
+#endif
 	g_object_unref(stream);
 
 	if (error != NULL) {
@@ -97,12 +101,16 @@ static void image_viewer_load_image(ImageViewer *imageviewer)
 		return;
 	}
 
+#if GDK_PIXBUF_CHECK_VERSION(2, 28, 0)
 	if (gdk_pixbuf_animation_is_static_image(animation)
 	    || imageviewer->resize_img) {
 		pixbuf = gdk_pixbuf_animation_get_static_image(animation);
 		g_object_ref(pixbuf);
 		g_object_unref(animation);
 		animation = NULL;
+#else
+	if (imageviewer->resize_img) {
+#endif
 
 		if (imageviewer->resize_img) {
 			gtk_widget_get_allocation(imageviewer->scrolledwin, &allocation);

commit 1ce55620fdfa1b9d5b9e92e9a7a0d8f87ecc5fa3
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Mar 5 23:13:29 2019 +0100

    Make textview load image attachments not via temporary files
    
    This causes a change in how interacting with the image
    attachments works. Previously, clicking the
    "[attachment info]" clickable line above the image would
    do different actions than clicking the image itself, which
    would have an URI pointing to a temporary image file.
    Now, they both do the same thing - left-click selects
    the attachment, right-click shows generic attachment
    context menu.

diff --git a/src/textview.c b/src/textview.c
index 17e5ada..9e4e37a 100644
--- a/src/textview.c
+++ b/src/textview.c
@@ -210,10 +210,6 @@ static void mail_to_uri_cb 			(GtkAction	*action,
 						 TextView	*textview);
 static void copy_mail_to_uri_cb			(GtkAction	*action,
 						 TextView	*textview);
-static void save_file_cb			(GtkAction	*action,
-						 TextView	*textview);
-static void open_image_cb			(GtkAction	*action,
-						 TextView	*textview);
 static void textview_show_tags(TextView *textview);
 
 static GtkActionEntry textview_link_popup_entries[] = 
@@ -232,13 +228,6 @@ static GtkActionEntry textview_mail_popup_entries[] =
 	{"TextviewPopupMail/Copy",		NULL, N_("Copy this add_ress"), NULL, NULL, G_CALLBACK(copy_mail_to_uri_cb) },
 };
 
-static GtkActionEntry textview_file_popup_entries[] = 
-{
-	{"TextviewPopupFile",			NULL, "TextviewPopupFile", NULL, NULL, NULL },
-	{"TextviewPopupFile/Open",		NULL, N_("_Open image"), NULL, NULL, G_CALLBACK(open_image_cb) },
-	{"TextviewPopupFile/Save",		NULL, N_("_Save image..."), NULL, NULL, G_CALLBACK(save_file_cb) },
-};
-
 static void scrolled_cb (GtkAdjustment *adj, TextView *textview)
 {
 #ifndef WIDTH
@@ -339,18 +328,12 @@ TextView *textview_create(void)
 			"TextviewPopupMail",
 			textview_mail_popup_entries,
 			G_N_ELEMENTS(textview_mail_popup_entries), (gpointer)textview);
-	textview->file_action_group = cm_menu_create_action_group_full(textview->ui_manager,
-			"TextviewPopupFile",
-			textview_file_popup_entries,
-			G_N_ELEMENTS(textview_file_popup_entries), (gpointer)textview);
 
 	MENUITEM_ADDUI_MANAGER(textview->ui_manager, "/", "Menus", "Menus", GTK_UI_MANAGER_MENUBAR)
 	MENUITEM_ADDUI_MANAGER(textview->ui_manager, 
 			"/Menus", "TextviewPopupLink", "TextviewPopupLink", GTK_UI_MANAGER_MENU)
 	MENUITEM_ADDUI_MANAGER(textview->ui_manager, 
 			"/Menus", "TextviewPopupMail", "TextviewPopupMail", GTK_UI_MANAGER_MENU)
-	MENUITEM_ADDUI_MANAGER(textview->ui_manager, 
-			"/Menus", "TextviewPopupFile", "TextviewPopupFile", GTK_UI_MANAGER_MENU)
 
 	MENUITEM_ADDUI_MANAGER(textview->ui_manager, 
 			"/Menus/TextviewPopupLink", "Open", "TextviewPopupLink/Open", GTK_UI_MANAGER_MENUITEM)
@@ -364,17 +347,11 @@ TextView *textview_create(void)
 			"/Menus/TextviewPopupMail", "AddAB", "TextviewPopupMail/AddAB", GTK_UI_MANAGER_MENUITEM)
 	MENUITEM_ADDUI_MANAGER(textview->ui_manager, 
 			"/Menus/TextviewPopupMail", "Copy", "TextviewPopupMail/Copy", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(textview->ui_manager, 
-			"/Menus/TextviewPopupFile", "Open", "TextviewPopupFile/Open", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(textview->ui_manager, 
-			"/Menus/TextviewPopupFile", "Save", "TextviewPopupFile/Save", GTK_UI_MANAGER_MENUITEM)
 
 	textview->link_popup_menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
 				gtk_ui_manager_get_widget(textview->ui_manager, "/Menus/TextviewPopupLink")) );
 	textview->mail_popup_menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
 				gtk_ui_manager_get_widget(textview->ui_manager, "/Menus/TextviewPopupMail")) );
-	textview->file_popup_menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
-				gtk_ui_manager_get_widget(textview->ui_manager, "/Menus/TextviewPopupFile")) );
 
 	textview->vbox               = vbox;
 	textview->scrolledwin        = scrolledwin;
@@ -703,32 +680,29 @@ static void textview_add_part(TextView *textview, MimeInfo *mimeinfo)
 		    prefs_common.inline_img ) {
 			GdkPixbuf *pixbuf;
 			GError *error = NULL;
-			gchar *filename;
 			ClickableText *uri;
-			gchar *uri_str;
-			gint err;
-			START_TIMING("inserting image");
+			GInputStream *stream;
 
-			filename = procmime_get_tmp_file_name(mimeinfo);
+			START_TIMING("inserting image");
 
-			if ((err = procmime_get_part(filename, mimeinfo)) < 0) {
-				g_warning("Can't get the image file.(%s)", g_strerror(-err));
-				g_free(filename);
+			stream = procmime_get_part_as_inputstream(mimeinfo, &error);
+			if (error != NULL) {
+				g_warning("Can't get the image file: %s", error->message);
+				g_error_free(error);
 				END_TIMING();
 				return;
 			}
 
-			pixbuf = gdk_pixbuf_new_from_file(filename, &error);
-			if (textview->stop_loading) {
-				return;
-			}
+			pixbuf = gdk_pixbuf_new_from_stream(stream, NULL, &error);
+			g_object_unref(stream);
+
 			if (error != NULL) {
-				g_warning("%s", error->message);
+				g_warning("Can't load the image: %s\n", error->message);
 				g_error_free(error);
+				END_TIMING();
+				return;
 			}
-			if (!pixbuf) {
-				g_warning("Can't load the image.");
-				g_free(filename);
+			if (textview->stop_loading) {
 				END_TIMING();
 				return;
 			}
@@ -739,39 +713,32 @@ static void textview_add_part(TextView *textview, MimeInfo *mimeinfo)
 					allocation.height);
 
 			if (textview->stop_loading) {
+				END_TIMING();
 				return;
 			}
 
-			uri_str = g_filename_to_uri(filename, NULL, NULL);
-			if (uri_str) {
-				uri = g_new0(ClickableText, 1);
-				uri->uri = uri_str;
-				uri->start = gtk_text_iter_get_offset(&iter);
-				
-				gtk_text_buffer_insert_pixbuf(buffer, &iter, pixbuf);
-				if (textview->stop_loading) {
-					g_free(uri);
-					return;
-				}
-				uri->end = uri->start + 1;
-				uri->filename = procmime_get_part_file_name(mimeinfo);
-				textview->uri_list =
-					g_slist_prepend(textview->uri_list, uri);
-				
-				gtk_text_buffer_insert(buffer, &iter, " ", 1);
-				gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, uri->start);	
-				gtk_text_buffer_apply_tag_by_name(buffer, "link", 
-						&start_iter, &iter);
-			} else {
-				gtk_text_buffer_insert_pixbuf(buffer, &iter, pixbuf);
-				if (textview->stop_loading) {
-					return;
-				}
-				gtk_text_buffer_insert(buffer, &iter, " ", 1);
-			}
+			uri = g_new0(ClickableText, 1);
+			uri->uri = g_strdup("");
+			uri->filename = g_strdup("sc://select_attachment");
+			uri->data = mimeinfo;
 
+			uri->start = gtk_text_iter_get_offset(&iter);
+			gtk_text_buffer_insert_pixbuf(buffer, &iter, pixbuf);
 			g_object_unref(pixbuf);
-			g_free(filename);
+			if (textview->stop_loading) {
+				g_free(uri);
+				return;
+			}
+			uri->end = gtk_text_iter_get_offset(&iter);
+
+			textview->uri_list =
+				g_slist_prepend(textview->uri_list, uri);
+
+			gtk_text_buffer_insert(buffer, &iter, " ", 1);
+			gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, uri->start);
+			gtk_text_buffer_apply_tag_by_name(buffer, "link",
+						&start_iter, &iter);
+
 			END_TIMING();
 			GTK_EVENTS_FLUSH();
 		}
@@ -2970,153 +2937,6 @@ static void open_uri_cb (GtkAction *action, TextView *textview)
 	}
 }
 
-static void open_image_cb (GtkAction *action, TextView *textview)
-{
-	ClickableText *uri = g_object_get_data(G_OBJECT(textview->file_popup_menu),
-					   "menu_button");
-
-	gchar *cmd = NULL;
-	gchar buf[1024];
-	const gchar *p;
-	gchar *filename = NULL, *filepath = NULL;
-	gchar *tmp_filename = NULL;
-
-	if (uri == NULL)
-		return;
-
-	if (uri->filename == NULL)
-		return;
-	
-	filename = g_strdup(uri->filename);
-	
-	if (!g_utf8_validate(filename, -1, NULL)) {
-		gchar *tmp = conv_filename_to_utf8(filename);
-		g_free(filename);
-		filename = tmp;
-	}
-
-	subst_for_filename(filename);
-
-	filepath = g_strconcat(get_mime_tmp_dir(), G_DIR_SEPARATOR_S,
-			       filename, NULL);
-
-	tmp_filename = g_filename_from_uri(uri->uri, NULL, NULL);
-	copy_file(tmp_filename, filepath, FALSE);
-	g_free(tmp_filename);
-
-	cmd = mailcap_get_command_for_type("image/jpeg", filename);
-	if (cmd == NULL) {
-		gboolean remember = FALSE;
-		cmd = input_dialog_combo_remember
-			(_("Open with"),
-			 _("Enter the command-line to open file:\n"
-			   "('%s' will be replaced with file name)"),
-			 prefs_common.mime_open_cmd,
-			 prefs_common.mime_open_cmd_history,
-			 &remember);
-		if (cmd && remember) {
-			mailcap_update_default("image/jpeg", cmd);
-		}
-	}
-	if (cmd && (p = strchr(cmd, '%')) && *(p + 1) == 's' &&
-	    !strchr(p + 2, '%'))
-		g_snprintf(buf, sizeof(buf), cmd, filepath);
-	else {
-		g_warning("Image viewer command-line is invalid: '%s'", cmd);
-		g_free(filepath);
-		g_free(filename);
-		return;
-	}
-
-	execute_command_line(buf, TRUE, NULL);
-
-	g_free(filepath);
-	g_free(filename);
-	g_free(cmd);
-
-	g_object_set_data(G_OBJECT(textview->file_popup_menu), "menu_button",
-			  NULL);
-}
-
-static void save_file_cb (GtkAction *action, TextView *textview)
-{
-	ClickableText *uri = g_object_get_data(G_OBJECT(textview->file_popup_menu),
-					   "menu_button");
-	gchar *filename = NULL;
-	gchar *filepath = NULL;
-	gchar *filedir = NULL;
-	gchar *tmp_filename = NULL;
-	GtkWidget *window;
-
-	if (uri == NULL)
-		return;
-
-	if (uri->filename == NULL)
-		return;
-	
-	filename = g_strdup(uri->filename);
-	
-	if (!g_utf8_validate(filename, -1, NULL)) {
-		gchar *tmp = conv_filename_to_utf8(filename);
-		g_free(filename);
-		filename = tmp;
-	}
-
-	subst_for_filename(filename);
-	
-	if (prefs_common.attach_save_dir && *prefs_common.attach_save_dir)
-		filepath = g_strconcat(prefs_common.attach_save_dir,
-				       G_DIR_SEPARATOR_S, filename, NULL);
-	else
-		filepath = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
-				       filename, NULL);
-
-	g_free(filename);
-
-	/* Pick correct window to set the file dialog "transient for" */
-	if (textview->messageview->window != NULL)
-		window = textview->messageview->window;
-	else
-		window = textview->messageview->mainwin->window;
-
-	manage_window_focus_in(window, NULL, NULL);
-
-	filename = filesel_select_file_save(_("Save as"), filepath);
-	if (!filename) {
-		g_free(filepath);
-		return;
-	}
-
-	if (is_file_exist(filename)) {
-		AlertValue aval;
-		gchar *res;
-		
-		res = g_strdup_printf(_("Overwrite existing file '%s'?"),
-				      filename);
-		aval = alertpanel(_("Overwrite"), res, GTK_STOCK_CANCEL, 
-				  GTK_STOCK_OK, NULL, ALERTFOCUS_FIRST);
-		g_free(res);					  
-		if (G_ALERTALTERNATE != aval)
-			return;
-	}
-
-	tmp_filename = g_filename_from_uri(uri->uri, NULL, NULL);
-	copy_file(tmp_filename, filename, FALSE);
-	g_free(tmp_filename);
-	
-	filedir = g_path_get_dirname(filename);
-	if (filedir && strcmp(filedir, ".")) {
-		g_free(prefs_common.attach_save_dir);
-		prefs_common.attach_save_dir = g_filename_to_utf8(filedir, -1, NULL, NULL, NULL);
-	}
-
-	g_free(filedir);
-	g_free(filepath);
-
-	g_object_set_data(G_OBJECT(textview->file_popup_menu), "menu_button",
-			  NULL);
-}
-
 static void copy_uri_cb	(GtkAction *action, TextView *textview)
 {
 	ClickableText *uri = g_object_get_data(G_OBJECT(textview->link_popup_menu),

commit 4699946d4002084d50451d631f66b1df5bfbe41b
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Mar 5 23:01:26 2019 +0100

    Rewrite image_viewer.c to not create a temporary file for the image being loaded
    
    Instead, we use new procmime_get_part_as_inputstream().

diff --git a/src/image_viewer.c b/src/image_viewer.c
index 1e4dc65..2541527 100644
--- a/src/image_viewer.c
+++ b/src/image_viewer.c
@@ -68,16 +68,35 @@ static GtkWidget *image_viewer_get_widget(MimeViewer *_mimeviewer)
 	return imageviewer->notebook;
 }
 
-static void image_viewer_load_file(ImageViewer *imageviewer, const gchar *imgfile)
+static void image_viewer_load_image(ImageViewer *imageviewer)
 {
 	GtkAllocation allocation;
 	GdkPixbufAnimation *animation = NULL;
 	GdkPixbuf *pixbuf = NULL;
 	GError *error = NULL;
+	GInputStream *stream;
 
-	debug_print("image_viewer_show_mimepart\n");
+	cm_return_if_fail(imageviewer != NULL);
+
+	if (imageviewer->mimeinfo == NULL)
+		return;
+
+	stream = procmime_get_part_as_inputstream(imageviewer->mimeinfo, &error);
+	if (error != NULL) {
+		g_warning("Couldn't get image MIME part: %s\n", error->message);
+		g_error_free(error);
+		return;
+	}
+
+	animation = gdk_pixbuf_animation_new_from_stream(stream, NULL, &error);
+	g_object_unref(stream);
+
+	if (error != NULL) {
+		g_warning("Couldn't load image: %s\n", error->message);
+		g_error_free(error);
+		return;
+	}
 
-	animation = gdk_pixbuf_animation_new_from_file(imgfile, &error);
 	if (gdk_pixbuf_animation_is_static_image(animation)
 	    || imageviewer->resize_img) {
 		pixbuf = gdk_pixbuf_animation_get_static_image(animation);
@@ -139,28 +158,12 @@ static void image_viewer_set_notebook_page(MimeViewer *_mimeviewer)
 		gtk_notebook_set_current_page(GTK_NOTEBOOK(imageviewer->notebook), 1);
 }
 
-static void image_viewer_load_image(ImageViewer *imageviewer)
-{
-	gchar *imgfile;
-
-	if (imageviewer->mimeinfo == NULL)
-		return;
-
-	imgfile = procmime_get_tmp_file_name(imageviewer->mimeinfo);
-	if (procmime_get_part(imgfile, imageviewer->mimeinfo) < 0) {
-		g_warning("Can't get mimepart file");	
-		g_free(imgfile);
-		return;
-	}
-	image_viewer_load_file(imageviewer, imgfile);
-	claws_unlink(imgfile);
-	g_free(imgfile);
-}
-
 static void image_viewer_show_mimepart(MimeViewer *_mimeviewer, const gchar *file, MimeInfo *mimeinfo)
 {
 	ImageViewer *imageviewer = (ImageViewer *) _mimeviewer;
 
+	debug_print("image_viewer_show_mimepart\n");
+
 	image_viewer_clear_viewer(_mimeviewer);
 	g_free(imageviewer->file);
 	imageviewer->file = g_strdup(file);

commit 52e13bbc7a9a703335c74fcd71202ef16fa18561
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Mar 5 22:59:10 2019 +0100

    Write procmime_get_part_as_inputstream()
    
    We also change procmime_get_part_as_string() to return
    a void* instead of a gchar*, and add an option to not
    null-terminate the returned buffer.

diff --git a/src/procmime.c b/src/procmime.c
index b58872d..7777901 100644
--- a/src/procmime.c
+++ b/src/procmime.c
@@ -2701,7 +2701,8 @@ gchar *procmime_get_part_file_name(MimeInfo *mimeinfo)
 	return base;
 }
 
-gchar *procmime_get_part_as_string(MimeInfo *mimeinfo)
+void *procmime_get_part_as_string(MimeInfo *mimeinfo,
+		gboolean null_terminate)
 {
 	FILE *infp;
 	gchar *data;
@@ -2728,7 +2729,8 @@ gchar *procmime_get_part_as_string(MimeInfo *mimeinfo)
 	}
 
 	length = mimeinfo->length;
-	data = g_malloc(length + 1);
+
+	data = g_malloc(null_terminate ? length + 1 : length);
 	cm_return_val_if_fail(data != NULL, NULL);
 
 	readlength = claws_fread(data, length, 1, infp);
@@ -2741,8 +2743,32 @@ gchar *procmime_get_part_as_string(MimeInfo *mimeinfo)
 
 	claws_fclose(infp);
 
-	data[length] = '\0';
+	if (null_terminate)
+		data[length] = '\0';
 
 	return data;
 }
 
+/* Returns an open GInputStream. The caller should just
+ * read mimeinfo->length bytes from it and then release it. */
+GInputStream *procmime_get_part_as_inputstream(MimeInfo *mimeinfo,
+		GError **error)
+{
+	cm_return_val_if_fail(mimeinfo != NULL, NULL);
+
+	if (mimeinfo->encoding_type != ENC_BINARY &&
+			!procmime_decode_content(mimeinfo))
+		return NULL;
+
+	if (mimeinfo->content == MIMECONTENT_MEM) {
+		/* NULL for destroy func, since we're not copying
+		 * the data for the stream. */
+		return g_memory_input_stream_new_from_data(
+				mimeinfo->data.mem,
+				mimeinfo->length, NULL);
+	} else {
+		return g_memory_input_stream_new_from_data(
+				procmime_get_part_as_string(mimeinfo, FALSE),
+				mimeinfo->length, g_free);
+	}
+}
diff --git a/src/procmime.h b/src/procmime.h
index ae8b0e6..b21dc94 100644
--- a/src/procmime.h
+++ b/src/procmime.h
@@ -24,6 +24,8 @@
 #include "claws-features.h"
 #endif
 
+#include <gio/gio.h>
+
 #include "utils.h"
 #include "proctypes.h"
 typedef enum
@@ -238,7 +240,10 @@ FILE *procmime_get_binary_content(MimeInfo *mimeinfo);
 gboolean procmime_scan_text_content(MimeInfo *mimeinfo,
 		gboolean (*scan_callback)(const gchar *str, gpointer cb_data),
 		gpointer cb_data);
-gchar *procmime_get_part_as_string(MimeInfo *mimeinfo);
+void *procmime_get_part_as_string(MimeInfo *mimeinfo,
+		gboolean null_terminate);
+GInputStream *procmime_get_part_as_inputstream(MimeInfo *mimeinfo,
+		GError **error);
 
 #ifdef __cplusplus
 }

commit ffe5a18e30b56f526f29e42812b2e805797eadae
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Mar 5 21:54:48 2019 +0100

    Rewrite procmime_get_part_as_string() to not use a temporary file

diff --git a/src/procmime.c b/src/procmime.c
index a7d1997..b58872d 100644
--- a/src/procmime.c
+++ b/src/procmime.c
@@ -2703,60 +2703,46 @@ gchar *procmime_get_part_file_name(MimeInfo *mimeinfo)
 
 gchar *procmime_get_part_as_string(MimeInfo *mimeinfo)
 {
-	gchar *textdata = NULL;
-	gchar *filename = NULL;
-	FILE *fp;
+	FILE *infp;
+	gchar *data;
+	gint length, readlength;
 
-	cm_return_val_if_fail(mimeinfo != NULL, 0);
-	procmime_decode_content(mimeinfo);
+	cm_return_val_if_fail(mimeinfo != NULL, NULL);
+
+	if (mimeinfo->encoding_type != ENC_BINARY &&
+			!procmime_decode_content(mimeinfo))
+		return NULL;
 
 	if (mimeinfo->content == MIMECONTENT_MEM)
-		textdata = g_strdup(mimeinfo->data.mem);
-	else {
-		filename = procmime_get_tmp_file_name(mimeinfo);
-		if (procmime_get_part(filename, mimeinfo) < 0) {
-			g_warning("error dumping temporary file '%s'", filename);
-			g_free(filename);
-			return NULL;
-		}
-		fp = claws_fopen(filename,"rb");
-		if (!fp) {
-			g_warning("error opening temporary file '%s'", filename);
+		return g_strdup(mimeinfo->data.mem);
 
-			g_free(filename);
-			return NULL;
-		}
-		textdata = file_read_stream_to_str_no_recode(fp);
+	if ((infp = claws_fopen(mimeinfo->data.filename, "rb")) == NULL) {
+		FILE_OP_ERROR(mimeinfo->data.filename, "claws_fopen");
+		return NULL;
+	}
 
-		claws_fclose(fp);
-		g_unlink(filename);
-		g_free(filename);
+	if (fseek(infp, mimeinfo->offset, SEEK_SET) < 0) {
+		FILE_OP_ERROR(mimeinfo->data.filename, "fseek");
+		claws_fclose(infp);
+		return NULL;
 	}
 
-	if (!g_utf8_validate(textdata, -1, NULL)) {
-		gchar *tmp = NULL;
-		codeconv_set_strict(TRUE);
-		if (procmime_mimeinfo_get_parameter(mimeinfo, "charset")) {
-			tmp = conv_codeset_strdup(textdata,
-				procmime_mimeinfo_get_parameter(mimeinfo, "charset"),
-				CS_UTF_8);
-		}
-		if (!tmp) {
-			tmp = conv_codeset_strdup(textdata,
-				conv_get_locale_charset_str_no_utf8(),
-				CS_UTF_8);
-		}
-		codeconv_set_strict(FALSE);
-		if (!tmp) {
-			tmp = conv_codeset_strdup(textdata,
-				conv_get_locale_charset_str_no_utf8(),
-				CS_UTF_8);
-		}
-		if (tmp) {
-			g_free(textdata);
-			textdata = tmp;
-		}
+	length = mimeinfo->length;
+	data = g_malloc(length + 1);
+	cm_return_val_if_fail(data != NULL, NULL);
+
+	readlength = claws_fread(data, length, 1, infp);
+	if (readlength <= 0) {
+		FILE_OP_ERROR(mimeinfo->data.filename, "fread");
+		g_free(data);
+		claws_fclose(infp);
+		return NULL;
 	}
 
-	return textdata;
+	claws_fclose(infp);
+
+	data[length] = '\0';
+
+	return data;
 }
+

commit 9da4fcef8f3410c5df9b18659a47b6fa4d7f9d8b
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sat May 4 16:36:56 2019 +0200

    Fix a typo in one of Fancy's context menu items

diff --git a/src/plugins/fancy/fancy_viewer.c b/src/plugins/fancy/fancy_viewer.c
index 481cc1b..c9df4f7 100644
--- a/src/plugins/fancy/fancy_viewer.c
+++ b/src/plugins/fancy/fancy_viewer.c
@@ -778,10 +778,7 @@ static void viewer_menu_handler(GtkWidget *menuitem, FancyViewer *viewer)
 		if (!g_ascii_strcasecmp(gtk_label_get_text(GTK_LABEL(menul)),
 					"Open Link" )) {
 
-			if (viewer->override_prefs_remote_content)
-				gtk_label_set_text(GTK_LABEL(menul), _("Open in Viewer"));
-			else
-				gtk_label_set_text(GTK_LABEL(menul), _("pen in Viewer (enable remote content)"));
+			gtk_label_set_text(GTK_LABEL(menul), _("Open in Viewer"));
 
 			GtkImageMenuItem *m_new = GTK_IMAGE_MENU_ITEM(menuitem);
 			gtk_widget_set_sensitive(GTK_WIDGET(m_new), viewer->override_prefs_remote_content);

commit 0695cdcb6cd24d13e462f158ac0368197b9c7b0f
Author: Michael Rasmussen <mir at datanom.net>
Date:   Tue Mar 5 00:12:33 2019 +0100

    Fix possible segmentation fault
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/etpan/imap-thread.c b/src/etpan/imap-thread.c
index be5678c..b68e303 100644
--- a/src/etpan/imap-thread.c
+++ b/src/etpan/imap-thread.c
@@ -3554,7 +3554,7 @@ void imap_threaded_cancel(Folder * folder)
 	mailimap * imap;
 	
 	imap = get_imap(folder);
-	if (imap->imap_stream != NULL)
+	if (imap && imap->imap_stream != NULL)
 		mailstream_cancel(imap->imap_stream);
 }
 

commit 59bd8db042b4514e696c3fc39906130563f0691a
Author: Paul <paul at claws-mail.org>
Date:   Fri Mar 1 16:33:52 2019 +0000

    add 2 includes
    
    prevents implicit declaration warnings, as reported by buildbot

diff --git a/src/plugins/pgpcore/pgp_utils.c b/src/plugins/pgpcore/pgp_utils.c
index 3903285..dc9dfd6 100644
--- a/src/plugins/pgpcore/pgp_utils.c
+++ b/src/plugins/pgpcore/pgp_utils.c
@@ -26,6 +26,8 @@
 #ifdef USE_GPGME
 
 #include <glib.h>
+#include <string.h> /* for strlen */
+#include <stdio.h> /* for strstr */
 
 /* It's only a valid armor header if it's at the
  * beginning of the buffer or a new line, and if

commit 7506d0eee5d92f5c58dcd284febd426c96f073be
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri Mar 1 15:45:45 2019 +0100

    Rewrite pgp_locate_armor_header() to more strictly follow RFC4880
    
    Not only has the armor header be at the beginning of
    the line, but also there cannot be any non-whitespace
    after it on the same line.

diff --git a/configure.ac b/configure.ac
index fd833eb..995ff74 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2076,6 +2076,7 @@ src/plugins/perl/tools/Makefile
 src/plugins/python/Makefile
 src/plugins/python/examples/Makefile
 src/plugins/pgpcore/Makefile
+src/plugins/pgpcore/tests/Makefile
 src/plugins/pgpmime/Makefile
 src/plugins/pgpinline/Makefile
 src/plugins/rssyl/Makefile
diff --git a/src/plugins/pgpcore/Makefile.am b/src/plugins/pgpcore/Makefile.am
index c19ebcf..1c40467 100644
--- a/src/plugins/pgpcore/Makefile.am
+++ b/src/plugins/pgpcore/Makefile.am
@@ -3,6 +3,11 @@
 # terms of the General Public License version 3 (or later).
 # See COPYING file for license details.
 
+if BUILD_TESTS
+include $(top_srcdir)/tests.mk
+SUBDIRS = . tests
+endif
+
 EXTRA_DIST = version.rc plugin.def claws.def
 
 IFLAGS = \
@@ -94,6 +99,3 @@ pgpcore_la_CPPFLAGS = \
 
 clean-local:
 	rm -f libclaws.a
-
-
-.PHONY: test
diff --git a/src/plugins/pgpcore/pgp_utils.c b/src/plugins/pgpcore/pgp_utils.c
index 31f2d34..3903285 100644
--- a/src/plugins/pgpcore/pgp_utils.c
+++ b/src/plugins/pgpcore/pgp_utils.c
@@ -27,23 +27,57 @@
 
 #include <glib.h>
 
-#include "pgp_utils.h"
-#include "codeconv.h"
-#include "file-utils.h"
-
-gchar *pgp_locate_armor_header(gchar *textdata, const gchar *armor_header)
+/* It's only a valid armor header if it's at the
+ * beginning of the buffer or a new line, and if
+ * there is only whitespace after it on the rest
+ * of the line. */
+gchar *pgp_locate_armor_header(const gchar *haystack, const gchar *needle)
 {
-	gchar *pos;
-
-	pos = strstr(textdata, armor_header);
-	/*
-	 * It's only a valid armor header if it's at the
-	 * beginning of the buffer or a new line.
-	 */
-	if (pos != NULL && (pos == textdata || *(pos-1) == '\n'))
-	{
-	      return pos;
+	gchar *txt, *x, *i;
+	gint ok;
+
+	g_return_val_if_fail(haystack != NULL, NULL);
+	g_return_val_if_fail(needle != NULL, NULL);
+
+	/* Start at the beginning */
+	txt = (gchar *)haystack;
+	while (*txt != '\0') {
+
+		/* Find next occurrence */
+		x = strstr(txt, needle);
+
+		if (x == NULL)
+			break;
+
+		/* Make sure that what we found is at the beginning of line */
+		if (x != haystack && *(x - 1) != '\n') {
+			txt = x + 1;
+			continue;
+		}
+
+		/* Now look at what's between end of needle and end of that line.
+		 * If there is anything else than whitespace, stop looking. */
+		i = x + strlen(needle);
+		ok = 1;
+		while (*i != '\0' && *i != '\r' && *i != '\n') {
+			if (!g_ascii_isspace(*i)) {
+				ok = 0;
+				break;
+			}
+			i++;
+		}
+
+		if (ok)
+			return x;
+
+		/* We are at the end of haystack */
+		if (*i == '\0')
+			return NULL;
+
+		txt = i + 1;
 	}
+
 	return NULL;
 }
+
 #endif /* USE_GPGME */
diff --git a/src/plugins/pgpcore/pgp_utils.h b/src/plugins/pgpcore/pgp_utils.h
index aa296b8..eb603cb 100644
--- a/src/plugins/pgpcore/pgp_utils.h
+++ b/src/plugins/pgpcore/pgp_utils.h
@@ -27,6 +27,6 @@
 
 #include "procmime.h"
 
-gchar *pgp_locate_armor_header(gchar *textdata, const gchar *armor_header);
+gchar *pgp_locate_armor_header(const gchar *textdata, const gchar *armor_header);
 
 #endif /* __PGP_UTILS_H__ */
diff --git a/src/plugins/pgpcore/tests/Makefile.am b/src/plugins/pgpcore/tests/Makefile.am
new file mode 100644
index 0000000..3bcc12d
--- /dev/null
+++ b/src/plugins/pgpcore/tests/Makefile.am
@@ -0,0 +1,18 @@
+include $(top_srcdir)/tests.mk
+
+common_ldadd = \
+	$(GLIB_LIBS)
+
+AM_CPPFLAGS = \
+	$(GLIB_CFLAGS) \
+	-I.. \
+	-I$(top_srcdir)/src \
+	-I$(top_srcdir)/src/common
+
+TEST_PROGS += pgp_utils_test
+pgp_utils_test_SOURCES = pgp_utils_test.c
+pgp_utils_test_LDADD = $(common_ldadd) ../pgpcore_la-pgp_utils.o
+
+noinst_PROGRAMS = $(TEST_PROGS)
+
+.PHONY: test
diff --git a/src/plugins/pgpcore/tests/pgp_utils_test.c b/src/plugins/pgpcore/tests/pgp_utils_test.c
new file mode 100644
index 0000000..d4a407a
--- /dev/null
+++ b/src/plugins/pgpcore/tests/pgp_utils_test.c
@@ -0,0 +1,85 @@
+#include "pgp_utils.h"
+
+#define HEADER "HEADER"
+struct td {
+	gchar *input;
+	gchar *expected_output;
+};
+
+static void
+test_pgp_locate_armor_header_null()
+{
+	if (!g_test_undefined())
+		return;
+
+	if (g_test_subprocess()) {
+		gchar *out = pgp_locate_armor_header(NULL, HEADER);
+		g_assert_null(out);
+		return;
+	}
+
+	g_test_trap_subprocess(NULL, 0, 0);
+	g_test_trap_assert_stderr("*assertion*failed*");
+	g_test_trap_assert_failed();
+}
+
+static void
+test_pgp_locate_armor_header(gconstpointer user_data)
+{
+	struct td *data = (struct td *)user_data;
+	gchar *out = pgp_locate_armor_header(data->input, HEADER);
+
+	g_assert_cmpstr(out, ==, data->expected_output);
+}
+
+struct td td_justheader = {
+	"HEADER",
+	"HEADER"
+};
+
+struct td td_leading = {
+	"leadingHEADER",
+	NULL
+};
+
+struct td td_trailingspaces = {
+	"HEADER     ",
+	"HEADER     "
+};
+
+struct td td_trailingtext1 = {
+	"HEADERblah",
+	NULL
+};
+
+struct td td_trailingtext2 = {
+	"HEADER   blah",
+	NULL
+};
+
+struct td td_leadinglines = {
+	"foo\nHEADER\nbar",
+	"HEADER\nbar"
+};
+
+#define TEST(name, data) \
+	g_test_add_data_func("/plugins/pgpcore/pgp_locate_armor_header_"name, \
+			&data, \
+			test_pgp_locate_armor_header)
+int
+main (int argc, char *argv[])
+{
+	g_test_init(&argc, &argv, NULL);
+
+	g_test_add_func("/plugins/pgpcore/pgp_locate_armor_header_null",
+			test_pgp_locate_armor_header_null);
+
+	TEST("justheader", td_justheader);
+	TEST("leading", td_leading);
+	TEST("trailingspaces", td_trailingspaces);
+	TEST("trailingtext1", td_trailingtext1);
+	TEST("trailingtext2", td_trailingtext2);
+	TEST("leadinglines", td_leadinglines);
+
+	return g_test_run();
+}

commit 51cff5109d0943007f75a34fd26034b2b987ce11
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri Mar 1 15:05:58 2019 +0100

    Simplify vcalviewer_get_uid_from_mimeinfo()

diff --git a/src/plugins/vcalendar/vcalendar.c b/src/plugins/vcalendar/vcalendar.c
index ed184b8..75acc11 100644
--- a/src/plugins/vcalendar/vcalendar.c
+++ b/src/plugins/vcalendar/vcalendar.c
@@ -644,27 +644,13 @@ void vcalviewer_display_event (VCalViewer *vcalviewer, VCalEvent *event)
 
 gchar *vcalviewer_get_uid_from_mimeinfo(MimeInfo *mimeinfo)
 {
-	gchar *tmpfile = procmime_get_tmp_file_name(mimeinfo);
-	const gchar *charset = procmime_mimeinfo_get_parameter(mimeinfo, "charset");
 	gchar *compstr = NULL;
 	gchar *res = NULL;
 	VCalEvent *event = NULL;
 
-	if (procmime_get_part(tmpfile, mimeinfo) < 0) {
-		g_warning("Can't get mimepart file");	
-		g_free(tmpfile);
-		return NULL;
-	}
-	
-	if (!charset)
-		charset = CS_WINDOWS_1252;
-
-	if (!strcasecmp(charset, CS_ISO_8859_1))
-		charset = CS_WINDOWS_1252;
-
-	compstr = file_read_to_str(tmpfile);
+	compstr = procmime_get_part_as_string(mimeinfo);
 	
-	event = vcal_get_event_from_ical(compstr, charset);
+	event = vcal_get_event_from_ical(compstr, NULL);
 	if (event)
 		res = g_strdup(event->uid);
 	

commit 85fab199401113cc31da29958727c709c0d09081
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri Mar 1 14:51:58 2019 +0100

    Move pgpcore's get_part_as_string() to procmime.c

diff --git a/src/plugins/pgpcore/pgp_utils.c b/src/plugins/pgpcore/pgp_utils.c
index 41c5d47..31f2d34 100644
--- a/src/plugins/pgpcore/pgp_utils.c
+++ b/src/plugins/pgpcore/pgp_utils.c
@@ -31,66 +31,6 @@
 #include "codeconv.h"
 #include "file-utils.h"
 
-gchar *get_part_as_string(MimeInfo *mimeinfo)
-{
-	gchar *textdata = NULL;
-	gchar *filename = NULL;
-	FILE *fp;
-
-	cm_return_val_if_fail(mimeinfo != NULL, 0);
-	procmime_decode_content(mimeinfo);
-	
-	if (mimeinfo->content == MIMECONTENT_MEM)
-		textdata = g_strdup(mimeinfo->data.mem);
-	else {
-		filename = procmime_get_tmp_file_name(mimeinfo);
-		if (procmime_get_part(filename, mimeinfo) < 0) {
-			g_warning("error dumping temporary file '%s'", filename);
-			g_free(filename);
-			return NULL;
-		}
-		fp = claws_fopen(filename,"rb");
-		if (!fp) {
-			g_warning("error opening temporary file '%s'", filename);
-
-			g_free(filename);
-			return NULL;
-		}
-		textdata = file_read_stream_to_str_no_recode(fp);
-
-		claws_fclose(fp);
-		g_unlink(filename);
-		g_free(filename);
-	}
-
-	if (!g_utf8_validate(textdata, -1, NULL)) {
-		gchar *tmp = NULL;
-		codeconv_set_strict(TRUE);
-		if (procmime_mimeinfo_get_parameter(mimeinfo, "charset")) {
-			tmp = conv_codeset_strdup(textdata,
-				procmime_mimeinfo_get_parameter(mimeinfo, "charset"),
-				CS_UTF_8);
-		}
-		if (!tmp) {
-			tmp = conv_codeset_strdup(textdata,
-				conv_get_locale_charset_str_no_utf8(), 
-				CS_UTF_8);
-		}
-		codeconv_set_strict(FALSE);
-		if (!tmp) {
-			tmp = conv_codeset_strdup(textdata,
-				conv_get_locale_charset_str_no_utf8(), 
-				CS_UTF_8);
-		}
-		if (tmp) {
-			g_free(textdata);
-			textdata = tmp;
-		}
-	}
-
-	return textdata;	
-}
-
 gchar *pgp_locate_armor_header(gchar *textdata, const gchar *armor_header)
 {
 	gchar *pos;
diff --git a/src/plugins/pgpcore/pgp_utils.h b/src/plugins/pgpcore/pgp_utils.h
index 0299dae..aa296b8 100644
--- a/src/plugins/pgpcore/pgp_utils.h
+++ b/src/plugins/pgpcore/pgp_utils.h
@@ -27,7 +27,6 @@
 
 #include "procmime.h"
 
-gchar *get_part_as_string(MimeInfo *mimeinfo);
 gchar *pgp_locate_armor_header(gchar *textdata, const gchar *armor_header);
 
 #endif /* __PGP_UTILS_H__ */
diff --git a/src/plugins/pgpcore/plugin.def b/src/plugins/pgpcore/plugin.def
index 5c48ea9..1f156d9 100644
--- a/src/plugins/pgpcore/plugin.def
+++ b/src/plugins/pgpcore/plugin.def
@@ -27,6 +27,5 @@ EXPORTS
 
 	cm_gpgme_data_rewind
 
-	get_part_as_string
 	pgp_locate_armor_header
 	prefs_gpg_auto_check_signatures
diff --git a/src/plugins/pgpinline/claws.def b/src/plugins/pgpinline/claws.def
index 4162a99..30f963e 100644
--- a/src/plugins/pgpinline/claws.def
+++ b/src/plugins/pgpinline/claws.def
@@ -25,4 +25,5 @@ procmime_mimeinfo_parent
 procmime_scan_file
 procmime_write_mimeinfo
 procmime_get_part
+procmime_get_part_as_string
 procmime_get_tmp_file_name
diff --git a/src/plugins/pgpinline/mypgpcore.def b/src/plugins/pgpinline/mypgpcore.def
index 1e17672..dbebe9b 100644
--- a/src/plugins/pgpinline/mypgpcore.def
+++ b/src/plugins/pgpinline/mypgpcore.def
@@ -14,6 +14,5 @@ sgpgme_sigstat_gpgme_to_privacy
 sgpgme_sigstat_info_full
 sgpgme_sigstat_info_short
 sgpgme_verify_signature
-get_part_as_string
 pgp_locate_armor_header
 prefs_gpg_auto_check_signatures
diff --git a/src/plugins/pgpinline/pgpinline.c b/src/plugins/pgpinline/pgpinline.c
index 4c7c98b..f0801c4 100644
--- a/src/plugins/pgpinline/pgpinline.c
+++ b/src/plugins/pgpinline/pgpinline.c
@@ -115,7 +115,7 @@ static gboolean pgpinline_is_signed(MimeInfo *mimeinfo)
 			return data->is_signed;
 	}
 	
-	textdata = get_part_as_string(mimeinfo);
+	textdata = procmime_get_part_as_string(mimeinfo);
 	if (!textdata)
 		return FALSE;
 	
@@ -164,7 +164,7 @@ static gint pgpinline_check_signature(MimeInfo *mimeinfo)
 	cm_return_val_if_fail(mimeinfo->privacy != NULL, 0);
 	data = (PrivacyDataPGP *) mimeinfo->privacy;
 
-	textdata = get_part_as_string(mimeinfo);
+	textdata = procmime_get_part_as_string(mimeinfo);
 
 	if (!textdata) {
 		g_free(textdata);
@@ -265,7 +265,7 @@ static gboolean pgpinline_is_encrypted(MimeInfo *mimeinfo)
 		mimeinfo->subtype = g_strdup("plain");
 	}
 
-	textdata = get_part_as_string(mimeinfo);
+	textdata = procmime_get_part_as_string(mimeinfo);
 	if (!textdata)
 		return FALSE;
 
@@ -317,7 +317,7 @@ static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo)
 		return NULL;
 	}
 
-	textdata = get_part_as_string(mimeinfo);
+	textdata = procmime_get_part_as_string(mimeinfo);
 	if (!textdata) {
 		gpgme_release(ctx);
 		privacy_set_error(_("Couldn't get text data."));
diff --git a/src/plugins/pgpmime/claws.def b/src/plugins/pgpmime/claws.def
index 3855a69..7f8f700 100644
--- a/src/plugins/pgpmime/claws.def
+++ b/src/plugins/pgpmime/claws.def
@@ -16,6 +16,7 @@ privacy_register_system
 privacy_reset_error
 privacy_set_error
 privacy_unregister_system
+procmime_get_part_as_string
 procmime_mimeinfo_free_all
 procmime_mimeinfo_get_parameter
 procmime_mimeinfo_new
diff --git a/src/plugins/pgpmime/mypgpcore.def b/src/plugins/pgpmime/mypgpcore.def
index cad93cb..ef81580 100644
--- a/src/plugins/pgpmime/mypgpcore.def
+++ b/src/plugins/pgpmime/mypgpcore.def
@@ -16,6 +16,5 @@ sgpgme_sigstat_info_full
 sgpgme_sigstat_info_short
 sgpgme_verify_signature
 cm_gpgme_data_rewind
-get_part_as_string
 pgp_locate_armor_header
 prefs_gpg_auto_check_signatures
diff --git a/src/plugins/pgpmime/pgpmime.c b/src/plugins/pgpmime/pgpmime.c
index 4ee1898..5633e0f 100644
--- a/src/plugins/pgpmime/pgpmime.c
+++ b/src/plugins/pgpmime/pgpmime.c
@@ -293,7 +293,7 @@ static gboolean pgpmime_is_encrypted(MimeInfo *mimeinfo)
 	if (g_ascii_strcasecmp(tmpinfo->subtype, "octet-stream"))
 		return FALSE;
 	
-	textdata = get_part_as_string(tmpinfo);
+	textdata = procmime_get_part_as_string(tmpinfo);
 	if (!textdata)
 		return FALSE;
 	
diff --git a/src/procmime.c b/src/procmime.c
index ca9da56..a7d1997 100644
--- a/src/procmime.c
+++ b/src/procmime.c
@@ -2701,3 +2701,62 @@ gchar *procmime_get_part_file_name(MimeInfo *mimeinfo)
 	return base;
 }
 
+gchar *procmime_get_part_as_string(MimeInfo *mimeinfo)
+{
+	gchar *textdata = NULL;
+	gchar *filename = NULL;
+	FILE *fp;
+
+	cm_return_val_if_fail(mimeinfo != NULL, 0);
+	procmime_decode_content(mimeinfo);
+
+	if (mimeinfo->content == MIMECONTENT_MEM)
+		textdata = g_strdup(mimeinfo->data.mem);
+	else {
+		filename = procmime_get_tmp_file_name(mimeinfo);
+		if (procmime_get_part(filename, mimeinfo) < 0) {
+			g_warning("error dumping temporary file '%s'", filename);
+			g_free(filename);
+			return NULL;
+		}
+		fp = claws_fopen(filename,"rb");
+		if (!fp) {
+			g_warning("error opening temporary file '%s'", filename);
+
+			g_free(filename);
+			return NULL;
+		}
+		textdata = file_read_stream_to_str_no_recode(fp);
+
+		claws_fclose(fp);
+		g_unlink(filename);
+		g_free(filename);
+	}
+
+	if (!g_utf8_validate(textdata, -1, NULL)) {
+		gchar *tmp = NULL;
+		codeconv_set_strict(TRUE);
+		if (procmime_mimeinfo_get_parameter(mimeinfo, "charset")) {
+			tmp = conv_codeset_strdup(textdata,
+				procmime_mimeinfo_get_parameter(mimeinfo, "charset"),
+				CS_UTF_8);
+		}
+		if (!tmp) {
+			tmp = conv_codeset_strdup(textdata,
+				conv_get_locale_charset_str_no_utf8(),
+				CS_UTF_8);
+		}
+		codeconv_set_strict(FALSE);
+		if (!tmp) {
+			tmp = conv_codeset_strdup(textdata,
+				conv_get_locale_charset_str_no_utf8(),
+				CS_UTF_8);
+		}
+		if (tmp) {
+			g_free(textdata);
+			textdata = tmp;
+		}
+	}
+
+	return textdata;
+}
diff --git a/src/procmime.h b/src/procmime.h
index 5fae87a..ae8b0e6 100644
--- a/src/procmime.h
+++ b/src/procmime.h
@@ -238,6 +238,8 @@ FILE *procmime_get_binary_content(MimeInfo *mimeinfo);
 gboolean procmime_scan_text_content(MimeInfo *mimeinfo,
 		gboolean (*scan_callback)(const gchar *str, gpointer cb_data),
 		gpointer cb_data);
+gchar *procmime_get_part_as_string(MimeInfo *mimeinfo);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

commit 99fbe41c47ff6bc119986d476e21aa24515c0cd4
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri Mar 1 14:29:53 2019 +0100

    Move file header to the top in pgp_utils.c

diff --git a/src/plugins/pgpcore/pgp_utils.c b/src/plugins/pgpcore/pgp_utils.c
index fbcf9dc..41c5d47 100644
--- a/src/plugins/pgpcore/pgp_utils.c
+++ b/src/plugins/pgpcore/pgp_utils.c
@@ -1,9 +1,3 @@
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#include "claws-features.h"
-#endif
-
 /*
  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
  * Copyright (C) 1999-2013 Colin Leroy <colin at colino.net> and 
@@ -24,6 +18,11 @@
  * 
  */
 
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#include "claws-features.h"
+#endif
+
 #ifdef USE_GPGME
 
 #include <glib.h>

commit 6c9f5e1b6350e8b510d39b91d9efa30902f14604
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Fri Mar 1 14:27:17 2019 +0100

    Remove pgpcore's fp_read_noconv() in favour of file_read_stream_to_str_no_recode() from file-utils.c

diff --git a/src/plugins/pgpcore/pgp_utils.c b/src/plugins/pgpcore/pgp_utils.c
index f7b2793..fbcf9dc 100644
--- a/src/plugins/pgpcore/pgp_utils.c
+++ b/src/plugins/pgpcore/pgp_utils.c
@@ -32,37 +32,6 @@
 #include "codeconv.h"
 #include "file-utils.h"
 
-gchar *fp_read_noconv(FILE *fp)
-{
-	GByteArray *array;
-	guchar buf[BUFSIZ];
-	gint n_read;
-	gchar *result = NULL;
-
-	if (!fp)
-		return NULL;
-	array = g_byte_array_new();
-
-	while ((n_read = claws_fread(buf, sizeof(gchar), sizeof(buf), fp)) > 0) {
-		if (n_read < sizeof(buf) && claws_ferror(fp))
-			break;
-		g_byte_array_append(array, buf, n_read);
-	}
-
-	if (claws_ferror(fp)) {
-		FILE_OP_ERROR("file stream", "claws_fread");
-		g_byte_array_free(array, TRUE);
-		return NULL;
-	}
-
-	buf[0] = '\0';
-	g_byte_array_append(array, buf, 1);
-	result = (gchar *)array->data;
-	g_byte_array_free(array, FALSE);
-	
-	return result;
-}
-
 gchar *get_part_as_string(MimeInfo *mimeinfo)
 {
 	gchar *textdata = NULL;
@@ -84,10 +53,12 @@ gchar *get_part_as_string(MimeInfo *mimeinfo)
 		fp = claws_fopen(filename,"rb");
 		if (!fp) {
 			g_warning("error opening temporary file '%s'", filename);
+
 			g_free(filename);
 			return NULL;
 		}
-		textdata = fp_read_noconv(fp);
+		textdata = file_read_stream_to_str_no_recode(fp);
+
 		claws_fclose(fp);
 		g_unlink(filename);
 		g_free(filename);
diff --git a/src/plugins/pgpcore/pgp_utils.h b/src/plugins/pgpcore/pgp_utils.h
index a7795f7..0299dae 100644
--- a/src/plugins/pgpcore/pgp_utils.h
+++ b/src/plugins/pgpcore/pgp_utils.h
@@ -27,7 +27,6 @@
 
 #include "procmime.h"
 
-gchar *fp_read_noconv(FILE *fp);
 gchar *get_part_as_string(MimeInfo *mimeinfo);
 gchar *pgp_locate_armor_header(gchar *textdata, const gchar *armor_header);
 
diff --git a/src/plugins/pgpcore/plugin.def b/src/plugins/pgpcore/plugin.def
index 94da174..5c48ea9 100644
--- a/src/plugins/pgpcore/plugin.def
+++ b/src/plugins/pgpcore/plugin.def
@@ -28,6 +28,5 @@ EXPORTS
 	cm_gpgme_data_rewind
 
 	get_part_as_string
-	fp_read_noconv
 	pgp_locate_armor_header
 	prefs_gpg_auto_check_signatures
diff --git a/src/plugins/pgpinline/mypgpcore.def b/src/plugins/pgpinline/mypgpcore.def
index a2f5c66..1e17672 100644
--- a/src/plugins/pgpinline/mypgpcore.def
+++ b/src/plugins/pgpinline/mypgpcore.def
@@ -17,4 +17,3 @@ sgpgme_verify_signature
 get_part_as_string
 pgp_locate_armor_header
 prefs_gpg_auto_check_signatures
-fp_read_noconv
diff --git a/src/plugins/pgpinline/pgpinline.c b/src/plugins/pgpinline/pgpinline.c
index b284e64..4c7c98b 100644
--- a/src/plugins/pgpinline/pgpinline.c
+++ b/src/plugins/pgpinline/pgpinline.c
@@ -508,7 +508,7 @@ static gboolean pgpinline_sign(MimeInfo *mimeinfo, PrefsAccount *account, const
 	rewind(fp);
 
 	/* read temporary file into memory */
-	textstr = fp_read_noconv(fp);
+	textstr = file_read_stream_to_str_no_recode(fp);
 	
 	claws_fclose(fp);
 		
@@ -702,7 +702,7 @@ static gboolean pgpinline_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
 	rewind(fp);
 
 	/* read temporary file into memory */
-	textstr = fp_read_noconv(fp);
+	textstr = file_read_stream_to_str_no_recode(fp);
 	
 	claws_fclose(fp);
 
diff --git a/src/plugins/smime/mypgpcore.def b/src/plugins/smime/mypgpcore.def
index eeba473..44dd8d2 100644
--- a/src/plugins/smime/mypgpcore.def
+++ b/src/plugins/smime/mypgpcore.def
@@ -17,4 +17,3 @@ sgpgme_sigstat_info_short
 sgpgme_verify_signature
 cm_gpgme_data_rewind
 prefs_gpg_auto_check_signatures
-fp_read_noconv
diff --git a/src/plugins/smime/smime.c b/src/plugins/smime/smime.c
index 2546343..f0cd96f 100644
--- a/src/plugins/smime/smime.c
+++ b/src/plugins/smime/smime.c
@@ -816,7 +816,7 @@ gboolean smime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
 	g_free(tmpfile);
 
 	/* read temporary file into memory */
-	textstr = fp_read_noconv(fp);
+	textstr = file_read_stream_to_str_no_recode(fp);
 
 	claws_fclose(fp);
 

commit 7855a65deb5fdc6a2db1fa1cb667dfe4b99f4f55
Author: Ricardo Mones <ricardo at mones.org>
Date:   Tue Feb 19 19:23:10 2019 +0100

    Check writting crash-indicator (CID 1440021)

diff --git a/src/main.c b/src/main.c
index 7c73076..f3a54a2 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1434,7 +1434,9 @@ int main(int argc, char *argv[])
 		folder_item_update_freeze();
 	}
 	/* make the crash-indicator file */
-	str_write_to_file("foo", get_crashfile_name(), FALSE);
+	if (str_write_to_file("foo", get_crashfile_name(), FALSE) < 0) {
+		g_warning("Can't create the crash-indicator file.");
+	}
 
 	inc_autocheck_timer_init(mainwin);
 

commit c0e2f35a7520634ddf723dc6954d5bf257652cbb
Author: Ricardo Mones <ricardo at mones.org>
Date:   Tue Feb 19 19:23:38 2019 +0100

    Check result of fputs (CID 1440024)

diff --git a/src/main.c b/src/main.c
index c9c49ab..7c73076 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2409,7 +2409,10 @@ static gint prohibit_duplicate_launch(void)
  			fd_gets(uxsock, buf, sizeof(buf) - 1);
 			buf[sizeof(buf) - 1] = '\0';
  			if (!strncmp(buf, ".\n", 2)) break;
- 			claws_fputs(buf, stdout);
+			if (claws_fputs(buf, stdout) == EOF) {
+				g_warning("writing to stdout failed.");
+				break;
+			}
  		}
 	} else if (cmd.exit) {
 		fd_write_all(uxsock, "exit\n", 5);
@@ -2420,7 +2423,10 @@ static gint prohibit_duplicate_launch(void)
  			fd_gets(uxsock, buf, sizeof(buf) - 1);
 			buf[sizeof(buf) - 1] = '\0';
  			if (!strncmp(buf, ".\n", 2)) break;
- 			claws_fputs(buf, stdout);
+			if (claws_fputs(buf, stdout) == EOF) {
+				g_warning("writing to stdout failed.");
+				break;
+			}
  		}
 	} else if (cmd.reset_statistics) {
 		fd_write(uxsock, "reset_statistics\n", 17);
@@ -2440,7 +2446,10 @@ static gint prohibit_duplicate_launch(void)
 			fd_gets(uxsock, buf, sizeof(buf) - 1);
 			buf[sizeof(buf) - 1] = '\0';
 			if (!strncmp(buf, ".\n", 2)) break;
-			claws_fputs(buf, stdout);
+			if (claws_fputs(buf, stdout) == EOF) {
+				g_warning("writing to stdout failed.");
+				break;
+			}
 		}
 	} else {
 #ifdef G_OS_UNIX

commit 04ecd4fcf4ae2e94fb023fb6f7ee60564d80fd18
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Thu Feb 14 18:08:56 2019 +0100

    Make key accelerators from menu work in addressbook window

diff --git a/src/addressbook.c b/src/addressbook.c
index 7f3daec..2454a13 100644
--- a/src/addressbook.c
+++ b/src/addressbook.c
@@ -995,6 +995,9 @@ static void addressbook_create(void)
 /* Help menu */
 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Help", "About", "Help/About", GTK_UI_MANAGER_MENUITEM)
 
+	gtk_window_add_accel_group(GTK_WINDOW(window),
+			gtk_ui_manager_get_accel_group(ui_manager));
+
 	menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
 
 	gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);

commit 6a2fdebfbf1c048f19fd082613157f3fd4741a0e
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Thu Feb 14 17:55:42 2019 +0100

    Change addressbook's internal UI name for Edit submenu to match its label

diff --git a/src/addressbook.c b/src/addressbook.c
index b69b651..7f3daec 100644
--- a/src/addressbook.c
+++ b/src/addressbook.c
@@ -403,7 +403,7 @@ static GtkActionEntry addressbook_entries[] =
 	{"Menu",				NULL, "Menu", NULL, NULL, NULL },
 /* menus */
 	{"Book",			NULL, N_("_Book"), NULL, NULL, NULL },
-	{"Address",			NULL, N_("_Edit"), NULL, NULL, NULL },
+	{"Edit",			NULL, N_("_Edit"), NULL, NULL, NULL },
 	{"Tools",			NULL, N_("_Tools"), NULL, NULL, NULL },
 	{"Help",			NULL, N_("_Help"), NULL, NULL, NULL },
 	
@@ -944,7 +944,7 @@ static void addressbook_create(void)
 	MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
 
 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Address", "Address", GTK_UI_MANAGER_MENU)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Edit", "Edit", GTK_UI_MANAGER_MENU)
 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Help", "Help", GTK_UI_MANAGER_MENU)
 
@@ -966,20 +966,20 @@ static void addressbook_create(void)
 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
 
 /* Address menu */
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
-	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Merge", "Address/Merge", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Merge", "Address/Merge", GTK_UI_MANAGER_MENUITEM)
 
 /* Tools menu */
 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
@@ -1790,15 +1790,15 @@ static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
 	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
 	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder",  sensitive );
 
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll",    TRUE );
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut",    sensitive );
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy",   sensitive );
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste",  sensitive );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/SelectAll",    TRUE );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut",    sensitive );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy",   sensitive );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste",  sensitive );
 
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup",   sensitive );
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto",     sensitive );
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Merge",      sensitive );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewAddress", sensitive );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewGroup",   sensitive );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Mailto",     sensitive );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Merge",      sensitive );
 	gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
 	gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
 }
@@ -1865,14 +1865,14 @@ static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNo
 		canEdit = FALSE;
 
 	/* Enable add */
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup",   canAdd );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewAddress", editAddress );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewGroup",   canAdd );
 	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder",  canAdd );
 	gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
 
 	/* Enable edit */
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit",   canEdit );
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Edit",   canEdit );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Delete", canDelete );
 	gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
 	gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
 
@@ -2104,14 +2104,14 @@ static void addressbook_list_menu_setup( void ) {
 	cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto",       canCopy );
 	cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Merge",        canMerge );
 
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut",           canCut );
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy",          canCopy );
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste",         canPaste );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut",           canCut );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy",          canCopy );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste",         canPaste );
 
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit",    canEdit );
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete",  canDelete );
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Merge",  canMerge );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Edit",    canEdit );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Delete",  canDelete );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Mailto", canCopy );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Merge",  canMerge );
 
 	gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
 	gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
@@ -2674,9 +2674,9 @@ just_set_sens:
 
 	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook",          canEdit );
 	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook",        canDelete );
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut",           canCut );
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy",          canCopy );
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste",         canPaste );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut",           canCut );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy",          canCopy );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste",         canPaste );
 
 	addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
 			addrbook.target_compose != NULL);
@@ -3429,9 +3429,9 @@ void addressbook_address_list_set_focus( void )
 void addressbook_address_list_disable_some_actions(void)
 {
 	/* disable address copy/pasting when editing contact's detail (embedded form) */
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut",   FALSE );
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy",  FALSE );
-	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut",   FALSE );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy",  FALSE );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", FALSE );
 }
 
 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {

commit 29694b10b75c2e39c074c61e86fad7a79d211cfd
Author: Paul <paul at claws-mail.org>
Date:   Thu Feb 14 14:12:35 2019 +0000

    fix bug 4155, 'remember directory of last saving'
    
    drop messageview_save_as(), use only summary_save_as()

diff --git a/src/messageview.c b/src/messageview.c
index 3e9a42b..7eff0ae 100644
--- a/src/messageview.c
+++ b/src/messageview.c
@@ -1814,52 +1814,6 @@ gboolean messageview_is_visible(MessageView *messageview)
 	return messageview->visible;
 }
 
-static void messageview_save_as(MessageView *messageview)
-{
-	gchar *filename = NULL;
-	MsgInfo *msginfo;
-	gchar *src, *dest, *tmp;
-
-	if (!messageview->msginfo) return;
-	msginfo = messageview->msginfo;
-
-	if (msginfo->subject) {
-		Xstrdup_a(filename, msginfo->subject, return);
-		subst_for_filename(filename);
-	}
-	if (filename && !g_utf8_validate(filename, -1, NULL)) {
-		gchar *oldstr = filename;
-		filename = conv_codeset_strdup(filename,
-					       conv_get_locale_charset_str(),
-					       CS_UTF_8);
-		if (!filename) {
-			g_warning("messageview_save_as(): failed to convert character set.");
-			filename = g_strdup(oldstr);
-		}
-		dest = filesel_select_file_save(_("Save as"), filename);
-		g_free(filename);
-	} else
-		dest = filesel_select_file_save(_("Save as"), filename);
-	if (!dest) return;
-	if (is_file_exist(dest)) {
-		AlertValue aval;
-
-		aval = alertpanel(_("Overwrite"),
-				  _("Overwrite existing file?"),
-				  GTK_STOCK_CANCEL, GTK_STOCK_OK, NULL, ALERTFOCUS_FIRST);
-		if (G_ALERTALTERNATE != aval) return;
-	}
-
-	src = procmsg_get_message_file(msginfo);
-	if (copy_file(src, dest, TRUE) < 0) {
-		tmp =  g_path_get_basename(dest);
-		alertpanel_error(_("Couldn't save the file '%s'."), tmp);
-		g_free(tmp);
-	}
-	g_free(dest);
-	g_free(src);
-}
-
 static gint messageview_delete_cb(GtkWidget *widget, GdkEventAny *event,
 				  MessageView *messageview)
 {
@@ -2200,7 +2154,7 @@ gchar *messageview_get_selection(MessageView *msgview)
 static void save_as_cb(GtkAction *action, gpointer data)
 {
 	MessageView *messageview = (MessageView *)data;
-	messageview_save_as(messageview);
+	summary_save_as(messageview->mainwin->summaryview);
 }
 
 static void print_mimeview(MimeView *mimeview, gint sel_start, gint sel_end, gint partnum) 
diff --git a/src/summaryview.c b/src/summaryview.c
index 0fa0c81..fa498b3 100644
--- a/src/summaryview.c
+++ b/src/summaryview.c
@@ -4962,6 +4962,7 @@ void summary_save_as(SummaryView *summaryview)
 	gchar *filename = NULL;
 	gchar *src, *dest;
 	gchar *tmp;
+	gchar *filedir = NULL;
 
 	AlertValue aval = 0;
 
@@ -4985,12 +4986,17 @@ void summary_save_as(SummaryView *summaryview)
 			g_warning("summary_save_as(): failed to convert character set.");
 			filename = g_strdup(oldstr);
 		}
-		dest = filesel_select_file_save(_("Save as"), filename);
+		dest = filename;
 		g_free(filename);
 	} else
-		dest = filesel_select_file_save(_("Save as"), filename);
+		dest = filename;
 	filename = NULL;
 	if (!dest) return;
+	if (prefs_common.attach_save_dir && *prefs_common.attach_save_dir)
+		dest = g_strconcat(prefs_common.attach_save_dir, G_DIR_SEPARATOR_S,
+				   dest, NULL);
+	dest = filesel_select_file_save(_("Save as"), dest);
+
 	if (is_file_exist(dest)) {
 		aval = alertpanel(_("Append or Overwrite"),
 				  _("Append or overwrite existing file?"),
@@ -5027,6 +5033,13 @@ void summary_save_as(SummaryView *summaryview)
 		}
 		g_free(src);
 	}
+
+	filedir = g_path_get_dirname(dest);
+	if (filedir && strcmp(filedir, ".")) {
+		g_free(prefs_common.attach_save_dir);
+		prefs_common.attach_save_dir = g_filename_to_utf8(filedir, -1, NULL, NULL, NULL);
+	}
+
 	g_free(dest);
 	g_free(tmp);
 }

-----------------------------------------------------------------------


hooks/post-receive
-- 
Claws Mail


More information about the Commits mailing list