#define __NR_ARENA_GLYPHS_C__

/*
 * RGBA display list system for inkscape
 *
 * Author:
 *   Lauris Kaplinski <lauris@kaplinski.com>
 *
 * Copyright (C) 2002 Lauris Kaplinski
 *
 * Released under GNU GPL
 *
 */


#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <libnr/nr-blit.h>
#include <libnr/nr-convert2geom.h>
#include <2geom/matrix.h>
#include "../style.h"
#include "nr-arena.h"
#include "nr-arena-glyphs.h"
#include <cairo.h>
#include "inkscape-cairo.h"

#ifdef test_glyph_liv
#include "../display/canvas-bpath.h"
#include <libnrtype/font-instance.h>
#include <libnrtype/raster-glyph.h>
#include <libnrtype/RasterFont.h>

// defined in nr-arena-shape.cpp
void nr_pixblock_render_shape_mask_or(NRPixBlock &m, Shape *theS);
#endif

#ifdef ENABLE_SVG_FONTS
#include "nr-svgfonts.h"
#endif //#ifdef ENABLE_SVG_FONTS

static void nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass);
static void nr_arena_glyphs_init(NRArenaGlyphs *glyphs);
static void nr_arena_glyphs_finalize(NRObject *object);

static guint nr_arena_glyphs_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
static guint nr_arena_glyphs_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb);
static NRArenaItem *nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky);

static NRArenaItemClass *glyphs_parent_class;

NRType
nr_arena_glyphs_get_type(void)
{
    static NRType type = 0;
    if (!type) {
        type = nr_object_register_type(NR_TYPE_ARENA_ITEM,
                                       "NRArenaGlyphs",
                                       sizeof(NRArenaGlyphsClass),
                                       sizeof(NRArenaGlyphs),
                                       (void (*)(NRObjectClass *)) nr_arena_glyphs_class_init,
                                       (void (*)(NRObject *)) nr_arena_glyphs_init);
    }
    return type;
}

static void
nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass)
{
    NRObjectClass *object_class;
    NRArenaItemClass *item_class;

    object_class = (NRObjectClass *) klass;
    item_class = (NRArenaItemClass *) klass;

    glyphs_parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent;

    object_class->finalize = nr_arena_glyphs_finalize;
    object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphs>;

    item_class->update = nr_arena_glyphs_update;
    item_class->clip = nr_arena_glyphs_clip;
    item_class->pick = nr_arena_glyphs_pick;
}

static void
nr_arena_glyphs_init(NRArenaGlyphs *glyphs)
{
    glyphs->style = NULL;
    glyphs->g_transform.setIdentity();
    glyphs->font = NULL;
    glyphs->glyph = 0;

    glyphs->rfont = NULL;
    glyphs->sfont = NULL;
    glyphs->x = glyphs->y = 0.0;
}

static void
nr_arena_glyphs_finalize(NRObject *object)
{
    NRArenaGlyphs *glyphs = static_cast<NRArenaGlyphs *>(object);

    if (glyphs->rfont) {
        glyphs->rfont->Unref();
        glyphs->rfont=NULL;
    }
    if (glyphs->sfont) {
        glyphs->sfont->Unref();
        glyphs->sfont=NULL;
    }

    if (glyphs->font) {
        glyphs->font->Unref();
        glyphs->font=NULL;
    }

    if (glyphs->style) {
        sp_style_unref(glyphs->style);
        glyphs->style = NULL;
    }

    ((NRObjectClass *) glyphs_parent_class)->finalize(object);
}

