ps_font* PICAPI ps_font_create(const char* name, ps_charset c, float s, int w, ps_bool i)
{
    if (!picasso::is_valid_system_device()) {
        global_status = STATUS_DEVICE_ERROR;
        return 0;
    }

    if (!name) {
        global_status = STATUS_INVALID_ARGUMENT;
        return 0;
    }

    ps_font* f = (ps_font*)mem_malloc(sizeof(ps_font));
    if (f) {
        f->refcount = 1;
        new ((void*)&(f->desc)) picasso::font_desc(name);
        f->desc.set_charset(c);
        f->desc.set_height(FLT_TO_SCALAR(s));
        f->desc.set_weight(FLT_TO_SCALAR(w));
        f->desc.set_italic(i ? true: false);
        f->desc.set_hint(true);
        f->desc.set_flip_y(true);
        global_status = STATUS_SUCCEED;
        return f;
    } else {
        global_status = STATUS_OUT_OF_MEMORY;
        return 0;
    }
}
void PICAPI ps_show_glyphs(ps_context* ctx, float x, float y, ps_glyph* g, unsigned int len)
{
    if (!picasso::is_valid_system_device()) {
        global_status = STATUS_DEVICE_ERROR;
        return;
    }

    if (!ctx || !g || !len) {
        global_status = STATUS_INVALID_ARGUMENT;
        return;
    }

    scalar gx = FLT_TO_SCALAR(x);
    scalar gy = FLT_TO_SCALAR(y);

    if (create_device_font(ctx)) {
        gy += ctx->fonts->current_font()->ascent();
        for (unsigned int i = 0; i < len; i++) {
            const picasso::glyph* glyph = (const picasso::glyph*)g[i].glyph;
            if (glyph) {
                if (ctx->font_kerning)
                    ctx->fonts->current_font()->add_kerning(&gx, &gy);
                if (ctx->fonts->current_font()->generate_raster(glyph, gx, gy)) 
                   ctx->canvas->p->render_glyph(ctx->state, ctx->raster, ctx->fonts->current_font(), glyph->type);

                gx += glyph->advance_x;
                gy += glyph->advance_y;
            }
        }
        ctx->canvas->p->render_glyphs_raster(ctx->state, ctx->raster, ctx->font_render_type);
    }
    global_status = STATUS_SUCCEED;
}
Example #3
0
ps_bool PICAPI ps_path_contains(const ps_path* path, const ps_point* p, ps_fill_rule rule)
{
    if (!picasso::is_valid_system_device()) {
        global_status = STATUS_DEVICE_ERROR;
        return False;
    }

    if (!path || !p) {
        global_status = STATUS_INVALID_ARGUMENT;
        return False;
    }

    if (!path->path.total_vertices()) {
        global_status = STATUS_SUCCEED;
        return False;
    }

    ps_rect br = picasso::_path_bounding_rect(path->path);
    if ((p->x < br.x) || (p->y < br.y) || (p->x > (br.x+br.w)) || (p->y > (br.y+br.h))) {
        //out of bounding rect
        global_status = STATUS_SUCCEED;
        return False;
    }

    global_status = STATUS_SUCCEED;
    return picasso::raster_adapter::fill_contents_point(path->path,
                FLT_TO_SCALAR(p->x), FLT_TO_SCALAR(p->y), (picasso::filling_rule)rule) ? True : False;
}
Example #4
0
//curve4_inc
void curve4_inc::init(scalar x1, scalar y1, scalar x2, scalar y2, scalar x3, scalar y3, scalar x4, scalar y4)
{
    m_start_x = x1;
    m_start_y = y1;
    m_end_x   = x4;
    m_end_y   = y4;

    scalar dx1 = x2 - x1;
    scalar dy1 = y2 - y1;
    scalar dx2 = x3 - x2;
    scalar dy2 = y3 - y2;
    scalar dx3 = x4 - x3;
    scalar dy3 = y4 - y3;

    scalar len = (Sqrt(dx1 * dx1 + dy1 * dy1) +
                  Sqrt(dx2 * dx2 + dy2 * dy2) +
                  Sqrt(dx3 * dx3 + dy3 * dy3)) * FLT_TO_SCALAR(0.25f) * m_scale;

    m_num_steps = uround(len);

    if (m_num_steps < 4) {
        m_num_steps = 4;
    }

    scalar subdivide_step  = FLT_TO_SCALAR(1.0f) / m_num_steps;
    scalar subdivide_step2 = subdivide_step * subdivide_step;
    scalar subdivide_step3 = subdivide_step * subdivide_step * subdivide_step;

    scalar pre1 = FLT_TO_SCALAR(3.0f) * subdivide_step;
    scalar pre2 = FLT_TO_SCALAR(3.0f) * subdivide_step2;
    scalar pre4 = FLT_TO_SCALAR(6.0f) * subdivide_step2;
    scalar pre5 = FLT_TO_SCALAR(6.0f) * subdivide_step3;

    scalar tmp1x = x1 - x2 * FLT_TO_SCALAR(2.0f) + x3;
    scalar tmp1y = y1 - y2 * FLT_TO_SCALAR(2.0f) + y3;

    scalar tmp2x = (x2 - x3) * FLT_TO_SCALAR(3.0f) - x1 + x4;
    scalar tmp2y = (y2 - y3) * FLT_TO_SCALAR(3.0f) - y1 + y4;

    m_saved_fx = m_fx = x1;
    m_saved_fy = m_fy = y1;

    m_saved_dfx = m_dfx = (x2 - x1) * pre1 + tmp1x * pre2 + tmp2x * subdivide_step3;
    m_saved_dfy = m_dfy = (y2 - y1) * pre1 + tmp1y * pre2 + tmp2y * subdivide_step3;

    m_saved_ddfx = m_ddfx = tmp1x * pre4 + tmp2x * pre5;
    m_saved_ddfy = m_ddfy = tmp1y * pre4 + tmp2y * pre5;

    m_dddfx = tmp2x * pre5;
    m_dddfy = tmp2y * pre5;

    m_step = m_num_steps;
}
Example #5
0
void PICAPI ps_path_move_to(ps_path* path, const ps_point* p)
{
    if (!picasso::is_valid_system_device()) {
        global_status = STATUS_DEVICE_ERROR;
        return;
    }

    if (!path || !p) {
        global_status = STATUS_INVALID_ARGUMENT;
        return;
    }
    path->path.move_to(FLT_TO_SCALAR(p->x), FLT_TO_SCALAR(p->y));
    global_status = STATUS_SUCCEED;
}
void PICAPI ps_set_text_stroke_color(ps_context* ctx, const ps_color* c)
{
    if (!picasso::is_valid_system_device()) {
        global_status = STATUS_DEVICE_ERROR;
        return;
    }

    if (!ctx || !c) {
        global_status = STATUS_INVALID_ARGUMENT;
        return;
    }

    ctx->state->font_scolor =
         picasso::rgba(FLT_TO_SCALAR(c->r), FLT_TO_SCALAR(c->g), FLT_TO_SCALAR(c->b), FLT_TO_SCALAR(c->a));
    global_status = STATUS_SUCCEED;
}
void PICAPI ps_mask_add_color_filter(ps_mask* mask, const ps_color* c)
{
    if (!picasso::is_valid_system_device()) {
        global_status = STATUS_DEVICE_ERROR;
        return;
    }

    if (!mask || !c) {
        global_status = STATUS_INVALID_ARGUMENT;
        return;
    }

    mask->mask.set_mask_type(MASK_COLORS);
    mask->mask.add_filter_color(picasso::rgba(FLT_TO_SCALAR(c->r), 
                FLT_TO_SCALAR(c->g), FLT_TO_SCALAR(c->b), FLT_TO_SCALAR(c->a))); 
    global_status = STATUS_SUCCEED;
}
Example #8
0
//curve3_div
void curve3_div::init(scalar x1, scalar y1, scalar x2, scalar y2, scalar x3, scalar y3)
{
    m_points.clear();
    m_distance_tolerance_square = FLT_TO_SCALAR(0.5f) / m_approximation_scale;
    m_distance_tolerance_square *= m_distance_tolerance_square;
    bezier(x1, y1, x2, y2, x3, y3);
    m_count = 0;
}
void gfx_gradient_adapter::init_radial(int spread, scalar x1, scalar y1, scalar radius1,
                                           scalar x2, scalar y2, scalar radius2)
{
    if (!m_wrapper) {
        if ((x1 == x2) && (y1 == y2)) {
            switch (spread) {
                case SPREAD_PAD:
                    m_wrapper = new gfx_gradient<gradient_radial,
                                             gradient_pad_adaptor<gradient_radial> >;
                    break;
                case SPREAD_REPEAT:
                    m_wrapper = new gfx_gradient<gradient_radial,
                                             gradient_repeat_adaptor<gradient_radial> >;
                    break;
                case SPREAD_REFLECT:
                    m_wrapper = new gfx_gradient<gradient_radial,
                                             gradient_reflect_adaptor<gradient_radial> >;
                    break;
            }
        } else {
            switch (spread) {
                case SPREAD_PAD:
                    m_wrapper = new gfx_gradient<gradient_radial_focus,
                                             gradient_pad_adaptor<gradient_radial_focus> >;
                    break;
                case SPREAD_REPEAT:
                    m_wrapper = new gfx_gradient<gradient_radial_focus,
                                             gradient_repeat_adaptor<gradient_radial_focus> >;
                    break;
                case SPREAD_REFLECT:
                    m_wrapper = new gfx_gradient<gradient_radial_focus,
                                             gradient_reflect_adaptor<gradient_radial_focus> >;
                    break;
            }

        }

        if (!m_wrapper)
            return;

        scalar len = Fabs(radius2);
        scalar fx = x1 - x2;
        scalar fy = y1 - y2;

        m_wrapper->init(len, fx, fy);

        if (!len)
            len = FLT_TO_SCALAR(2.0f); // len can not be zero

        gfx_trans_affine mtx;
        mtx.translate(x1 - fx, y1 - fy);


        m_start = Fabs(radius1);
        m_length = len;
        m_matrix = mtx;
    }
}
Example #10
0
void PICAPI ps_path_add_rect(ps_path* path, const ps_rect* r)
{
    if (!picasso::is_valid_system_device()) {
        global_status = STATUS_DEVICE_ERROR;
        return;
    }

    if (!path || !r) {
        global_status = STATUS_INVALID_ARGUMENT;
        return;
    }

    path->path.move_to(FLT_TO_SCALAR(r->x), FLT_TO_SCALAR(r->y));
    path->path.hline_rel(FLT_TO_SCALAR(r->w));
    path->path.vline_rel(FLT_TO_SCALAR(r->h));
    path->path.hline_rel(-FLT_TO_SCALAR(r->w));
    path->path.end_poly();
    global_status = STATUS_SUCCEED;
}
Example #11
0
void PICAPI ps_path_bezier_to(ps_path* path, const ps_point* cp1, const ps_point* cp2, const ps_point* ep)
{
    if (!picasso::is_valid_system_device()) {
        global_status = STATUS_DEVICE_ERROR;
        return;
    }

    if (!path || !cp1 || !cp2 || !ep) {
        global_status = STATUS_INVALID_ARGUMENT;
        return;
    }

    picasso::curve4 c(path->path.last_x(), path->path.last_y(), FLT_TO_SCALAR(cp1->x), FLT_TO_SCALAR(cp1->y),
                    FLT_TO_SCALAR(cp2->x), FLT_TO_SCALAR(cp2->y), FLT_TO_SCALAR(ep->x), FLT_TO_SCALAR(ep->y));
    if (picasso::_is_closed_path(path->path))
        path->path.concat_path(c, 0);
    else
        path->path.join_path(c, 0);
    global_status = STATUS_SUCCEED;
}
Example #12
0
void PICAPI ps_path_add_ellipse(ps_path* path, const ps_rect* r)
{
    if (!picasso::is_valid_system_device()) {
        global_status = STATUS_DEVICE_ERROR;
        return;
    }

    if (!path || !r) {
        global_status = STATUS_INVALID_ARGUMENT;
        return;
    }

    picasso::ellipse e(FLT_TO_SCALAR(r->x+r->w/2), FLT_TO_SCALAR(r->y+r->h/2),
                            FLT_TO_SCALAR(r->w/2), FLT_TO_SCALAR(r->h/2));
    if (picasso::_is_closed_path(path->path))
        path->path.concat_path(e, 0);
    else
        path->path.join_path(e, 0);
    global_status = STATUS_SUCCEED;
}
void PICAPI ps_image_set_transparent_color(ps_image* img, const ps_color* c)
{
    if (!picasso::is_valid_system_device()) {
        global_status = STATUS_DEVICE_ERROR;
        return;
    }

    if (!img) {
        global_status = STATUS_INVALID_ARGUMENT;
        return;
    }
    
    if (!c) {
        img->buffer.clear_color_channel(); 
    } else {
        img->buffer.set_color_channel(picasso::rgba(FLT_TO_SCALAR(c->r),
                        FLT_TO_SCALAR(c->g),FLT_TO_SCALAR(c->b),FLT_TO_SCALAR(c->a)));
    }
    global_status = STATUS_SUCCEED;
}
Example #14
0
void PICAPI ps_path_add_arc(ps_path* path, const ps_point* cp, float r, float sa, float ea, ps_bool cw)
{
    if (!picasso::is_valid_system_device()) {
        global_status = STATUS_DEVICE_ERROR;
        return;
    }

    if (!path || !cp) {
        global_status = STATUS_INVALID_ARGUMENT;
        return;
    }

    if (r <= 0.0f) {
        global_status = STATUS_SUCCEED;
        return;
    }

    picasso::arc a(FLT_TO_SCALAR(cp->x), FLT_TO_SCALAR(cp->y), FLT_TO_SCALAR(r), FLT_TO_SCALAR(r),
                FLT_TO_SCALAR(sa), FLT_TO_SCALAR(ea), (cw ? true : false));

    if (picasso::_is_closed_path(path->path))
        path->path.concat_path(a, 0);
    else
        path->path.join_path(a, 0);
    global_status = STATUS_SUCCEED;
}
void PICAPI ps_wide_text_out_length(ps_context* ctx, float x, float y, const ps_uchar16* text, unsigned int len)
{
    if (!picasso::is_valid_system_device()) {
        global_status = STATUS_DEVICE_ERROR;
        return;
    }

    if (!ctx || !text || !len) {
        global_status = STATUS_INVALID_ARGUMENT;
        return;
    }

    scalar gx = FLT_TO_SCALAR(x);
    scalar gy = FLT_TO_SCALAR(y);

    if (create_device_font(ctx)) {
        gy += ctx->fonts->current_font()->ascent();

        const ps_uchar16* p = text;
        while (*p && len) {
            register ps_uchar16 c = *p;
            const picasso::glyph* glyph = ctx->fonts->current_font()->get_glyph(c);
            if (glyph) {
                if (ctx->font_kerning)
                    ctx->fonts->current_font()->add_kerning(&gx, &gy);
                if (ctx->fonts->current_font()->generate_raster(glyph, gx, gy)) 
                   ctx->canvas->p->render_glyph(ctx->state, ctx->raster, ctx->fonts->current_font(), glyph->type);

                gx += glyph->advance_x;
                gy += glyph->advance_y;
            }
            len--;
            p++;
        }
        ctx->canvas->p->render_glyphs_raster(ctx->state, ctx->raster, ctx->font_render_type);
    }
    global_status = STATUS_SUCCEED;
}
// gfx gradient adapter
void gfx_gradient_adapter::init_linear(int spread, scalar x1, scalar y1, scalar x2, scalar y2)
{
    if (!m_wrapper) {
        switch (spread) {
            case SPREAD_PAD:
                m_wrapper = new gfx_gradient<gradient_x, gradient_pad_adaptor<gradient_x> >;
                break;
            case SPREAD_REPEAT:
                m_wrapper = new gfx_gradient<gradient_x, gradient_repeat_adaptor<gradient_x> >;
                break;
            case SPREAD_REFLECT:
                m_wrapper = new gfx_gradient<gradient_x, gradient_reflect_adaptor<gradient_x> >;
                break;
        };

        if (!m_wrapper)
            return;

        scalar len = calc_distance(x1, y1, x2, y2);

        gfx_trans_affine mtx;
        if (len) {
            if (x2 < x1)
                mtx.rotate(PI - Asin((y2 - y1) / len));
            else
                mtx.rotate(Asin((y2 - y1) / len));
        } else
            len = FLT_TO_SCALAR(2.0f); // len can not be zero

        mtx.translate(x1, y1);

        m_start = FLT_TO_SCALAR(0.0f);
        m_length = len;
        m_matrix = mtx;
    }
}
void PICAPI ps_font_set_size(ps_font* f, float s)
{
    if (!picasso::is_valid_system_device()) {
        global_status = STATUS_DEVICE_ERROR;
        return;
    }

    if (!f || s < 0.0) {
        global_status = STATUS_INVALID_ARGUMENT;
        return;
    }
    
    f->desc.set_height(FLT_TO_SCALAR(s));
    global_status = STATUS_SUCCEED;
}
void PICAPI ps_font_set_weight(ps_font* f, int w)
{
    if (!picasso::is_valid_system_device()) {
        global_status = STATUS_DEVICE_ERROR;
        return;
    }

    if (!f || w < 100 || w > 900) {
        global_status = STATUS_INVALID_ARGUMENT;
        return;
    }

    f->desc.set_weight(FLT_TO_SCALAR(w));
    global_status = STATUS_SUCCEED;
}
Example #19
0
void PICAPI ps_path_arc_to(ps_path* path, float rx, float ry, float a, ps_bool large, ps_bool cw, const ps_point* ep)
{
    if (!picasso::is_valid_system_device()) {
        global_status = STATUS_DEVICE_ERROR;
        return;
    }

    if (!path || !ep || rx <= 0.0 || ry <= 0.0) {
        global_status = STATUS_INVALID_ARGUMENT;
        return;
    }

    scalar x1 = path->path.last_x();
    scalar y1 = path->path.last_y();

    picasso::bezier_arc_svg arc(x1, y1, FLT_TO_SCALAR(rx), FLT_TO_SCALAR(ry), FLT_TO_SCALAR(a),
                            (large ? true : false), (cw ? true : false), FLT_TO_SCALAR(ep->x), FLT_TO_SCALAR(ep->y));
    picasso::conv_curve cr(arc);
    if (picasso::_is_closed_path(path->path))
        path->path.concat_path(cr, 0);
    else
        path->path.join_path(cr, 0);
    global_status = STATUS_SUCCEED;
}
Example #20
0
// curve3_inc
void curve3_inc::init(scalar x1, scalar y1, scalar x2, scalar y2, scalar x3, scalar y3)
{
    m_start_x = x1;
    m_start_y = y1;
    m_end_x   = x3;
    m_end_y   = y3;

    scalar dx1 = x2 - x1;
    scalar dy1 = y2 - y1;
    scalar dx2 = x3 - x2;
    scalar dy2 = y3 - y2;

    scalar len = Sqrt(dx1 * dx1 + dy1 * dy1) + Sqrt(dx2 * dx2 + dy2 * dy2);

    m_num_steps = uround(len * FLT_TO_SCALAR(0.25f) * m_scale);

    if (m_num_steps < 4) {
        m_num_steps = 4;
    }

    scalar subdivide_step  = FLT_TO_SCALAR(1.0f) / m_num_steps;
    scalar subdivide_step2 = subdivide_step * subdivide_step;

    scalar tmpx = (x1 - x2 * FLT_TO_SCALAR(2.0f) + x3) * subdivide_step2;
    scalar tmpy = (y1 - y2 * FLT_TO_SCALAR(2.0f) + y3) * subdivide_step2;

    m_saved_fx = m_fx = x1;
    m_saved_fy = m_fy = y1;

    m_saved_dfx = m_dfx = tmpx + (x2 - x1) * (FLT_TO_SCALAR(2.0f) * subdivide_step);
    m_saved_dfy = m_dfy = tmpy + (y2 - y1) * (FLT_TO_SCALAR(2.0f) * subdivide_step);

    m_ddfx = tmpx * FLT_TO_SCALAR(2.0f);
    m_ddfy = tmpy * FLT_TO_SCALAR(2.0f);

    m_step = m_num_steps;
}
 scalar calc_weight(scalar x) const
 {
     return FLT_TO_SCALAR(1.0f) - x;
 }
 scalar calc_weight(scalar x) const
 {
     return Exp(-FLT_TO_SCALAR(2.0f) * x * x) * Sqrt(FLT_TO_SCALAR(2.0f) * _1divPI);
 }
