Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

suggestion for support of dev->glyph() #123

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
c1852df
add a dev->typeset() that just renders the first value in span$text f…
pmur002 Aug 23, 2022
ec6899f
Add layout_text(), which is analogue of draw_text(), and have agg_typ…
pmur002 Aug 25, 2022
7b2f79d
Add render_glyphs(), called by agg_renderText(), via device->renderTe…
pmur002 Aug 29, 2022
1719457
dev->renderText() changed to dev->glyph() (r82767)
pmur002 Aug 30, 2022
c288eb9
add 'width' argument to dev->typeset()
pmur002 Sep 2, 2022
025c304
use font size from glyph info
pmur002 Sep 6, 2022
ee012c2
update for simplified dev->glyph() API
pmur002 Sep 12, 2022
cda4bcf
tweaking glyph placement (still just to get something working)
pmur002 Sep 13, 2022
040d3a0
playing with positioning of glyphs
pmur002 Sep 18, 2022
3141b0f
dev->glyph() only receives x/y (no offset)
pmur002 Sep 20, 2022
216cd85
update for changes to glyphInfo() structure and dev->glyph() API
pmur002 Sep 26, 2022
657f212
remove dev->typeset()
pmur002 Sep 27, 2022
d938bf1
Merge branch 'r-lib:main' into master
pmur002 Sep 29, 2022
ff52ed2
Merge branch 'r-lib:main' into master
pmur002 Oct 6, 2022
e9dcccb
add colour to dev->glyph()
pmur002 Oct 17, 2022
e8c79b2
Merge branch 'r-lib:main' into master
pmur002 Oct 28, 2022
502bcb3
improve dev->glyph() support: add 'rot' arg; use font 'file' if pos…
pmur002 Nov 13, 2022
9d02aa9
update for new 'PSname' in glyphInfo()
pmur002 Nov 15, 2022
49abae8
Merge branch 'r-lib:main' into master
pmur002 Jan 17, 2023
c51069c
updates for changes to r-devel-typeset; dev->glyph() now passes font…
pmur002 Jan 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 136 additions & 0 deletions src/AggDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ class AggDevice {
bool interpolate);
void drawText(double x, double y, const char *str, const char *family,
int face, double size, double rot, double hadj, int col);
void drawGlyph(int n, int *glyphs, double *x, double *y,
SEXP font, double size,
int colour, double rot);

protected:
virtual inline R_COLOR convertColour(unsigned int col) {
Expand Down Expand Up @@ -1035,3 +1038,136 @@ void AggDevice<PIXFMT, R_COLOR, BLNDFMT>::drawText(double x, double y, const cha
}
}
}