static guint
nr_arena_glyphs_update(NRArenaItem *item, NRRectL */*area*/, NRGC *gc, guint /*state*/, guint /*reset*/)
{
    NRArenaGlyphs *glyphs;
    raster_font *rfont;

    glyphs = NR_ARENA_GLYPHS(item);

    if (!glyphs->font || !glyphs->style)
        return NR_ARENA_ITEM_STATE_ALL;
    if ((glyphs->style->fill.isNone()) && (glyphs->style->stroke.isNone()))
        return NR_ARENA_ITEM_STATE_ALL;

    NRRect bbox;
    bbox.x0 = bbox.y0 = NR_HUGE;
    bbox.x1 = bbox.y1 = -NR_HUGE;

    float const scale = gc->transform.descrim();

    if (!glyphs->style->fill.isNone()) {
        Geom::Matrix t;
        t = glyphs->g_transform * gc->transform;
        glyphs->x = t[4];
        glyphs->y = t[5];
        t[4]=0;
        t[5]=0;
        rfont = glyphs->font->RasterFont(t, 0);
        if (glyphs->rfont) glyphs->rfont->Unref();
        glyphs->rfont = rfont;

        if (glyphs->style->stroke.isNone() || fabs(glyphs->style->stroke_width.computed * scale) <= 0.01) { // Optimization: do fill bbox only if there's no stroke
            NRRect narea;
            if ( glyphs->rfont ) glyphs->rfont->BBox(glyphs->glyph, &narea);
            bbox.x0 = narea.x0 + glyphs->x;
            bbox.y0 = narea.y0 + glyphs->y;
            bbox.x1 = narea.x1 + glyphs->x;
            bbox.y1 = narea.y1 + glyphs->y;
        }
    }

    if (!glyphs->style->stroke.isNone()) {
        /* Build state data */
        Geom::Matrix t;
        t = glyphs->g_transform * gc->transform;
        glyphs->x = t[4];
        glyphs->y = t[5];
        t[4]=0;
        t[5]=0;

        if ( fabs(glyphs->style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord
            font_style nstyl;
            nstyl.transform = t;
            nstyl.stroke_width=MAX(0.125, glyphs->style->stroke_width.computed * scale);
            if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_BUTT ) nstyl.stroke_cap=butt_straight;
            if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_ROUND ) nstyl.stroke_cap=butt_round;
            if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_SQUARE ) nstyl.stroke_cap=butt_square;
            if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_MITER ) nstyl.stroke_join=join_pointy;
            if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_ROUND ) nstyl.stroke_join=join_round;
            if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_BEVEL ) nstyl.stroke_join=join_straight;
            nstyl.stroke_miter_limit = glyphs->style->stroke_miterlimit.value;
            nstyl.nbDash=0;
            nstyl.dash_offset = 0;
            nstyl.dashes=NULL;
            if ( glyphs->style->stroke_dash.n_dash > 0 ) {
                nstyl.dash_offset = glyphs->style->stroke_dash.offset * scale;
                nstyl.nbDash=glyphs->style->stroke_dash.n_dash;
                nstyl.dashes=(double*)malloc(nstyl.nbDash*sizeof(double));
                for (int i = 0; i < nstyl.nbDash; i++) nstyl.dashes[i]= glyphs->style->stroke_dash.dash[i] * scale;
            }
            rfont = glyphs->font->RasterFont( nstyl);
            if ( nstyl.dashes ) free(nstyl.dashes);
            if (glyphs->sfont) glyphs->sfont->Unref();
            glyphs->sfont = rfont;

            NRRect narea;
            if ( glyphs->sfont ) glyphs->sfont->BBox(glyphs->glyph, &narea);
            narea.x0-=nstyl.stroke_width;
            narea.y0-=nstyl.stroke_width;
            narea.x1+=nstyl.stroke_width;
            narea.y1+=nstyl.stroke_width;
            bbox.x0 = narea.x0 + glyphs->x;
            bbox.y0 = narea.y0 + glyphs->y;
            bbox.x1 = narea.x1 + glyphs->x;
            bbox.y1 = narea.y1 + glyphs->y;
        }
    }
    if (nr_rect_d_test_empty(bbox)) return NR_ARENA_ITEM_STATE_ALL;

    item->bbox.x0 = static_cast<NR::ICoord>(floor(bbox.x0));
    item->bbox.y0 = static_cast<NR::ICoord>(floor(bbox.y0));
    item->bbox.x1 = static_cast<NR::ICoord>(ceil (bbox.x1));
    item->bbox.y1 = static_cast<NR::ICoord>(ceil (bbox.y1));

    return NR_ARENA_ITEM_STATE_ALL;
}

