Skip to content

Commit bcb8a60

Browse files
author
murrell
committed
add variable font support to glyph rendering
git-svn-id: https://svn.r-project.org/R/trunk@88293 00db46b3-68df-0310-9c12-caf00c1e9a41
1 parent 804f800 commit bcb8a60

File tree

11 files changed

+316
-28
lines changed

11 files changed

+316
-28
lines changed

doc/NEWS.Rd

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,21 @@
4949
}
5050
}
5151
52+
\subsection{GRAPHICS}{
53+
\itemize{
54+
\item The graphics engine version, \code{R_GE_version}, has been
55+
bumped to \code{17} and so packages that provide graphics devices
56+
should be reinstalled.
57+
58+
The \code{glyphFont()} function gains a \code{variations}
59+
argument, which allows variable font axes to be specified,
60+
e.g., \code{c(wght=100)}.
61+
62+
Only Cairo-based graphics devices (but not \code{cairo_pdf()})
63+
support variable font axes so far.
64+
}
65+
}
66+
5267
\subsection{INSTALLATION}{
5368
\itemize{
5469
\item .

src/include/R_ext/GraphicsEngine.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,16 @@ extern "C" {
8888
* Version 16: For R 4.3.0
8989
* Added more advanced typesetting
9090
* - glyphs
91+
* Version 17: For R 4.6.0
92+
* - variable fonts
9193
*/
9294
#define R_GE_definitions 13
9395
#define R_GE_deviceClip 14
9496
#define R_GE_group 15
9597
#define R_GE_glyphs 16
98+
#define R_GE_fontVar 17
9699

97-
#define R_GE_version R_GE_glyphs
100+
#define R_GE_version R_GE_fontVar
98101

99102
int R_GE_getVersion(void);
100103

@@ -662,6 +665,7 @@ int R_GE_maskType(SEXP mask);
662665
#define R_GE_capability_transformations 10
663666
#define R_GE_capability_paths 11
664667
#define R_GE_capability_glyphs 12
668+
#define R_GE_capability_variableFonts 13
665669

666670
/* Must match order in ../library/grDevices/R/glyph.R */
667671
#define R_GE_text_style_normal 1
@@ -686,6 +690,10 @@ const char* R_GE_glyphFontFamily(SEXP glyphFont);
686690
double R_GE_glyphFontWeight(SEXP glyphFont);
687691
int R_GE_glyphFontStyle(SEXP glyphFont);
688692
const char* R_GE_glyphFontPSname(SEXP glyphFont);
693+
int R_GE_glyphFontNumVar(SEXP glyphFont);
694+
const char* R_GE_glyphFontVarAxis(SEXP glyphFont, int index);
695+
double R_GE_glyphFontVarValue(SEXP glyphFont, int index);
696+
const char* R_GE_glyphFontVarFormatted(SEXP glyphFont, int index);
689697

690698
void GEGlyph(int n, int *glyphs, double *x, double *y,
691699
SEXP font, double size,

src/library/grDevices/NAMESPACE

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ export(Hershey, adjustcolor, as.graphicsAnnot, as.raster, axisTicks,
99
dev.copy, dev.copy2eps, dev.copy2pdf, dev.cur, dev.hold,
1010
dev.flush, dev.interactive, dev.list, dev.new, dev.next,
1111
dev.off, dev.prev, dev.print, dev.set, dev.size, dev2bitmap,
12-
deviceIsInteractive, embedFonts, embedGlyphs, extendrange,
12+
deviceIsInteractive, embedFonts, embedGlyphs, extendrange,
1313
getGraphicsEvent, getGraphicsEventEnv,
14-
glyphInfo, glyphAnchor, glyphFont, glyphFontList,
14+
glyphInfo, glyphAnchor, glyphFont, glyphFontList, glyphFontVariation,
1515
glyphWidth, glyphHeight, glyphWidthLeft, glyphHeightBottom, glyphJust,
1616
graphics.off, gray, grey, gray.colors,
1717
grSoftVersion, grey.colors, heat.colors, hsv, hcl, hcl.colors, hcl.pals,
@@ -71,6 +71,8 @@ S3method("glyphJust", "character")
7171
S3method("glyphJust", "numeric")
7272
S3method("glyphJust", "GlyphJust")
7373

74+
S3method("print", "FontVariation")
75+
7476
if(tools:::.OStype() == "windows") {
7577
export(bringToTop, msgWindow, win.graph, win.metafile, win.print,
7678
windows, windows.options, windowsFont, windowsFonts)

src/library/grDevices/R/device.R

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ dev.capture <- function(native = FALSE) .External(C_devcapture, native)
358358

359359
dev.capabilities <- function(what = NULL)
360360
{
361-
ncap <- 13
361+
ncap <- 14
362362
template <- vector("list", ncap)
363363
capabilities <- .External(C_devcap, template)
364364
## The device may have filled in some capabilities so check it is still
@@ -381,7 +381,8 @@ dev.capabilities <- function(what = NULL)
381381
"compositing",
382382
"transformations",
383383
"paths",
384-
"glyphs")
384+
"glyphs",
385+
"variableFonts")
385386
z[[1L]] <- c(NA, FALSE, TRUE)[capabilities[[1L]] + 1L]
386387
z[[2L]] <- c(NA, "no", "fully", "semi")[capabilities[[2L]] + 1L]
387388
z[[3L]] <- c(NA, "no", "yes", "non-missing")[capabilities[[3L]] + 1L]
@@ -439,6 +440,11 @@ dev.capabilities <- function(what = NULL)
439440
z[[13]] <- NA
440441
else
441442
z[[13]] <- as.logical(capabilities[[13]])
443+
## VariableFonts
444+
if (is.na(capabilities[[14]]))
445+
z[[14]] <- NA
446+
else
447+
z[[14]] <- as.logical(capabilities[[14]])
442448

443449
if (!is.null(what)) z[charmatch(what, names(z), 0L)] else z
444450
}

src/library/grDevices/R/glyph.R

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,72 @@ glyphJust.numeric <- function(just, which=NULL, ...) {
113113

114114
################################################################################
115115
## glyph font
116+
117+
standardAxes <- c("wght", "wdth", "ital", "slnt", "opsz")
118+
standardAxisMin <- c(wght=1, wdth=0, ital=0, slnt=-90, opsz=0)
119+
standardAxisMax <- c(wght=1000, wdth=Inf, ital=1, slnt=90, opsz=Inf)
120+
121+
checkAxisCase <- function(axis, registered) {
122+
if (any(registered) &&
123+
(!all(tolower(axis[registered]) == axis[registered]))) {
124+
warning("Registered axis names must be lower case")
125+
}
126+
if (any(!registered) &&
127+
(!all(toupper(axis[!registered]) == axis[!registered]))) {
128+
warning("Custom axis names must be upper case")
129+
}
130+
}
131+
132+
checkAxisRange <- function(axis, value) {
133+
low <- value < standardAxisMin[axis]
134+
high <- value > standardAxisMax[axis]
135+
if (any(low) || any(high)) {
136+
warning("Axis value(s) out of range: ",
137+
paste(paste0(axis[low|high], "=", value[low|high]),
138+
collapse="; "))
139+
}
140+
}
141+
142+
fontVariation <- function(axis, value) {
143+
if (!length(axis)) {
144+
stop("No axes specified")
145+
}
146+
if (!is.character(axis) || any(is.na(axis)) || any(nchar(axis) != 4)||
147+
any(grepl("[^a-zA-Z]", axis))) {
148+
stop("Axis names must 4 ASCII letters long")
149+
}
150+
if (!is.numeric(value) || any(is.na(value))) {
151+
stop("Axis values must be numeric")
152+
}
153+
registered <- tolower(axis) %in% standardAxes
154+
checkAxisCase(axis, registered)
155+
if (any(registered)) {
156+
checkAxisRange(tolower(axis[registered]), value[registered])
157+
}
158+
variant <- value
159+
names(variant) <- axis
160+
attr(variant, "formatted") <- paste(axis, value, sep="=")
161+
attr(variant, "registered") <- registered
162+
class(variant) <- "FontVariation"
163+
variant
164+
}
165+
166+
glyphFontVariation <- function(...) {
167+
values <- c(...)
168+
axes <- names(values)
169+
fontVariation(axes, values)
170+
}
171+
172+
print.FontVariation <- function(x, ...) {
173+
names <- names(x)
174+
attributes(x) <- NULL
175+
names(x) <- names
176+
print(unclass(x))
177+
}
178+
116179
glyphFont <- function(file, index,
117180
family, weight, style,
118-
PSname=NA) {
181+
PSname=NA, variations=NULL) {
119182
file <- as.character(file)
120183
nafile <- is.na(file)
121184
if (any(nchar(file[!nafile], "bytes") > 500))
@@ -151,17 +214,31 @@ glyphFont <- function(file, index,
151214
names <- rle(PSname)$lengths
152215
if (!(all(families == files) && all(files == names)))
153216
stop("Font information is inconsistent")
154-
217+
if (!is.null(variations)) {
218+
if (!inherits(variations, "FontVariation")) {
219+
variations <- do.call(glyphFontVariation, as.list(variations))
220+
}
221+
}
222+
155223
font <- list(file=file, index=index,
156224
family=family, weight=weight, style=style,
157-
PSname=PSname)
225+
PSname=PSname, variations=variations)
158226
class(font) <- "RGlyphFont"
159227
font
160228
}
161229

162230
print.RGlyphFont <- function(x, ...) {
163-
cat(paste0(x$family, " wgt: ", x$weight, " style: ", invertStyle(x$style),
164-
"\n (", x$file, " [", x$index, "])\n"))
231+
format <- paste0(x$family, " wgt: ", x$weight,
232+
" style: ", invertStyle(x$style),
233+
"\n (", x$file, " [", x$index, "]")
234+
if (!is.null(x$variations)) {
235+
format <- paste0(format,
236+
" [",
237+
paste(paste0(names(x$variations), "=", x$variations),
238+
collapse="; "),
239+
"]")
240+
}
241+
cat(format, ")\n")
165242
}
166243

167244
glyphFontList <- function(...) {

src/library/grDevices/man/glyphInfo.Rd

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
\name{glyphInfo}
88
\alias{glyphInfo}
99
\alias{glyphFont}
10+
\alias{glyphFontVariation}
1011
\alias{glyphFontList}
1112
\alias{glyphAnchor}
1213
\alias{glyphWidth}
@@ -29,7 +30,8 @@ glyphInfo(id, x, y, font, size, fontList,
2930
width, height, hAnchor, vAnchor,
3031
col=NA, rot=0)
3132

32-
glyphFont(file, index, family, weight, style, PSname=NA)
33+
glyphFont(file, index, family, weight, style, PSname=NA, variations=NULL)
34+
glyphFontVariation(...)
3335
glyphFontList(...)
3436
glyphAnchor(value, label)
3537
glyphWidth(w, label="width", left="left")
@@ -70,13 +72,19 @@ glyphJust(just, ...)
7072
\item{style}{Character style of glyphs (\code{"normal"}, \code{"italic"},
7173
or \code{"oblique"}).}
7274
\item{PSname}{The PostScript name for each font. Can be \code{NA}.}
75+
\item{variations}{Axis coordinate settings for variable fonts. Either
76+
\code{NULL}, or a call to \code{glyphFontVariation()}, or a named vector,
77+
or a named list.}
7378
\item{value, w, h}{A numeric value.}
7479
\item{label, left, bottom}{A character value.}
7580
\item{just}{A justification value. Either a character value like
7681
\code{"left"} or a numeric value like \code{0}.}
7782
\item{which}{When \code{x} is numeric, a character value identifying
7883
which width metric the numeric value is relative to.}
79-
\item{\dots}{Further arguments passed to other methods.}
84+
\item{\dots}{For \code{glyphFontList()}, one or more
85+
\code{glyphFont()}s. For \code{glyphFontVar()}, one or more named
86+
numeric values (see Details). Otherwise, further arguments passed to
87+
other methods.}
8088
}
8189
\value{
8290
The result from \code{glyphInfo()} is an \code{"RGlyphInfo"} object,
@@ -130,6 +138,12 @@ glyphJust(just, ...)
130138
\code{glyphWidthLeft()} and \code{glyphWidthHeight()} provide
131139
an API for code that needs to access the relevant anchors for
132140
width and height metrics.
141+
142+
\code{glyphFontVariation()} accepts arguments of the form \code{wght=100}.
143+
Every argument should be named, each name should be 4 ASCII characters
144+
long, each name should be either one of the standard axes
145+
(wght, slnt, wdth, ital, opsz), in lowercase, otherwise (if a
146+
custom axis) in uppercase. Every argument value should be numeric.
133147
}
134148
\section{Warning}{
135149
Any glyph with \code{NA} in any of \code{id}, \code{x}, \code{y},

src/library/grDevices/src/cairo/cairoBM.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ BMDeviceDriver(pDevDesc dd, int kind, SEXP filename,
553553
dd->startfont = 1;
554554
dd->startgamma = 1;
555555
dd->displayListOn = FALSE;
556-
dd->deviceVersion = R_GE_glyphs;
556+
dd->deviceVersion = R_GE_fontVar;
557557

558558
dd->deviceSpecific = (void *) xd;
559559

0 commit comments

Comments
 (0)