Skip to content
Permalink
Browse files
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):


Canonical link: https://commits.webkit.org/23167@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@29334 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
Alp Toker committed Jan 9, 2008
1 parent a3c0f7b commit a321d18f2bbcf33f1f3a5e4b72864a444a41f735
Showing 2 changed files with 219 additions and 15 deletions.
@@ -1,3 +1,21 @@
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):

2008-01-08 Timothy Hatcher <timothy@apple.com>

Reviewed by Darin Adler.
@@ -1,6 +1,10 @@
/*
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
* Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
* Copyright (c) 2007 Hiroyuki Ikezoe
* Copyright (c) 2007 Kouhei Sutou
* Copyright (C) 2007 Alp Toker <alp@atoker.com>
* Copyright (C) 2008 Xan Lopez <xan@gnome.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,25 +35,145 @@
#include "GraphicsContext.h"
#include "NotImplemented.h"
#include "SimpleFontData.h"

#include <cairo.h>
#include <pango/pango.h>
#include <pango/pangocairo.h>

namespace WebCore {

#define IS_HIGH_SURROGATE(u) ((UChar)(u) >= (UChar)0xd800 && (UChar)(u) <= (UChar)0xdbff)
#define IS_LOW_SURROGATE(u) ((UChar)(u) >= (UChar)0xdc00 && (UChar)(u) <= (UChar)0xdfff)

static void utf16_to_utf8(const UChar* aText, gint aLength, char* &text, gint &length)
{
gboolean need_copy = FALSE;
int i;

for (i = 0; i < aLength; i++) {
if (!aText[i] || IS_LOW_SURROGATE(aText[i])) {
need_copy = TRUE;
break;
}
else if (IS_HIGH_SURROGATE(aText[i])) {
if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1]))
i++;
else {
need_copy = TRUE;
break;
}
}
}

if (need_copy) {

/* Pango doesn't correctly handle nuls. We convert them to 0xff. */
/* Also "validate" UTF-16 text to make sure conversion doesn't fail. */

UChar* p = (UChar*)g_memdup(aText, aLength * sizeof(aText[0]));

/* don't need to reset i */
for (i = 0; i < aLength; i++) {
if (!p[i] || IS_LOW_SURROGATE(p[i]))
p[i] = 0xFFFD;
else if (IS_HIGH_SURROGATE(p[i])) {
if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1]))
i++;
else
p[i] = 0xFFFD;
}
}

aText = p;
}

glong items_written;
text = g_utf16_to_utf8(aText, aLength, NULL, &items_written, NULL);
length = items_written;

if (need_copy)
g_free((gpointer)aText);

}

static gchar* convertUniCharToUTF8(const UChar* characters, gint length, int from, int to)
{
gchar* utf8 = 0;
gint new_length = 0;
utf16_to_utf8(characters, length, utf8, new_length);
if (!utf8)
return NULL;

if (from > 0) {
// discard the first 'from' characters
// FIXME: we should do this before the conversion probably
gchar* str_left = g_utf8_offset_to_pointer(utf8, from);
gchar* tmp = g_strdup(str_left);
g_free(utf8);
utf8 = tmp;
}

gchar* pos = utf8;
gint len = strlen(pos);
GString* ret = g_string_new_len(NULL, len);

// replace line break by space
while (len > 0) {
gint index, start;
pango_find_paragraph_boundary(pos, len, &index, &start);
g_string_append_len(ret, pos, index);
if (index == start)
break;
g_string_append_c(ret, ' ');
pos += start;
len -= start;
}
return g_string_free(ret, FALSE);
}