static guint
nr_arena_glyphs_clip(NRArenaItem *item, NRRectL */*area*/, NRPixBlock */*pb*/)
{
    NRArenaGlyphs *glyphs;

    glyphs = NR_ARENA_GLYPHS(item);

    if (!glyphs->font ) return item->state;

    /* TODO : render to greyscale pixblock provided for clipping */

    return item->state;
}

static NRArenaItem *
nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned int /*sticky*/)
{
    NRArenaGlyphs *glyphs;

    glyphs = NR_ARENA_GLYPHS(item);

    if (!glyphs->font ) return NULL;
    if (!glyphs->style) return NULL;

    double const x = p[Geom::X];
    double const y = p[Geom::Y];
    /* With text we take a simple approach: pick if the point is in a characher bbox */
    if ((x + delta >= item->bbox.x0) && (y + delta >= item->bbox.y0) && (x - delta <= item->bbox.x1) && (y - delta <= item->bbox.y1)) return item;

    return NULL;
}

void
nr_arena_glyphs_set_path(NRArenaGlyphs *glyphs, SPCurve */*curve*/, unsigned int /*lieutenant*/, font_instance *font, gint glyph, Geom::Matrix const *transform)
{
    nr_return_if_fail(glyphs != NULL);
    nr_return_if_fail(NR_IS_ARENA_GLYPHS(glyphs));

    nr_arena_item_request_render(NR_ARENA_ITEM(glyphs));

    if (transform) {
        glyphs->g_transform = *transform;
    } else {
        glyphs->g_transform.setIdentity();
    }

    if (font) font->Ref();
    if (glyphs->font) glyphs->font->Unref();
    glyphs->font=font;
    glyphs->glyph = glyph;

    nr_arena_item_request_update(NR_ARENA_ITEM(glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE);
}

void
nr_arena_glyphs_set_style(NRArenaGlyphs *glyphs, SPStyle *style)
{
    nr_return_if_fail(glyphs != NULL);
    nr_return_if_fail(NR_IS_ARENA_GLYPHS(glyphs));

    if (style) sp_style_ref(style);
    if (glyphs->style) sp_style_unref(glyphs->style);
    glyphs->style = style;

    nr_arena_item_request_update(NR_ARENA_ITEM(glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE);
}

static guint
nr_arena_glyphs_fill_mask(NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m)
{
    /* fixme: area == m->area, so merge these */

    NRArenaItem *item = NR_ARENA_ITEM(glyphs);

    if (glyphs->rfont && nr_rect_l_test_intersect_ptr(area, &item->bbox)) {
        raster_glyph *g = glyphs->rfont->GetGlyph(glyphs->glyph);
        if ( g ) g->Blit(Geom::Point(glyphs->x, glyphs->y), *m);
    }

    return item->state;
}

static guint
nr_arena_glyphs_stroke_mask(NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m)
{
    NRArenaItem *item = NR_ARENA_ITEM(glyphs);
    if (glyphs->sfont && nr_rect_l_test_intersect_ptr(area, &item->bbox)) {
        raster_glyph *g=glyphs->sfont->GetGlyph(glyphs->glyph);
        if ( g ) g->Blit(Geom::Point(glyphs->x, glyphs->y),*m);
    }

    return item->state;
}

static void nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass);
static void nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group);
static void nr_arena_glyphs_group_finalize(NRObject *object);

static guint nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
static unsigned int nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
static unsigned int nr_arena_glyphs_group_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb);
static NRArenaItem *nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned int sticky);

static NRArenaGroupClass *group_parent_class;

