From: Andrej Kacian Date: Mon, 25 Feb 2019 22:19:24 +0000 (+0100) Subject: Use Pango to render text in Litehtml plugin X-Git-Tag: 3.17.4~98 X-Git-Url: http://git.claws-mail.org/?p=claws.git;a=commitdiff_plain;h=79df8adbfee87e42bd4ca6071537619289de85b5;ds=inline 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 d603a3000..81ce76660 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 a2b190859..15f8836ad 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 43a917c6e..8132bfb50 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 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 da2dc7fb1..55fc56dc3 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 000000000..ed290559f --- /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 + +#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); +}