static void setPangoAttributes(const Font* font, const TextRun& run, PangoLayout* layout)
{
PangoAttrList* list = pango_attr_list_new();
PangoAttribute* attr;

attr = pango_attr_size_new_absolute((int)(font->size() * PANGO_SCALE));
attr->end_index = G_MAXUINT;
pango_attr_list_insert_before(list, attr);

if (!run.spacingDisabled()) {
attr = pango_attr_letter_spacing_new(font->letterSpacing() * PANGO_SCALE);
attr->end_index = G_MAXUINT;
pango_attr_list_insert_before(list, attr);
}

// Pango does not yet support synthesising small caps
// See http://bugs.webkit.org/show_bug.cgi?id=15610

pango_layout_set_attributes(layout, list);
pango_attr_list_unref(list);

pango_layout_set_auto_dir(layout, FALSE);

PangoContext* pangoContext = pango_layout_get_context(layout);
PangoDirection direction = run.rtl() ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
pango_context_set_base_dir(pangoContext, direction);
}

void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
int from, int numGlyphs, const FloatPoint& point) const
{
cairo_t* context = graphicsContext->platformContext();
cairo_t* cr = graphicsContext->platformContext();
cairo_save(cr);

// Set the text color to use for drawing.
float red, green, blue, alpha;
Color penColor = graphicsContext->fillColor();
penColor.getRGBA(red, green, blue, alpha);
cairo_set_source_rgba(context, red, green, blue, alpha);
cairo_set_source_rgba(cr, red, green, blue, alpha);

// This was commented out as it made "some text invisible" but seems to work now.
font->setFont(context);
font->setFont(cr);

GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*) glyphBuffer.glyphs(from);
GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from);

float offset = point.x();

@@ -58,27 +182,89 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo
glyphs[i].y = point.y();
offset += glyphBuffer.advanceAt(from + i);
}
cairo_show_glyphs(context, glyphs, numGlyphs);
cairo_show_glyphs(cr, glyphs, numGlyphs);

cairo_restore(cr);
}

void Font::drawComplexText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const
void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
{
notImplemented();
cairo_t* cr = context->platformContext();
cairo_save(cr);

PangoLayout* layout = pango_cairo_create_layout(cr);

gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), from, to);
pango_layout_set_text(layout, utf8, -1);
g_free(utf8);

setPangoAttributes(this, run, layout);

// Set the text color to use for drawing.
float red, green, blue, alpha;
Color penColor = context->fillColor();
penColor.getRGBA(red, green, blue, alpha);
cairo_set_source_rgba(cr, red, green, blue, alpha);

// Our layouts are single line
cairo_move_to(cr, point.x(), point.y());
PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0);
pango_cairo_show_layout_line(cr, layoutLine);

g_object_unref(layout);
cairo_restore(cr);
}

float Font::floatWidthForComplexText(const TextRun&) const
// FIXME: we should create the layout with our actual context, but it seems
// we can't access it from here
static PangoLayout* getDefaultPangoLayout(const TextRun& run)
{
notImplemented();
return 0.0f;
PangoFontMap* map = pango_cairo_font_map_get_default();
PangoContext* pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(map));
PangoLayout* layout = pango_layout_new(pangoContext);
g_object_unref(pangoContext);

return layout;
}

int Font::offsetForPositionForComplexText(const TextRun&, int, bool) const
float Font::floatWidthForComplexText(const TextRun& run) const
{
notImplemented();
return 0;
if (run.length() == 0)
return 0.0f;

PangoLayout* layout = getDefaultPangoLayout(run);
setPangoAttributes(this, run, layout);

gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
pango_layout_set_text(layout, utf8, -1);
g_free(utf8);

int layoutWidth;
pango_layout_get_size(layout, &layoutWidth, 0);
float width = (float)layoutWidth / (double)PANGO_SCALE;
g_object_unref(layout);

return width;
}

int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const
{
PangoLayout* layout = getDefaultPangoLayout(run);
setPangoAttributes(this, run, layout);

gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
pango_layout_set_text(layout, utf8, -1);

int index, trailing;
pango_layout_xy_to_index(layout, x * PANGO_SCALE, 1, &index, &trailing);
glong offset = g_utf8_pointer_to_offset(utf8, utf8 + index);
g_free(utf8);
g_object_unref(layout);

return offset;
}

FloatRect Font::selectionRectForComplexText(const TextRun&, const IntPoint&, int, int, int) const
FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
{
notImplemented();
return FloatRect();

0 comments on commit a321d18

Please sign in to comment.