NRType
nr_arena_glyphs_group_get_type(void)
{
    static NRType type = 0;
    if (!type) {
        type = nr_object_register_type(NR_TYPE_ARENA_GROUP,
                                       "NRArenaGlyphsGroup",
                                       sizeof(NRArenaGlyphsGroupClass),
                                       sizeof(NRArenaGlyphsGroup),
                                       (void (*)(NRObjectClass *)) nr_arena_glyphs_group_class_init,
                                       (void (*)(NRObject *)) nr_arena_glyphs_group_init);
    }
    return type;
}

static void
nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass)
{
    NRObjectClass *object_class;
    NRArenaItemClass *item_class;

    object_class = (NRObjectClass *) klass;
    item_class = (NRArenaItemClass *) klass;

    group_parent_class = (NRArenaGroupClass *) ((NRObjectClass *) klass)->parent;

    object_class->finalize = nr_arena_glyphs_group_finalize;
    object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphsGroup>;

    item_class->update = nr_arena_glyphs_group_update;
    item_class->render = nr_arena_glyphs_group_render;
    item_class->clip = nr_arena_glyphs_group_clip;
    item_class->pick = nr_arena_glyphs_group_pick;
}

static void
nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group)
{
    group->style = NULL;
    group->paintbox.x0 = group->paintbox.y0 = 0.0F;
    group->paintbox.x1 = group->paintbox.y1 = 1.0F;

    group->fill_painter = NULL;
    group->stroke_painter = NULL;
}

static void
nr_arena_glyphs_group_finalize(NRObject *object)
{
    NRArenaGlyphsGroup *group=static_cast<NRArenaGlyphsGroup *>(object);

    if (group->fill_painter) {
        sp_painter_free(group->fill_painter);
        group->fill_painter = NULL;
    }

    if (group->stroke_painter) {
        sp_painter_free(group->stroke_painter);
        group->stroke_painter = NULL;
    }

    if (group->style) {
        sp_style_unref(group->style);
        group->style = NULL;
    }

    ((NRObjectClass *) group_parent_class)->finalize(object);
}

static guint
nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset)
{
    NRArenaGlyphsGroup *group = NR_ARENA_GLYPHS_GROUP(item);

    if (group->fill_painter) {
        sp_painter_free(group->fill_painter);
        group->fill_painter = NULL;
    }

    if (group->stroke_painter) {
        sp_painter_free(group->stroke_painter);
        group->stroke_painter = NULL;
    }

    item->render_opacity = TRUE;
    if (group->style->fill.isPaintserver()) {
        group->fill_painter = sp_paint_server_painter_new(SP_STYLE_FILL_SERVER(group->style),
                                                          gc->transform, gc->parent->transform,
                                                          &group->paintbox);
        item->render_opacity = FALSE;
    }

    if (group->style->stroke.isPaintserver()) {
        group->stroke_painter = sp_paint_server_painter_new(SP_STYLE_STROKE_SERVER(group->style),
                                                            gc->transform, gc->parent->transform,
                                                            &group->paintbox);
        item->render_opacity = FALSE;
    }

    if ( item->render_opacity == TRUE && !group->style->stroke.isNone() && !group->style->fill.isNone() ) {
        item->render_opacity=FALSE;
    }

    if (((NRArenaItemClass *) group_parent_class)->update)
        return ((NRArenaItemClass *) group_parent_class)->update(item, area, gc, state, reset);

    return NR_ARENA_ITEM_STATE_ALL;
}


