Use Pango to render text in Litehtml plugin
authorAndrej Kacian <ticho@claws-mail.org>
Mon, 25 Feb 2019 22:19:24 +0000 (23:19 +0100)
committerAndrej Kacian <ticho@claws-mail.org>
Mon, 25 Feb 2019 23:05:24 +0000 (00:05 +0100)
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.

src/plugins/litehtml_viewer/Makefile.am
src/plugins/litehtml_viewer/container_linux.cpp
src/plugins/litehtml_viewer/container_linux.h
src/plugins/litehtml_viewer/lh_widget.h
src/plugins/litehtml_viewer/lh_widget_text.cpp [new file with mode: 0644]

index d603a30..81ce766 100644 (file)
@@ -44,6 +44,7 @@ litehtml_viewer_la_SOURCES = \
        lh_prefs.c \
        lh_viewer.c \
        lh_widget.cpp \
        lh_prefs.c \
        lh_viewer.c \
        lh_widget.cpp \
+       lh_widget_text.cpp \
        container_linux.h \
        lh_prefs.h \
        lh_viewer.h \
        container_linux.h \
        lh_prefs.h \
        lh_viewer.h \
index a2b1908..15f8836 100644 (file)
@@ -46,169 +46,6 @@ container_linux::~container_linux(void)
        cairo_destroy(m_temp_cr);
 }
 
        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();
 int container_linux::pt_to_px( int pt )
 {
        GdkScreen* screen = gdk_screen_get_default();
index 43a917c..8132bfb 100644 (file)
@@ -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;
 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);
 
        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;
        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 );
        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:
 
 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                                                            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);
 };
        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);
 };
index da2dc7f..55fc56d 100644 (file)
@@ -4,6 +4,13 @@
 
 #include "container_linux.h"
 
 
 #include "container_linux.h"
 
+struct pango_font
+{
+       PangoFontDescription *font;
+       bool underline;
+       bool strikethrough;
+};
+
 class lh_widget : public container_linux
 {
        public:
 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; };
                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);
 
                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);
                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 (file)
index 0000000..ed29055
--- /dev/null
@@ -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);
+}