Bug 17727 - [wx] Implement non-kerned drawing on wxGTK w/wxGC
Summary: [wx] Implement non-kerned drawing on wxGTK w/wxGC
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebKit wx (show other bugs)
Version: 528+ (Nightly build)
Hardware: PC Linux
: P2 Normal
Assignee: Kevin Ollivier
URL:
Keywords: Wx
Depends on:
Blocks:
 
Reported: 2008-03-08 12:33 PST by Kevin Ollivier
Modified: 2009-05-11 05:23 PDT (History)
2 users (show)

See Also:


Attachments
Implementation for wxGC mode (9.86 KB, patch)
2008-03-08 12:35 PST, Kevin Ollivier
darin: review+
Details | Formatted Diff | Diff
new patch using PANGO instead of FT for better results (12.00 KB, patch)
2008-10-27 16:27 PDT, Kevin Ollivier
aroben: review-
Details | Formatted Diff | Diff
Revised patch with Adam's comments addressed (11.67 KB, patch)
2008-12-01 22:27 PST, Kevin Ollivier
no flags Details | Formatted Diff | Diff
Updated the patch to support recent changes and satisfied a FIXME (14.76 KB, patch)
2009-02-11 23:09 PST, Diggilin
kevino: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Kevin Ollivier 2008-03-08 12:33:59 PST
wx currently only draws text kerned, so we need to provide our own implementation of non-kerned drawing there.
Comment 1 Kevin Ollivier 2008-03-08 12:35:06 PST
Created attachment 19611 [details]
Implementation for wxGC mode

Here is the implementation using wxGC (which is basically Cairo under the hood).
Comment 2 Alp Toker 2008-03-20 14:22:10 PDT
Hey, we have three copies of some of this code already, and there is at least one bug bug in the part you ended up copying (which we now have in three places). Wonder if we can find a better way to share this Cairo code. It really is mostly identical for each port.
Comment 3 Kevin Ollivier 2008-03-21 13:20:10 PDT
I much prefer sharing code as well, but which copy should I base the shared code off of? I see there are now Pango and non-Pango versions... We (wx) can use Pango I think, but does GTK need to support both? 
Comment 4 Darin Adler 2008-06-08 18:06:27 PDT
Comment on attachment 19611 [details]
Implementation for wxGC mode

r=me
Comment 5 Darin Adler 2008-10-12 15:14:21 PDT
Kevin, why haven't you landed this yet?
Comment 6 Kevin Ollivier 2008-10-15 18:58:28 PDT
Sorry, there were a couple issues I found with this patch that turned out to be really hard to resolve, which in turn led me to think the way I approached this problem might not have been the right one. I actually did recently get a chance to redo the implementation using Pango which gives much better results. Should I just clear the review field for this patch until I've got the new one ready to upload? 
Comment 7 Kevin Ollivier 2008-10-27 16:27:07 PDT
Created attachment 24701 [details]
new patch using PANGO instead of FT for better results

Here's the new patch I promised. This one has been better tested and doesn't have the issues the old one did.
Comment 8 Adam Roben (:aroben) 2008-11-24 09:42:21 PST
Comment on attachment 24701 [details]
new patch using PANGO instead of FT for better results

> +++ WebCore/platform/graphics/GlyphBuffer.h	(working copy)
> @@ -33,7 +33,7 @@
>  
>  #if PLATFORM(CG)
>  #include <ApplicationServices/ApplicationServices.h>
> -#elif PLATFORM(CAIRO)
> +#elif PLATFORM(CAIRO) || (PLATFORM(WX) && defined(__WXGTK__))

Should we just make PLATFORM(CAIRO) be defined globally when building wxgtk?

