ps_bool PICAPI ps_get_font_info(ps_context* ctx, ps_font_info* info) { if (!picasso::is_valid_system_device()) { global_status = STATUS_DEVICE_ERROR; return False; } if (!ctx || !info) { global_status = STATUS_INVALID_ARGUMENT; return False; } if (create_device_font(ctx)) { info->size = SCALAR_TO_FLT(ctx->fonts->current_font()->height()); info->ascent = SCALAR_TO_FLT(ctx->fonts->current_font()->ascent()); info->descent = SCALAR_TO_FLT(ctx->fonts->current_font()->descent()); info->leading = SCALAR_TO_FLT(ctx->fonts->current_font()->leading()); info->unitsEM = SCALAR_TO_INT(ctx->fonts->current_font()->units_per_em()); global_status = STATUS_SUCCEED; return True; } global_status = STATUS_UNKNOWN_ERROR; return False; }
ps_size PICAPI ps_get_text_extent(ps_context* ctx, const void* text, unsigned int len) { ps_size size = {0 , 0}; if (!picasso::is_valid_system_device()) { global_status = STATUS_DEVICE_ERROR; return size; } if (!ctx || !text || !len) { global_status = STATUS_INVALID_ARGUMENT; return size; } scalar width = 0; if (create_device_font(ctx)) { 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) width += glyph->advance_x; 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) width += glyph->advance_x; len--; p++; } } } size.h = SCALAR_TO_FLT(ctx->fonts->current_font()->height()); size.w = SCALAR_TO_FLT(width); global_status = STATUS_SUCCEED; return size; }
ps_path_cmd PICAPI ps_path_get_vertex(const ps_path* path, unsigned int index, ps_point* point) { if (!picasso::is_valid_system_device()) { global_status = STATUS_DEVICE_ERROR; return PATH_CMD_STOP; } if (!path || !point || (index > path->path.total_vertices()-1)) { global_status = STATUS_INVALID_ARGUMENT; return PATH_CMD_STOP; } scalar x = 0, y = 0; unsigned int cmd = path->path.vertex(index, &x, &y); point->x = SCALAR_TO_FLT(x); point->y = SCALAR_TO_FLT(y); global_status = STATUS_SUCCEED; return (ps_path_cmd)cmd; }
ps_size PICAPI ps_glyph_get_extent(const ps_glyph* g) { ps_size size = {0 , 0}; if (!picasso::is_valid_system_device()) { global_status = STATUS_DEVICE_ERROR; return size; } if (!g) { global_status = STATUS_INVALID_ARGUMENT; return size; } if (g->glyph) { const picasso::glyph* gp = reinterpret_cast<const picasso::glyph*>(g->glyph); size.w = SCALAR_TO_FLT(gp->advance_x); size.h = SCALAR_TO_FLT(gp->height); //Note: advance_y is 0 } global_status = STATUS_SUCCEED; return size; }
float PICAPI ps_path_get_length(const ps_path* path) { if (!picasso::is_valid_system_device()) { global_status = STATUS_DEVICE_ERROR; return (0.0); } if (!path) { global_status = STATUS_INVALID_ARGUMENT; return (0.0); } global_status = STATUS_SUCCEED; return SCALAR_TO_FLT(picasso::path_length(const_cast<ps_path*>(path)->path, 0)); }
void* gfx_font_adapter::create_storage(byte* buf, unsigned int len, scalar x, scalar y) { m_impl->cur_font_storage_bin.init(buf, len, SCALAR_TO_FLT(Ceil(x)), SCALAR_TO_FLT(Ceil(y))); return (void*)&m_impl->cur_font_storage_bin; }
void PICAPI ps_path_tangent_arc_to(ps_path* path, float r, const ps_point* tp, const ps_point* ep) { if (!picasso::is_valid_system_device()) { global_status = STATUS_DEVICE_ERROR; return; } if (!path || !tp || !ep || r < 0) { global_status = STATUS_INVALID_ARGUMENT; return; } ps_point sp; sp.x = SCALAR_TO_FLT(path->path.last_x()); sp.y = SCALAR_TO_FLT(path->path.last_y()); if ((tp->x == sp.x && tp->y == sp.y) || (tp->x == ep->x && tp->y == ep->y) || r == 0.f) { ps_path_line_to(path, tp); global_status = STATUS_SUCCEED; return; } ps_point p1p0 = {(sp.x - tp->x), (sp.y - tp->y)}; ps_point p1p2 = {(ep->x - tp->x), (ep->y - tp->y)}; float p1p0_length = sqrtf(p1p0.x * p1p0.x + p1p0.y * p1p0.y); float p1p2_length = sqrtf(p1p2.x * p1p2.x + p1p2.y * p1p2.y); float cos_phi = (p1p0.x * p1p2.x + p1p0.y * p1p2.y) / (p1p0_length * p1p2_length); // all points on a line logic if (cos_phi == -1.0f) { ps_path_line_to(path, tp); global_status = STATUS_SUCCEED; return; } if (cos_phi == 1.0f) { // add infinite far away point unsigned int max_length = 65535; float factor_max = max_length / p1p0_length; ps_point np = {(sp.x + factor_max * p1p0.x), (sp.y + factor_max * p1p0.y)}; ps_path_line_to(path, &np); global_status = STATUS_SUCCEED; return; } float tangent = r / tanf(acosf(cos_phi) / 2); float factor_p1p0 = tangent / p1p0_length; ps_point t_p1p0 = {(tp->x + factor_p1p0 * p1p0.x), (tp->y + factor_p1p0 * p1p0.y)}; ps_point orth_p1p0 = {p1p0.y, -p1p0.x}; float orth_p1p0_length = sqrtf(orth_p1p0.x * orth_p1p0.x + orth_p1p0.y * orth_p1p0.y); float factor_ra = r / orth_p1p0_length; // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0 float cos_alpha = (orth_p1p0.x * p1p2.x + orth_p1p0.y * p1p2.y) / (orth_p1p0_length * p1p2_length); if (cos_alpha < 0.f) { orth_p1p0.x = -orth_p1p0.x; orth_p1p0.y = -orth_p1p0.y; } ps_point p = {(t_p1p0.x + factor_ra * orth_p1p0.x), (t_p1p0.y + factor_ra * orth_p1p0.y)}; // calculate angles for addArc orth_p1p0.x = -orth_p1p0.x; orth_p1p0.y = -orth_p1p0.y; float sa = acosf(orth_p1p0.x / orth_p1p0_length); if (orth_p1p0.y < 0.f) sa = 2 * PI - sa; // clockwise logic ps_bool clockwise = True; float factor_p1p2 = tangent / p1p2_length; ps_point t_p1p2 = {(tp->x + factor_p1p2 * p1p2.x), (tp->y + factor_p1p2 * p1p2.y)}; ps_point orth_p1p2 = {(t_p1p2.x - p.x),(t_p1p2.y - p.y)}; float orth_p1p2_length = sqrtf(orth_p1p2.x * orth_p1p2.x + orth_p1p2.y * orth_p1p2.y); float ea = acosf(orth_p1p2.x / orth_p1p2_length); if (orth_p1p2.y < 0) ea = 2 * PI - ea; if ((sa > ea) && ((sa - ea) < PI)) clockwise = False; if ((sa < ea) && ((ea - sa) > PI)) clockwise = False; ps_path_line_to(path, &t_p1p0); ps_path_add_arc(path, &p, r, sa, ea, clockwise); 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; }