HmtxTable.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.
*/
namespace BirdFont {
public class HmtxTable : OtfTable {
uint32 nmetrics;
uint32 nmonospaced;
uint16* advance_width = null;
uint16* left_side_bearing = null;
uint16* left_side_bearing_monospaced = null;
public int16 max_advance = 0;
public int16 max_extent = 0;
public int16 min_lsb = int16.MAX;
public int16 min_rsb = int16.MAX;
HeadTable head_table;
GlyfTable glyf_table;
public HmtxTable (HeadTable h, GlyfTable gt) {
head_table = h;
glyf_table = gt;
id = "hmtx";
}
~HmtxTable () {
if (advance_width != null) {
delete advance_width;
}
if (left_side_bearing != null) {
delete left_side_bearing;
}
}
public double get_advance (uint32 i) {
if (i >= nmetrics) {
warning (@"i >= nmetrics $i >= $nmetrics");
return 0;
}
return_val_if_fail (advance_width != null, 0.0);
return advance_width[i] * 1000 / head_table.get_units_per_em ();
}
/** Get left side bearing relative to xmin. */
public double get_lsb (uint32 i) {
return_val_if_fail (i < nmetrics, 0.0);
return_val_if_fail (left_side_bearing != null, 0.0);
return left_side_bearing[i] * 1000 / head_table.get_units_per_em ();
}
public new void parse (FontData dis, HheaTable hhea_table, LocaTable loca_table) throws GLib.Error {
nmetrics = hhea_table.num_horizontal_metrics;
nmonospaced = loca_table.size - nmetrics;
dis.seek (offset);
if (nmetrics > loca_table.size) {
warning (@"(nmetrics > loca_table.size) ($nmetrics > $(loca_table.size))");
return;
}
printd (@"nmetrics: $nmetrics\n");
printd (@"loca_table.size: $(loca_table.size)\n");
advance_width = new uint16[nmetrics];
left_side_bearing = new uint16[nmetrics];
left_side_bearing_monospaced = new uint16[nmonospaced];
for (int i = 0; i < nmetrics; i++) {
advance_width[i] = dis.read_ushort ();
left_side_bearing[i] = dis.read_short ();
}
for (int i = 0; i < nmonospaced; i++) {
left_side_bearing_monospaced[i] = dis.read_short ();
}
}
public void process () {
FontData fd = new FontData ();
int16 advance;
int16 extent;
int16 rsb;
int16 lsb;
int16 left_guide;
int16 right_guide;
double xmin;
double xmax;
int i;
Glyph g;
if (advance_width != null) {
warning ("advance_width is set");
delete advance_width;
}
advance_width = new uint16 [glyf_table.glyphs.size];
// advance and lsb
nmetrics = 0;
i = 0;
foreach (GlyphCollection gc in glyf_table.glyphs) {
g = gc.get_current ();
return_if_fail (0 <= i < glyf_table.glyf_data.size);
GlyfData gd = glyf_table.glyf_data.get (i);
xmax = gd.bounding_box_xmax;
xmin = gd.bounding_box_xmin;
left_guide = (int16) Math.rint (g.left_limit * HeadTable.UNITS);
right_guide = (int16) Math.rint (g.right_limit * HeadTable.UNITS);
lsb = (int16) xmin;
advance = right_guide - left_guide;
extent = (int16) xmax;
rsb = (int16) Math.rint (advance - extent);
fd.add_u16 (advance);
fd.add_16 (lsb);
if (!g.is_empty_ttf ()) {
if (advance > max_advance) {
max_advance = advance;
}
if (extent > max_extent) {
max_extent = extent;
}
if (rsb < min_rsb) {
min_rsb = rsb;
}
if (lsb < min_lsb) {
min_lsb = lsb;
}
}
if (extent < 0) {
warning (@"Negative extent in $(gc.get_name ()).");
}
advance_width[nmetrics] = (uint16) extent;
nmetrics++;
i++;
}
// monospaced lsb ...
font_data = fd;
if (max_advance == 0) {
warning ("max_advance is zero");
}
}
public int16 get_average_width () {
double total_width = 0;
uint non_zero_glyphs = 0;
for (int i = 0; i < nmetrics; i++) {
if (advance_width[i] != 0) {
total_width += advance_width[i];
non_zero_glyphs++;
}
}
return (int16) Math.rint (total_width / non_zero_glyphs);
}
}
}