>  float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
>  {
> +#if __WXGTK__ && USE(WXGC)
> +    PangoFont* pangoFont = createPangoFontForFont(m_font.font());

Do you need to free this font somewhere? I guess WXGC might mean "garbage collection"?

It seems kind of strange that all non-wxgtk/wxgc cases will fall into the Windows-only code path.

> +++ WebCore/platform/wx/wxcode/gtk/non-kerned-drawing.cpp	(working copy)
> @@ -33,15 +33,163 @@
>  #include <wx/gdicmn.h>
>  #include <vector>
>  
> +#if USE(WXGC)
> +#include <cairo.h>
> +#include <assert.h>
> +
> +#include <pango/pango.h>
> +#include <pango/pangocairo.h>
> +
> +// Use cairo-ft i a recent enough Pango version isn't available

Typo: i -> if

> +PangoFontMap* g_fontMap = 0;

This should be marked static. That will give it internal linkage. Once you do that you won't have to explicitly initialize to 0, either.

> +PangoFontMap* pangoFontMap()
> +{
> +    return g_fontMap;
> +}

Should this function perform initialization of g_fontMap?

> +
> +PangoFont* createPangoFontForFont(const wxFont wxfont)
> +{
> +const char* face = wxfont.GetFaceName().mb_str(wxConvUTF8);
> +    char const* families[] = {
> +      face,
> +      NULL
> +    };

Indentation seems wrong here. We also use 0 instead of NULL in C++ code, though maybe this file is trying to follow wx coding style?

> +
> +   switch (wxfont.GetFamily()) {
> +        case wxFONTFAMILY_ROMAN:
> +            families[1] = "serif";
> +            break;
> +        case wxFONTFAMILY_SWISS:
> +            families[1] = "sans";
> +            break;
> +        case wxFONTFAMILY_MODERN:
> +            families[1] = "monospace";
> +            break;
> +        default:
> +            families[1] = "sans";
> +    }
> +    
> +    PangoFontDescription* description = pango_font_description_new();
> +    pango_font_description_set_absolute_size(description, wxfont.GetPointSize() * PANGO_SCALE);
> + 
> +    PangoFont* pangoFont = 0;
> +    PangoContext* pangoContext = 0;
> +    // FIXME: Map all FontWeight values to Pango font weights.
> +    if (wxfont.GetWeight() == wxFONTWEIGHT_BOLD)
> +        pango_font_description_set_weight(description, PANGO_WEIGHT_BOLD);
> +    if (wxfont.GetStyle() == wxFONTSTYLE_ITALIC)
> +        pango_font_description_set_style(description, PANGO_STYLE_ITALIC);
> +
> +    if (!g_fontMap)
> +        g_fontMap = pango_cairo_font_map_get_default();
> +
> +    pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(g_fontMap));

> +    for (unsigned int i = 0; !pangoFont && i < G_N_ELEMENTS(families); i++) {

We normally just say "unsigned" instead of "unsigned int".

> +        pango_font_description_set_family(description, "sans"); //families[i]);

This looks wrong.

> +PangoGlyph pango_font_get_glyph(PangoFont* font, PangoContext* context, gunichar wc)
> +{
> +    PangoGlyph result = 0;
> +    gchar buffer[7];
> +
> +    gint  length = g_unichar_to_utf8(wc, buffer);
> +    g_return_val_if_fail(length, 0);
> +
> +    GList* items = pango_itemize(context, buffer, 0, length, NULL, NULL);
> +
> +    if (g_list_length(items) == 1) {
> +        PangoItem* item = reinterpret_cast<PangoItem*>(items->data);

static_cast would be better here.

>  void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point)
>  {
>  #if USE(WXGC)
>      wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext());
> +    wxGraphicsContext* gc = dc->GetGraphicsContext();
> +    gc->PushState();
> +    cairo_t* cr = (cairo_t*)gc->GetNativeContext();
> +
> +    wxFont wxfont = font->getWxFont();
> +    PangoFont* pangoFont = createPangoFontForFont(wxfont);
> +    PangoContext* pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(g_fontMap));
> +    cairo_scaled_font_t* scaled_font = createScaledFontForFont(wxfont); 
> +    ASSERT(scaled_font);
> +
> +    cairo_glyph_t* glyphs = NULL;
> +    glyphs = (cairo_glyph_t*)malloc (sizeof(cairo_glyph_t) * numGlyphs);

Extra space after "malloc". static_cast would be better than a C-style cast.

>  wxFontProperties::wxFontProperties(wxFont* font):
>  m_ascent(0), m_descent(0), m_lineGap(0), m_lineSpacing(0), m_xHeight(0)
>  {
> +#if USE(WXGC)
> +    cairo_font_extents_t font_extents;
> +    cairo_text_extents_t text_extents;
> +    cairo_scaled_font_t* scaled_font = WebCore::createScaledFontForFont(*font);
> +    
> +    cairo_scaled_font_extents(scaled_font, &font_extents);
> +    m_ascent = static_cast<int>(font_extents.ascent);
> +    m_descent = static_cast<int>(font_extents.descent);
> +    m_lineSpacing = static_cast<int>(font_extents.height);
> +    cairo_scaled_font_text_extents(scaled_font, "x", &text_extents);
> +    m_xHeight = text_extents.height;
> +    cairo_scaled_font_text_extents(scaled_font, " ", &text_extents);
> +    //m_spaceWidth =  static_cast<int>(text_extents.x_advance);

We don't like to commit commented-out code.

r- so this can be cleaned up a little more before going in.
Comment 9 Kevin Ollivier 2008-12-01 22:27:18 PST
Created attachment 25665 [details]
Revised patch with Adam's comments addressed
Comment 10 Kevin Ollivier 2008-12-01 22:41:44 PST
(In reply to comment #8)
> (From update of attachment 24701 [details] [review])
> > +++ WebCore/platform/graphics/GlyphBuffer.h	(working copy)
> > @@ -33,7 +33,7 @@
> >  
> >  #if PLATFORM(CG)
> >  #include <ApplicationServices/ApplicationServices.h>
> > -#elif PLATFORM(CAIRO)
> > +#elif PLATFORM(CAIRO) || (PLATFORM(WX) && defined(__WXGTK__))
> 
> Should we just make PLATFORM(CAIRO) be defined globally when building wxgtk?

We do not use all of the Cairo port, in fact we don't use most of it. As a result, we'd probably actually end up with many more #ifdefs, mostly #if PLATFORM(CAIRO) && !PLATFORM(WX), for things that the wx port implements separately from Cairo.

These special platform-specific defines will eventually go away, as this code is eventually going to be part of wx once we craft a proper API for it. If we move it there now, though, wxWebKit could no longer be used with the current stable release (2.8.9) and there aren't any releases of the 2.9 cycle yet, which would cause problems for some projects currently using wxWebKit.

> >  float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
> >  {
> > +#if __WXGTK__ && USE(WXGC)
> > +    PangoFont* pangoFont = createPangoFontForFont(m_font.font());
> 
> Do you need to free this font somewhere? I guess WXGC might mean "garbage
> collection"?

No, sorry, I overlooked this. WXGC actually stands for wxGraphicsContext, which is a frontend to the various vector-based drawing APIs (GDI+, Cairo, and Core Graphics). 

> It seems kind of strange that all non-wxgtk/wxgc cases will fall into the
> Windows-only code path.

The fallback is actually a wx codepath, not Windows, and in the latest path I removed the special case so that there's no special case for wxGTK/Cairo in SimpleFontData. The necessary code was moved into WebCore/platform/wx/wxcode/gtk/fontprops.cpp

> > +++ WebCore/platform/wx/wxcode/gtk/non-kerned-drawing.cpp	(working copy)
> > @@ -33,15 +33,163 @@
> >  #include <wx/gdicmn.h>
> >  #include <vector>
> >  
> > +#if USE(WXGC)
> > +#include <cairo.h>
> > +#include <assert.h>
> > +
> > +#include <pango/pango.h>
> > +#include <pango/pangocairo.h>
> > +
> > +// Use cairo-ft i a recent enough Pango version isn't available
> 
> Typo: i -> if
> 
> > +PangoFontMap* g_fontMap = 0;
> 
> This should be marked static. That will give it internal linkage. Once you do
> that you won't have to explicitly initialize to 0, either.

Done, thanks!

> > +PangoFontMap* pangoFontMap()
> > +{
> > +    return g_fontMap;
> > +}
> 
> Should this function perform initialization of g_fontMap?

yeah, this is definitely better. I've implemented that in the latest patch.

> > +
> > +PangoFont* createPangoFontForFont(const wxFont wxfont)
> > +{
> > +const char* face = wxfont.GetFaceName().mb_str(wxConvUTF8);
> > +    char const* families[] = {
> > +      face,
> > +      NULL
> > +    };
> 
> Indentation seems wrong here. We also use 0 instead of NULL in C++ code, though
> maybe this file is trying to follow wx coding style?

No, not sure how that got messed up, but I fixed it.

> > +
> > +   switch (wxfont.GetFamily()) {
> > +        case wxFONTFAMILY_ROMAN:
> > +            families[1] = "serif";
> > +            break;
> > +        case wxFONTFAMILY_SWISS:
> > +            families[1] = "sans";
> > +            break;
> > +        case wxFONTFAMILY_MODERN:
> > +            families[1] = "monospace";
> > +            break;
> > +        default:
> > +            families[1] = "sans";
> > +    }
> > +    
> > +    PangoFontDescription* description = pango_font_description_new();
> > +    pango_font_description_set_absolute_size(description, wxfont.GetPointSize() * PANGO_SCALE);
> > + 
> > +    PangoFont* pangoFont = 0;
> > +    PangoContext* pangoContext = 0;
> > +    // FIXME: Map all FontWeight values to Pango font weights.
> > +    if (wxfont.GetWeight() == wxFONTWEIGHT_BOLD)
> > +        pango_font_description_set_weight(description, PANGO_WEIGHT_BOLD);
> > +    if (wxfont.GetStyle() == wxFONTSTYLE_ITALIC)
> > +        pango_font_description_set_style(description, PANGO_STYLE_ITALIC);
> > +
> > +    if (!g_fontMap)
> > +        g_fontMap = pango_cairo_font_map_get_default();
> > +
> > +    pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(g_fontMap));
> 
> > +    for (unsigned int i = 0; !pangoFont && i < G_N_ELEMENTS(families); i++) {
> 
> We normally just say "unsigned" instead of "unsigned int".

Okay, done.

> > +        pango_font_description_set_family(description, "sans"); //families[i]);
> 
> This looks wrong.

Yeah, I think I added that when debugging and forgot to undo it. :( Fixed now.

> > +PangoGlyph pango_font_get_glyph(PangoFont* font, PangoContext* context, gunichar wc)
> > +{
> > +    PangoGlyph result = 0;
> > +    gchar buffer[7];
> > +
> > +    gint  length = g_unichar_to_utf8(wc, buffer);
> > +    g_return_val_if_fail(length, 0);
> > +
> > +    GList* items = pango_itemize(context, buffer, 0, length, NULL, NULL);
> > +
> > +    if (g_list_length(items) == 1) {
> > +        PangoItem* item = reinterpret_cast<PangoItem*>(items->data);
> 
> static_cast would be better here.

Done.

> >  void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point)
> >  {
> >  #if USE(WXGC)
> >      wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext());
> > +    wxGraphicsContext* gc = dc->GetGraphicsContext();
> > +    gc->PushState();
> > +    cairo_t* cr = (cairo_t*)gc->GetNativeContext();
> > +
> > +    wxFont wxfont = font->getWxFont();
> > +    PangoFont* pangoFont = createPangoFontForFont(wxfont);
> > +    PangoContext* pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(g_fontMap));
> > +    cairo_scaled_font_t* scaled_font = createScaledFontForFont(wxfont); 
> > +    ASSERT(scaled_font);
> > +
> > +    cairo_glyph_t* glyphs = NULL;
> > +    glyphs = (cairo_glyph_t*)malloc (sizeof(cairo_glyph_t) * numGlyphs);
> 
> Extra space after "malloc". static_cast would be better than a C-style cast.

Done. :)

> >  wxFontProperties::wxFontProperties(wxFont* font):
> >  m_ascent(0), m_descent(0), m_lineGap(0), m_lineSpacing(0), m_xHeight(0)
> >  {
> > +#if USE(WXGC)
> > +    cairo_font_extents_t font_extents;
> > +    cairo_text_extents_t text_extents;
> > +    cairo_scaled_font_t* scaled_font = WebCore::createScaledFontForFont(*font);
> > +    
> > +    cairo_scaled_font_extents(scaled_font, &font_extents);
> > +    m_ascent = static_cast<int>(font_extents.ascent);
> > +    m_descent = static_cast<int>(font_extents.descent);
> > +    m_lineSpacing = static_cast<int>(font_extents.height);
> > +    cairo_scaled_font_text_extents(scaled_font, "x", &text_extents);
> > +    m_xHeight = text_extents.height;
> > +    cairo_scaled_font_text_extents(scaled_font, " ", &text_extents);
> > +    //m_spaceWidth =  static_cast<int>(text_extents.x_advance);
> 
> We don't like to commit commented-out code.

Yes, sorry, another oversight. Fixed now.

> r- so this can be cleaned up a little more before going in.
> 

Thanks a lot for taking a look at this! 
Comment 11 Diggilin 2008-12-20 15:41:25 PST
Any chance this can get the fast lane?
wxWebKit is useless under linux without it...
Comment 12 Nikolas Zimmermann 2009-01-22 20:35:20 PST
Adding Adam to the CC list, in case he forgot about this long-pending bug.

Comment 13 Diggilin 2009-02-11 23:09:13 PST
Created attachment 27588 [details]
Updated the patch to support recent changes and satisfied a FIXME
Comment 14 Kevin Ollivier 2009-02-12 21:42:55 PST
Landed in r40965, thanks! :-)