template<class PIXFMT, class R_COLOR, typename BLNDFMT>
void AggDevice<PIXFMT, R_COLOR, BLNDFMT>::drawGlyph(int n, int *glyphs,
double *x, double *y,
SEXP font, double size,
int colour, double rot) {
agg::glyph_rendering gren = std::fmod(rot, 90) == 0.0 && recording_clip == NULL ? agg::glyph_ren_agg_gray8 : agg::glyph_ren_outline;

int i;
for (i=0; i<n; i++) {
*x += x_trans;
*y += y_trans;
}

size *= res_mod;

char file[501];
strncpy(file, R_GE_glyphFontFile(font), 500);
int index = R_GE_glyphFontIndex(font);
char family[201];
strncpy(family, R_GE_glyphFontFamily(font),
200);
double weight = R_GE_glyphFontWeight(font);
int style = R_GE_glyphFontStyle(font);

FontSettings f;
strncpy(f.file, file, 500);
f.index = index;
f.features = NULL;
f.n_features = 0;

if (!t_ren.load_font_from_file(f, gren, size, device_id)) {
int face;
if (weight > 400) {
if (style != R_GE_text_style_normal) {
face = 4;
} else {
face = 2;
}
} else {
if (style != R_GE_text_style_normal) {
face = 3;
} else {
face = 1;
}
}
f = locate_font_with_features(family,
face == 2 ||
face == 4,
face == 3 ||
face == 4);
if (!t_ren.load_font(gren, family, face, size, device_id))
return;
}

agg::rasterizer_scanline_aa<> ras_clip(MAX_CELLS);
if (current_clip != NULL) {
ras_clip.add_path(*current_clip);
if (current_clip_rule_is_evenodd) {
ras_clip.filling_rule(agg::fill_even_odd);
}
}

agg::scanline_u8 slu;
if (recording_mask == NULL && recording_pattern == NULL) {
solid_renderer.color(convertColour(colour));
if (current_mask == NULL) {
t_ren.template render_glyphs<BLNDFMT>(n, glyphs, x, y,
family, weight, style,
file, index, size, rot,
solid_renderer, renderer,
slu, device_id,
ras_clip, current_clip != NULL,
recording_clip);
} else {
t_ren.template render_glyphs<BLNDFMT>(n, glyphs, x, y,
family, weight, style,
file, index, size, rot,
solid_renderer, renderer,
current_mask->get_masked_scanline(),
device_id,
ras_clip, current_clip != NULL,
recording_clip);
}
} else if (recording_pattern == NULL) {
recording_mask->set_colour(convertMaskCol(colour));
if (current_mask == NULL) {
t_ren.template render_glyphs<pixfmt_type_32>(n, glyphs, x, y,
family, weight, style,
file, index, size, rot,
recording_mask->get_solid_renderer(),
recording_mask->get_renderer(),
slu, device_id,
ras_clip,
current_clip != NULL,
recording_clip);
} else {
t_ren.template render_glyphs<pixfmt_type_32>(n, glyphs, x, y,
family, weight, style,
file, index, size, rot,
recording_mask->get_solid_renderer(),
recording_mask->get_renderer(),
current_mask->get_masked_scanline(),
device_id,
ras_clip,
current_clip != NULL,
recording_clip);
}
} else {
recording_pattern->set_colour(convertColour(colour));
if (current_mask == NULL) {
t_ren.template render_glyphs<BLNDFMT>(n, glyphs, x, y,
family, weight, style,
file, index, size, rot,
recording_pattern->get_solid_renderer(),
recording_pattern->get_renderer(),
slu, device_id,
ras_clip, current_clip != NULL,
recording_clip);
} else {
t_ren.template render_glyphs<BLNDFMT>(n, glyphs, x, y,
family, weight, style,
file, index, size, rot,
recording_pattern->get_solid_renderer(),
recording_pattern->get_renderer(),
current_mask->get_masked_scanline(),
device_id,
ras_clip, current_clip != NULL,
recording_clip);
}
}

}
43 changes: 42 additions & 1 deletion src/init_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,37 @@ void agg_releaseMask(SEXP ref, pDevDesc dd) {
END_CPP
}

template<class T>
SEXP agg_defineGroup(SEXP source, int op, SEXP destination, pDevDesc dd) {
return R_NilValue;
}

template<class T>
void agg_useGroup(SEXP ref, SEXP trans, pDevDesc dd) {}

template<class T>
void agg_releaseGroup(SEXP ref, pDevDesc dd) {}

template<class T>
void agg_stroke(SEXP path, const pGEcontext gc, pDevDesc dd) {}

template<class T>
void agg_fill(SEXP path, int rule, const pGEcontext gc, pDevDesc dd) {}

template<class T>
void agg_fillStroke(SEXP path, int rule, const pGEcontext gc, pDevDesc dd) {}

template<class T>
void agg_glyph(int n, int *glyphs, double *x, double *y,
SEXP font, double size,
int colour, double rot,
pDevDesc dd) {
T * device = (T *) dd->deviceSpecific;
BEGIN_CPP
device->drawGlyph(n, glyphs, x, y, font, size, colour, rot);
END_CPP
}

static unsigned int DEVICE_COUNTER = 0;

