systemfonts/0000755000176200001440000000000013506400572012652 5ustar liggesuserssystemfonts/inst/0000755000176200001440000000000013506366517013641 5ustar liggesuserssystemfonts/inst/doc/0000755000176200001440000000000013506366517014406 5ustar liggesuserssystemfonts/inst/doc/c_interface.R0000644000176200001440000000035413506366516016774 0ustar liggesusers## ---- include = FALSE---------------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ## ----setup--------------------------------------------------------------- library(systemfonts) systemfonts/inst/doc/c_interface.Rmd0000644000176200001440000000367013502750205017305 0ustar liggesusers--- title: "systemfonts C interface" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{systemfonts C interface} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ```{r setup} library(systemfonts) ``` Most of the functionality in systemfonts is intended to be used from compiled code to help e.g. graphic devices to resolve font specifications to a font file prior to rendering. systemfonts provide key functionality to get called at the C level using the `R_getCCallable()` function. The systemfonts namespace must be loaded for this to work, so be sure to import e.g. `match_font()` in the package namespace. For more information about this interface see [*Registering native routines*](https://cran.r-project.org/doc/manuals/R-exts.html#Registering-native-routines) in *Writing R Extensions*. ## Font matching The C equivalent of the `match_font()` R function is `locate_font()` with the following signature: ```C int locate_font(const char *family, int italic, int bold, char *path, int max_path_length) ``` It takes a UTF-8 encoded string with the font family name, an int setting both italic and bold styles along with a char pointer to be filled with the located path and the maximum length it can hold. The return value is an int giving the index of the font in the font file. The best way to use the function in a package is to wrap it in a function to avoid fetching it multiple times, e.g. ```C static int locate_font(const char *family, int italic, int bold, char *path, int max_path_length) { static int (*p_locate_font)(const char *family, int italic, int bold, char *path, int max_path_length) = NULL; if (p_locate_font == NULL) { p_locate_font = (int(*)(const char *, int, int, char *, int)) R_GetCCallable("systemfonts", "locate_font"); } return p_locate_font(family, italic, bold, path, max_path_length); } ``` systemfonts/inst/doc/c_interface.html0000644000176200001440000002571513506366517017550 0ustar liggesusers systemfonts C interface

systemfonts C interface

library(systemfonts)

Most of the functionality in systemfonts is intended to be used from compiled code to help e.g. graphic devices to resolve font specifications to a font file prior to rendering. systemfonts provide key functionality to get called at the C level using the R_getCCallable() function. The systemfonts namespace must be loaded for this to work, so be sure to import e.g. match_font() in the package namespace. For more information about this interface see Registering native routines in Writing R Extensions.

Font matching

The C equivalent of the match_font() R function is locate_font() with the following signature:

int locate_font(const char *family, int italic, int bold, char *path, int max_path_length)

It takes a UTF-8 encoded string with the font family name, an int setting both italic and bold styles along with a char pointer to be filled with the located path and the maximum length it can hold. The return value is an int giving the index of the font in the font file.

The best way to use the function in a package is to wrap it in a function to avoid fetching it multiple times, e.g.