static unsigned int
nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int /*flags*/)
{
    NRArenaItem *child;

    NRArenaGroup *group = NR_ARENA_GROUP(item);
    NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item);
    SPStyle const *style = ggroup->style;

    guint ret = item->state;
    bool print_colors_preview = (item->arena->rendermode == Inkscape::RENDERMODE_PRINT_COLORS_PREVIEW);

    if (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) {

        if (!ct)
            return item->state;

        guint32 rgba = item->arena->outlinecolor;
        // FIXME: we use RGBA buffers but cairo writes BGRA (on i386), so we must cheat
        // by setting color channels in the "wrong" order
        cairo_set_source_rgba(ct, SP_RGBA32_B_F(rgba), SP_RGBA32_G_F(rgba), SP_RGBA32_R_F(rgba), SP_RGBA32_A_F(rgba));
        cairo_set_tolerance(ct, 1.25); // low quality, but good enough for outline mode

        for (child = group->children; child != NULL; child = child->next) {
            NRArenaGlyphs *g = NR_ARENA_GLYPHS(child);

            Geom::PathVector const * pathv = g->font->PathVector(g->glyph);

            cairo_new_path(ct);
            Geom::Matrix transform = g->g_transform * group->ctm;
            feed_pathvector_to_cairo (ct, *pathv, transform, to_2geom((pb->area).upgrade()), false, 0);
            cairo_fill(ct);
            pb->empty = FALSE;
        }

        return ret;
    }



    /* Fill */
    if (!style->fill.isNone() || item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) {
        NRPixBlock m;
        nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);

        // if memory allocation failed, abort
        if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) {
            nr_pixblock_release (&m);
            return (item->state);
        }

        m.visible_area = pb->visible_area;

        /* Render children fill mask */
        for (child = group->children; child != NULL; child = child->next) {
            ret = nr_arena_glyphs_fill_mask(NR_ARENA_GLYPHS(child), area, &m);
            if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) {
                nr_pixblock_release(&m);
                return ret;
            }
        }

        /* Composite into buffer */
        if (style->fill.isPaintserver()) {
            if (ggroup->fill_painter) {
                nr_arena_render_paintserver_fill(pb, area, ggroup->fill_painter, SP_SCALE24_TO_FLOAT(style->fill_opacity.value), &m);
            }
        } else if (style->fill.isColor() || item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) {
            guint32 rgba;
            if (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) {
                // In outline mode, render fill only, using outlinecolor
                rgba = item->arena->outlinecolor;
            } else if ( item->render_opacity ) {
                rgba = style->fill.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->fill_opacity.value) *
                                                         SP_SCALE24_TO_FLOAT(style->opacity.value) );
            } else {
                rgba = style->fill.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->fill_opacity.value) );
            }

            if (print_colors_preview)
                nr_arena_separate_color_plates(&rgba);

            nr_blit_pixblock_mask_rgba32(pb, &m, rgba);
            pb->empty = FALSE;
        }

        nr_pixblock_release(&m);
    }

    /* Stroke */
    if (!style->stroke.isNone() && !(item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE)) {
        NRPixBlock m;
        guint32 rgba;
        nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);

        // if memory allocation failed, abort
        if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) {
            nr_pixblock_release (&m);
            return (item->state);
        }

        m.visible_area = pb->visible_area;
        /* Render children stroke mask */
        for (child = group->children; child != NULL; child = child->next) {
            ret = nr_arena_glyphs_stroke_mask(NR_ARENA_GLYPHS(child), area, &m);
            if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) {
                nr_pixblock_release(&m);
                return ret;
            }
        }
        /* Composite into buffer */
        if (style->stroke.isPaintserver()) {
            if (ggroup->stroke_painter) {
                nr_arena_render_paintserver_fill(pb, area, ggroup->stroke_painter, SP_SCALE24_TO_FLOAT(style->stroke_opacity.value), &m);
            }
        } else if (style->stroke.isColor()) {
            if ( item->render_opacity ) {
                rgba = style->stroke.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->stroke_opacity.value) *
                                                           SP_SCALE24_TO_FLOAT(style->opacity.value) );
            } else {
                rgba = style->stroke.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->stroke_opacity.value) );
            }

            if (print_colors_preview)
                nr_arena_separate_color_plates(&rgba);

            nr_blit_pixblock_mask_rgba32(pb, &m, rgba);
            pb->empty = FALSE;
        } else {
            // nothing
        }
        nr_pixblock_release(&m);
    }

    return ret;
}

