|
|
@ -45,6 +45,20 @@ enum { |
|
|
|
, TEXT_BASELINE_HANGING |
|
|
|
}; |
|
|
|
|
|
|
|
#if HAVE_PANGO |
|
|
|
|
|
|
|
/*
|
|
|
|
* State helper function |
|
|
|
*/ |
|
|
|
|
|
|
|
void state_assign_fontFamily(canvas_state_t *state, const char *str) { |
|
|
|
free(state->fontFamily); |
|
|
|
state->fontFamily = (char *) malloc(strlen(str) + 1); |
|
|
|
strcpy(state->fontFamily, str); |
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize Context2d. |
|
|
|
*/ |
|
|
@ -121,6 +135,9 @@ Context2d::Initialize(Handle<Object> target) { |
|
|
|
Context2d::Context2d(Canvas *canvas) { |
|
|
|
_canvas = canvas; |
|
|
|
_context = cairo_create(canvas->surface()); |
|
|
|
#if HAVE_PANGO |
|
|
|
_layout = pango_cairo_create_layout(_context); |
|
|
|
#endif |
|
|
|
cairo_set_line_width(_context, 1); |
|
|
|
state = states[stateno = 0] = (canvas_state_t *) malloc(sizeof(canvas_state_t)); |
|
|
|
state->shadowBlur = 0; |
|
|
@ -129,7 +146,7 @@ Context2d::Context2d(Canvas *canvas) { |
|
|
|
state->textAlignment = -1; |
|
|
|
state->fillPattern = state->strokePattern = NULL; |
|
|
|
state->fillGradient = state->strokeGradient = NULL; |
|
|
|
state->textBaseline = NULL; |
|
|
|
state->textBaseline = TEXT_BASELINE_ALPHABETIC; |
|
|
|
rgba_t transparent = { 0,0,0,1 }; |
|
|
|
rgba_t transparent_black = { 0,0,0,0 }; |
|
|
|
state->fill = transparent; |
|
|
@ -137,6 +154,14 @@ Context2d::Context2d(Canvas *canvas) { |
|
|
|
state->shadow = transparent_black; |
|
|
|
state->patternQuality = CAIRO_FILTER_GOOD; |
|
|
|
state->textDrawingMode = TEXT_DRAW_PATHS; |
|
|
|
#if HAVE_PANGO |
|
|
|
state->fontWeight = PANGO_WEIGHT_NORMAL; |
|
|
|
state->fontStyle = PANGO_STYLE_NORMAL; |
|
|
|
state->fontSize = 10; |
|
|
|
state->fontFamily = NULL; |
|
|
|
state_assign_fontFamily(state, "sans serif"); |
|
|
|
setFontFromState(); |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
@ -177,6 +202,10 @@ Context2d::saveState() { |
|
|
|
if (stateno == CANVAS_MAX_STATES) return; |
|
|
|
states[++stateno] = (canvas_state_t *) malloc(sizeof(canvas_state_t)); |
|
|
|
memcpy(states[stateno], state, sizeof(canvas_state_t)); |
|
|
|
#if HAVE_PANGO |
|
|
|
states[stateno]->fontFamily = (char *) malloc(strlen(state->fontFamily) + 1); |
|
|
|
strcpy(states[stateno]->fontFamily, state->fontFamily); |
|
|
|
#endif |
|
|
|
state = states[stateno]; |
|
|
|
} |
|
|
|
|
|
|
@ -188,9 +217,15 @@ void |
|
|
|
Context2d::restoreState() { |
|
|
|
if (0 == stateno) return; |
|
|
|
// Olaf (2011-02-21): Free old state data
|
|
|
|
#if HAVE_PANGO |
|
|
|
free(states[stateno]->fontFamily); |
|
|
|
#endif |
|
|
|
free(states[stateno]); |
|
|
|
states[stateno] = NULL; |
|
|
|
state = states[--stateno]; |
|
|
|
#if HAVE_PANGO |
|
|
|
setFontFromState(); |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
@ -936,6 +971,8 @@ Context2d::GetTextDrawingMode(Local<String> prop, const AccessorInfo &info) { |
|
|
|
mode = "path"; |
|
|
|
} else if (context->state->textDrawingMode == TEXT_DRAW_GLYPHS) { |
|
|
|
mode = "glyph"; |
|
|
|
} else { |
|
|
|
mode = "unknown"; |
|
|
|
} |
|
|
|
return scope.Close(String::NewSymbol(mode)); |
|
|
|
} |
|
|
@ -1517,8 +1554,62 @@ 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 |
|
|
|
|
|
|
|
PangoRectangle ink_rect, logical_rect; |
|
|
|
PangoFontMetrics *metrics = NULL; |
|
|
|
|
|
|
|
pango_layout_set_text(_layout, str, -1); |
|
|
|
pango_cairo_update_layout(_context, _layout); |
|
|
|
|
|
|
|
switch (state->textAlignment) { |
|
|
|
// center
|
|
|
|
case 0: |
|
|
|
GET_EXTENTS(); |
|
|
|
x -= logical_rect.width / 2; |
|
|
|
break; |
|
|
|
// right
|
|
|
|
case 1: |
|
|
|
GET_EXTENTS(); |
|
|
|
x -= logical_rect.width; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
switch (state->textBaseline) { |
|
|
|
case TEXT_BASELINE_ALPHABETIC: |
|
|
|
GET_METRICS(); |
|
|
|
y -= pango_font_metrics_get_ascent(metrics) / PANGO_SCALE; |
|
|
|
break; |
|
|
|
case TEXT_BASELINE_MIDDLE: |
|
|
|
GET_METRICS(); |
|
|
|
y -= (pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics))/(2.0 * PANGO_SCALE); |
|
|
|
break; |
|
|
|
case TEXT_BASELINE_BOTTOM: |
|
|
|
GET_METRICS(); |
|
|
|
y -= (pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics)) / PANGO_SCALE; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
if (metrics) pango_font_metrics_unref(metrics); |
|
|
|
|
|
|
|
cairo_move_to(_context, x, y); |
|
|
|
if (state->textDrawingMode == TEXT_DRAW_PATHS) { |
|
|
|
pango_cairo_layout_path(_context, _layout); |
|
|
|
} else if (state->textDrawingMode == TEXT_DRAW_GLYPHS) { |
|
|
|
pango_cairo_show_layout(_context, _layout); |
|
|
|
} |
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
cairo_text_extents_t te; |
|
|
|
cairo_font_extents_t fe; |
|
|
|
|
|
|
@ -1567,6 +1658,8 @@ Context2d::setTextPath(const char *str, double x, double y) { |
|
|
|
} else if (state->textDrawingMode == TEXT_DRAW_GLYPHS) { |
|
|
|
cairo_show_text(_context, str); |
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
@ -1636,8 +1729,49 @@ Context2d::SetFont(const Arguments &args) { |
|
|
|
double size = args[2]->NumberValue(); |
|
|
|
String::AsciiValue unit(args[3]); |
|
|
|
String::AsciiValue family(args[4]); |
|
|
|
|
|
|
|
|
|
|
|
Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This()); |
|
|
|
|
|
|
|
#if HAVE_PANGO |
|
|
|
|
|
|
|
if (strlen(*family) > 0) state_assign_fontFamily(context->state, *family); |
|
|
|
|
|
|
|
if (size > 0) context->state->fontSize = size; |
|
|
|
|
|
|
|
if (strlen(*style) > 0) { |
|
|
|
if (0 == strcmp("italic", *style)) { |
|
|
|
context->state->fontStyle = PANGO_STYLE_ITALIC; |
|
|
|
} else if (0 == strcmp("oblique", *style)) { |
|
|
|
context->state->fontStyle = PANGO_STYLE_OBLIQUE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (strlen(*weight) > 0) { |
|
|
|
if (0 == strcmp("bold", *weight)) { |
|
|
|
context->state->fontWeight = PANGO_WEIGHT_BOLD; |
|
|
|
} else if (0 == strcmp("200", *weight)) { |
|
|
|
context->state->fontWeight = PANGO_WEIGHT_ULTRALIGHT; |
|
|
|
} else if (0 == strcmp("300", *weight)) { |
|
|
|
context->state->fontWeight = PANGO_WEIGHT_LIGHT; |
|
|
|
} else if (0 == strcmp("400", *weight)) { |
|
|
|
context->state->fontWeight = PANGO_WEIGHT_NORMAL; |
|
|
|
} else if (0 == strcmp("500", *weight)) { |
|
|
|
context->state->fontWeight = PANGO_WEIGHT_MEDIUM; |
|
|
|
} else if (0 == strcmp("600", *weight)) { |
|
|
|
context->state->fontWeight = PANGO_WEIGHT_SEMIBOLD; |
|
|
|
} else if (0 == strcmp("700", *weight)) { |
|
|
|
context->state->fontWeight = PANGO_WEIGHT_BOLD; |
|
|
|
} else if (0 == strcmp("800", *weight)) { |
|
|
|
context->state->fontWeight = PANGO_WEIGHT_ULTRABOLD; |
|
|
|
} else if (0 == strcmp("900", *weight)) { |
|
|
|
context->state->fontWeight = PANGO_WEIGHT_HEAVY; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
context->setFontFromState(); |
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
cairo_t *ctx = context->context(); |
|
|
|
|
|
|
|
// Size
|
|
|
@ -1658,10 +1792,33 @@ Context2d::SetFont(const Arguments &args) { |
|
|
|
} |
|
|
|
|
|
|
|
cairo_select_font_face(ctx, *family, s, w); |
|
|
|
|
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
return Undefined(); |
|
|
|
} |
|
|
|
|
|
|
|
#if HAVE_PANGO |
|
|
|
|
|
|
|
/*
|
|
|
|
* Sets PangoLayout options from the current font state |
|
|
|
*/ |
|
|
|
|
|
|
|
void |
|
|
|
Context2d::setFontFromState() { |
|
|
|
PangoFontDescription *fd = pango_font_description_new(); |
|
|
|
|
|
|
|
pango_font_description_set_family(fd, state->fontFamily); |
|
|
|
pango_font_description_set_absolute_size(fd, state->fontSize * PANGO_SCALE); |
|
|
|
pango_font_description_set_style(fd, state->fontStyle); |
|
|
|
pango_font_description_set_weight(fd, state->fontWeight); |
|
|
|
|
|
|
|
pango_layout_set_font_description(_layout, fd); |
|
|
|
pango_font_description_free(fd); |
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
/*
|
|
|
|
* Return the given text extents. |
|
|
|
* TODO: Support for: |
|
|
|