static int locate_font(const char *family, int italic, int bold, char *path, int max_path_length) {
  static int (*p_locate_font)(const char *family, int italic, int bold, char *path, int max_path_length) = NULL;
  if (p_locate_font == NULL) {
    p_locate_font = (int(*)(const char *, int, int, char *, int)) R_GetCCallable("systemfonts", "locate_font");
  }
  return p_locate_font(family, italic, bold, path, max_path_length);
}
systemfonts/tests/0000755000176200001440000000000013502411462014010 5ustar liggesuserssystemfonts/tests/testthat.R0000644000176200001440000000010213502411462015764 0ustar liggesuserslibrary(testthat) library(systemfonts) test_check("systemfonts") systemfonts/tests/testthat/0000755000176200001440000000000013506400572015654 5ustar liggesuserssystemfonts/tests/testthat/test-system_fonts.R0000644000176200001440000000044413502666007021516 0ustar liggesuserscontext("Font listing") test_that("System fonts can be listed", { fonts <- system_fonts() expect_is(fonts, 'data.frame') expect_gt(nrow(fonts), 0) expect_named(fonts, c("path", "index", "name", "family", "style", "weight", "width", "italic", "monospace")) }) systemfonts/tests/testthat/test-match_font.R0000644000176200001440000000132413506366416021106 0ustar liggesuserscontext("Font Matching") sysname <- tolower(Sys.info()[["sysname"]]) font <- switch( sysname, darwin = "Helvetica", linux = "DejaVuSans", windows = "arial" ) test_that("Font files can be found", { font_path <- match_font("sans")$path expect_true(file.exists(font_path)) skip_on_os("linux") # Different fonts for different distros skip_on_os("solaris") # Have no idea what it is supposed to give expect_equal(tools::file_path_sans_ext(basename(font_path)), font) }) test_that("Default font is correct", { font_path <- match_font("sans")$path expect_true(file.exists(font_path)) skip_on_os("linux") skip_on_os("solaris") expect_equal(tools::file_path_sans_ext(basename(font_path)), font) }) systemfonts/src/0000755000176200001440000000000013506366517013453 5ustar liggesuserssystemfonts/src/FontDescriptor.h0000755000176200001440000000705113502433634016566 0ustar liggesusers#ifndef FONT_DESCRIPTOR_H #define FONT_DESCRIPTOR_H #include #include enum FontWeight { FontWeightUndefined = 0, FontWeightThin = 100, FontWeightUltraLight = 200, FontWeightLight = 300, FontWeightNormal = 400, FontWeightMedium = 500, FontWeightSemiBold = 600, FontWeightBold = 700, FontWeightUltraBold = 800, FontWeightHeavy = 900 }; enum FontWidth { FontWidthUndefined = 0, FontWidthUltraCondensed = 1, FontWidthExtraCondensed = 2, FontWidthCondensed = 3, FontWidthSemiCondensed = 4, FontWidthNormal = 5, FontWidthSemiExpanded = 6, FontWidthExpanded = 7, FontWidthExtraExpanded = 8, FontWidthUltraExpanded = 9 }; struct FontDescriptor { public: const char *path; int index; const char *postscriptName; const char *family; const char *style; FontWeight weight; FontWidth width; bool italic; bool monospace; FontDescriptor() { path = NULL; index = -1; postscriptName = NULL; family = NULL; style = NULL; weight = FontWeightUndefined; width = FontWidthUndefined; italic = false; monospace = false; } // Constructor added by Thomas Lin Pedersen FontDescriptor(const char *family, bool italic, bool bold) { this->path = NULL; this->index = -1; this->postscriptName = NULL; this->family = copyString(family); this->style = NULL; this->weight = bold ? FontWeightBold : FontWeightNormal; this->width = FontWidthUndefined; this->italic = italic; this->monospace = false; } FontDescriptor(const char *path, const char *postscriptName, const char *family, const char *style, FontWeight weight, FontWidth width, bool italic, bool monospace) { this->path = copyString(path); this->index = 0; this->postscriptName = copyString(postscriptName); this->family = copyString(family); this->style = copyString(style); this->weight = weight; this->width = width; this->italic = italic; this->monospace = monospace; } FontDescriptor(const char *path, int index, const char *postscriptName, const char *family, const char *style, FontWeight weight, FontWidth width, bool italic, bool monospace) { this->path = copyString(path); this->index = index; this->postscriptName = copyString(postscriptName); this->family = copyString(family); this->style = copyString(style); this->weight = weight; this->width = width; this->italic = italic; this->monospace = monospace; } FontDescriptor(FontDescriptor *desc) { path = copyString(desc->path); index = desc->index; postscriptName = copyString(desc->postscriptName); family = copyString(desc->family); style = copyString(desc->style); weight = desc->weight; width = desc->width; italic = desc->italic; monospace = desc->monospace; } ~FontDescriptor() { if (path) delete[] path; if (postscriptName) delete[] postscriptName; if (family) delete[] family; if (style) delete[] style; postscriptName = NULL; family = NULL; style = NULL; } private: char *copyString(const char *input) { if (!input) return NULL; char *str = new char[strlen(input) + 1]; strcpy(str, input); return str; } }; class ResultSet : public std::vector { public: ~ResultSet() { for (ResultSet::iterator it = this->begin(); it != this->end(); it++) { delete *it; } } int n_fonts() { return size(); } }; #endif systemfonts/src/systemfonts.cpp0000755000176200001440000001355213502710243016547 0ustar liggesusers#include #include #include "systemfonts.h" #include "utils.h" #include "FontDescriptor.h" // these functions are implemented by the platform ResultSet *getAvailableFonts(); ResultSet *findFonts(FontDescriptor *); FontDescriptor *findFont(FontDescriptor *); FontDescriptor *substituteFont(char *, char *); // Default fonts based on browser behaviour #if defined _WIN32 #define SANS "Arial" #define SERIF "Times New Roman" #define MONO "Courier New" #elif defined __APPLE__ #define SANS "Helvetica" #define SERIF "Times" #define MONO "Courier" #else #define SANS "sans" #define SERIF "serif" #define MONO "mono" #endif int locate_font(const char *family, int italic, int bold, char *path, int max_path_length) { const char* resolved_family = family; if (strcmp_no_case(family, "") || strcmp_no_case(family, "sans")) { resolved_family = SANS; } else if (strcmp_no_case(family, "serif")) { resolved_family = SERIF; } else if (strcmp_no_case(family, "mono")) { resolved_family = MONO; } FontDescriptor font_desc(resolved_family, italic, bold); FontDescriptor* font_loc = findFont(&font_desc); strncpy(path, font_loc->path, max_path_length); int index = font_loc->index; delete font_loc; return index; } SEXP match_font(SEXP family, SEXP italic, SEXP bold) { char *path = new char[PATH_MAX+1]; path[PATH_MAX] = '\0'; int index = locate_font(Rf_translateCharUTF8(STRING_ELT(family, 0)), LOGICAL(italic)[0], LOGICAL(bold)[0], path, PATH_MAX); SEXP font = PROTECT(Rf_allocVector(VECSXP, 2)); SET_VECTOR_ELT(font, 0, Rf_mkString(path)); SET_VECTOR_ELT(font, 1, Rf_ScalarInteger(index)); SEXP names = PROTECT(Rf_allocVector(STRSXP, 2)); SET_STRING_ELT(names, 0, Rf_mkChar("path")); SET_STRING_ELT(names, 1, Rf_mkChar("index")); Rf_setAttrib(font, Rf_install("names"), names); delete[] path; UNPROTECT(2); return font; } SEXP system_fonts() { SEXP res = PROTECT(Rf_allocVector(VECSXP, 9)); SEXP cl = PROTECT(Rf_allocVector(STRSXP, 3)); SET_STRING_ELT(cl, 0, Rf_mkChar("tbl_df")); SET_STRING_ELT(cl, 1, Rf_mkChar("tbl")); SET_STRING_ELT(cl, 2, Rf_mkChar("data.frame")); Rf_classgets(res, cl); SEXP names = PROTECT(Rf_allocVector(STRSXP, 9)); SET_STRING_ELT(names, 0, Rf_mkChar("path")); SET_STRING_ELT(names, 1, Rf_mkChar("index")); SET_STRING_ELT(names, 2, Rf_mkChar("name")); SET_STRING_ELT(names, 3, Rf_mkChar("family")); SET_STRING_ELT(names, 4, Rf_mkChar("style")); SET_STRING_ELT(names, 5, Rf_mkChar("weight")); SET_STRING_ELT(names, 6, Rf_mkChar("width")); SET_STRING_ELT(names, 7, Rf_mkChar("italic")); SET_STRING_ELT(names, 8, Rf_mkChar("monospace")); setAttrib(res, Rf_install("names"), names); ResultSet* all_fonts = getAvailableFonts(); int n = all_fonts->n_fonts(); SEXP path = PROTECT(Rf_allocVector(STRSXP, n)); SEXP index = PROTECT(Rf_allocVector(INTSXP, n)); SEXP name = PROTECT(Rf_allocVector(STRSXP, n)); SEXP family = PROTECT(Rf_allocVector(STRSXP, n)); SEXP style = PROTECT(Rf_allocVector(STRSXP, n)); SEXP fct_cl = PROTECT(Rf_allocVector(STRSXP, 2)); SET_STRING_ELT(fct_cl, 0, Rf_mkChar("ordered")); SET_STRING_ELT(fct_cl, 0, Rf_mkChar("factor")); SEXP weight = PROTECT(Rf_allocVector(INTSXP, n)); SEXP weight_lvl = PROTECT(Rf_allocVector(STRSXP, 9)); SET_STRING_ELT(weight_lvl, 0, Rf_mkChar("thin")); SET_STRING_ELT(weight_lvl, 1, Rf_mkChar("ultralight")); SET_STRING_ELT(weight_lvl, 2, Rf_mkChar("light")); SET_STRING_ELT(weight_lvl, 3, Rf_mkChar("normal")); SET_STRING_ELT(weight_lvl, 4, Rf_mkChar("medium")); SET_STRING_ELT(weight_lvl, 5, Rf_mkChar("semibold")); SET_STRING_ELT(weight_lvl, 6, Rf_mkChar("bold")); SET_STRING_ELT(weight_lvl, 7, Rf_mkChar("ultrabold")); SET_STRING_ELT(weight_lvl, 8, Rf_mkChar("heavy")); Rf_classgets(weight, fct_cl); Rf_setAttrib(weight, Rf_install("levels"), weight_lvl); SEXP width = PROTECT(Rf_allocVector(INTSXP, n)); SEXP width_lvl = PROTECT(Rf_allocVector(STRSXP, 9)); SET_STRING_ELT(width_lvl, 0, Rf_mkChar("ultracondensed")); SET_STRING_ELT(width_lvl, 1, Rf_mkChar("extracondensed")); SET_STRING_ELT(width_lvl, 2, Rf_mkChar("condensed")); SET_STRING_ELT(width_lvl, 3, Rf_mkChar("semicondensed")); SET_STRING_ELT(width_lvl, 4, Rf_mkChar("normal")); SET_STRING_ELT(width_lvl, 5, Rf_mkChar("semiexpanded")); SET_STRING_ELT(width_lvl, 6, Rf_mkChar("expanded")); SET_STRING_ELT(width_lvl, 7, Rf_mkChar("extraexpanded")); SET_STRING_ELT(width_lvl, 8, Rf_mkChar("ultraexpanded")); Rf_classgets(width, fct_cl); Rf_setAttrib(width, Rf_install("levels"), width_lvl); SEXP italic = PROTECT(Rf_allocVector(LGLSXP, n)); SEXP monospace = PROTECT(Rf_allocVector(LGLSXP, n)); SET_VECTOR_ELT(res, 0, path); SET_VECTOR_ELT(res, 1, index); SET_VECTOR_ELT(res, 2, name); SET_VECTOR_ELT(res, 3, family); SET_VECTOR_ELT(res, 4, style); SET_VECTOR_ELT(res, 5, weight); SET_VECTOR_ELT(res, 6, width); SET_VECTOR_ELT(res, 7, italic); SET_VECTOR_ELT(res, 8, monospace); int i = 0; for (ResultSet::iterator it = all_fonts->begin(); it != all_fonts->end(); it++) { SET_STRING_ELT(path, i, Rf_mkChar((*it)->path)); INTEGER(index)[i] = (*it)->index; SET_STRING_ELT(name, i, Rf_mkChar((*it)->postscriptName)); SET_STRING_ELT(family, i, Rf_mkChar((*it)->family)); SET_STRING_ELT(style, i, Rf_mkChar((*it)->style)); if ((*it)->weight == 0) { INTEGER(weight)[i] = NA_INTEGER; } else { INTEGER(weight)[i] = (*it)->weight / 100; } if ((*it)->width == 0) { INTEGER(width)[i] = NA_INTEGER; } else { INTEGER(width)[i] = (int) (*it)->width; } LOGICAL(italic)[i] = (int) (*it)->italic; LOGICAL(monospace)[i] = (int) (*it)->monospace; i++; } SEXP row_names = PROTECT(Rf_allocVector(REALSXP, 2)); REAL(row_names)[0] = NA_REAL; REAL(row_names)[1] = -n; setAttrib(res, Rf_install("row.names"), row_names); UNPROTECT(16); return res; } systemfonts/src/systemfonts.h0000644000176200001440000000031713502434122016203 0ustar liggesusers#include #include int locate_font(const char *family, int italic, int bold, char *path, int max_path_length); SEXP match_font(SEXP family, SEXP italic, SEXP bold); SEXP system_fonts(); systemfonts/src/win/0000755000176200001440000000000013502424665014243 5ustar liggesuserssystemfonts/src/win/DirectWriteFontManagerWindows.cpp0000755000176200001440000003043413476460513022702 0ustar liggesusers#define WINVER 0x0600 #include "../FontDescriptor.h" #include #include #include // throws a JS error when there is some exception in DirectWrite #define HR(hr) \ if (FAILED(hr)) throw "Font loading error"; WCHAR *utf8ToUtf16(const char *input) { unsigned int len = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0); WCHAR *output = new WCHAR[len]; MultiByteToWideChar(CP_UTF8, 0, input, -1, output, len); return output; } char *utf16ToUtf8(const WCHAR *input) { unsigned int len = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL); char *output = new char[len]; WideCharToMultiByte(CP_UTF8, 0, input, -1, output, len, NULL, NULL); return output; } // returns the index of the user's locale in the set of localized strings unsigned int getLocaleIndex(IDWriteLocalizedStrings *strings) { unsigned int index = 0; BOOL exists = false; wchar_t localeName[LOCALE_NAME_MAX_LENGTH]; // Get the default locale for this user. int success = GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH); // If the default locale is returned, find that locale name, otherwise use "en-us". if (success) { HR(strings->FindLocaleName(localeName, &index, &exists)); } // if the above find did not find a match, retry with US English if (!exists) { HR(strings->FindLocaleName(L"en-us", &index, &exists)); } if (!exists) index = 0; return index; } // gets a localized string for a font char *getString(IDWriteFont *font, DWRITE_INFORMATIONAL_STRING_ID string_id) { char *res = NULL; IDWriteLocalizedStrings *strings = NULL; BOOL exists = false; HR(font->GetInformationalStrings( string_id, &strings, &exists )); if (exists) { unsigned int index = getLocaleIndex(strings); unsigned int len = 0; WCHAR *str = NULL; HR(strings->GetStringLength(index, &len)); str = new WCHAR[len + 1]; HR(strings->GetString(index, str, len + 1)); // convert to utf8 res = utf16ToUtf8(str); delete str; strings->Release(); } if (!res) { res = new char[1]; res[0] = '\0'; } return res; } FontDescriptor *resultFromFont(IDWriteFont *font) { FontDescriptor *res = NULL; IDWriteFontFace *face = NULL; unsigned int numFiles = 0; HR(font->CreateFontFace(&face)); // get the font files from this font face IDWriteFontFile *files = NULL; HR(face->GetFiles(&numFiles, NULL)); HR(face->GetFiles(&numFiles, &files)); // return the first one if (numFiles > 0) { IDWriteFontFileLoader *loader = NULL; IDWriteLocalFontFileLoader *fileLoader = NULL; unsigned int nameLength = 0; const void *referenceKey = NULL; unsigned int referenceKeySize = 0; WCHAR *name = NULL; HR(files[0].GetLoader(&loader)); // check if this is a local font file HRESULT hr = loader->QueryInterface(__uuidof(IDWriteLocalFontFileLoader), (void **)&fileLoader); if (SUCCEEDED(hr)) { // get the file path HR(files[0].GetReferenceKey(&referenceKey, &referenceKeySize)); HR(fileLoader->GetFilePathLengthFromKey(referenceKey, referenceKeySize, &nameLength)); name = new WCHAR[nameLength + 1]; HR(fileLoader->GetFilePathFromKey(referenceKey, referenceKeySize, name, nameLength + 1)); char *psName = utf16ToUtf8(name); char *postscriptName = getString(font, DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME); char *family = getString(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES); char *style = getString(font, DWRITE_INFORMATIONAL_STRING_WIN32_SUBFAMILY_NAMES); // this method requires windows 7, so we need to cast to an IDWriteFontFace1 IDWriteFontFace1 *face1 = static_cast(face); bool monospace = face1->IsMonospacedFont() == TRUE; res = new FontDescriptor( psName, postscriptName, family, style, (FontWeight) font->GetWeight(), (FontWidth) font->GetStretch(), font->GetStyle() == DWRITE_FONT_STYLE_ITALIC, monospace ); delete psName; delete name; delete postscriptName; delete family; delete style; fileLoader->Release(); } loader->Release(); } face->Release(); files->Release(); return res; } ResultSet *getAvailableFonts() { ResultSet *res = new ResultSet(); int count = 0; IDWriteFactory *factory = NULL; HR(DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast(&factory) )); // Get the system font collection. IDWriteFontCollection *collection = NULL; HR(factory->GetSystemFontCollection(&collection)); // Get the number of font families in the collection. int familyCount = collection->GetFontFamilyCount(); // track postscript names we've already added // using a set so we don't get any duplicates. std::unordered_set psNames; for (int i = 0; i < familyCount; i++) { IDWriteFontFamily *family = NULL; // Get the font family. HR(collection->GetFontFamily(i, &family)); int fontCount = family->GetFontCount(); for (int j = 0; j < fontCount; j++) { IDWriteFont *font = NULL; HR(family->GetFont(j, &font)); FontDescriptor *result = resultFromFont(font); if (psNames.count(result->postscriptName) == 0) { res->push_back(resultFromFont(font)); psNames.insert(result->postscriptName); } } family->Release(); } collection->Release(); factory->Release(); return res; } bool resultMatches(FontDescriptor *result, FontDescriptor *desc) { if (desc->postscriptName && strcmp(desc->postscriptName, result->postscriptName) != 0) return false; if (desc->family && strcmp(desc->family, result->family) != 0) return false; if (desc->style && strcmp(desc->style, result->style) != 0) return false; if (desc->weight && desc->weight != result->weight) return false; if (desc->width && desc->width != result->width) return false; if (desc->italic != result->italic) return false; if (desc->monospace != result->monospace) return false; return true; } ResultSet *findFonts(FontDescriptor *desc) { ResultSet *fonts = getAvailableFonts(); for (ResultSet::iterator it = fonts->begin(); it != fonts->end();) { if (!resultMatches(*it, desc)) { delete *it; it = fonts->erase(it); } else { it++; } } return fonts; } FontDescriptor *findFont(FontDescriptor *desc) { ResultSet *fonts = findFonts(desc); // if we didn't find anything, try again with only the font traits, no string names if (fonts->size() == 0) { delete fonts; FontDescriptor *fallback = new FontDescriptor( NULL, NULL, NULL, NULL, desc->weight, desc->width, desc->italic, false ); fonts = findFonts(fallback); } // ok, nothing. shouldn't happen often. // just return the first available font if (fonts->size() == 0) { delete fonts; fonts = getAvailableFonts(); } // hopefully we found something now. // copy and return the first result if (fonts->size() > 0) { FontDescriptor *res = new FontDescriptor(fonts->front()); delete fonts; return res; } // whoa, weird. no fonts installed or something went wrong. delete fonts; return NULL; } // custom text renderer used to determine the fallback font for a given char class FontFallbackRenderer : public IDWriteTextRenderer { public: IDWriteFontCollection *systemFonts; IDWriteFont *font; unsigned long refCount; FontFallbackRenderer(IDWriteFontCollection *collection) { refCount = 0; collection->AddRef(); systemFonts = collection; font = NULL; } ~FontFallbackRenderer() { if (systemFonts) systemFonts->Release(); if (font) font->Release(); } // IDWriteTextRenderer methods IFACEMETHOD(DrawGlyphRun)( void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode, DWRITE_GLYPH_RUN const *glyphRun, DWRITE_GLYPH_RUN_DESCRIPTION const *glyphRunDescription, IUnknown *clientDrawingEffect) { // save the font that was actually rendered return systemFonts->GetFontFromFontFace(glyphRun->fontFace, &font); } IFACEMETHOD(DrawUnderline)( void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_UNDERLINE const *underline, IUnknown *clientDrawingEffect) { return E_NOTIMPL; } IFACEMETHOD(DrawStrikethrough)( void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_STRIKETHROUGH const *strikethrough, IUnknown *clientDrawingEffect) { return E_NOTIMPL; } IFACEMETHOD(DrawInlineObject)( void *clientDrawingContext, FLOAT originX, FLOAT originY, IDWriteInlineObject *inlineObject, BOOL isSideways, BOOL isRightToLeft, IUnknown *clientDrawingEffect) { return E_NOTIMPL; } // IDWritePixelSnapping methods IFACEMETHOD(IsPixelSnappingDisabled)(void *clientDrawingContext, BOOL *isDisabled) { *isDisabled = FALSE; return S_OK; } IFACEMETHOD(GetCurrentTransform)(void *clientDrawingContext, DWRITE_MATRIX *transform) { const DWRITE_MATRIX ident = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0}; *transform = ident; return S_OK; } IFACEMETHOD(GetPixelsPerDip)(void *clientDrawingContext, FLOAT *pixelsPerDip) { *pixelsPerDip = 1.0f; return S_OK; } // IUnknown methods IFACEMETHOD_(unsigned long, AddRef)() { return InterlockedIncrement(&refCount); } IFACEMETHOD_(unsigned long, Release)() { unsigned long newCount = InterlockedDecrement(&refCount); if (newCount == 0) { delete this; return 0; } return newCount; } IFACEMETHOD(QueryInterface)(IID const& riid, void **ppvObject) { if (__uuidof(IDWriteTextRenderer) == riid) { *ppvObject = this; } else if (__uuidof(IDWritePixelSnapping) == riid) { *ppvObject = this; } else if (__uuidof(IUnknown) == riid) { *ppvObject = this; } else { *ppvObject = nullptr; return E_FAIL; } this->AddRef(); return S_OK; } }; FontDescriptor *substituteFont(char *postscriptName, char *string) { FontDescriptor *res = NULL; IDWriteFactory *factory = NULL; HR(DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast(&factory) )); // Get the system font collection. IDWriteFontCollection *collection = NULL; HR(factory->GetSystemFontCollection(&collection)); // find the font for the given postscript name FontDescriptor *desc = new FontDescriptor(); desc->postscriptName = postscriptName; FontDescriptor *font = findFont(desc); // create a text format object for this font IDWriteTextFormat *format = NULL; if (font) { WCHAR *familyName = utf8ToUtf16(font->family); // create a text format HR(factory->CreateTextFormat( familyName, collection, (DWRITE_FONT_WEIGHT) font->weight, font->italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, (DWRITE_FONT_STRETCH) font->width, 12.0, L"en-us", &format )); delete familyName; delete font; } else { // this should never happen, but just in case, let the system // decide the default font in case findFont returned nothing. HR(factory->CreateTextFormat( L"", collection, DWRITE_FONT_WEIGHT_REGULAR, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 12.0, L"en-us", &format )); } // convert utf8 string for substitution to utf16 WCHAR *str = utf8ToUtf16(string); // create a text layout for the substitution string IDWriteTextLayout *layout = NULL; HR(factory->CreateTextLayout( str, wcslen(str), format, 100.0, 100.0, &layout )); // render it using a custom renderer that saves the physical font being used FontFallbackRenderer *renderer = new FontFallbackRenderer(collection); HR(layout->Draw(NULL, renderer, 100.0, 100.0)); // if we found something, create a result object if (renderer->font) { res = resultFromFont(renderer->font); } // free all the things delete renderer; layout->Release(); format->Release(); desc->postscriptName = NULL; delete desc; delete str; collection->Release(); factory->Release(); return res; } systemfonts/src/win/FontManagerWindows.cpp0000644000176200001440000001732613502707172020531 0ustar liggesusers#include #include #include #include FT_FREETYPE_H #include FT_TRUETYPE_TABLES_H #include "../FontDescriptor.h" #include "../utils.h" ResultSet* get_font_list(); WCHAR *utf8ToUtf16(const char *input) { unsigned int len = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0); WCHAR *output = new WCHAR[len]; MultiByteToWideChar(CP_UTF8, 0, input, -1, output, len); return output; } char *utf16ToUtf8(const WCHAR *input) { unsigned int len = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL); char *output = new char[len]; WideCharToMultiByte(CP_UTF8, 0, input, -1, output, len, NULL, NULL); return output; } FontWeight get_font_weight(FT_Face face) { void* table = FT_Get_Sfnt_Table(face, FT_SFNT_OS2); if (table == NULL) { return FontWeightUndefined; } TT_OS2* os2_table = (TT_OS2*) table; return (FontWeight) os2_table->usWeightClass; } FontWidth get_font_width(FT_Face face) { void* table = FT_Get_Sfnt_Table(face, FT_SFNT_OS2); if (table == NULL) { return FontWidthUndefined; } TT_OS2* os2_table = (TT_OS2*) table; return (FontWidth) os2_table->usWidthClass; } FontDescriptor* descriptor_from_face(FT_Face &face, const char* path, int index) { FontDescriptor* res = NULL; res = new FontDescriptor( path, index, FT_Get_Postscript_Name(face) == NULL ? "" : FT_Get_Postscript_Name(face), face->family_name, face->style_name, get_font_weight(face), get_font_width(face), face->style_flags & FT_STYLE_FLAG_ITALIC, FT_IS_FIXED_WIDTH(face) ); return res; } int scan_font_dir() { char win_dir[MAX_PATH]; GetWindowsDirectoryA(win_dir, MAX_PATH); std::string font_dir; font_dir += win_dir; font_dir += "\\Fonts\\"; static const LPCSTR font_registry_path = "Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; HKEY h_key; LONG result; result = RegOpenKeyExA(HKEY_LOCAL_MACHINE, font_registry_path, 0, KEY_READ, &h_key); if (result != ERROR_SUCCESS) { return 1; } DWORD max_value_name_size, max_value_data_size; result = RegQueryInfoKey(h_key, 0, 0, 0, 0, 0, 0, 0, &max_value_name_size, &max_value_data_size, 0, 0); if (result != ERROR_SUCCESS) { return 1; } DWORD value_index = 0; LPSTR value_name = new CHAR[max_value_name_size]; LPBYTE value_data = new BYTE[max_value_data_size]; DWORD value_name_size, value_data_size, value_type; std::string font_path; ResultSet* font_list = get_font_list(); FT_Library library; FT_Face face; FT_Error error; error = FT_Init_FreeType(&library); if (error) { return 1; } do { // Loop over font registry, construct file path and parse with freetype value_data_size = max_value_data_size; value_name_size = max_value_name_size; result = RegEnumValueA(h_key, value_index, value_name, &value_name_size, 0, &value_type, value_data, &value_data_size); value_index++; if (result != ERROR_SUCCESS || value_type != REG_SZ) { continue; } font_path.clear(); font_path += font_dir; font_path.append((LPSTR) value_data, value_data_size); error = FT_New_Face(library, font_path.c_str(), 0, &face); if (error) { continue; } font_list->push_back(descriptor_from_face(face, font_path.c_str(), 0)); int n_fonts = face->num_faces; FT_Done_Face(face); for (int i = 1; i < n_fonts; i++) { error = FT_New_Face(library, font_path.c_str(), i, &face); if (error) { continue; } font_list->push_back(descriptor_from_face(face, font_path.c_str(), i)); FT_Done_Face(face); } } while (result != ERROR_NO_MORE_ITEMS); // Cleanup delete[] value_name; delete[] value_data; FT_Done_FreeType(library); // Move Arial Regular to front for (ResultSet::iterator it = font_list->begin(); it != font_list->end(); it++) { if (strcmp((*it)->family, "Arial") == 0 && strcmp((*it)->style, "Regular") == 0) { FontDescriptor* arial = *it; font_list->erase(it); font_list->insert(font_list->begin(), arial); break; } } return 0; } ResultSet *getAvailableFonts() { ResultSet *res = new ResultSet(); ResultSet* font_list = get_font_list(); if (font_list->size() == 0) scan_font_dir(); for (ResultSet::iterator it = font_list->begin(); it != font_list->end(); it++) { FontDescriptor* font = new FontDescriptor(*it); res->push_back(font); } return res; } bool resultMatches(FontDescriptor *result, FontDescriptor *desc) { if (desc->postscriptName && !strcmp_no_case(desc->postscriptName, result->postscriptName)) return false; if (desc->family && !strcmp_no_case(desc->family, result->family)) return false; if (desc->style && !strcmp_no_case(desc->style, result->style)) return false; if (desc->weight && desc->weight != result->weight) return false; if (desc->width && desc->width != result->width) return false; if (desc->italic != result->italic) return false; if (desc->monospace != result->monospace) return false; return true; } ResultSet *findFonts(FontDescriptor *desc) { ResultSet *res = new ResultSet(); ResultSet* font_list = get_font_list(); if (font_list->size() == 0) scan_font_dir(); for (ResultSet::iterator it = font_list->begin(); it != font_list->end(); it++) { if (!resultMatches(*it, desc)) { continue; } FontDescriptor* font = new FontDescriptor(*it); res->push_back(font); } return res; } FontDescriptor *findFont(FontDescriptor *desc) { ResultSet *fonts = findFonts(desc); // if we didn't find anything, try again with only the font traits, no string names if (fonts->size() == 0) { delete fonts; FontDescriptor *fallback = new FontDescriptor( NULL, NULL, NULL, NULL, desc->weight, desc->width, desc->italic, false ); fonts = findFonts(fallback); } // ok, nothing. shouldn't happen often. // just return the first available font if (fonts->size() == 0) { delete fonts; fonts = getAvailableFonts(); } // hopefully we found something now. // copy and return the first result if (fonts->size() > 0) { FontDescriptor *res = new FontDescriptor(fonts->front()); delete fonts; return res; } // whoa, weird. no fonts installed or something went wrong. delete fonts; return NULL; } bool font_has_glyphs(const char * font_path, FT_Library library, WCHAR * str) { FT_Face face; FT_Error error; error = FT_New_Face(library, font_path, 0, &face); if (error) { return false; } int i = 0; while (str[i]) { if (FT_Get_Char_Index( face, str[i])) { return false; } i++; } FT_Done_Face(face); return true; } FontDescriptor *substituteFont(char *postscriptName, char *string) { FontDescriptor *res = NULL; // find the font for the given postscript name FontDescriptor *desc = new FontDescriptor(); desc->postscriptName = postscriptName; FontDescriptor *font = findFont(desc); desc->postscriptName = NULL; desc->weight = font->weight; desc->width = font->width; desc->italic = font->italic; desc->monospace = font->monospace; ResultSet* style_matches = findFonts(desc); WCHAR *str = utf8ToUtf16(string); FT_Library library; FT_Error error; error = FT_Init_FreeType( &library ); if (error) { return res; } for (ResultSet::iterator it = style_matches->begin(); it != style_matches->end(); it++) { if (font_has_glyphs((*it)->path, library, str)) { res = new FontDescriptor(*it); break; } } FT_Done_FreeType(library); delete str; delete desc; delete font; return res; } systemfonts/src/utils.h0000644000176200001440000000053013502707115014747 0ustar liggesusers#ifndef SFUTILS_H #define SFUTILS_H #include #include static bool strcmp_no_case(const char * A, const char * B) { unsigned int a_len = strlen(A); if (strlen(B) != a_len) return false; for (unsigned int i = 0; i < a_len; ++i) if (tolower(A[i]) != tolower(B[i])) return false; return true; } #endif systemfonts/src/Makevars.in0000644000176200001440000000045713502666265015561 0ustar liggesusersPKG_CPPFLAGS=@cflags@ -DSTRICT_R_HEADERS DARWIN_LIBS = -framework CoreText -framework Foundation DARWIN_OBJECTS = mac/FontManagerMac.o UNIX_OBJECTS = unix/FontManagerLinux.o PKG_LIBS = @libs@ $(@SYS@_LIBS) OBJECTS = systemfonts.o init.o $(@SYS@_OBJECTS) all: clean clean: rm -f $(SHLIB) $(OBJECTS) systemfonts/src/unix/0000755000176200001440000000000013502432513014420 5ustar liggesuserssystemfonts/src/unix/FontManagerLinux.cpp0000755000176200001440000001603513506334560020364 0ustar liggesusers#include #include "../FontDescriptor.h" int convertWeight(FontWeight weight) { switch (weight) { case FontWeightThin: return FC_WEIGHT_THIN; case FontWeightUltraLight: return FC_WEIGHT_ULTRALIGHT; case FontWeightLight: return FC_WEIGHT_LIGHT; case FontWeightNormal: return FC_WEIGHT_REGULAR; case FontWeightMedium: return FC_WEIGHT_MEDIUM; case FontWeightSemiBold: return FC_WEIGHT_SEMIBOLD; case FontWeightBold: return FC_WEIGHT_BOLD; case FontWeightUltraBold: return FC_WEIGHT_EXTRABOLD; case FontWeightHeavy: return FC_WEIGHT_ULTRABLACK; default: return FC_WEIGHT_REGULAR; } } FontWeight convertWeight(int weight) { switch (weight) { case FC_WEIGHT_THIN: return FontWeightThin; case FC_WEIGHT_ULTRALIGHT: return FontWeightUltraLight; case FC_WEIGHT_LIGHT: return FontWeightLight; case FC_WEIGHT_REGULAR: return FontWeightNormal; case FC_WEIGHT_MEDIUM: return FontWeightMedium; case FC_WEIGHT_SEMIBOLD: return FontWeightSemiBold; case FC_WEIGHT_BOLD: return FontWeightBold; case FC_WEIGHT_EXTRABOLD: return FontWeightUltraBold; case FC_WEIGHT_ULTRABLACK: return FontWeightHeavy; default: return FontWeightNormal; } } int convertWidth(FontWidth width) { switch (width) { case FontWidthUltraCondensed: return FC_WIDTH_ULTRACONDENSED; case FontWidthExtraCondensed: return FC_WIDTH_EXTRACONDENSED; case FontWidthCondensed: return FC_WIDTH_CONDENSED; case FontWidthSemiCondensed: return FC_WIDTH_SEMICONDENSED; case FontWidthNormal: return FC_WIDTH_NORMAL; case FontWidthSemiExpanded: return FC_WIDTH_SEMIEXPANDED; case FontWidthExpanded: return FC_WIDTH_EXPANDED; case FontWidthExtraExpanded: return FC_WIDTH_EXTRAEXPANDED; case FontWidthUltraExpanded: return FC_WIDTH_ULTRAEXPANDED; default: return FC_WIDTH_NORMAL; } } FontWidth convertWidth(int width) { switch (width) { case FC_WIDTH_ULTRACONDENSED: return FontWidthUltraCondensed; case FC_WIDTH_EXTRACONDENSED: return FontWidthExtraCondensed; case FC_WIDTH_CONDENSED: return FontWidthCondensed; case FC_WIDTH_SEMICONDENSED: return FontWidthSemiCondensed; case FC_WIDTH_NORMAL: return FontWidthNormal; case FC_WIDTH_SEMIEXPANDED: return FontWidthSemiExpanded; case FC_WIDTH_EXPANDED: return FontWidthExpanded; case FC_WIDTH_EXTRAEXPANDED: return FontWidthExtraExpanded; case FC_WIDTH_ULTRAEXPANDED: return FontWidthUltraExpanded; default: return FontWidthNormal; } } FontDescriptor *createFontDescriptor(FcPattern *pattern) { FcChar8 *path, *psName, *family, *style; int index, weight, width, slant, spacing; FcPatternGetString(pattern, FC_FILE, 0, &path); #ifdef FC_POSTSCRIPT_NAME FcPatternGetString(pattern, FC_POSTSCRIPT_NAME, 0, &psName); #else psName = (FcChar8*) ""; #endif FcPatternGetString(pattern, FC_FAMILY, 0, &family); FcPatternGetString(pattern, FC_STYLE, 0, &style); FcPatternGetInteger(pattern, FC_INDEX, 0, &index); FcPatternGetInteger(pattern, FC_WEIGHT, 0, &weight); FcPatternGetInteger(pattern, FC_WIDTH, 0, &width); FcPatternGetInteger(pattern, FC_SLANT, 0, &slant); FcPatternGetInteger(pattern, FC_SPACING, 0, &spacing); return new FontDescriptor( (char *) path, index, (char *) psName, (char *) family, (char *) style, convertWeight(weight), convertWidth(width), slant == FC_SLANT_ITALIC, spacing == FC_MONO ); } ResultSet *getResultSet(FcFontSet *fs) { ResultSet *res = new ResultSet(); if (!fs) return res; for (int i = 0; i < fs->nfont; i++) { res->push_back(createFontDescriptor(fs->fonts[i])); } return res; } ResultSet *getAvailableFonts() { FcInit(); FcPattern *pattern = FcPatternCreate(); #ifdef FC_POSTSCRIPT_NAME FcObjectSet *os = FcObjectSetBuild(FC_FILE, FC_POSTSCRIPT_NAME, FC_FAMILY, FC_STYLE, FC_WEIGHT, FC_WIDTH, FC_SLANT, FC_SPACING, NULL); #else FcObjectSet *os = FcObjectSetBuild(FC_FILE, FC_FAMILY, FC_STYLE, FC_WEIGHT, FC_WIDTH, FC_SLANT, FC_SPACING, NULL); #endif FcFontSet *fs = FcFontList(NULL, pattern, os); ResultSet *res = getResultSet(fs); FcPatternDestroy(pattern); FcObjectSetDestroy(os); FcFontSetDestroy(fs); return res; } FcPattern *createPattern(FontDescriptor *desc) { FcInit(); FcPattern *pattern = FcPatternCreate(); #ifdef FC_POSTSCRIPT_NAME if (desc->postscriptName) FcPatternAddString(pattern, FC_POSTSCRIPT_NAME, (FcChar8 *) desc->postscriptName); #endif if (desc->family) FcPatternAddString(pattern, FC_FAMILY, (FcChar8 *) desc->family); if (desc->style) FcPatternAddString(pattern, FC_STYLE, (FcChar8 *) desc->style); if (desc->italic) FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); if (desc->weight) FcPatternAddInteger(pattern, FC_WEIGHT, convertWeight(desc->weight)); if (desc->width) FcPatternAddInteger(pattern, FC_WIDTH, convertWidth(desc->width)); if (desc->monospace) FcPatternAddInteger(pattern, FC_SPACING, FC_MONO); return pattern; } ResultSet *findFonts(FontDescriptor *desc) { FcPattern *pattern = createPattern(desc); #ifdef FC_POSTSCRIPT_NAME FcObjectSet *os = FcObjectSetBuild(FC_FILE, FC_POSTSCRIPT_NAME, FC_FAMILY, FC_STYLE, FC_WEIGHT, FC_WIDTH, FC_SLANT, FC_SPACING, NULL); #else FcObjectSet *os = FcObjectSetBuild(FC_FILE, FC_FAMILY, FC_STYLE, FC_WEIGHT, FC_WIDTH, FC_SLANT, FC_SPACING, NULL); #endif FcFontSet *fs = FcFontList(NULL, pattern, os); ResultSet *res = getResultSet(fs); FcFontSetDestroy(fs); FcPatternDestroy(pattern); FcObjectSetDestroy(os); return res; } FontDescriptor *findFont(FontDescriptor *desc) { FcPattern *pattern = createPattern(desc); FcConfigSubstitute(NULL, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); FcResult result; FcPattern *font = FcFontMatch(NULL, pattern, &result); FontDescriptor *res = createFontDescriptor(font); FcPatternDestroy(pattern); FcPatternDestroy(font); return res; } FontDescriptor *substituteFont(char *postscriptName, char *string) { FcInit(); // create a pattern with the postscript name FcPattern* pattern = FcPatternCreate(); #ifdef FC_POSTSCRIPT_NAME FcPatternAddString(pattern, FC_POSTSCRIPT_NAME, (FcChar8 *) postscriptName); #endif // create a charset with each character in the string FcCharSet* charset = FcCharSetCreate(); int len = strlen(string); for (int i = 0; i < len;) { FcChar32 c; i += FcUtf8ToUcs4((FcChar8 *)string + i, &c, len - i); FcCharSetAddChar(charset, c); } FcPatternAddCharSet(pattern, FC_CHARSET, charset); FcCharSetDestroy(charset); FcConfigSubstitute(0, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); // find the best match font FcResult result; FcPattern *font = FcFontMatch(NULL, pattern, &result); FontDescriptor *res = createFontDescriptor(font); FcPatternDestroy(pattern); FcPatternDestroy(font); return res; } systemfonts/src/mac/0000755000176200001440000000000013506366517014213 5ustar liggesuserssystemfonts/src/mac/FontManagerMac.mm0000755000176200001440000002215413502665646017400 0ustar liggesusers#include #include #include #include #include "../FontDescriptor.h" // converts a CoreText weight (-1 to +1) to a standard weight (100 to 900) static int convertWeight(float weight) { if (weight <= -0.8f) return 100; else if (weight <= -0.6f) return 200; else if (weight <= -0.4f) return 300; else if (weight <= 0.0f) return 400; else if (weight <= 0.25f) return 500; else if (weight <= 0.35f) return 600; else if (weight <= 0.4f) return 700; else if (weight <= 0.6f) return 800; else return 900; } // converts a CoreText width (-1 to +1) to a standard width (1 to 9) static int convertWidth(float unit) { if (unit < 0) { return 1 + (1 + unit) * 4; } else { return 5 + unit * 4; } } void addFontIndex(FontDescriptor* font) { static std::map font_index; std::string font_name(font->postscriptName); int font_no; std::map::iterator it = font_index.find(font_name); if (it == font_index.end()) { NSString *font_path = [NSString stringWithUTF8String:font->path]; NSURL *font_url = [NSURL fileURLWithPath: font_path]; CFArrayRef font_descriptors = CTFontManagerCreateFontDescriptorsFromURL((CFURLRef) font_url); int n_fonts = CFArrayGetCount(font_descriptors); if (n_fonts == 1) { font_no = 0; font_index[font_name] = 0; } else { for (int i = 0; i < n_fonts; i++) { CTFontDescriptorRef font_at_i = (CTFontDescriptorRef) CFArrayGetValueAtIndex(font_descriptors, i); std::string font_name_at_i = [(NSString *) CTFontDescriptorCopyAttribute(font_at_i, kCTFontNameAttribute) UTF8String]; font_index[font_name_at_i] = i; if (font_name.compare(font_name_at_i) == 0) { font_no = i; } } } [font_path release]; [font_url release]; } else { font_no = (*it).second; } font->index = font_no; } FontDescriptor *createFontDescriptor(CTFontDescriptorRef descriptor) { NSURL *url = (NSURL *) CTFontDescriptorCopyAttribute(descriptor, kCTFontURLAttribute); NSString *psName = (NSString *) CTFontDescriptorCopyAttribute(descriptor, kCTFontNameAttribute); NSString *family = (NSString *) CTFontDescriptorCopyAttribute(descriptor, kCTFontFamilyNameAttribute); NSString *style = (NSString *) CTFontDescriptorCopyAttribute(descriptor, kCTFontStyleNameAttribute); NSDictionary *traits = (NSDictionary *) CTFontDescriptorCopyAttribute(descriptor, kCTFontTraitsAttribute); NSNumber *weightVal = traits[(id)kCTFontWeightTrait]; FontWeight weight = (FontWeight) convertWeight([weightVal floatValue]); NSNumber *widthVal = traits[(id)kCTFontWidthTrait]; FontWidth width = (FontWidth) convertWidth([widthVal floatValue]); NSNumber *symbolicTraitsVal = traits[(id)kCTFontSymbolicTrait]; unsigned int symbolicTraits = [symbolicTraitsVal unsignedIntValue]; FontDescriptor *res = new FontDescriptor( [[url path] UTF8String], [psName UTF8String], [family UTF8String], [style UTF8String], weight, width, (symbolicTraits & kCTFontItalicTrait) != 0, (symbolicTraits & kCTFontMonoSpaceTrait) != 0 ); addFontIndex(res); [url release]; [psName release]; [family release]; [style release]; [traits release]; return res; } ResultSet *getAvailableFonts() { // cache font collection for fast use in future calls static CTFontCollectionRef collection = NULL; if (collection == NULL) collection = CTFontCollectionCreateFromAvailableFonts(NULL); NSArray *matches = (NSArray *) CTFontCollectionCreateMatchingFontDescriptors(collection); ResultSet *results = new ResultSet(); for (id m in matches) { CTFontDescriptorRef match = (CTFontDescriptorRef) m; results->push_back(createFontDescriptor(match)); } [matches release]; return results; } // helper to square a value static inline int sqr(int value) { return value * value; } CTFontDescriptorRef getFontDescriptor(FontDescriptor *desc) { // build a dictionary of font attributes NSMutableDictionary *attrs = [NSMutableDictionary dictionary]; CTFontSymbolicTraits symbolicTraits = 0; if (desc->postscriptName) { NSString *postscriptName = [NSString stringWithUTF8String:desc->postscriptName]; attrs[(id)kCTFontNameAttribute] = postscriptName; } if (desc->family) { NSString *family = [NSString stringWithUTF8String:desc->family]; attrs[(id)kCTFontFamilyNameAttribute] = family; } if (desc->style) { NSString *style = [NSString stringWithUTF8String:desc->style]; attrs[(id)kCTFontStyleNameAttribute] = style; } // build symbolic traits if (desc->italic) symbolicTraits |= kCTFontItalicTrait; if (desc->weight == FontWeightBold) symbolicTraits |= kCTFontBoldTrait; if (desc->monospace) symbolicTraits |= kCTFontMonoSpaceTrait; if (desc->width == FontWidthCondensed) symbolicTraits |= kCTFontCondensedTrait; if (desc->width == FontWidthExpanded) symbolicTraits |= kCTFontExpandedTrait; if (symbolicTraits) { NSDictionary *traits = @{(id)kCTFontSymbolicTrait:[NSNumber numberWithUnsignedInt:symbolicTraits]}; attrs[(id)kCTFontTraitsAttribute] = traits; } // create a font descriptor and search for matches return CTFontDescriptorCreateWithAttributes((CFDictionaryRef) attrs); } int metricForMatch(CTFontDescriptorRef match, FontDescriptor *desc) { NSDictionary *dict = (NSDictionary *)CTFontDescriptorCopyAttribute(match, kCTFontTraitsAttribute); bool italic = ([dict[(id)kCTFontSymbolicTrait] unsignedIntValue] & kCTFontItalicTrait); // normalize everything to base-900 int metric = 0; if (desc->weight) metric += sqr(convertWeight([dict[(id)kCTFontWeightTrait] floatValue]) - desc->weight); if (desc->width) metric += sqr((convertWidth([dict[(id)kCTFontWidthTrait] floatValue]) - desc->width) * 100); metric += sqr((italic != desc->italic) * 900); [dict release]; return metric; } ResultSet *findFonts(FontDescriptor *desc) { CTFontDescriptorRef descriptor = getFontDescriptor(desc); NSArray *matches = (NSArray *) CTFontDescriptorCreateMatchingFontDescriptors(descriptor, NULL); ResultSet *results = new ResultSet(); NSArray *sorted = [matches sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { int ma = metricForMatch((CTFontDescriptorRef) a, desc); int mb = metricForMatch((CTFontDescriptorRef) b, desc); return ma < mb ? NSOrderedAscending : ma > mb ? NSOrderedDescending : NSOrderedSame; }]; for (id m in sorted) { CTFontDescriptorRef match = (CTFontDescriptorRef) m; int mb = metricForMatch((CTFontDescriptorRef) m, desc); if (mb < 10000) { results->push_back(createFontDescriptor(match)); } } CFRelease(descriptor); [matches release]; return results; } CTFontDescriptorRef findBest(FontDescriptor *desc, NSArray *matches) { // find the closest match for width and weight attributes CTFontDescriptorRef best = NULL; int bestMetric = INT_MAX; for (id m in matches) { int metric = metricForMatch((CTFontDescriptorRef) m, desc); if (metric < bestMetric) { bestMetric = metric; best = (CTFontDescriptorRef) m; } // break if this is an exact match if (metric == 0) break; } return best; } FontDescriptor *findFont(FontDescriptor *desc) { FontDescriptor *res = NULL; CTFontDescriptorRef descriptor = getFontDescriptor(desc); NSArray *matches = (NSArray *) CTFontDescriptorCreateMatchingFontDescriptors(descriptor, NULL); // if there was no match, try again but only try to match traits if ([matches count] == 0) { [matches release]; NSSet *set = [NSSet setWithObjects:(id)kCTFontTraitsAttribute, nil]; matches = (NSArray *) CTFontDescriptorCreateMatchingFontDescriptors(descriptor, (CFSetRef) set); } // find the closest match for width and weight attributes CTFontDescriptorRef best = findBest(desc, matches); // if we found a match, generate and return a URL for it if (best) { res = createFontDescriptor(best); } [matches release]; CFRelease(descriptor); return res; } FontDescriptor *substituteFont(char *postscriptName, char *string) { FontDescriptor *res = NULL; // create a font descriptor to find the font by its postscript name // we don't use CTFontCreateWithName because that supports font // names other than the postscript name but prints warnings. NSString *ps = [NSString stringWithUTF8String:postscriptName]; NSDictionary *attrs = @{(id)kCTFontNameAttribute: ps}; CTFontDescriptorRef descriptor = CTFontDescriptorCreateWithAttributes((CFDictionaryRef) attrs); CTFontRef font = CTFontCreateWithFontDescriptor(descriptor, 12.0, NULL); // find a substitute font that support the given characters NSString *str = [NSString stringWithUTF8String:string]; CTFontRef substituteFont = CTFontCreateForString(font, (CFStringRef) str, CFRangeMake(0, [str length])); CTFontDescriptorRef substituteDescriptor = CTFontCopyFontDescriptor(substituteFont); // finally, create and return a result object for this substitute font res = createFontDescriptor(substituteDescriptor); CFRelease(font); CFRelease(substituteFont); CFRelease(substituteDescriptor); return res; } systemfonts/src/Makevars.win0000644000176200001440000000063413504077362015741 0ustar liggesusersVERSION = 1.16.0 RWINLIB = ../windows/cairo-${VERSION} PKG_CPPFLAGS = -I${RWINLIB}/include/freetype2 \ -DSTRICT_R_HEADERS PKG_LIBS = -L${RWINLIB}/lib${R_ARCH} \ -lfreetype -lharfbuzz -lfreetype -lpng -lbz2 -lz OBJECTS = systemfonts.o init.o win/FontManagerWindows.o all: clean winlibs winlibs: "${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" "../tools/winlibs.R" ${VERSION} clean: rm -f $(OBJECTS) $(SHLIB) systemfonts/src/init.cpp0000644000176200001440000000131213502237404015103 0ustar liggesusers#include #include #include // for NULL #include #include "systemfonts.h" #include "FontDescriptor.h" static ResultSet* fonts; ResultSet& get_font_list(){ return *fonts; } static const R_CallMethodDef CallEntries[] = { {"match_font_c", (DL_FUNC) &match_font, 3}, {"system_fonts_c", (DL_FUNC) &system_fonts, 0}, {NULL, NULL, 0} }; extern "C" void R_init_systemfonts(DllInfo *dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); fonts = new ResultSet(); R_RegisterCCallable("systemfonts", "locate_font", (DL_FUNC)locate_font); } extern "C" void R_unload_systemfonts(DllInfo *dll) { delete fonts; } systemfonts/NAMESPACE0000644000176200001440000000020313503144216014061 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(match_font) export(system_fonts) useDynLib(systemfonts, .registration = TRUE) systemfonts/NEWS.md0000644000176200001440000000040613506340131013742 0ustar liggesusers# systemfonts 0.1.1 * Fix compilation on systems with a very old fontconfig version (Solaris) # systemfonts 0.1.0 * First version with `match_font()` and `system_fonts()` capabilities. More to come. * Added a `NEWS.md` file to track changes to the package. systemfonts/R/0000755000176200001440000000000013476160671013064 5ustar liggesuserssystemfonts/R/system_fonts.R0000644000176200001440000000051713502752111015731 0ustar liggesusers#' List all fonts installed on your system #' #' @return A data frame with a row for each font and various information in each #' column #' #' @export #' #' @examples #' # See all monospace fonts #' fonts <- system_fonts() #' fonts[fonts$monospace, ] #' system_fonts <- function() { .Call("system_fonts_c", PACKAGE = "systemfonts") }systemfonts/R/match_font.R0000644000176200001440000000205713502712762015327 0ustar liggesusers#' Find a system font by name and style #' #' This function locates the font file (and index) best matching a name and #' optional style (italic/bold). A font file will be returned even if a match #' isn't found, but it is not necessarily similar to the requested family and #' it should not be relied on for font substitution. The aliases `"sans"`, #' `"serif"`, and `"mono"` match to the system default sans-serif, serif, and #' mono fonts respectively (`""` is equivalent to `"sans"`). #' #' #' @param family The name of the font family #' @param italic,bold logicals indicating the font style #' #' @return A list containing the path locating the font file and the 0-based #' index of the font in the file. #' #' @export #' #' @examples #' # Get the system default sans-serif font in italic #' match_font('sans', italic = TRUE) #' match_font <- function(family, italic = FALSE, bold = FALSE) { if (!is.character(family)) stop("family must be a string", call. = FALSE) .Call("match_font_c", family, as.logical(italic), as.logical(bold), PACKAGE = "systemfonts") } systemfonts/R/systemfonts-package.R0000644000176200001440000000037213475431426017176 0ustar liggesusers#' @keywords internal #' @useDynLib systemfonts, .registration = TRUE "_PACKAGE" # The following block is used by usethis to automatically manage # roxygen namespace tags. Modify with care! ## usethis namespace: start ## usethis namespace: end NULL systemfonts/vignettes/0000755000176200001440000000000013506366517014674 5ustar liggesuserssystemfonts/vignettes/c_interface.Rmd0000644000176200001440000000367013502750205017573 0ustar liggesusers--- title: "systemfonts C interface" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{systemfonts C interface} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ```{r setup} library(systemfonts) ``` Most of the functionality in systemfonts is intended to be used from compiled code to help e.g. graphic devices to resolve font specifications to a font file prior to rendering. systemfonts provide key functionality to get called at the C level using the `R_getCCallable()` function. The systemfonts namespace must be loaded for this to work, so be sure to import e.g. `match_font()` in the package namespace. For more information about this interface see [*Registering native routines*](https://cran.r-project.org/doc/manuals/R-exts.html#Registering-native-routines) in *Writing R Extensions*. ## Font matching The C equivalent of the `match_font()` R function is `locate_font()` with the following signature: ```C int locate_font(const char *family, int italic, int bold, char *path, int max_path_length) ``` It takes a UTF-8 encoded string with the font family name, an int setting both italic and bold styles along with a char pointer to be filled with the located path and the maximum length it can hold. The return value is an int giving the index of the font in the font file. The best way to use the function in a package is to wrap it in a function to avoid fetching it multiple times, e.g. ```C static int locate_font(const char *family, int italic, int bold, char *path, int max_path_length) { static int (*p_locate_font)(const char *family, int italic, int bold, char *path, int max_path_length) = NULL; if (p_locate_font == NULL) { p_locate_font = (int(*)(const char *, int, int, char *, int)) R_GetCCallable("systemfonts", "locate_font"); } return p_locate_font(family, italic, bold, path, max_path_length); } ``` systemfonts/README.md0000644000176200001440000001110713506332105014125 0ustar liggesusers # systemfonts [![Travis build status](https://travis-ci.org/r-lib/systemfonts.svg?branch=master)](https://travis-ci.org/r-lib/systemfonts) [![AppVeyor build status](https://ci.appveyor.com/api/projects/status/github/r-lib/systemfonts?branch=master&svg=true)](https://ci.appveyor.com/project/r-lib/systemfonts) [![Codecov test coverage](https://codecov.io/gh/r-lib/systemfonts/branch/master/graph/badge.svg)](https://codecov.io/gh/r-lib/systemfonts?branch=master) [![CRAN status](https://www.r-pkg.org/badges/version/systemfonts)](https://cran.r-project.org/package=systemfonts) [![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental) systemfonts is a package that locates installed fonts. It uses the system-native libraries on Mac (CoreText) and Linux (FontConfig), and uses Freetype to parse the fonts in the registry on Windows. ## Installation systemfonts is available from CRAN using `install.packages('systemfonts')`. It is however still under development and you can install the development version using devtools. ``` r # install.packages('devtools') devtools::install_github('thomasp85/systemfonts') ``` ## Examples The main use of this package is to locate font files based on family and style: ``` r library(systemfonts) match_font('Avenir', italic = TRUE) #> $path #> [1] "/System/Library/Fonts/Avenir.ttc" #> #> $index #> [1] 1 ``` This function returns the path to the file holding the font, as well as the 0-based index of the font in the file. It is also possible to get a data.frame of all available fonts: ``` r system_fonts() #> # A tibble: 627 x 9 #> path index name family style weight width italic monospace #> #> 1 /Users/thom… 0 Averia… Averia … Regul… normal norm… FALSE FALSE #> 2 /Library/Fo… 1 ITFDev… ITF Dev… Bold bold norm… FALSE FALSE #> 3 /Library/Fo… 0 SignPa… SignPai… House… normal semi… FALSE FALSE #> 4 /Library/Fo… 1 Kannad… Kannada… Bold bold norm… FALSE FALSE #> 5 /Library/Fo… 0 Damasc… Damascus Regul… normal norm… FALSE FALSE #> 6 /Users/thom… 0 Spectr… Spectral Extra… ultra… norm… TRUE FALSE #> 7 /System/Lib… 3 Kohino… Kohinoo… Bold bold norm… FALSE FALSE #> 8 /System/Lib… 5 PingFa… PingFan… Medium medium norm… FALSE FALSE #> 9 /Users/thom… 0 Source… Source … Bold bold norm… FALSE FALSE #> 10 /Library/Fo… 7 PTSans… PT Sans Bold bold norm… FALSE FALSE #> # … with 617 more rows ``` While getting this information in R is nice, the intended use is mostly through compiled code so that graphic devices can easily locate relevant font files etc. In order to use functions from systemfonts in C(++) code you should import them using the `R_GetCCallable()` function, optimally wrapping it in a function to avoid repeated fetches, such as done by ragg: ``` cpp static int locate_font(const char *family, int italic, int bold, char *path, int max_path_length) { static int (*p_locate_font)(const char *family, int italic, int bold, char *path, int max_path_length) = NULL; if (p_locate_font == NULL) { p_locate_font = (int(*)(const char *, int, int, char *, int)) R_GetCCallable("systemfonts", "locate_font"); } return p_locate_font(family, italic, bold, path, max_path_length); } ``` ## System Defaults systemfonts will always try to find a font for you, even if none exist with the given family name or style. How it resolves this is system specific and should not be relied on, but it can be expected that a valid font file is always returned no matter the input. A few special aliases exist that behaves predictably but system dependent: - `""` and `"sans"` return *Helvetica* on Mac, *Arial* on Windows, and the default sans-serif font on Linux (*DejaVu Sans* on Ubuntu) - `"serif"` return *Times* on Mac, *Times New Roman* on Windows, and the default serif font on Linux (*DejaVu Serif* on Ubuntu) - `"mono"` return *Courier* on Mac, *Courier New* on Windows, and the default mono font on Linux (*DejaVu Mono* on Ubuntu) ## Code of Conduct Please note that the ‘systemfonts’ project is released with a [Contributor Code of Conduct](https://github.com/r-lib/systemfonts/blob/master/CODE_OF_CONDUCT.md). By contributing to this project, you agree to abide by its terms. systemfonts/MD50000644000176200001440000000335713506400572013172 0ustar liggesusersdae842db4cbc6f1571f92efb63838664 *DESCRIPTION c31ee18d335f7158ed985f5939319c1f *LICENSE 2eac5d5a6f2f7560dc03397420004cc5 *NAMESPACE 0edffdaeb70477d280e4f1fd4435f8d9 *NEWS.md 4a277c2db7d4fca58848785962b06bef *R/match_font.R ff7abbbd062ed0cf7a00a7b354603137 *R/system_fonts.R c37f3cd43d3c984f5296a4e7d4805eb0 *R/systemfonts-package.R f52e11d0afb9bbe20c3a31272216e3b1 *README.md 3e880dbb0aa843125c281e261e8d51a9 *build/vignette.rds 6071edd604dbeb75308cfbedc7790398 *cleanup edbb2acb3c3c9f6176d794419c9e4b08 *configure 05d23b16b302ce775c0e655ec6f03213 *inst/doc/c_interface.R 864f7b19fe1e8b5080c8f5c51d4178eb *inst/doc/c_interface.Rmd 4b022f4c7dc4e77e822202d0cdec1ee1 *inst/doc/c_interface.html 75e018c1a3b0e79a2c562e411be05f72 *man/match_font.Rd 8c3dc7bc1e63c3195611e49364bea5da *man/system_fonts.Rd 91cc2cd75c24ee28214dda1a78a39b9e *man/systemfonts-package.Rd 8df5ff00925d8d3a23c5c7e57004c5f7 *src/FontDescriptor.h f92e4b07b3742bd507ae864385881288 *src/Makevars.in 0cfcfb7992d382b31929d9d55b695abe *src/Makevars.win 037946b1b94bca13caeb5b3b2895ec9c *src/init.cpp e8781ce272f330d9a395134338efa339 *src/mac/FontManagerMac.mm 5d868e54629b8ca0d6ec885619216afe *src/systemfonts.cpp 76f75014d2f951545e42407eca83ee1d *src/systemfonts.h a8e0db450f7051a9f2a319ecbcb84959 *src/unix/FontManagerLinux.cpp 8cddb04fde39370e6ae2c34c9d700be4 *src/utils.h 882d23bb7c881e87eb82a0de7952d0da *src/win/DirectWriteFontManagerWindows.cpp e9d36a373fa1cb4aa539b3e550de9436 *src/win/FontManagerWindows.cpp 2b7eaaf1f6572e72dde8052c8c14412a *tests/testthat.R 67874f8c9e8d68433167033af2a26c34 *tests/testthat/test-match_font.R 928495dc1e966e04e0c4fc7c89e56056 *tests/testthat/test-system_fonts.R b4e631b807cfc1d857d50f5367200070 *tools/winlibs.R 864f7b19fe1e8b5080c8f5c51d4178eb *vignettes/c_interface.Rmd systemfonts/build/0000755000176200001440000000000013506366517013763 5ustar liggesuserssystemfonts/build/vignette.rds0000644000176200001440000000032513506366517016322 0ustar liggesusersb```b`f@&0rH'g敤%&妠IW+8+)@6%$7M{E@„5/17vԂԼ?iN,/AQU▙ 7$apq2݀a>9`~AMI,F(WJbI^ZP?{gsystemfonts/DESCRIPTION0000644000176200001440000000332513506400572014363 0ustar liggesusersPackage: systemfonts Type: Package Title: System Native Font Finding Version: 0.1.1 Authors@R: c(person(given = "Thomas Lin", family = "Pedersen", role = c("aut", "cre"), email = "thomas.pedersen@rstudio.com"), person(given = "Jeroen", family = "Ooms", role = "aut", email = "jeroen@berkeley.edu", comment = c(ORCID = "0000-0002-4035-0289")), person(given = "Devon", family = "Govett", role = "aut", comment = "Author of font-manager"), person(given = "RStudio", role = "cph")) Maintainer: Thomas Lin Pedersen Description: Provides system native access to the font catalogue. As font handling varies between systems it is difficult to correctly locate installed fonts across different operating systems. The 'systemfonts' package provides bindings to the native libraries on Windows, macOS and Linux for finding font files that can then be used further by e.g. graphic devices. The main use is intended to be from compiled code but 'systemfonts' also provides access from R. License: MIT + file LICENSE Encoding: UTF-8 LazyData: true RoxygenNote: 6.1.1 Suggests: testthat (>= 2.1.0), covr, knitr, rmarkdown, tools VignetteBuilder: knitr URL: https://github.com/r-lib/systemfonts BugReports: https://github.com/r-lib/systemfonts/issues NeedsCompilation: yes Packaged: 2019-07-01 11:23:59 UTC; thomas Author: Thomas Lin Pedersen [aut, cre], Jeroen Ooms [aut] (), Devon Govett [aut] (Author of font-manager), RStudio [cph] Repository: CRAN Date/Publication: 2019-07-01 12:50:02 UTC systemfonts/configure0000755000176200001440000000525113506366517014576 0ustar liggesusers#!/bin/bash # Anticonf (tm) script by Jeroen Ooms (2019) # This script will query 'pkg-config' for the required cflags and ldflags. # If pkg-config is unavailable or does not find the library, try setting # INCLUDE_DIR and LIB_DIR manually via e.g: # R CMD INSTALL --configure-vars='INCLUDE_DIR=/.../include LIB_DIR=/.../lib' # Library settings SYS="UNIX" PKG_CONFIG_NAME="fontconfig" PKG_DEB_NAME="libfontconfig1-dev" PKG_RPM_NAME="fontconfig-devel" PKG_CSW_NAME="fontconfig_dev" PKG_BREW_NAME="freetype" PKG_TEST_HEADER="" PKG_LIBS="-lfontconfig -lfreetype" # Alternative config on MacOS for native APIs # Freetype is not actually used on MacOS right now, but will be in the future if [[ "$OSTYPE" == "darwin"* ]]; then SYS="DARWIN" PKG_CONFIG_NAME="freetype2" PKG_TEST_HEADER="" PKG_LIBS="-lfreetype" fi # Use pkg-config if available if [ $(command -v pkg-config) ]; then PKGCONFIG_CFLAGS=$(pkg-config --cflags --silence-errors ${PKG_CONFIG_NAME}) PKGCONFIG_LIBS=$(pkg-config --libs ${PKG_CONFIG_NAME}) fi # Note that cflags may be empty in case of success if [ "$INCLUDE_DIR" ] || [ "$LIB_DIR" ]; then echo "Found INCLUDE_DIR and/or LIB_DIR!" PKG_CFLAGS="-I$INCLUDE_DIR $PKG_CFLAGS" PKG_LIBS="-L$LIB_DIR $PKG_LIBS" elif [ "$PKGCONFIG_CFLAGS" ] || [ "$PKGCONFIG_LIBS" ]; then echo "Found pkg-config cflags and libs!" PKG_CFLAGS=${PKGCONFIG_CFLAGS} PKG_LIBS=${PKGCONFIG_LIBS} fi # For debugging echo "Using PKG_CFLAGS=$PKG_CFLAGS" echo "Using PKG_LIBS=$PKG_LIBS" # Find compiler CC=$(${R_HOME}/bin/R CMD config CC) CFLAGS=$(${R_HOME}/bin/R CMD config CFLAGS) CPPFLAGS=$(${R_HOME}/bin/R CMD config CPPFLAGS) # Test configuration echo "#include $PKG_TEST_HEADER" | ${CC} ${CPPFLAGS} ${PKG_CFLAGS} ${CFLAGS} -E -xc - >/dev/null # Customize the error if [ $? -ne 0 ]; then echo "------------------------- ANTICONF ERROR ---------------------------" echo "Configuration failed because $PKG_CONFIG_NAME was not found. Try installing:" echo " * deb: $PKG_DEB_NAME (Debian, Ubuntu, etc)" echo " * rpm: $PKG_RPM_NAME (Fedora, EPEL)" echo " * csw: $PKG_CSW_NAME (Solaris)" echo " * brew: $PKG_BREW_NAME (OSX)" echo "If $PKG_CONFIG_NAME is already installed, check that 'pkg-config' is in your" echo "PATH and PKG_CONFIG_PATH contains a $PKG_CONFIG_NAME.pc file. If pkg-config" echo "is unavailable you can set INCLUDE_DIR and LIB_DIR manually via:" echo "R CMD INSTALL --configure-vars='INCLUDE_DIR=... LIB_DIR=...'" echo "--------------------------------------------------------------------" exit 1; fi # Write to Makevars sed -e "s|@cflags@|$PKG_CFLAGS|" -e "s|@libs@|$PKG_LIBS|" -e "s|@SYS@|$SYS|g" src/Makevars.in > src/Makevars # Success exit 0 systemfonts/man/0000755000176200001440000000000013476161070013430 5ustar liggesuserssystemfonts/man/match_font.Rd0000644000176200001440000000177513502752115016047 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/match_font.R \name{match_font} \alias{match_font} \title{Find a system font by name and style} \usage{ match_font(family, italic = FALSE, bold = FALSE) } \arguments{ \item{family}{The name of the font family} \item{italic, bold}{logicals indicating the font style} } \value{ A list containing the path locating the font file and the 0-based index of the font in the file. } \description{ This function locates the font file (and index) best matching a name and optional style (italic/bold). A font file will be returned even if a match isn't found, but it is not necessarily similar to the requested family and it should not be relied on for font substitution. The aliases \code{"sans"}, \code{"serif"}, and \code{"mono"} match to the system default sans-serif, serif, and mono fonts respectively (\code{""} is equivalent to \code{"sans"}). } \examples{ # Get the system default sans-serif font in italic match_font('sans', italic = TRUE) } systemfonts/man/system_fonts.Rd0000644000176200001440000000066713502752115016461 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/system_fonts.R \name{system_fonts} \alias{system_fonts} \title{List all fonts installed on your system} \usage{ system_fonts() } \value{ A data frame with a row for each font and various information in each column } \description{ List all fonts installed on your system } \examples{ # See all monospace fonts fonts <- system_fonts() fonts[fonts$monospace, ] } systemfonts/man/systemfonts-package.Rd0000644000176200001440000000203213503144216017675 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/systemfonts-package.R \docType{package} \name{systemfonts-package} \alias{systemfonts} \alias{systemfonts-package} \title{systemfonts: System Native Font Finding} \description{ Provides system native access to the font catalogue. As font handling varies between systems it is difficult to correctly locate installed fonts accros different operating systems. The 'systemfonts' package provides bindings to the native libraries on Windows, macOS and Linux for finding font files that can then be used further by e.g. graphic devices. The main use is intended to be from compiled code but 'systemfonts' also provides access from R. } \author{ \strong{Maintainer}: Thomas Lin Pedersen \email{thomas.pedersen@rstudio.com} Authors: \itemize{ \item Jeroen Ooms \email{jeroen@berkeley.edu} (0000-0002-4035-0289) \item Devon Govett (Author of font-manager) } Other contributors: \itemize{ \item RStudio [copyright holder] } } \keyword{internal} systemfonts/cleanup0000755000176200001440000000003513506366517014237 0ustar liggesusers#!/bin/sh rm -f src/Makevars systemfonts/tools/0000755000176200001440000000000013502236220014003 5ustar liggesuserssystemfonts/tools/winlibs.R0000644000176200001440000000057213502236220015601 0ustar liggesusersVERSION <- commandArgs(TRUE) if(!file.exists(sprintf("../windows/cairo-%s/include/cairo/cairo.h", VERSION))){ if(getRversion() < "3.3.0") setInternet2() download.file(sprintf("https://github.com/rwinlib/cairo/archive/v%s.zip", VERSION), "lib.zip", quiet = TRUE) dir.create("../windows", showWarnings = FALSE) unzip("lib.zip", exdir = "../windows") unlink("lib.zip") } systemfonts/LICENSE0000644000176200001440000000006113475425733013667 0ustar liggesusersYEAR: 2019 COPYRIGHT HOLDER: Thomas Lin Pedersen