Browse Source

Add measureText implementation for pango

v1.x
c-spencer 13 years ago
parent
commit
efadaead73
  1. 109
      src/CanvasRenderingContext2d.cc

109
src/CanvasRenderingContext2d.cc

@ -56,6 +56,16 @@ void state_assign_fontFamily(canvas_state_t *state, const char *str) {
state->fontFamily = strndup(str, 100);
}
/*
* Simple helper macro for a rather verbose function call.
*/
#define PANGO_LAYOUT_GET_METRICS(LAYOUT) pango_context_get_metrics( \
pango_layout_get_context(LAYOUT), \
pango_layout_get_font_description(LAYOUT), \
pango_context_get_language(pango_layout_get_context(LAYOUT)))
#endif
/*
@ -1552,13 +1562,6 @@ Context2d::StrokeText(const Arguments &args) {
* Set text path for the given string at (x, y).
*/
// Define simple macro substitution so we can use these lazily within setTextPath
#define GET_EXTENTS() pango_layout_get_pixel_extents(_layout, &ink_rect, &logical_rect)
#define GET_METRICS() metrics = pango_context_get_metrics( \
pango_layout_get_context(_layout), \
pango_layout_get_font_description(_layout), \
pango_context_get_language(pango_layout_get_context(_layout)))
void
Context2d::setTextPath(const char *str, double x, double y) {
#if HAVE_PANGO
@ -1572,27 +1575,27 @@ Context2d::setTextPath(const char *str, double x, double y) {
switch (state->textAlignment) {
// center
case 0:
GET_EXTENTS();
pango_layout_get_pixel_extents(_layout, &ink_rect, &logical_rect);
x -= logical_rect.width / 2;
break;
// right
case 1:
GET_EXTENTS();
pango_layout_get_pixel_extents(_layout, &ink_rect, &logical_rect);
x -= logical_rect.width;
break;
}
switch (state->textBaseline) {
case TEXT_BASELINE_ALPHABETIC:
GET_METRICS();
metrics = PANGO_LAYOUT_GET_METRICS(_layout);
y -= pango_font_metrics_get_ascent(metrics) / PANGO_SCALE;
break;
case TEXT_BASELINE_MIDDLE:
GET_METRICS();
metrics = PANGO_LAYOUT_GET_METRICS(_layout);
y -= (pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics))/(2.0 * PANGO_SCALE);
break;
case TEXT_BASELINE_BOTTOM:
GET_METRICS();
metrics = PANGO_LAYOUT_GET_METRICS(_layout);
y -= (pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics)) / PANGO_SCALE;
break;
}
@ -1834,14 +1837,72 @@ Context2d::MeasureText(const Arguments &args) {
String::Utf8Value str(args[0]->ToString());
Local<Object> obj = Object::New();
#if HAVE_PANGO
PangoRectangle ink_rect, logical_rect;
PangoFontMetrics *metrics;
PangoLayout *layout = context->layout();
pango_layout_set_text(layout, *str, -1);
pango_cairo_update_layout(ctx, layout);
pango_layout_get_pixel_extents(layout, &ink_rect, &logical_rect);
metrics = PANGO_LAYOUT_GET_METRICS(layout);
double x_offset;
switch (context->state->textAlignment) {
case 0: // center
x_offset = logical_rect.width / 2;
break;
case 1: // right
x_offset = logical_rect.width;
break;
default: // left
x_offset = 0.0;
}
double y_offset;
switch (context->state->textBaseline) {
case TEXT_BASELINE_ALPHABETIC:
y_offset = -pango_font_metrics_get_ascent(metrics) / PANGO_SCALE;
break;
case TEXT_BASELINE_MIDDLE:
y_offset = -(pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics))/(2.0 * PANGO_SCALE);
break;
case TEXT_BASELINE_BOTTOM:
y_offset = -(pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics)) / PANGO_SCALE;
break;
default:
y_offset = 0.0;
}
obj->Set(String::New("width"), Number::New(logical_rect.width));
obj->Set(String::New("actualBoundingBoxLeft"),
Number::New(x_offset - PANGO_LBEARING(logical_rect)));
obj->Set(String::New("actualBoundingBoxRight"),
Number::New(x_offset + PANGO_RBEARING(logical_rect)));
obj->Set(String::New("actualBoundingBoxAscent"),
Number::New(-(y_offset+ink_rect.y)));
obj->Set(String::New("actualBoundingBoxDescent"),
Number::New((PANGO_DESCENT(ink_rect) + y_offset)));
obj->Set(String::New("emHeightAscent"),
Number::New(PANGO_ASCENT(logical_rect) - y_offset));
obj->Set(String::New("emHeightDescent"),
Number::New(PANGO_DESCENT(logical_rect) + y_offset));
obj->Set(String::New("alphabeticBaseline"),
Number::New((pango_font_metrics_get_ascent(metrics) / PANGO_SCALE)
+ y_offset));
pango_font_metrics_unref(metrics);
#else
cairo_text_extents_t te;
cairo_font_extents_t fe;
cairo_text_extents(ctx, *str, &te);
cairo_font_extents(ctx, &fe);
obj->Set(String::New("width"), Number::New(te.x_advance));
double x_offset;
switch (context->state->textAlignment) {
case 0: // center
@ -1854,9 +1915,6 @@ Context2d::MeasureText(const Arguments &args) {
x_offset = 0.0;
}
obj->Set(String::New("actualBoundingBoxLeft"), Number::New(x_offset - te.x_bearing));
obj->Set(String::New("actualBoundingBoxRight"), Number::New((te.x_bearing + te.width) - x_offset));
double y_offset;
switch (context->state->textBaseline) {
case TEXT_BASELINE_TOP:
@ -1872,12 +1930,21 @@ Context2d::MeasureText(const Arguments &args) {
default:
y_offset = 0.0;
}
obj->Set(String::New("actualBoundingBoxAscent"), Number::New(-(te.y_bearing + y_offset)));
obj->Set(String::New("actualBoundingBoxDescent"), Number::New(te.height + te.y_bearing + y_offset));
obj->Set(String::New("width"), Number::New(te.x_advance));
obj->Set(String::New("actualBoundingBoxLeft"),
Number::New(x_offset - te.x_bearing));
obj->Set(String::New("actualBoundingBoxRight"),
Number::New((te.x_bearing + te.width) - x_offset));
obj->Set(String::New("actualBoundingBoxAscent"),
Number::New(-(te.y_bearing + y_offset)));
obj->Set(String::New("actualBoundingBoxDescent"),
Number::New(te.height + te.y_bearing + y_offset));
obj->Set(String::New("emHeightAscent"), Number::New(fe.ascent - y_offset));
obj->Set(String::New("emHeightDescent"), Number::New(fe.descent + y_offset));
obj->Set(String::New("alphabeticBaseline"), Number::New(-y_offset));
obj->Set(String::New("alphabeticBaseline"), Number::New(y_offset));
#endif
return scope.Close(obj);
}

Loading…
Cancel
Save