Cmap.vala
/*
Copyright (C) 2012, 2013, 2014 Johan Mattsson
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 3 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
*/
using Gee;
namespace BirdFont {
public class CmapTable : OtfTable {
GlyfTable glyf_table;
CmapSubtableFormat4 cmap_format4 = new CmapSubtableFormat4 ();
public CmapTable(GlyfTable gt) {
glyf_table = gt;
id = "cmap";
}
public unichar get_char (uint32 i) {
return get_prefered_table ().get_char (i) ;
}
CmapSubtableFormat4 get_prefered_table () {
return cmap_format4;
}
public override string get_id () {
return "cmap";
}
public override void parse (FontData dis) throws GLib.Error {
uint16 version;
uint16 nsubtables;
uint16 platform;
uint16 encoding;
uint32 sub_offset;
return_if_fail (offset > 0 && length > 0);
dis.seek (offset);
version = dis.read_ushort ();
nsubtables = dis.read_ushort ();
printd (@"cmap version: $version\n");
printd (@"cmap subtables: $nsubtables\n");
if (version != 0) {
warning (@"Bad version for cmap table: $version expecting 0. Number of subtables: $nsubtables");
return;
}
for (uint i = 0; i < nsubtables; i++) {
platform = dis.read_ushort ();
encoding = dis.read_ushort ();
sub_offset = dis.read_ulong ();
if (platform == 3 && encoding == 1) {
printd (@"Parsing Unicode BMP (UCS-2) Platform: $platform Encoding: $encoding\n");
cmap_format4.offset = offset + sub_offset;
} else {
stderr.printf (@"Unknown cmap format. Platform: $platform Encoding: $encoding.\n");
}
if (encoding == 3) {
stderr.printf ("Font contains a cmap table with the obsolete encoding 3.\n");
}
}
if (cmap_format4.offset > 0) {
cmap_format4.parse (dis);
} else {
warning ("No cmap subtable4 found.");
}
}
/** Character to glyph mapping */
public void process (GlyfTable glyf_table) throws GLib.Error {
FontData fd = new FontData ();
CmapSubtableFormat0 cmap0 = new CmapSubtableFormat0 ();
CmapSubtableFormat4 cmap4 = new CmapSubtableFormat4 ();
CmapSubtableFormat12 cmap12 = new CmapSubtableFormat12 ();
uint16 n_encoding_tables;
ArrayList<CmapSubtable> cmap_tables = new ArrayList<CmapSubtable> ();
cmap0.generate_cmap_data (glyf_table);
cmap4.generate_cmap_data (glyf_table);
cmap12.generate_cmap_data (glyf_table);
cmap_tables.add(cmap0);
cmap_tables.add(cmap4);
cmap_tables.add(cmap12);
n_encoding_tables = (uint16) cmap_tables.size;
fd.add_u16 (0); // table version
fd.add_u16 (n_encoding_tables);
uint subtable_offset = 4 + 8 * cmap_tables.size;
foreach (CmapSubtable subtable in cmap_tables) {
fd.add_u16 (subtable.get_platform ());
fd.add_u16 (subtable.get_encoding ());
fd.add_ulong (subtable_offset);
subtable_offset += subtable.get_cmap_data ().length ();
}
foreach (CmapSubtable subtable in cmap_tables) {
fd.append (subtable.get_cmap_data ());
}
fd.pad ();
this.font_data = fd;
}
}
/** Largest power of two less than max. */
internal static uint16 largest_pow2 (uint16 max) {
uint16 x = 1;
uint16 l = 0;
while (x <= max) {
l = x;
x = x << 1;
}
return l;
}
/** Largest exponent for a power of two less than max. */
internal static uint16 largest_pow2_exponent (uint16 max) {
uint16 exp = 0;
uint16 l = 0;
uint16 x = 0;
while (x <= max) {
l = exp;
exp++;
x = 1 << exp;
}
return l;
}
}