Example #23
0
namespace picasso {

const scalar curve_distance_epsilon          = FLT_TO_SCALAR(1e-30f);
const scalar curve_collinearity_epsilon      = FLT_TO_SCALAR(1e-30f);
const scalar curve_angle_tolerance_epsilon   = FLT_TO_SCALAR(0.01f);

enum curve_recursion_limit
{
    curve_recursion_limit = 32,
};

// curve3_inc
void curve3_inc::init(scalar x1, scalar y1, scalar x2, scalar y2, scalar x3, scalar y3)
{
    m_start_x = x1;
    m_start_y = y1;
    m_end_x   = x3;
    m_end_y   = y3;

    scalar dx1 = x2 - x1;
    scalar dy1 = y2 - y1;
    scalar dx2 = x3 - x2;
    scalar dy2 = y3 - y2;

    scalar len = Sqrt(dx1 * dx1 + dy1 * dy1) + Sqrt(dx2 * dx2 + dy2 * dy2);

    m_num_steps = uround(len * FLT_TO_SCALAR(0.25f) * m_scale);

    if (m_num_steps < 4) {
        m_num_steps = 4;
    }

    scalar subdivide_step  = FLT_TO_SCALAR(1.0f) / m_num_steps;
    scalar subdivide_step2 = subdivide_step * subdivide_step;

    scalar tmpx = (x1 - x2 * FLT_TO_SCALAR(2.0f) + x3) * subdivide_step2;
    scalar tmpy = (y1 - y2 * FLT_TO_SCALAR(2.0f) + y3) * subdivide_step2;

    m_saved_fx = m_fx = x1;
    m_saved_fy = m_fy = y1;

    m_saved_dfx = m_dfx = tmpx + (x2 - x1) * (FLT_TO_SCALAR(2.0f) * subdivide_step);
    m_saved_dfy = m_dfy = tmpy + (y2 - y1) * (FLT_TO_SCALAR(2.0f) * subdivide_step);

    m_ddfx = tmpx * FLT_TO_SCALAR(2.0f);
    m_ddfy = tmpy * FLT_TO_SCALAR(2.0f);

    m_step = m_num_steps;
}

void curve3_inc::rewind(unsigned int)
{
    if (m_num_steps == 0) {
        m_step = -1;
        return;
    }
    m_step = m_num_steps;
    m_fx   = m_saved_fx;
    m_fy   = m_saved_fy;
    m_dfx  = m_saved_dfx;
    m_dfy  = m_saved_dfy;
}

unsigned int curve3_inc::vertex(scalar* x, scalar* y)
{
    if (m_step < 0)
        return path_cmd_stop;

    if (m_step == m_num_steps) {
        *x = m_start_x;
        *y = m_start_y;
        --m_step;
        return path_cmd_move_to;
    }

    if (m_step == 0) {
        *x = m_end_x;
        *y = m_end_y;
        --m_step;
        return path_cmd_line_to;
    }

    m_fx  += m_dfx;
    m_fy  += m_dfy;
    m_dfx += m_ddfx;
    m_dfy += m_ddfy;
    *x = m_fx;
    *y = m_fy;
    --m_step;
    return path_cmd_line_to;
}


//curve3_div
void curve3_div::init(scalar x1, scalar y1, scalar x2, scalar y2, scalar x3, scalar y3)
{
    m_points.clear();
    m_distance_tolerance_square = FLT_TO_SCALAR(0.5f) / m_approximation_scale;
    m_distance_tolerance_square *= m_distance_tolerance_square;
    bezier(x1, y1, x2, y2, x3, y3);
    m_count = 0;
}

//------------------------------------------------------------------------
void curve3_div::recursive_bezier(scalar x1, scalar y1, scalar x2, scalar y2, scalar x3, scalar y3, unsigned int level)
{
    if (level > curve_recursion_limit) {
        return;
    }

    // Calculate all the mid-points of the line segments
    //----------------------
    scalar x12   = (x1 + x2) / 2;
    scalar y12   = (y1 + y2) / 2;
    scalar x23   = (x2 + x3) / 2;
    scalar y23   = (y2 + y3) / 2;
    scalar x123  = (x12 + x23) / 2;
    scalar y123  = (y12 + y23) / 2;

    scalar dx = x3-x1;
    scalar dy = y3-y1;
    scalar d = Fabs(((x2 - x3) * dy - (y2 - y3) * dx));
    scalar da;

    if (d > curve_collinearity_epsilon) {
        // Regular case
        //-----------------
        if (d * d <= m_distance_tolerance_square * (dx*dx + dy*dy)) {
            // If the curvature doesn't exceed the distance_tolerance value
            // we tend to finish subdivisions.
            //----------------------
            if (m_angle_tolerance < curve_angle_tolerance_epsilon) {
                m_points.add(vertex_s(x123, y123));
                return;
            }

            // Angle & Cusp Condition
            //----------------------
            da = Fabs(Atan2(y3 - y2, x3 - x2) - Atan2(y2 - y1, x2 - x1));
            if (da >= PI)
                da = _2PI - da;

            if (da < m_angle_tolerance) {
                // Finally we can stop the recursion
                //----------------------
                m_points.add(vertex_s(x123, y123));
                return;
            }
        }
    } else {
        // Collinear case
        //------------------
        da = dx*dx + dy*dy;
        if (da == 0) {
            d = calc_sq_distance(x1, y1, x2, y2);
        } else {
            d = ((x2 - x1)*dx + (y2 - y1)*dy) / da;
            if (d > 0 && d < 1) {
                // Simple collinear case, 1---2---3
                // We can leave just two endpoints
                return;
            }

            if (d <= 0)
                d = calc_sq_distance(x2, y2, x1, y1);
            else if (d >= 1)
                d = calc_sq_distance(x2, y2, x3, y3);
            else
                d = calc_sq_distance(x2, y2, x1 + d*dx, y1 + d*dy);
        }

        if (d < m_distance_tolerance_square) {
            m_points.add(vertex_s(x2, y2));
            return;
        }
    }

    // Continue subdivision
    //----------------------
    recursive_bezier(x1, y1, x12, y12, x123, y123, level + 1);
    recursive_bezier(x123, y123, x23, y23, x3, y3, level + 1);
}

//------------------------------------------------------------------------
void curve3_div::bezier(scalar x1, scalar y1, scalar x2, scalar y2, scalar x3, scalar y3)
{
    m_points.add(vertex_s(x1, y1));
    recursive_bezier(x1, y1, x2, y2, x3, y3, 0);
    m_points.add(vertex_s(x3, y3));
}

//curve4_inc
void curve4_inc::init(scalar x1, scalar y1, scalar x2, scalar y2, scalar x3, scalar y3, scalar x4, scalar y4)
{
    m_start_x = x1;
    m_start_y = y1;
    m_end_x   = x4;
    m_end_y   = y4;

    scalar dx1 = x2 - x1;
    scalar dy1 = y2 - y1;
    scalar dx2 = x3 - x2;
    scalar dy2 = y3 - y2;
    scalar dx3 = x4 - x3;
    scalar dy3 = y4 - y3;

    scalar len = (Sqrt(dx1 * dx1 + dy1 * dy1) +
                  Sqrt(dx2 * dx2 + dy2 * dy2) +
                  Sqrt(dx3 * dx3 + dy3 * dy3)) * FLT_TO_SCALAR(0.25f) * m_scale;

    m_num_steps = uround(len);

    if (m_num_steps < 4) {
        m_num_steps = 4;
    }

    scalar subdivide_step  = FLT_TO_SCALAR(1.0f) / m_num_steps;
    scalar subdivide_step2 = subdivide_step * subdivide_step;
    scalar subdivide_step3 = subdivide_step * subdivide_step * subdivide_step;

    scalar pre1 = FLT_TO_SCALAR(3.0f) * subdivide_step;
    scalar pre2 = FLT_TO_SCALAR(3.0f) * subdivide_step2;
    scalar pre4 = FLT_TO_SCALAR(6.0f) * subdivide_step2;
    scalar pre5 = FLT_TO_SCALAR(6.0f) * subdivide_step3;

    scalar tmp1x = x1 - x2 * FLT_TO_SCALAR(2.0f) + x3;
    scalar tmp1y = y1 - y2 * FLT_TO_SCALAR(2.0f) + y3;

    scalar tmp2x = (x2 - x3) * FLT_TO_SCALAR(3.0f) - x1 + x4;
    scalar tmp2y = (y2 - y3) * FLT_TO_SCALAR(3.0f) - y1 + y4;

    m_saved_fx = m_fx = x1;
    m_saved_fy = m_fy = y1;

    m_saved_dfx = m_dfx = (x2 - x1) * pre1 + tmp1x * pre2 + tmp2x * subdivide_step3;
    m_saved_dfy = m_dfy = (y2 - y1) * pre1 + tmp1y * pre2 + tmp2y * subdivide_step3;

    m_saved_ddfx = m_ddfx = tmp1x * pre4 + tmp2x * pre5;
    m_saved_ddfy = m_ddfy = tmp1y * pre4 + tmp2y * pre5;

    m_dddfx = tmp2x * pre5;
    m_dddfy = tmp2y * pre5;

    m_step = m_num_steps;
}

void curve4_inc::rewind(unsigned int)
{
    if (m_num_steps == 0) {
        m_step = -1;
        return;
    }
    m_step = m_num_steps;
    m_fx   = m_saved_fx;
    m_fy   = m_saved_fy;
    m_dfx  = m_saved_dfx;
    m_dfy  = m_saved_dfy;
    m_ddfx = m_saved_ddfx;
    m_ddfy = m_saved_ddfy;
}

unsigned int curve4_inc::vertex(scalar* x, scalar* y)
{
    if (m_step < 0)
        return path_cmd_stop;

    if (m_step == m_num_steps) {
        *x = m_start_x;
        *y = m_start_y;
        --m_step;
        return path_cmd_move_to;
    }

    if (m_step == 0) {
        *x = m_end_x;
        *y = m_end_y;
        --m_step;
        return path_cmd_line_to;
    }

    m_fx   += m_dfx;
    m_fy   += m_dfy;
    m_dfx  += m_ddfx;
    m_dfy  += m_ddfy;
    m_ddfx += m_dddfx;
    m_ddfy += m_dddfy;

    *x = m_fx;
    *y = m_fy;
    --m_step;
    return path_cmd_line_to;
}

//curve4_div
void curve4_div::init(scalar x1, scalar y1,
        scalar x2, scalar y2,
        scalar x3, scalar y3,
        scalar x4, scalar y4)
{
    m_points.clear();
    m_distance_tolerance_square = FLT_TO_SCALAR(0.5f) / m_approximation_scale;
    m_distance_tolerance_square *= m_distance_tolerance_square;
    bezier(x1, y1, x2, y2, x3, y3, x4, y4);
    m_count = 0;
}

void curve4_div::recursive_bezier(scalar x1, scalar y1, scalar x2, scalar y2, scalar x3, scalar y3, scalar x4, scalar y4, unsigned int level)
{
    if (level > curve_recursion_limit) {
        return;
    }

    // Calculate all the mid-points of the line segments
    //----------------------
    scalar x12   = (x1 + x2) / 2;
    scalar y12   = (y1 + y2) / 2;
    scalar x23   = (x2 + x3) / 2;
    scalar y23   = (y2 + y3) / 2;
    scalar x34   = (x3 + x4) / 2;
    scalar y34   = (y3 + y4) / 2;
    scalar x123  = (x12 + x23) / 2;
    scalar y123  = (y12 + y23) / 2;
    scalar x234  = (x23 + x34) / 2;
    scalar y234  = (y23 + y34) / 2;
    scalar x1234 = (x123 + x234) / 2;
    scalar y1234 = (y123 + y234) / 2;


    // Try to approximate the full cubic curve by a single straight line
    //------------------
    scalar dx = x4-x1;
    scalar dy = y4-y1;

    scalar d2 = Fabs(((x2 - x4) * dy - (y2 - y4) * dx));
    scalar d3 = Fabs(((x3 - x4) * dy - (y3 - y4) * dx));
    scalar da1, da2, k;

    switch((int(d2 > curve_collinearity_epsilon) << 1) + int(d3 > curve_collinearity_epsilon))
    {
    case 0:
        // All collinear OR p1==p4
        //----------------------
        k = dx*dx + dy*dy;
        if (k == 0) {
            d2 = calc_sq_distance(x1, y1, x2, y2);
            d3 = calc_sq_distance(x4, y4, x3, y3);
        } else {
            k   = 1 / k;
            da1 = x2 - x1;
            da2 = y2 - y1;
            d2  = k * (da1*dx + da2*dy);
            da1 = x3 - x1;
            da2 = y3 - y1;
            d3  = k * (da1*dx + da2*dy);
            if (d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1) {
                // Simple collinear case, 1---2---3---4
                // We can leave just two endpoints
                return;
            }

            if (d2 <= 0)
                d2 = calc_sq_distance(x2, y2, x1, y1);
            else if(d2 >= 1)
                d2 = calc_sq_distance(x2, y2, x4, y4);
            else
                d2 = calc_sq_distance(x2, y2, x1 + d2*dx, y1 + d2*dy);

            if (d3 <= 0)
                d3 = calc_sq_distance(x3, y3, x1, y1);
            else if(d3 >= 1)
                d3 = calc_sq_distance(x3, y3, x4, y4);
            else
                d3 = calc_sq_distance(x3, y3, x1 + d3*dx, y1 + d3*dy);
        }

        if (d2 > d3) {
            if (d2 < m_distance_tolerance_square) {
                m_points.add(vertex_s(x2, y2));
                return;
            }
        } else {
            if (d3 < m_distance_tolerance_square) {
                m_points.add(vertex_s(x3, y3));
                return;
            }
        }
        break;

    case 1:
        // p1,p2,p4 are collinear, p3 is significant
        //----------------------
        if (d3 * d3 <= m_distance_tolerance_square * (dx*dx + dy*dy)) {
            if (m_angle_tolerance < curve_angle_tolerance_epsilon) {
                m_points.add(vertex_s(x23, y23));
                return;
            }

            // Angle Condition
            //----------------------
            da1 = Fabs(Atan2(y4 - y3, x4 - x3) - Atan2(y3 - y2, x3 - x2));
            if (da1 >= PI)
                da1 = _2PI - da1;

            if (da1 < m_angle_tolerance) {
                m_points.add(vertex_s(x2, y2));
                m_points.add(vertex_s(x3, y3));
                return;
            }

            if (m_cusp_limit != 0.0) {
                if (da1 > m_cusp_limit) {
                    m_points.add(vertex_s(x3, y3));
                    return;
                }
            }
        }
        break;

    case 2:
        // p1,p3,p4 are collinear, p2 is significant
        //----------------------
        if (d2 * d2 <= m_distance_tolerance_square * (dx*dx + dy*dy)) {
            if (m_angle_tolerance < curve_angle_tolerance_epsilon) {
                m_points.add(vertex_s(x23, y23));
                return;
            }

            // Angle Condition
            //----------------------
            da1 = Fabs(Atan2(y3 - y2, x3 - x2) - Atan2(y2 - y1, x2 - x1));
            if (da1 >= PI)
                da1 = _2PI - da1;

            if (da1 < m_angle_tolerance) {
                m_points.add(vertex_s(x2, y2));
                m_points.add(vertex_s(x3, y3));
                return;
            }

            if (m_cusp_limit != 0.0) {
                if (da1 > m_cusp_limit) {
                    m_points.add(vertex_s(x2, y2));
                    return;
                }
            }
        }
        break;

    case 3:
        // Regular case
        //-----------------
        if ((d2 + d3)*(d2 + d3) <= m_distance_tolerance_square * (dx*dx + dy*dy)) {
            // If the curvature doesn't exceed the distance_tolerance value
            // we tend to finish subdivisions.
            //----------------------
            if (m_angle_tolerance < curve_angle_tolerance_epsilon) {
                m_points.add(vertex_s(x23, y23));
                return;
            }

            // Angle & Cusp Condition
            //----------------------
            k   = Atan2(y3 - y2, x3 - x2);
            da1 = Fabs(k - Atan2(y2 - y1, x2 - x1));
            da2 = Fabs(Atan2(y4 - y3, x4 - x3) - k);
            if (da1 >= PI)
                da1 = _2PI - da1;
            if (da2 >= PI)
                da2 = _2PI - da2;

            if (da1 + da2 < m_angle_tolerance) {
                // Finally we can stop the recursion
                //----------------------
                m_points.add(vertex_s(x23, y23));
                return;
            }

            if (m_cusp_limit != 0.0) {
                if (da1 > m_cusp_limit) {
                    m_points.add(vertex_s(x2, y2));
                    return;
                }

                if (da2 > m_cusp_limit) {
                    m_points.add(vertex_s(x3, y3));
                    return;
                }
            }
        }
        break;
    }

    // Continue subdivision
    //----------------------
    recursive_bezier(x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1);
    recursive_bezier(x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1);
}

void curve4_div::bezier(scalar x1, scalar y1, scalar x2, scalar y2, scalar x3, scalar y3, scalar x4, scalar y4)
{
    m_points.add(vertex_s(x1, y1));
    recursive_bezier(x1, y1, x2, y2, x3, y3, x4, y4, 0);
    m_points.add(vertex_s(x4, y4));
}

}
bool gfx_font_adapter::prepare_glyph(unsigned int code)
{
    if (m_impl->font) {
        m_impl->cur_glyph_index = FT_Get_Char_Index(m_impl->font, code);

        int error = FT_Load_Glyph(m_impl->font, m_impl->cur_glyph_index,
                                 m_impl->hinting ? FT_LOAD_DEFAULT : FT_LOAD_NO_HINTING);

        bool is_sys_bitmap = false;
        if (m_impl->font->glyph->format == FT_GLYPH_FORMAT_BITMAP)
            is_sys_bitmap = true;

        if (error == 0) {
            if (m_impl->antialias && !is_sys_bitmap) {
                if (m_impl->weight == 500) {
                    int strength = 1 << 5;
                    FT_Outline_Embolden(&(m_impl->font->glyph->outline), strength);
                } else if (m_impl->weight == 700) {
                    int strength = 1 << 6;
                    FT_Outline_Embolden(&(m_impl->font->glyph->outline), strength);
                } else if (m_impl->weight == 900) {
                    int strength = 1 << 7;
                    FT_Outline_Embolden(&(m_impl->font->glyph->outline), strength);
                }
                // outline text
                m_impl->cur_data_type = glyph_type_outline;
                m_impl->cur_font_path.remove_all();

                if (decompose_ft_outline(m_impl->font->glyph->outline,
                            m_impl->flip_y, m_impl->matrix, m_impl->cur_font_path))
                {
                    m_impl->cur_bound_rect = get_bounding_rect(m_impl->cur_font_path);
                    m_impl->cur_data_size = m_impl->cur_font_path.total_byte_size()+sizeof(unsigned int);//count data
                    m_impl->cur_advance_x = FLT_TO_SCALAR(int26p6_to_flt(m_impl->font->glyph->advance.x));
                    m_impl->cur_advance_y = FLT_TO_SCALAR(int26p6_to_flt(m_impl->font->glyph->advance.y));
                    m_impl->matrix.transform(&m_impl->cur_advance_x, &m_impl->cur_advance_y);
                    return true;
                }
            } else {
                m_impl->cur_data_type = glyph_type_mono;
                if (is_sys_bitmap || !FT_IS_SCALABLE(m_impl->font) || m_impl->matrix.is_identity()) {
                    gfx_scanline_bin sl;
                    error = FT_Render_Glyph(m_impl->font->glyph, FT_RENDER_MODE_MONO);
                    if (error == 0) {
                        decompose_ft_bitmap_mono(m_impl->font->glyph->bitmap,
                           m_impl->font->glyph->bitmap_left, m_impl->flip_y ? -m_impl->font->glyph->bitmap_top :
                           m_impl->font->glyph->bitmap_top, m_impl->flip_y, sl, m_impl->cur_font_scanlines_bin);

                        m_impl->cur_bound_rect = rect(m_impl->cur_font_scanlines_bin.min_x(),
                                m_impl->cur_font_scanlines_bin.min_y(),
                                m_impl->cur_font_scanlines_bin.max_x() + 1,
                                m_impl->cur_font_scanlines_bin.max_y() + 1);
                        m_impl->cur_data_size = m_impl->cur_font_scanlines_bin.byte_size();
                        m_impl->cur_advance_x = FLT_TO_SCALAR(int26p6_to_flt(m_impl->font->glyph->advance.x));
                        m_impl->cur_advance_y = FLT_TO_SCALAR(int26p6_to_flt(m_impl->font->glyph->advance.y));
                        return true;
                    }
                } else {
                    if (m_impl->weight == 500) {
                        int strength = 1 << 5;
                        FT_Outline_Embolden(&(m_impl->font->glyph->outline), strength);
                    } else if (m_impl->weight == 700) {
                        int strength = 1 << 6;
                        FT_Outline_Embolden(&(m_impl->font->glyph->outline), strength);
                    } else if (m_impl->weight == 900) {
                        int strength = 1 << 7;
                        FT_Outline_Embolden(&(m_impl->font->glyph->outline), strength);
                    }

                    m_impl->cur_font_path.remove_all();
                    if (decompose_ft_outline(m_impl->font->glyph->outline,
                                m_impl->flip_y, m_impl->matrix, m_impl->cur_font_path))
                    {
                        gfx_rasterizer_scanline_aa<> rasterizer;
                        picasso::conv_curve curves(m_impl->cur_font_path);
                        curves.approximation_scale(4.0);
                        rasterizer.add_path(curves);

                        gfx_scanline_bin sl;
                        m_impl->cur_font_scanlines_bin.prepare(); // Remove all
                        gfx_render_scanlines(rasterizer, sl, m_impl->cur_font_scanlines_bin);
                        m_impl->cur_bound_rect = rect(m_impl->cur_font_scanlines_bin.min_x(),
                                m_impl->cur_font_scanlines_bin.min_y(),
                                m_impl->cur_font_scanlines_bin.max_x() + 1,
                                m_impl->cur_font_scanlines_bin.max_y() + 1);
                        m_impl->cur_data_size = m_impl->cur_font_scanlines_bin.byte_size();
                        m_impl->cur_advance_x = FLT_TO_SCALAR(int26p6_to_flt(m_impl->font->glyph->advance.x));
                        m_impl->cur_advance_y = FLT_TO_SCALAR(int26p6_to_flt(m_impl->font->glyph->advance.y));
                        m_impl->matrix.transform(&m_impl->cur_advance_x, &m_impl->cur_advance_y);
                        return true;
                    }
                }
            }
        }
    }
    return false;
}
static bool decompose_ft_outline(const FT_Outline& outline,
                              bool flip_y, const gfx_trans_affine& mtx, graphic_path& path)
{
    FT_Vector   v_last;
    FT_Vector   v_control;
    FT_Vector   v_start;
    float x1, y1, x2, y2, x3, y3;

    FT_Vector*  point;
    FT_Vector*  limit;
    char*       tags;

    int   first;     // index of first point in contour
    char  tag;       // current point's state

    first = 0;

    for (int n = 0; n < outline.n_contours; n++) {
        int  last;  // index of last point in contour

        last  = outline.contours[n];
        limit = outline.points + last;

        v_start = outline.points[first];
        v_last  = outline.points[last];

        v_control = v_start;

        point = outline.points + first;
        tags  = outline.tags  + first;
        tag   = FT_CURVE_TAG(tags[0]);

        // A contour cannot start with a cubic control point!
        if (tag == FT_CURVE_TAG_CUBIC)
            return false;

        // check first point to determine origin
        if (tag == FT_CURVE_TAG_CONIC) {
            // first point is conic control.
            if (FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON) {
                // start at last point if it is on the curve
                v_start = v_last;
                limit--;
            } else {
                // if both first and last points are conic,
                // start at their middle and record its position
                // for closure
                v_start.x = (v_start.x + v_last.x) / 2;
                v_start.y = (v_start.y + v_last.y) / 2;

                v_last = v_start;
            }
            point--;
            tags--;
        }

        x1 = int26p6_to_flt(v_start.x);
        y1 = int26p6_to_flt(v_start.y);

        if (flip_y)
            y1 = -y1;

        mtx.transform(&x1, &y1);
        path.move_to(FLT_TO_SCALAR(x1), FLT_TO_SCALAR(y1));

        while (point < limit) {
            point++;
            tags++;

            tag = FT_CURVE_TAG(tags[0]);
            switch (tag) {
                case FT_CURVE_TAG_ON:  // emit a single line_to
                    {
                        x1 = int26p6_to_flt(point->x);
                        y1 = int26p6_to_flt(point->y);
                        if (flip_y)
                            y1 = -y1;
                        mtx.transform(&x1, &y1);
                        path.line_to(FLT_TO_SCALAR(x1), FLT_TO_SCALAR(y1));
                        continue;
                    }
                case FT_CURVE_TAG_CONIC:  // consume conic arcs
                    {
                        v_control.x = point->x;
                        v_control.y = point->y;
                    Do_Conic:
                        if (point < limit) {
                            FT_Vector vec;
                            FT_Vector v_middle;

                            point++;
                            tags++;
                            tag = FT_CURVE_TAG(tags[0]);

                            vec.x = point->x;
                            vec.y = point->y;

                            if (tag == FT_CURVE_TAG_ON) {
                                x1 = int26p6_to_flt(v_control.x);
                                y1 = int26p6_to_flt(v_control.y);
                                x2 = int26p6_to_flt(vec.x);
                                y2 = int26p6_to_flt(vec.y);
                                if (flip_y) {
                                    y1 = -y1;
                                    y2 = -y2;
                                }
                                mtx.transform(&x1, &y1);
                                mtx.transform(&x2, &y2);
                                path.curve3(FLT_TO_SCALAR(x1),
                                            FLT_TO_SCALAR(y1),
                                            FLT_TO_SCALAR(x2),
                                            FLT_TO_SCALAR(y2));
                                continue;
                            }

                            if (tag != FT_CURVE_TAG_CONIC)
                                return false;

                            v_middle.x = (v_control.x + vec.x) / 2;
                            v_middle.y = (v_control.y + vec.y) / 2;

                            x1 = int26p6_to_flt(v_control.x);
                            y1 = int26p6_to_flt(v_control.y);
                            x2 = int26p6_to_flt(v_middle.x);
                            y2 = int26p6_to_flt(v_middle.y);
                            if (flip_y) {
                                y1 = -y1;
                                y2 = -y2;
                            }
                            mtx.transform(&x1, &y1);
                            mtx.transform(&x2, &y2);
                            path.curve3(FLT_TO_SCALAR(x1),
                                        FLT_TO_SCALAR(y1),
                                        FLT_TO_SCALAR(x2),
                                        FLT_TO_SCALAR(y2));
                            v_control = vec;
                            goto Do_Conic;
                        }

                        x1 = int26p6_to_flt(v_control.x);
                        y1 = int26p6_to_flt(v_control.y);
                        x2 = int26p6_to_flt(v_start.x);
                        y2 = int26p6_to_flt(v_start.y);
                        if (flip_y) {
                            y1 = -y1;
                            y2 = -y2;
                        }
                        mtx.transform(&x1, &y1);
                        mtx.transform(&x2, &y2);
                        path.curve3(FLT_TO_SCALAR(x1),
                                    FLT_TO_SCALAR(y1),
                                    FLT_TO_SCALAR(x2),
                                    FLT_TO_SCALAR(y2));
                        goto Close;
                    }
                default:  // FT_CURVE_TAG_CUBIC
                    {
                        FT_Vector vec1, vec2;

                        if (point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC) {
                            return false;
                        }

                        vec1.x = point[0].x;
                        vec1.y = point[0].y;
                        vec2.x = point[1].x;
                        vec2.y = point[1].y;

                        point += 2;
                        tags  += 2;

                        if (point <= limit) {
                            FT_Vector vec;

                            vec.x = point->x;
                            vec.y = point->y;

                            x1 = int26p6_to_flt(vec1.x);
                            y1 = int26p6_to_flt(vec1.y);
                            x2 = int26p6_to_flt(vec2.x);
                            y2 = int26p6_to_flt(vec2.y);
                            x3 = int26p6_to_flt(vec.x);
                            y3 = int26p6_to_flt(vec.y);
                            if (flip_y) {
                                y1 = -y1;
                                y2 = -y2;
                                y3 = -y3;
                            }
                            mtx.transform(&x1, &y1);
                            mtx.transform(&x2, &y2);
                            mtx.transform(&x3, &y3);
                            path.curve4(FLT_TO_SCALAR(x1),
                                        FLT_TO_SCALAR(y1),
                                        FLT_TO_SCALAR(x2),
                                        FLT_TO_SCALAR(y2),
                                        FLT_TO_SCALAR(x3),
                                        FLT_TO_SCALAR(y3));
                            continue;
                        }

                        x1 = int26p6_to_flt(vec1.x);
                        y1 = int26p6_to_flt(vec1.y);
                        x2 = int26p6_to_flt(vec2.x);
                        y2 = int26p6_to_flt(vec2.y);
                        x3 = int26p6_to_flt(v_start.x);
                        y3 = int26p6_to_flt(v_start.y);
                        if (flip_y) {
                            y1 = -y1;
                            y2 = -y2;
                            y3 = -y3;
                        }
                        mtx.transform(&x1, &y1);
                        mtx.transform(&x2, &y2);
                        mtx.transform(&x3, &y3);
                        path.curve4(FLT_TO_SCALAR(x1),
                                    FLT_TO_SCALAR(y1),
                                    FLT_TO_SCALAR(x2),
                                    FLT_TO_SCALAR(y2),
                                    FLT_TO_SCALAR(x3),
                                    FLT_TO_SCALAR(y3));
                        goto Close;
                    }
            }
        }

        path.close_polygon();
Close:
        first = last + 1;
    }
    return true;
}
Example #26
0
void PICAPI ps_path_add_rounded_rect(ps_path*path, const ps_rect* r, float ltx, float lty, float rtx, float rty,
                                                                        float lbx, float lby, float rbx, float rby)
{
    if (!picasso::is_valid_system_device()) {
        global_status = STATUS_DEVICE_ERROR;
        return;
    }

    if (!path || !r) {
        global_status = STATUS_INVALID_ARGUMENT;
        return;
    }

    picasso::rounded_rect rr;
    rr.rect(FLT_TO_SCALAR(r->x), FLT_TO_SCALAR(r->y), FLT_TO_SCALAR(r->x+r->w), FLT_TO_SCALAR(r->y+r->h));
    rr.radius(FLT_TO_SCALAR(ltx), FLT_TO_SCALAR(lty), FLT_TO_SCALAR(rtx), FLT_TO_SCALAR(rty),
                FLT_TO_SCALAR(lbx), FLT_TO_SCALAR(lby), FLT_TO_SCALAR(rbx), FLT_TO_SCALAR(rby));
    rr.normalize_radius();
    if (picasso::_is_closed_path(path->path))
        path->path.concat_path(rr, 0);
    else
        path->path.join_path(rr, 0);
    global_status = STATUS_SUCCEED;
}
void PICAPI ps_draw_text(ps_context* ctx, const ps_rect* area, const void* text, unsigned int len,
                                                                ps_draw_text_type type, ps_text_align align)
{
    if (!picasso::is_valid_system_device()) {
        global_status = STATUS_DEVICE_ERROR;
        return;
    }

    if (!ctx || !area || !text || !len) {
        global_status = STATUS_INVALID_ARGUMENT;
        return;
    }

    scalar x = FLT_TO_SCALAR(area->x);
    scalar y = FLT_TO_SCALAR(area->y);

    picasso::graphic_path text_path;

    ps_bool text_antialias = ctx->font_antialias;
    ctx->font_antialias = True;
    if (create_device_font(ctx)) {

        // align layout
        scalar w = 0, h = 0;
        const picasso::glyph* glyph_test = 0;

        if (ctx->state->font->desc.charset() == CHARSET_ANSI) {
            const char* p = (const char*)text;
            glyph_test = ctx->fonts->current_font()->get_glyph(*p);
        } else {
            const ps_uchar16* p = (const ps_uchar16*)text;
            glyph_test = ctx->fonts->current_font()->get_glyph(*p);
        }

        if (glyph_test) {
            w = glyph_test->advance_x;
            h = glyph_test->height; //Note: advance_y always 0.
        }

        w *= len; //FIXME: estimate!

        if (align & TEXT_ALIGN_LEFT)
            x = FLT_TO_SCALAR(area->x);
        else if (align & TEXT_ALIGN_RIGHT)
            x = FLT_TO_SCALAR(area->x + (area->w - w));
        else
            x = FLT_TO_SCALAR(area->x + (area->w - w)/2);

        if (align & TEXT_ALIGN_TOP) {
            y = FLT_TO_SCALAR(area->y);
            y += ctx->fonts->current_font()->ascent();
        } else if (align & TEXT_ALIGN_BOTTOM) {
            y = FLT_TO_SCALAR(area->y + (area->h - SCALAR_TO_FLT(h)));
            y -= ctx->fonts->current_font()->descent();
        } else {
            y = FLT_TO_SCALAR(area->y + (area->h - SCALAR_TO_FLT(h))/2);
            y += (ctx->fonts->current_font()->ascent() - ctx->fonts->current_font()->descent())/2;
        }

        // draw the text
        if (ctx->state->font->desc.charset() == CHARSET_ANSI) {
            const char* p = (const char*)text;
            while (*p && len) {
                register char c = *p;
                const picasso::glyph* glyph = ctx->fonts->current_font()->get_glyph(c);
                if (glyph) {
                    if (ctx->font_kerning)
                        ctx->fonts->current_font()->add_kerning(&x, &y);
                    if (ctx->fonts->current_font()->generate_raster(glyph, x, y))
                        _add_glyph_to_path(ctx, text_path);

                    x += glyph->advance_x;
                    y += glyph->advance_y;
                }
                len--;
                p++;
            }
        } else {
            const ps_uchar16* p = (const ps_uchar16*)text;
            while (*p && len) {
                register ps_uchar16 c = *p;
                const picasso::glyph* glyph = ctx->fonts->current_font()->get_glyph(c);
                if (glyph) {
                    if (ctx->font_kerning)
                        ctx->fonts->current_font()->add_kerning(&x, &y);
                    if (ctx->fonts->current_font()->generate_raster(glyph, x, y))
                        _add_glyph_to_path(ctx, text_path);

                    x += glyph->advance_x;
                    y += glyph->advance_y;
                }
                len--;
                p++;
            }
        }
    }

    text_path.close_polygon();
    ctx->font_antialias = text_antialias;

    //store the old color
    picasso::rgba bc = ctx->state->brush.color;
    picasso::rgba pc = ctx->state->pen.color;

    ctx->state->brush.color = ctx->state->font_fcolor;
    ctx->state->pen.color = ctx->state->font_scolor;

    switch (type) {
        case DRAW_TEXT_FILL:
            ctx->canvas->p->render_shadow(ctx->state, text_path, true, false);
            ctx->canvas->p->render_fill(ctx->state, ctx->raster, text_path);
            ctx->canvas->p->render_blur(ctx->state);
            break;
        case DRAW_TEXT_STROKE:
            ctx->canvas->p->render_shadow(ctx->state, text_path, false, true);
            ctx->canvas->p->render_stroke(ctx->state, ctx->raster, text_path);
            ctx->canvas->p->render_blur(ctx->state);
            break;
        case DRAW_TEXT_BOTH:
            ctx->canvas->p->render_shadow(ctx->state, text_path, true, true);
            ctx->canvas->p->render_paint(ctx->state, ctx->raster, text_path);
            ctx->canvas->p->render_blur(ctx->state);
            break;
    }

    ctx->state->brush.color = bc;
    ctx->state->pen.color = pc;
    ctx->raster.reset();
    global_status = STATUS_SUCCEED;
}
 scalar radius(void) const { return FLT_TO_SCALAR(2.0f); }