static unsigned int
nr_arena_glyphs_group_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb)
{
    NRArenaGroup *group = NR_ARENA_GROUP(item);

    guint ret = item->state;

    /* Render children fill mask */
    for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
        ret = nr_arena_glyphs_fill_mask(NR_ARENA_GLYPHS(child), area, pb);
        if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) return ret;
    }

    return ret;
}

static NRArenaItem *
nr_arena_glyphs_group_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned int sticky)
{
    NRArenaItem *picked = NULL;

    if (((NRArenaItemClass *) group_parent_class)->pick)
        picked = ((NRArenaItemClass *) group_parent_class)->pick(item, p, delta, sticky);

    if (picked) picked = item;

    return picked;
}

void
nr_arena_glyphs_group_clear(NRArenaGlyphsGroup *sg)
{
    NRArenaGroup *group = NR_ARENA_GROUP(sg);

    nr_arena_item_request_render(NR_ARENA_ITEM(group));

    while (group->children) {
        nr_arena_item_remove_child(NR_ARENA_ITEM(group), group->children);
    }
}

void
nr_arena_glyphs_group_add_component(NRArenaGlyphsGroup *sg, font_instance *font, int glyph, Geom::Matrix const &transform)
{
    NRArenaGroup *group;

    group = NR_ARENA_GROUP(sg);

    Geom::PathVector const * pathv = ( font
                                       ? font->PathVector(glyph)
                                       : NULL );
    if ( pathv ) {
        nr_arena_item_request_render(NR_ARENA_ITEM(group));

        NRArenaItem *new_arena = NRArenaGlyphs::create(group->arena);
        nr_arena_item_append_child(NR_ARENA_ITEM(group), new_arena);
        nr_arena_item_unref(new_arena);
        nr_arena_glyphs_set_path(NR_ARENA_GLYPHS(new_arena), NULL, FALSE, font, glyph, &transform);
        nr_arena_glyphs_set_style(NR_ARENA_GLYPHS(new_arena), sg->style);
    }
}

void
nr_arena_glyphs_group_set_style(NRArenaGlyphsGroup *sg, SPStyle *style)
{
    nr_return_if_fail(sg != NULL);
    nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(sg));

    NRArenaGroup *group = NR_ARENA_GROUP(sg);

    if (style) sp_style_ref(style);
    if (sg->style) sp_style_unref(sg->style);
    sg->style = style;

    for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
        nr_return_if_fail(NR_IS_ARENA_GLYPHS(child));
        nr_arena_glyphs_set_style(NR_ARENA_GLYPHS(child), sg->style);
    }

    nr_arena_item_request_update(NR_ARENA_ITEM(sg), NR_ARENA_ITEM_STATE_ALL, FALSE);
}

void
nr_arena_glyphs_group_set_paintbox(NRArenaGlyphsGroup *gg, NRRect const *pbox)
{
    nr_return_if_fail(gg != NULL);
    nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(gg));
    nr_return_if_fail(pbox != NULL);

    if ((pbox->x0 < pbox->x1) && (pbox->y0 < pbox->y1)) {
        gg->paintbox.x0 = pbox->x0;
        gg->paintbox.y0 = pbox->y0;
        gg->paintbox.x1 = pbox->x1;
        gg->paintbox.y1 = pbox->y1;
    } else {
        /* fixme: We kill warning, although not sure what to do here (Lauris) */
        gg->paintbox.x0 = gg->paintbox.y0 = 0.0F;
        gg->paintbox.x1 = gg->paintbox.y1 = 256.0F;
    }

    nr_arena_item_request_update(NR_ARENA_ITEM(gg), NR_ARENA_ITEM_STATE_ALL, FALSE);
}


/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
  indent-tabs-mode:nil
  fill-column:99
  End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