template<class T>
Expand Down Expand Up @@ -301,6 +332,14 @@ pDevDesc agg_device_new(T* device) {
dd->releaseClipPath = agg_releaseClipPath<T>;
dd->setMask = agg_setMask<T>;
dd->releaseMask = agg_releaseMask<T>;
dd->defineGroup = agg_defineGroup<T>;
dd->useGroup = agg_useGroup<T>;
dd->releaseGroup = agg_releaseGroup<T>;
dd->stroke = agg_stroke<T>;
dd->fill = agg_fill<T>;
dd->fillStroke = agg_fillStroke<T>;

dd->glyph = agg_glyph<T>;
#endif
// UTF-8 support
dd->wantSymbolUTF8 = (Rboolean) 1;
Expand Down Expand Up @@ -339,7 +378,9 @@ pDevDesc agg_device_new(T* device) {
dd->useRotatedTextInContour = (Rboolean) 1;

#if R_GE_version >= 13
dd->deviceVersion = R_GE_definitions;
// Very dangerous because we have skipped over R_GE_Group
// so we are vulnerable to being called by, e.g., dev->stroke()
dd->deviceVersion = R_GE_glyphs;
#endif

device->device_id = DEVICE_COUNTER++;
Expand Down
105 changes: 86 additions & 19 deletions src/text_renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,25 @@ class TextRenderer {
return true;
}

bool load_font_from_file(FontSettings font, agg::glyph_rendering gren, double size,
unsigned int id) {
if (id != get_engine().id() ||
!(gren == last_gren &&
font.index == last_font.index &&
strncmp(font.file, last_font.file, PATH_MAX) == 0)) {
if (!get_engine().load_font(font.file, font.index, gren)) {
return false;
}
last_gren = gren;
get_engine().height(size);
get_engine().id(id);
} else if (size != get_engine().height()) {
get_engine().height(size);
}
last_font = font;
return true;
}

double get_text_width(const char* string) {
double width = 0.0;
int error = textshaping::string_width(
Expand Down Expand Up @@ -338,6 +357,73 @@ class TextRenderer {
}
}

template<typename TARGET, typename renderer_solid, typename renderer, typename raster, typename scanline>
void render_glyphs(int n, int *glyphs, double *x, double *y,
const char* family, double weight, int style,
const char* file, int index, double size, double rot,
renderer_solid &ren_solid, renderer &ren,
scanline &sl, unsigned int id,
raster &ras_clip, bool clip,
agg::path_storage* recording_clip) {

agg::rasterizer_scanline_aa<> ras;
agg::conv_curve<font_manager_type::path_adaptor_type> curves(get_manager().path_adaptor());
curves.approximation_scale(2.0);

int i;

agg::trans_affine mtx;
if (rot != 0) {
rot = agg::deg2rad(-rot);
mtx *= agg::trans_affine_rotation(rot);
}

for (i = 0; i < n; i++) {
if (rot != 0) {
agg::trans_affine mtx2;
mtx2 *= mtx;
get_engine().transform(mtx2);
}

const agg::glyph_cache*
glyph = get_manager().glyph(glyphs[i]);
if (glyph) {

get_manager().init_embedded_adaptors(glyph, x[i], y[i]);
switch(glyph->data_type) {
default: break;
case agg::glyph_data_gray8:
render<agg::scanline_u8>(get_manager().gray8_adaptor(),
ras_clip, sl, ren_solid,
clip);
break;

case agg::glyph_data_color:
renderColourGlyph<TARGET>(glyph, x[i], y[i],
0.0, // rot
ren, sl,
1.0, // scaling
ras_clip, clip);
break;

case agg::glyph_data_outline:
if (recording_clip != NULL) {
recording_clip->concat_path(curves);
break;
}
ras.reset();
ras.add_path(curves);
render<agg::scanline_u8>(ras, ras_clip, sl,
ren_solid, clip);
break;
}
}
if (rot != 0) {
get_engine().transform(agg::trans_affine());
}
}
}

private:
inline font_engine_type& get_engine() {
static font_engine_type engine;
Expand All @@ -358,25 +444,6 @@ class TextRenderer {
return locate_font_with_features(fontfamily, italic, bold);
}

bool load_font_from_file(FontSettings font, agg::glyph_rendering gren, double size,
unsigned int id) {
if (id != get_engine().id() ||
!(gren == last_gren &&
font.index == last_font.index &&
strncmp(font.file, last_font.file, PATH_MAX) == 0)) {
if (!get_engine().load_font(font.file, font.index, gren)) {
return false;
}
last_gren = gren;
get_engine().height(size);
get_engine().id(id);
} else if (size != get_engine().height()) {
get_engine().height(size);
}
last_font = font;
return true;
}

template<typename TARGET, typename ren, typename raster, typename scanline>
void renderColourGlyph(const agg::glyph_cache* glyph, double x, double y,
double rot, ren &renderer, scanline &sl, double scaling, raster &ras_clip,
Expand Down