diff --git a/src/cairogd.c b/src/cairogd.c index c305b86..33d3972 100644 --- a/src/cairogd.c +++ b/src/cairogd.c @@ -144,9 +144,12 @@ Rboolean Rcairo_new_device_driver(NewDevDesc *dd, const char *type, int conn, co #endif #if R_GE_version >= 13 - dd->deviceVersion = R_GE_definitions; + dd->deviceVersion = R_GE_definitions; +#endif +#if R_GE_version >= 16 + /* FIXME: we don't actually implement 14 and 15 */ + dd->deviceVersion = R_GE_glyphs; #endif - dd->deviceSpecific = (void *) xd; #ifdef JGD_DEBUG diff --git a/src/cairotalk.c b/src/cairotalk.c index 06452ef..cf2d998 100644 --- a/src/cairotalk.c +++ b/src/cairotalk.c @@ -110,6 +110,16 @@ static void CairoGD_releaseClipPath(SEXP ref, pDevDesc dd); static SEXP CairoGD_setMask(SEXP path, SEXP ref, pDevDesc dd); static void CairoGD_releaseMask(SEXP ref, pDevDesc dd); +#if R_GE_version >= 16 +/* this is required since 14 otherwise R segfaults */ +static SEXP CairoGD_Capabilities(SEXP capabilities); + +/* GE 16 glyph API */ +static void CairoGD_Glyph(int n, int *glyphs, double *x, double *y, + SEXP font, double size, + int col, double rot, pDevDesc dd); +#endif + /* fake mbcs support for old R versions */ #if R_GE_version < 4 #define mbcslocale 0 @@ -1419,6 +1429,82 @@ static void CairoGD_TextNative(double x, double y, constxt char *str, CairoGD_TextEnc(x, y, str, rot, hadj, gc, dd, ""); } +#if R_GE_version >= 16 +static SEXP CairoGD_Capabilities(SEXP capabilities) { + SEXP glyphs = PROTECT(ScalarInteger(1)); + SET_VECTOR_ELT(capabilities, R_GE_capability_glyphs, glyphs); + UNPROTECT(1); + return capabilities; +} + +static void CairoGD_Glyph(int n, int *glyphs, double *x, double *y, + SEXP font, double size, + int col, double rot, pDevDesc dd) { + CairoGDDesc *xd = (CairoGDDesc *) dd->deviceSpecific; + cairo_t *cc; + + if (!xd || !xd->cb) return; + + cc = xd->cb->cc; + + /* font info is explicit so we don't use our regular cache and mapping */ + double weight = R_GE_glyphFontWeight(font); + int style = R_GE_glyphFontStyle(font); + int wt = (weight > 400) ? CAIRO_FONT_WEIGHT_BOLD : CAIRO_FONT_WEIGHT_NORMAL; + int sl = (style == R_GE_text_style_normal) ? CAIRO_FONT_SLANT_NORMAL : CAIRO_FONT_SLANT_ITALIC; + +#ifdef JGD_DEBUG + Rprintf("INFO: Glyph(n=%d), fontfile='%s', index=%d, weight=%f, style=%d, col=%x, rot=%f\n", + n, R_GE_glyphFontFile(font) ? R_GE_glyphFontFile(font) : "", + R_GE_glyphFontIndex(font), weight, style, col, rot); +#endif + + cairo_font_face_t *cairo_face = NULL; +#if USE_CAIRO_FT + FcPattern *pattern = FcPatternBuild(NULL, + FC_FILE, FcTypeString, + R_GE_glyphFontFile(font), + FC_INDEX, FcTypeInteger, + R_GE_glyphFontIndex(font), + NULL); + cairo_face = cairo_ft_font_face_create_for_pattern(pattern); + FcPatternDestroy(pattern); +#endif + if (cairo_face && + cairo_font_face_status(cairo_face) == CAIRO_STATUS_SUCCESS) { + cairo_set_font_face(cc, cairo_face); + } else /* fall back - hopefully not needed */ + cairo_select_font_face(cc, R_GE_glyphFontFamily(font), sl, wt); + + /* FIXME: not sure if we need to scale - Quartz uses 72 baseline - check sizes */ + cairo_set_font_size (cc, size / (72*dd->ipr[0])); + + Rcairo_set_color(cc, col); + + int i = 0; + while (i < n) { + if (rot != 0.0) { + cairo_save(cc); + cairo_translate(cc, x[i], y[i]); + cairo_rotate(cc, -rot/180.*M_PI); + cairo_translate(cc, -x[i], -y[i]); + } + + cairo_glyph_t cairoGlyph; + cairoGlyph.index = glyphs[i]; + cairoGlyph.x = x[i]; + cairoGlyph.y = y[i]; + + cairo_show_glyphs(cc, &cairoGlyph, 1); + /* for path ops use cairo_glyph_path(cc, &cairoGlyph, 1); instead */ + + if (rot != 0.0) + cairo_restore(cc); + i++; + } +} +#endif + static SEXP CairoGD_setPattern(SEXP pattern, pDevDesc dd) { return R_NilValue; } @@ -1475,6 +1561,11 @@ void Rcairo_setup_gd_functions(NewDevDesc *dd) { dd->releaseClipPath = CairoGD_releaseClipPath; dd->setMask = CairoGD_setMask; dd->releaseMask = CairoGD_releaseMask; +#if R_GE_version >= 16 + /* NOTE: caps must be set from 14 on or else R segfaults */ + dd->capabilities = CairoGD_Capabilities; + dd->glyph = CairoGD_Glyph; +#endif #endif #endif #endif