Changeset 29334 in webkit


Ignore:
Timestamp:
Jan 8, 2008 8:45:32 PM (16 years ago)
Author:
alp@webkit.org
Message:

2008-01-08 Xan Lopez <xan@gnome.org>

Reviewed by Alp Toker.

http://bugs.webkit.org/show_bug.cgi?id=15610
[GTK] Text rendering using Pango

Use Pango to render Complex path text.

  • platform/graphics/gtk/FontGtk.cpp: (WebCore::utf16_to_utf8): (WebCore::convertUniCharToUTF8): (WebCore::setPangoAttributes): (WebCore::Font::drawGlyphs): (WebCore::Font::drawComplexText): (WebCore::Font::floatWidthForComplexText): (WebCore::Font::offsetForPositionForComplexText):
Location:
trunk/WebCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r29333 r29334  
     12008-01-08  Xan Lopez  <xan@gnome.org>
     2
     3        Reviewed by Alp Toker.
     4
     5        http://bugs.webkit.org/show_bug.cgi?id=15610
     6        [GTK] Text rendering using Pango
     7
     8        Use Pango to render Complex path text.
     9
     10        * platform/graphics/gtk/FontGtk.cpp:
     11        (WebCore::utf16_to_utf8):
     12        (WebCore::convertUniCharToUTF8):
     13        (WebCore::setPangoAttributes):
     14        (WebCore::Font::drawGlyphs):
     15        (WebCore::Font::drawComplexText):
     16        (WebCore::Font::floatWidthForComplexText):
     17        (WebCore::Font::offsetForPositionForComplexText):
     18
    1192008-01-08  Timothy Hatcher  <timothy@apple.com>
    220
  • trunk/WebCore/platform/graphics/gtk/FontGtk.cpp

    r29250 r29334  
    22 * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
    33 * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
     4 * Copyright (c) 2007 Hiroyuki Ikezoe
     5 * Copyright (c) 2007 Kouhei Sutou
     6 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
     7 * Copyright (C) 2008 Xan Lopez <xan@gnome.org>
    48 * All rights reserved.
    59 *
     
    3236#include "NotImplemented.h"
    3337#include "SimpleFontData.h"
     38
    3439#include <cairo.h>
     40#include <pango/pango.h>
     41#include <pango/pangocairo.h>
    3542
    3643namespace WebCore {
     44
     45#define IS_HIGH_SURROGATE(u)  ((UChar)(u) >= (UChar)0xd800 && (UChar)(u) <= (UChar)0xdbff)
     46#define IS_LOW_SURROGATE(u)  ((UChar)(u) >= (UChar)0xdc00 && (UChar)(u) <= (UChar)0xdfff)
     47
     48static void utf16_to_utf8(const UChar* aText, gint aLength, char* &text, gint &length)
     49{
     50  gboolean need_copy = FALSE;
     51  int i;
     52
     53  for (i = 0; i < aLength; i++) {
     54    if (!aText[i] || IS_LOW_SURROGATE(aText[i])) {
     55      need_copy = TRUE;
     56      break;
     57    }
     58    else if (IS_HIGH_SURROGATE(aText[i])) {
     59      if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1]))
     60        i++;
     61      else {
     62        need_copy = TRUE;
     63        break;
     64      }
     65    }
     66  }
     67
     68  if (need_copy) {
     69
     70    /* Pango doesn't correctly handle nuls.  We convert them to 0xff. */
     71    /* Also "validate" UTF-16 text to make sure conversion doesn't fail. */
     72
     73    UChar* p = (UChar*)g_memdup(aText, aLength * sizeof(aText[0]));
     74
     75    /* don't need to reset i */
     76    for (i = 0; i < aLength; i++) {
     77      if (!p[i] || IS_LOW_SURROGATE(p[i]))
     78        p[i] = 0xFFFD;
     79      else if (IS_HIGH_SURROGATE(p[i])) {
     80        if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1]))
     81          i++;
     82        else
     83          p[i] = 0xFFFD;
     84      }
     85    }
     86
     87    aText = p;
     88  }
     89
     90  glong items_written;
     91  text = g_utf16_to_utf8(aText, aLength, NULL, &items_written, NULL);
     92  length = items_written;
     93
     94  if (need_copy)
     95    g_free((gpointer)aText);
     96
     97}
     98
     99static gchar* convertUniCharToUTF8(const UChar* characters, gint length, int from, int to)
     100{
     101    gchar* utf8 = 0;
     102    gint new_length = 0;
     103    utf16_to_utf8(characters, length, utf8, new_length);
     104    if (!utf8)
     105        return NULL;
     106
     107    if (from > 0) {
     108        // discard the first 'from' characters
     109        // FIXME: we should do this before the conversion probably
     110        gchar* str_left = g_utf8_offset_to_pointer(utf8, from);
     111        gchar* tmp = g_strdup(str_left);
     112        g_free(utf8);
     113        utf8 = tmp;
     114    }
     115
     116    gchar* pos = utf8;
     117    gint len = strlen(pos);
     118    GString* ret = g_string_new_len(NULL, len);
     119
     120    // replace line break by space
     121    while (len > 0) {
     122        gint index, start;
     123        pango_find_paragraph_boundary(pos, len, &index, &start);
     124        g_string_append_len(ret, pos, index);
     125        if (index == start)
     126            break;
     127        g_string_append_c(ret, ' ');
     128        pos += start;
     129        len -= start;
     130    }
     131    return g_string_free(ret, FALSE);
     132}
     133
     134static void setPangoAttributes(const Font* font, const TextRun& run, PangoLayout* layout)
     135{
     136    PangoAttrList* list = pango_attr_list_new();
     137    PangoAttribute* attr;
     138
     139    attr = pango_attr_size_new_absolute((int)(font->size() * PANGO_SCALE));
     140    attr->end_index = G_MAXUINT;
     141    pango_attr_list_insert_before(list, attr);
     142
     143    if (!run.spacingDisabled()) {
     144        attr = pango_attr_letter_spacing_new(font->letterSpacing() * PANGO_SCALE);
     145        attr->end_index = G_MAXUINT;
     146        pango_attr_list_insert_before(list, attr);
     147    }
     148
     149    // Pango does not yet support synthesising small caps
     150    // See http://bugs.webkit.org/show_bug.cgi?id=15610
     151
     152    pango_layout_set_attributes(layout, list);
     153    pango_attr_list_unref(list);
     154
     155    pango_layout_set_auto_dir(layout, FALSE);
     156
     157    PangoContext* pangoContext = pango_layout_get_context(layout);
     158    PangoDirection direction = run.rtl() ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
     159    pango_context_set_base_dir(pangoContext, direction);
     160}
    37161
    38162void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
    39163                      int from, int numGlyphs, const FloatPoint& point) const
    40164{
    41     cairo_t* context = graphicsContext->platformContext();
     165    cairo_t* cr = graphicsContext->platformContext();
     166    cairo_save(cr);
    42167
    43168    // Set the text color to use for drawing.
     
    45170    Color penColor = graphicsContext->fillColor();
    46171    penColor.getRGBA(red, green, blue, alpha);
    47     cairo_set_source_rgba(context, red, green, blue, alpha);
    48 
    49     // This was commented out as it made "some text invisible" but seems to work now.
    50     font->setFont(context);
    51 
    52     GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*) glyphBuffer.glyphs(from);
     172    cairo_set_source_rgba(cr, red, green, blue, alpha);
     173
     174    font->setFont(cr);
     175
     176    GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from);
    53177
    54178    float offset = point.x();
     
    59183        offset += glyphBuffer.advanceAt(from + i);
    60184    }
    61     cairo_show_glyphs(context, glyphs, numGlyphs);
    62 }
    63 
    64 void Font::drawComplexText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const
    65 {
    66     notImplemented();
    67 }
    68 
    69 float Font::floatWidthForComplexText(const TextRun&) const
    70 {
    71     notImplemented();
    72     return 0.0f;
    73 }
    74 
    75 int Font::offsetForPositionForComplexText(const TextRun&, int, bool) const
    76 {
    77     notImplemented();
    78     return 0;
    79 }
    80 
    81 FloatRect Font::selectionRectForComplexText(const TextRun&, const IntPoint&, int, int, int) const
     185    cairo_show_glyphs(cr, glyphs, numGlyphs);
     186
     187    cairo_restore(cr);
     188}
     189
     190void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
     191{
     192    cairo_t* cr = context->platformContext();
     193    cairo_save(cr);
     194
     195    PangoLayout* layout = pango_cairo_create_layout(cr);
     196
     197    gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), from, to);
     198    pango_layout_set_text(layout, utf8, -1);
     199    g_free(utf8);
     200
     201    setPangoAttributes(this, run, layout);
     202
     203    // Set the text color to use for drawing.
     204    float red, green, blue, alpha;
     205    Color penColor = context->fillColor();
     206    penColor.getRGBA(red, green, blue, alpha);
     207    cairo_set_source_rgba(cr, red, green, blue, alpha);
     208
     209    // Our layouts are single line
     210    cairo_move_to(cr, point.x(), point.y());
     211    PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0);
     212    pango_cairo_show_layout_line(cr, layoutLine);
     213
     214    g_object_unref(layout);
     215    cairo_restore(cr);
     216}
     217
     218// FIXME: we should create the layout with our actual context, but it seems
     219// we can't access it from here
     220static PangoLayout* getDefaultPangoLayout(const TextRun& run)
     221{
     222    PangoFontMap* map = pango_cairo_font_map_get_default();
     223    PangoContext* pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(map));
     224    PangoLayout* layout = pango_layout_new(pangoContext);
     225    g_object_unref(pangoContext);
     226
     227    return layout;
     228}
     229
     230float Font::floatWidthForComplexText(const TextRun& run) const
     231{
     232    if (run.length() == 0)
     233        return 0.0f;
     234
     235    PangoLayout* layout = getDefaultPangoLayout(run);
     236    setPangoAttributes(this, run, layout);
     237
     238    gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
     239    pango_layout_set_text(layout, utf8, -1);
     240    g_free(utf8);
     241
     242    int layoutWidth;
     243    pango_layout_get_size(layout, &layoutWidth, 0);
     244    float width = (float)layoutWidth / (double)PANGO_SCALE;
     245    g_object_unref(layout);
     246
     247    return width;
     248}
     249
     250int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const
     251{
     252    PangoLayout* layout = getDefaultPangoLayout(run);
     253    setPangoAttributes(this, run, layout);
     254
     255    gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
     256    pango_layout_set_text(layout, utf8, -1);
     257
     258    int index, trailing;
     259    pango_layout_xy_to_index(layout, x * PANGO_SCALE, 1, &index, &trailing);
     260    glong offset = g_utf8_pointer_to_offset(utf8, utf8 + index);
     261    g_free(utf8);
     262    g_object_unref(layout);
     263
     264    return offset;
     265}
     266
     267FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
    82268{
    83269    notImplemented();
Note: See TracChangeset for help on using the changeset viewer.