Index: lily/open-type-font-scheme.cc |
diff --git a/lily/open-type-font-scheme.cc b/lily/open-type-font-scheme.cc |
index 2797ac3e9e15ec5736ec38644276e2267796fe93..d69d41d8eea936b6fc438ef571707b6da7f08ddc 100644 |
--- a/lily/open-type-font-scheme.cc |
+++ b/lily/open-type-font-scheme.cc |
@@ -17,6 +17,7 @@ |
along with LilyPond. If not, see <http://www.gnu.org/licenses/>. |
*/ |
+#include <cstdio> |
#include "international.hh" |
#include "modified-font-metric.hh" |
#include "open-type-font.hh" |
@@ -218,3 +219,161 @@ LY_DEFINE (ly_has_glyph_names_p, "ly:has-glyph-names?", |
return has_glyph_names ? SCM_BOOL_T : SCM_BOOL_F; |
} |
+ |
+LY_DEFINE (ly_get_cff_offset, "ly:get-cff-offset", |
+ 1, 1, 0, (SCM font_file_name, SCM idx), |
+ "Get the offset of 'CFF' table for @var{font_file_name}," |
+ " returning it as an integer. The optional" |
+ " @var{idx} argument is useful for" |
+ " OpenType/CFF collections (OTC) only;" |
+ " it specifies the font index within the OTC." |
+ " The default value of @var{idx} is@tie{}0.") |
+{ |
+ LY_ASSERT_TYPE (scm_is_string, font_file_name, 1); |
+ |
+ int i = 0; |
+ if (!SCM_UNBNDP (idx)) |
+ { |
+ LY_ASSERT_TYPE (scm_is_integer, idx, 2); |
+ i = scm_to_int (idx); |
+ if (i < 0) |
+ { |
+ warning (_ ("font index must be non-negative, using index 0")); |
+ i = 0; |
+ } |
+ } |
+ |
+ string file_name = ly_scm2string (font_file_name); |
+ |
+ FILE *fp = fopen (file_name.c_str (), "rb"); |
+ if (!fp) |
+ { |
+ warning (_f ("cannot open font filename `%s'", file_name.c_str ())); |
+ return SCM_BOOL_F; |
+ } |
+ |
+ char buff[4]; |
+ |
+ // Read `sfnt version` (for OTF) or `TTCTag` (for OTC) |
+ if (fread (buff, 4, 1, fp) != 1) |
+ { |
+ fclose (fp); |
+ warning (_f ("cannot read %s of `%s'", "header", file_name.c_str ())); |
+ return SCM_BOOL_F; |
+ } |
+ |
+ if (buff[0] == 't' && buff[1] == 't' && buff[2] == 'c' && buff[3] == 'f') |
+ { |
+ // For OTC |
+ // Find subfont |
+ |
+ // Skip `Version` |
+ fseek (fp, 4, SEEK_CUR); |
+ |
+ // Read `numFonts` |
+ if (fread (buff, 4, 1, fp) != 1) |
+ { |
+ fclose (fp); |
+ warning (_f ("cannot read %s of `%s'", |
+ "numFonts", file_name.c_str ())); |
+ return SCM_BOOL_F; |
+ } |
+ int numfonts = |
+ static_cast<unsigned char>(buff[0]) << 24 | |
+ static_cast<unsigned char>(buff[1]) << 16 | |
+ static_cast<unsigned char>(buff[2]) << 8 | |
+ static_cast<unsigned char>(buff[3]); |
+ |
+ if ( i > numfonts ) |
+ { |
+ warning (_f ("font index %d too large for font `%s', using index 0", |
+ i, file_name.c_str ())); |
+ i = 0; |
+ } |
+ |
+ // Read `OffsetTable[i]` |
+ if (i) |
+ fseek (fp, i * 4, SEEK_CUR); |
+ if (fread (buff, 4, 1, fp) != 1) |
+ { |
+ fclose (fp); |
+ warning (_f ("cannot read %s of `%s'", |
+ "OffsetTable", file_name.c_str ())); |
+ return SCM_BOOL_F; |
+ } |
+ unsigned int offset = |
+ static_cast<unsigned char>(buff[0]) << 24 | |
+ static_cast<unsigned char>(buff[1]) << 16 | |
+ static_cast<unsigned char>(buff[2]) << 8 | |
+ static_cast<unsigned char>(buff[3]); |
+ |
+ // Seek to subfont and skip `sfnt version` |
+ fseek (fp, offset + 4, SEEK_SET); |
+ } |
+ |
+ // For OTF or subfont of OTC |
+ |
+ // Read `numTables` |
+ if (fread (buff, 2, 1, fp) != 1) |
+ { |
+ fclose (fp); |
+ warning (_f ("cannot read %s of `%s'", |
+ "numTables", file_name.c_str ())); |
+ return SCM_BOOL_F; |
+ } |
+ int numtables = |
+ static_cast<unsigned char>(buff[0]) << 8 | |
+ static_cast<unsigned char>(buff[1]); |
+ |
+ // Skip `searchRange`, `entrySelector` and `rangeShift` |
+ fseek (fp, 6, SEEK_CUR); |
+ |
+ // Read Table Records |
+ for (int t = 0; t < numtables; t++) |
+ { |
+ // Read `tag` |
+ if (fread (buff, 4, 1, fp) != 1) |
+ { |
+ fclose (fp); |
+ warning (_f ("cannot read %s of `%s'", |
+ "tag", file_name.c_str ())); |
+ return SCM_BOOL_F; |
+ } |
+ |
+ if (buff[0] == 'C' && buff[1] == 'F' && buff[2] == 'F' && buff[3] == ' ') |
+ { |
+ // CFF table is found. |
+ |
+ // Skip `checkSum` |
+ fseek (fp, 4, SEEK_CUR); |
+ |
+ // Read `offset` |
+ if (fread (buff, 4, 1, fp) != 1) |
+ { |
+ fclose (fp); |
+ warning (_f ("cannot read %s of `%s'", |
+ "CFF offset", file_name.c_str ())); |
+ return SCM_BOOL_F; |
+ } |
+ unsigned int offset = |
+ static_cast<unsigned char>(buff[0]) << 24 | |
+ static_cast<unsigned char>(buff[1]) << 16 | |
+ static_cast<unsigned char>(buff[2]) << 8 | |
+ static_cast<unsigned char>(buff[3]); |
+ |
+ // Done |
+ fclose (fp); |
+ return scm_from_unsigned_integer (offset); |
+ } |
+ |
+ // For non-CFF table |
+ |
+ // Skip `checkSum`, `offset` and `length` |
+ fseek (fp, 12, SEEK_CUR); |
+ } |
+ |
+ fclose (fp); |
+ warning (_f ("font `%s' index %d does not have `CFF' table", |
+ file_name.c_str (), i)); |
+ return SCM_BOOL_F; |
+} |