From 1aea07a33fa0002c09a446969857a8fd98430773 Mon Sep 17 00:00:00 2001 From: Andres Riofrio Date: Fri, 17 May 2013 09:52:05 -0700 Subject: [PATCH] Read typographic hints from Pango for text decorations --- weasyprint/draw.py | 23 +++++++++++++++++------ weasyprint/text.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/weasyprint/draw.py b/weasyprint/draw.py index 02862d73..369a2e68 100644 --- a/weasyprint/draw.py +++ b/weasyprint/draw.py @@ -666,28 +666,39 @@ def draw_text(context, textbox, enable_hinting): context.set_source_rgba(*textbox.style.color) show_first_line(context, textbox.pango_layout, enable_hinting) values = textbox.style.text_decoration + + metrics = textbox.pango_layout.get_font_metrics() + thickness = textbox.style.font_size / 18 + if enable_hinting and thickness < 1: + thickness = 1 + if 'overline' in values: draw_text_decoration( context, textbox, - textbox.baseline - 0.15 * textbox.style.font_size, + textbox.baseline - metrics.ascent + thickness / 2, + thickness, enable_hinting) elif 'underline' in values: draw_text_decoration( context, textbox, - textbox.baseline + 0.15 * textbox.style.font_size, + textbox.baseline - metrics.underline_position + thickness / 2, + thickness, enable_hinting) elif 'line-through' in values: - draw_text_decoration(context, textbox, textbox.height * 0.5, - enable_hinting) + draw_text_decoration( + context, textbox, + textbox.baseline - metrics.strikethrough_position, + thickness, + enable_hinting) -def draw_text_decoration(context, textbox, offset_y, enable_hinting): +def draw_text_decoration(context, textbox, offset_y, thickness, enable_hinting): """Draw text-decoration of ``textbox`` to a ``cairo.Context``.""" with stacked(context): if enable_hinting: context.set_antialias(cairo.ANTIALIAS_NONE) context.set_source_rgba(*textbox.style.color) - context.set_line_width(1) # TODO: make this proportional to font_size? + context.set_line_width(thickness) context.move_to(textbox.position_x, textbox.position_y + offset_y) context.rel_line_to(textbox.width, 0) context.stroke() diff --git a/weasyprint/text.py b/weasyprint/text.py index 7552d56e..a918460c 100644 --- a/weasyprint/text.py +++ b/weasyprint/text.py @@ -65,6 +65,9 @@ ffi.cdef(''' typedef void* gpointer; typedef ... cairo_t; typedef ... PangoLayout; + typedef ... PangoContext; + typedef ... PangoFontMetrics; + typedef ... PangoLanguage; typedef ... PangoFontDescription; typedef ... PangoLayoutIter; typedef ... PangoAttrList; @@ -151,6 +154,27 @@ ffi.cdef(''' PangoLayoutLine *line, PangoRectangle *ink_rect, PangoRectangle *logical_rect); + PangoContext * pango_layout_get_context (PangoLayout *layout); + PangoFontMetrics * pango_context_get_metrics (PangoContext *context, + const PangoFontDescription *desc, + PangoLanguage *language); + + void pango_font_metrics_unref (PangoFontMetrics *metrics); + int pango_font_metrics_get_ascent (PangoFontMetrics *metrics); + int pango_font_metrics_get_descent (PangoFontMetrics *metrics); + int pango_font_metrics_get_approximate_char_width + (PangoFontMetrics *metrics); + int pango_font_metrics_get_approximate_digit_width + (PangoFontMetrics *metrics); + int pango_font_metrics_get_underline_thickness + (PangoFontMetrics *metrics); + int pango_font_metrics_get_underline_position + (PangoFontMetrics *metrics); + int pango_font_metrics_get_strikethrough_thickness + (PangoFontMetrics *metrics); + int pango_font_metrics_get_strikethrough_position + (PangoFontMetrics *metrics); + void pango_cairo_update_layout (cairo_t *cr, PangoLayout *layout); void pango_cairo_show_layout_line (cairo_t *cr, PangoLayoutLine *line); @@ -286,6 +310,28 @@ class Layout(object): self.text_bytes = bytestring pango.pango_layout_set_text(self.layout, text, -1) + def get_font_metrics(self): + context = pango.pango_layout_get_context(self.layout) + return FontMetrics(context, self.font) + + +class FontMetrics(object): + def __init__(self, context, font): + self.metrics = ffi.gc( + pango.pango_context_get_metrics(context, font, ffi.NULL), + pango.pango_font_metrics_unref) + + def __dir__(self): + return ['ascent', 'descent', + 'approximate_char_width', 'approximate_digit_width', + 'underline_thickness', 'underline_position', + 'strikethrough_thickness', 'strikethrough_position'] + + def __getattr__(self, key): + if key in dir(self): + return units_to_double( + getattr(pango, 'pango_font_metrics_get_' + key)(self.metrics)) + def create_layout(text, style, hinting, max_width): """Return an opaque Pango layout with default Pango line-breaks.